aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Schimpf <kschimpf@google.com>2013-08-14 14:57:21 -0700
committerKarl Schimpf <kschimpf@google.com>2013-08-14 14:57:21 -0700
commit1d5f6749707a8821be66ad7bad1b48ad67257110 (patch)
tree1aed5bd3e31b35a51d48b6aad4e16b0118d51693
parent1a563f0e433442f3f7aa60b636cc6a95d1c22c29 (diff)
Remove ptrtoint instructions from the PNaCl bitcode file.
Removes ptrtoint instructions when applicable (currently only in stores), and add them back just before their use. Note: This code does not handle ptrtoint casts for calls and phi nodes, binary operators, etc. because handling of casts for these instructions has not been added yet. BUG= https://code.google.com/p/nativeclient/issues/detail?id=3544 R=jvoung@chromium.org Review URL: https://codereview.chromium.org/22633002
-rw-r--r--include/llvm/Bitcode/NaCl/NaClReaderWriter.h3
-rw-r--r--lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp49
-rw-r--r--lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h19
-rw-r--r--lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp2
-rw-r--r--lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp83
-rw-r--r--lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h10
-rw-r--r--test/NaCl/Bitcode/ptrtoint-elide.ll897
7 files changed, 1046 insertions, 17 deletions
diff --git a/include/llvm/Bitcode/NaCl/NaClReaderWriter.h b/include/llvm/Bitcode/NaCl/NaClReaderWriter.h
index 1eb188a83e..d415b85de8 100644
--- a/include/llvm/Bitcode/NaCl/NaClReaderWriter.h
+++ b/include/llvm/Bitcode/NaCl/NaClReaderWriter.h
@@ -25,6 +25,9 @@ namespace llvm {
class Module;
class raw_ostream;
+ /// \brief Defines the integer bit size used to model pointers in PNaCl.
+ static const unsigned PNaClIntPtrTypeBitSize = 32;
+
/// getNaClLazyBitcodeModule - Read the header of the specified bitcode buffer
/// and prepare for lazy deserialization of function bodies. If successful,
/// this takes ownership of 'buffer' and returns a non-null pointer. On
diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp
index f9d479767b..1bbbf4516a 100644
--- a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp
+++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp
@@ -1314,6 +1314,15 @@ bool NaClBitcodeReader::InstallInstruction(
return false;
}
+Value *NaClBitcodeReader::ConvertOpToScalar(Value *Op, BasicBlock *BB) {
+ if (Op->getType()->isPointerTy()) {
+ Instruction *Conversion = new PtrToIntInst(Op, IntPtrType);
+ InstallInstruction(BB, Conversion);
+ return Conversion;
+ }
+ return Op;
+}
+
Value *NaClBitcodeReader::ConvertOpToType(Value *Op, Type *T, BasicBlock *BB) {
// Note: Currently only knows how to add inttoptr and bitcast type
// conversions for non-phi nodes, since these are the only elided
@@ -1326,7 +1335,7 @@ Value *NaClBitcodeReader::ConvertOpToType(Value *Op, Type *T, BasicBlock *BB) {
if (OpTy->isPointerTy()) {
Conversion = new BitCastInst(Op, T);
- } else if (OpTy->isIntegerTy()) {
+ } else if (OpTy == IntPtrType) {
Conversion = new IntToPtrInst(Op, T);
}
@@ -1341,6 +1350,10 @@ Value *NaClBitcodeReader::ConvertOpToType(Value *Op, Type *T, BasicBlock *BB) {
return Conversion;
}
+Type *NaClBitcodeReader::ConvertTypeToScalarType(Type *T) {
+ return T->isPointerTy() ? IntPtrType : T;
+}
+
/// ParseFunctionBody - Lazily parse the specified function body block.
bool NaClBitcodeReader::ParseFunctionBody(Function *F) {
DEBUG(dbgs() << "-> ParseFunctionBody\n");
@@ -1427,6 +1440,9 @@ bool NaClBitcodeReader::ParseFunctionBody(Function *F) {
OpNum+1 > Record.size())
return Error("Invalid BINOP record");
+ LHS = ConvertOpToScalar(LHS, CurBB);
+ RHS = ConvertOpToScalar(RHS, CurBB);
+
int Opc = GetDecodedBinaryOpcode(Record[OpNum++], LHS->getType());
if (Opc == -1) return Error("Invalid BINOP record");
I = BinaryOperator::Create((Instruction::BinaryOps)Opc, LHS, RHS);
@@ -1475,6 +1491,24 @@ bool NaClBitcodeReader::ParseFunctionBody(Function *F) {
int Opc = GetDecodedCastOpcode(Record[OpNum+1]);
if (Opc == -1 || ResTy == 0)
return Error("Invalid CAST record");
+
+ if (GetPNaClVersion() == 2) {
+ // If a ptrtoint cast was elided on the argument of the cast,
+ // add it back. Note: The casts allowed here should match the
+ // casts in NaClValueEnumerator::ExpectsScalarValue.
+ switch (Opc) {
+ case Instruction::Trunc:
+ case Instruction::ZExt:
+ case Instruction::SExt:
+ case Instruction::UIToFP:
+ case Instruction::SIToFP:
+ Op = ConvertOpToScalar(Op, CurBB);
+ break;
+ default:
+ break;
+ }
+ }
+
I = CastInst::Create((Instruction::CastOps)Opc, Op, ResTy);
break;
}
@@ -1489,6 +1523,9 @@ bool NaClBitcodeReader::ParseFunctionBody(Function *F) {
popValue(Record, &OpNum, NextValueNo, &Cond))
return Error("Invalid SELECT record");
+ TrueVal = ConvertOpToScalar(TrueVal, CurBB);
+ FalseVal = ConvertOpToScalar(FalseVal, CurBB);
+
// expect i1
if (Cond->getType() != Type::getInt1Ty(Context))
return Error("Invalid SELECT condition type");
@@ -1507,6 +1544,9 @@ bool NaClBitcodeReader::ParseFunctionBody(Function *F) {
OpNum+1 != Record.size())
return Error("Invalid CMP record");
+ LHS = ConvertOpToScalar(LHS, CurBB);
+ RHS = ConvertOpToScalar(RHS, CurBB);
+
if (LHS->getType()->isFPOrFPVectorTy())
I = new FCmpInst((FCmpInst::Predicate)Record[OpNum], LHS, RHS);
else
@@ -1612,6 +1652,9 @@ bool NaClBitcodeReader::ParseFunctionBody(Function *F) {
Type *Ty = getTypeByID(Record[0]);
if (!Ty) return Error("Invalid PHI record");
+ // TODO(kschimpf): Fix handling of converting types for values,
+ // to handle elided casts, once the bitcode writer knows how.
+
PHINode *PN = PHINode::Create(Ty, (Record.size()-1)/2);
for (unsigned i = 0, e = Record.size()-1; i != e; i += 2) {
@@ -1684,6 +1727,7 @@ bool NaClBitcodeReader::ParseFunctionBody(Function *F) {
case 2:
if (OpNum+1 != Record.size())
return Error("Invalid STORE record");
+ Val = ConvertOpToScalar(Val, CurBB);
Ptr = ConvertOpToType(Ptr, Val->getType()->getPointerTo(), CurBB);
I = new StoreInst(Val, Ptr, false, (1 << Record[OpNum]) >> 1);
break;
@@ -1695,6 +1739,9 @@ bool NaClBitcodeReader::ParseFunctionBody(Function *F) {
if (Record.size() < 2)
return Error("Invalid CALL record");
+ // TODO(kschimpf): Fix handling of type conversion to arguments for PNaCl,
+ // to handle elided casts, once the bitcode writer knows how.
+
unsigned CCInfo = Record[0];
unsigned OpNum = 1;
diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h
index 805bddf0b2..814ef44efb 100644
--- a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h
+++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h
@@ -20,6 +20,7 @@
#include "llvm/Bitcode/NaCl/NaClBitstreamReader.h"
#include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h"
#include "llvm/GVMaterializer.h"
+#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/OperandTraits.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/ValueHandle.h"
@@ -167,6 +168,9 @@ class NaClBitcodeReader : public GVMaterializer {
/// \brief True if we should only accept supported bitcode format.
bool AcceptSupportedBitcodeOnly;
+ /// \brief Integer type use for PNaCl conversion of pointers.
+ Type *IntPtrType;
+
public:
explicit NaClBitcodeReader(MemoryBuffer *buffer, LLVMContext &C,
bool AcceptSupportedOnly = true)
@@ -174,7 +178,8 @@ public:
LazyStreamer(0), NextUnreadBit(0), SeenValueSymbolTable(false),
ValueList(C),
SeenFirstFunctionBody(false), UseRelativeIDs(false),
- AcceptSupportedBitcodeOnly(AcceptSupportedOnly) {
+ AcceptSupportedBitcodeOnly(AcceptSupportedOnly),
+ IntPtrType(IntegerType::get(C, PNaClIntPtrTypeBitSize)) {
}
explicit NaClBitcodeReader(DataStreamer *streamer, LLVMContext &C,
bool AcceptSupportedOnly = true)
@@ -182,7 +187,8 @@ public:
LazyStreamer(streamer), NextUnreadBit(0), SeenValueSymbolTable(false),
ValueList(C),
SeenFirstFunctionBody(false), UseRelativeIDs(false),
- AcceptSupportedBitcodeOnly(AcceptSupportedOnly) {
+ AcceptSupportedBitcodeOnly(AcceptSupportedOnly),
+ IntPtrType(IntegerType::get(C, PNaClIntPtrTypeBitSize)) {
}
~NaClBitcodeReader() {
FreeState();
@@ -275,6 +281,15 @@ private:
/// an appropriate error message and calls Error).
Value *ConvertOpToType(Value *Op, Type *T, BasicBlock *BB);
+ /// \brief If Op is a scalar value, this is a nop. If Op is a
+ /// pointer value, a PtrToInt instruction is inserted (in BB) to
+ /// convert Op to an integer.
+ Value *ConvertOpToScalar(Value *Op, BasicBlock *BB);
+
+ /// \brief Returns the corresponding, PNaCl non-pointer equivalent
+ /// for the given type.
+ Type *ConvertTypeToScalarType(Type *T);
+
/// \brief Install instruction I into basic block BB.
bool InstallInstruction(BasicBlock *BB, Instruction *I);
diff --git a/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp b/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp
index f6b85108e6..047e0c84db 100644
--- a/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp
+++ b/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp
@@ -413,7 +413,7 @@ void WriteGlobalInit(const Constant *C, unsigned GlobalVarID,
}
return;
}
- if (C->getType()->isIntegerTy(32)) {
+ if (VE.IsIntPtrType(C->getType())) {
// This constant defines a relocation. Start by verifying the
// relocation is of the right form.
const ConstantExpr *CE = dyn_cast<ConstantExpr>(C);
diff --git a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp
index 34f4f2bbe9..bee36e2631 100644
--- a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp
+++ b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp
@@ -44,6 +44,8 @@ NaClValueEnumerator::NaClValueEnumerator(const Module *M, uint32_t PNaClVersion)
TypeCountMapType count_map;
TypeCountMap = &count_map;
+ IntPtrType = IntegerType::get(M->getContext(), PNaClIntPtrTypeBitSize);
+
// Enumerate the functions. Note: We do this before global
// variables, so that global variable initializations can refer to
// the functions without a forward reference.
@@ -429,10 +431,10 @@ void NaClValueEnumerator::purgeFunction() {
}
// Returns true if the bitcode writer can assume that the given
-// argument of the given operation can accept a normalized pointer.
+// 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 AllowsNormalizedPtr(const Value *V, const Instruction *Arg) {
+static bool ExpectsNormalizedPtr(const Value *V, const Instruction *Arg) {
const Instruction *I = dyn_cast<Instruction>(V);
if (I == 0) return false;
@@ -443,22 +445,19 @@ static bool AllowsNormalizedPtr(const Value *V, const Instruction *Arg) {
default:
return false;
case Instruction::Load:
- // Verify it is the ptr argument of the load. Note: This check is
- // not really necessary in that a load only has one argument.
return I->getOperand(0) == Arg;
case Instruction::Store:
- // Verify it is the ptr argument of the store.
return I->getOperand(1) == Arg;
}
}
// Returns true if the bitcode reader and writer can assume that the
-// uses of the given inttotpr I2P allow normalized pointers (as
+// uses of the given inttotpr I2P expect normalized pointers (as
// defined in llvm/lib/Transforms/NaCl/ReplacePtrsWithInts.cpp).
-static bool AllUsesAllowNormalizedPtr(const Instruction *I2P) {
+static bool AllUsesExpectsNormalizedPtr(const Instruction *I2P) {
for (Value::const_use_iterator u = I2P->use_begin(), e = I2P->use_end();
u != e; ++u) {
- if (!AllowsNormalizedPtr(cast<Value>(*u), I2P)) return false;
+ 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
@@ -466,6 +465,57 @@ static bool AllUsesAllowNormalizedPtr(const Instruction *I2P) {
return true;
}
+// Given Value that uses scalar value Arg, returns true if the bitcode
+// writer can assume that Value always expects Arg to be scalar. This
+// function is used to infer cases where PtrToInt casts can be
+// removed.
+static bool ExpectsScalarValue(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::Trunc:
+ case Instruction::ZExt:
+ case Instruction::SExt:
+ case Instruction::UIToFP:
+ case Instruction::SIToFP:
+ case Instruction::ICmp:
+ 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();
+ }
+ }
+ // TODO(kschimpf): Need to think more about how to handle following
+ // instructions:
+ // case Instruction::IntToPtr:
+ // case Instruction::BitCast:
+ // case Instruction::PHI:
+ // case Instruction::Call:
+ }
+}
+
+// Returns true if the bitcode reader and writer can assume that the
+// uses of the given PtrToInt expect scalar values (i.e. non-pointer),
+// and hence, we can elide the PtrToInt cast.
+static bool AllUsesExpectsScalarValue(const Instruction *I) {
+ for (Value::const_use_iterator Use = I->use_begin(), UseEnd = I->use_end();
+ Use != UseEnd; ++Use) {
+ if (!ExpectsScalarValue(*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 InherentPtr (as defined in
// llvm/lib/Transforms/NaCl/ReplacePtrsWithInts.cpp).
static inline bool IsInherentPtr(const Value *V) {
@@ -483,14 +533,21 @@ const Value *NaClValueEnumerator::ElideCasts(const Value *V) {
break;
case Instruction::BitCast:
if (I->getType()->isPointerTy() &&
- AllUsesAllowNormalizedPtr(I) &&
- IsInherentPtr(I->getOperand(0))) {
- return ElideCasts(I->getOperand(0));
+ IsInherentPtr(I->getOperand(0)) &&
+ AllUsesExpectsNormalizedPtr(I)) {
+ V = I->getOperand(0);
}
break;
case Instruction::IntToPtr:
- if (AllUsesAllowNormalizedPtr(I)) {
- return ElideCasts(I->getOperand(0));
+ if (AllUsesExpectsNormalizedPtr(I)) {
+ V = ElideCasts(I->getOperand(0));
+ }
+ break;
+ case Instruction::PtrToInt:
+ if (IsIntPtrType(I->getType()) &&
+ IsInherentPtr(I->getOperand(0)) &&
+ AllUsesExpectsScalarValue(I)) {
+ V = I->getOperand(0);
}
break;
}
diff --git a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h
index 22de263c4b..71638dd4eb 100644
--- a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h
+++ b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
#include <vector>
namespace llvm {
@@ -83,6 +84,9 @@ private:
// The version of PNaCl bitcode to generate.
uint32_t PNaClVersion;
+ /// \brief Integer type use for PNaCl conversion of pointers.
+ Type *IntPtrType;
+
NaClValueEnumerator(const NaClValueEnumerator &) LLVM_DELETED_FUNCTION;
void operator=(const NaClValueEnumerator &) LLVM_DELETED_FUNCTION;
public:
@@ -144,6 +148,12 @@ public:
return V != ElideCasts(V);
}
+ /// \brief Returns true if the type of V is the integer used to
+ /// model pointers in PNaCl.
+ bool IsIntPtrType(Type *T) const {
+ return T == IntPtrType;
+ }
+
private:
void OptimizeTypes(const Module *M);
void OptimizeConstants(unsigned CstStart, unsigned CstEnd);
diff --git a/test/NaCl/Bitcode/ptrtoint-elide.ll b/test/NaCl/Bitcode/ptrtoint-elide.ll
new file mode 100644
index 0000000000..10504a8577
--- /dev/null
+++ b/test/NaCl/Bitcode/ptrtoint-elide.ll
@@ -0,0 +1,897 @@
+; Test how we handle eliding ptrtoint instructions.
+; TODO(kschimpf) Expand these tests as further CL's are added for issue 3544.
+
+; RUN: llvm-as < %s | pnacl-freeze --pnacl-version=1 \
+; RUN: | pnacl-bcanalyzer -dump-records \
+; RUN: | FileCheck %s -check-prefix=PF1
+
+; RUN: llvm-as < %s | pnacl-freeze --pnacl-version=1 | pnacl-thaw \
+; RUN: | llvm-dis - | FileCheck %s -check-prefix=TD1
+
+; RUN: llvm-as < %s | pnacl-freeze --pnacl-version=2 \
+; RUN: | pnacl-bcanalyzer -dump-records \
+; RUN: | FileCheck %s -check-prefix=PF2
+
+; RUN: llvm-as < %s | pnacl-freeze --pnacl-version=2 | pnacl-thaw \
+; RUN: | llvm-dis - | FileCheck %s -check-prefix=TD2
+
+; ------------------------------------------------------
+
+declare i32 @bar(i32)
+
+@bytes = internal global [4 x i8] c"abcd"
+
+; ------------------------------------------------------
+
+; Show simple case where we use ptrtoint
+define void @AllocCastSimple() {
+ %1 = alloca i8, i32 4, align 8
+ %2 = ptrtoint i8* %1 to i32
+ %3 = bitcast [4 x i8]* @bytes to i32*
+ store i32 %2, i32* %3, align 1
+ ret void
+}
+
+; TD1: define void @AllocCastSimple() {
+; TD1-NEXT: %1 = alloca i8, i32 4, align 8
+; TD1-NEXT: %2 = ptrtoint i8* %1 to i32
+; TD1-NEXT: %3 = bitcast [4 x i8]* @bytes to i32*
+; TD1-NEXT: store i32 %2, i32* %3, align 1
+; TD1-NEXT: ret void
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK>
+; PF1: </CONSTANTS_BLOCK>
+; PF1-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF1-NEXT: <INST_CAST op0=1 op1=0 op2=9/>
+; PF1-NEXT: <INST_CAST op0=4 op1=4 op2=11/>
+; PF1-NEXT: <INST_STORE op0=1 op1=2 op2=1 op3=0/>
+; PF1-NEXT: <INST_RET/>
+; PF1-NEXT: </FUNCTION_BLOCK>
+
+; TD2: define void @AllocCastSimple() {
+; TD2-NEXT: %1 = alloca i8, i32 4, align 8
+; TD2-NEXT: %2 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %3 = bitcast [4 x i8]* @bytes to i32*
+; TD2-NEXT: store i32 %2, i32* %3, align 1
+; TD2-NEXT: ret void
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK>
+; PF2: </CONSTANTS_BLOCK>
+; PF2-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF2-NEXT: <INST_STORE op0=3 op1=1 op2=1/>
+; PF2-NEXT: <INST_RET/>
+; PF2-NEXT: </FUNCTION_BLOCK>
+
+; ------------------------------------------------------
+
+; Same as above, but with the cast order changed. Shows
+; that we always inject casts back in a fixed order. Hence,
+; in PNaCl version 2, the casts will be reversed.
+define void @AllocCastSimpleReversed() {
+ %1 = alloca i8, i32 4, align 8
+ %2 = bitcast [4 x i8]* @bytes to i32*
+ %3 = ptrtoint i8* %1 to i32
+ store i32 %3, i32* %2, align 1
+ ret void
+}
+
+; TD1: define void @AllocCastSimpleReversed() {
+; TD1-NEXT: %1 = alloca i8, i32 4, align 8
+; TD1-NEXT: %2 = bitcast [4 x i8]* @bytes to i32*
+; TD1-NEXT: %3 = ptrtoint i8* %1 to i32
+; TD1-NEXT: store i32 %3, i32* %2, align 1
+; TD1-NEXT: ret void
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK>
+; PF1: </CONSTANTS_BLOCK>
+; PF1-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF1-NEXT: <INST_CAST op0=3 op1=4 op2=11/>
+; PF1-NEXT: <INST_CAST op0=2 op1=0 op2=9/>
+; PF1-NEXT: <INST_STORE op0=2 op1=1 op2=1 op3=0/>
+; PF1-NEXT: <INST_RET/>
+; PF1-NEXT: </FUNCTION_BLOCK>
+
+; TD2: define void @AllocCastSimpleReversed() {
+; TD2-NEXT: %1 = alloca i8, i32 4, align 8
+; TD2-NEXT: %2 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %3 = bitcast [4 x i8]* @bytes to i32*
+; TD2-NEXT: store i32 %2, i32* %3, align 1
+; TD2-NEXT: ret void
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK>
+; PF2: </CONSTANTS_BLOCK>
+; PF2-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF2-NEXT: <INST_STORE op0=3 op1=1 op2=1/>
+; PF2-NEXT: <INST_RET/>
+; PF2-NEXT: </FUNCTION_BLOCK>
+
+; ------------------------------------------------------
+
+; Show case where we delete ptrtoint because they aren't used.
+define void @AllocCastDelete() {
+ %1 = alloca i8, i32 4, align 8
+ %2 = ptrtoint i8* %1 to i32
+ %3 = alloca i8, i32 4, align 8
+ %4 = ptrtoint i8* %3 to i32
+ ret void
+}
+
+; TD1: define void @AllocCastDelete() {
+; TD1-NEXT: %1 = alloca i8, i32 4, align 8
+; TD1-NEXT: %2 = ptrtoint i8* %1 to i32
+; TD1-NEXT: %3 = alloca i8, i32 4, align 8
+; TD1-NEXT: %4 = ptrtoint i8* %3 to i32
+; TD1-NEXT: ret void
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK>
+; PF1: </CONSTANTS_BLOCK>
+; PF1-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF1-NEXT: <INST_CAST op0=1 op1=0 op2=9/>
+; PF1-NEXT: <INST_ALLOCA op0=3 op1=4/>
+; PF1-NEXT: <INST_CAST op0=1 op1=0 op2=9/>
+; PF1-NEXT: <INST_RET/>
+; PF1-NEXT: </FUNCTION_BLOCK>
+
+; TD2: define void @AllocCastDelete() {
+; TD2-NEXT: %1 = alloca i8, i32 4, align 8
+; TD2-NEXT: %2 = alloca i8, i32 4, align 8
+; TD2-NEXT: ret void
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK>
+; PF2: </CONSTANTS_BLOCK>
+; PF2-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF2-NEXT: <INST_ALLOCA op0=2 op1=4/>
+; PF2-NEXT: <INST_RET/>
+; PF2-NEXT: </FUNCTION_BLOCK>
+
+; ------------------------------------------------------
+
+; Show case where we have optimized the ptrtoint (and bitcast) into a
+; single instruction, but will get duplicated after reading back the
+; bitcode file, since we insert elided casts immediately before each use.
+define void @AllocCastOpt() {
+ %1 = alloca i8, i32 4, align 8
+ %2 = bitcast [4 x i8]* @bytes to i32*
+ %3 = ptrtoint i8* %1 to i32
+ store i32 %3, i32* %2, align 1
+ store i32 %3, i32* %2, align 1
+ ret void
+}
+
+; TD1: define void @AllocCastOpt() {
+; TD1-NEXT: %1 = alloca i8, i32 4, align 8
+; TD1-NEXT: %2 = bitcast [4 x i8]* @bytes to i32*
+; TD1-NEXT: %3 = ptrtoint i8* %1 to i32
+; TD1-NEXT: store i32 %3, i32* %2, align 1
+; TD1-NEXT: store i32 %3, i32* %2, align 1
+; TD1-NEXT: ret void
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK>
+; PF1: </CONSTANTS_BLOCK>
+; PF1-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF1-NEXT: <INST_CAST op0=3 op1=4 op2=11/>
+; PF1-NEXT: <INST_CAST op0=2 op1=0 op2=9/>
+; PF1-NEXT: <INST_STORE op0=2 op1=1 op2=1 op3=0/>
+; PF1-NEXT: <INST_STORE op0=2 op1=1 op2=1 op3=0/>
+; PF1-NEXT: <INST_RET/>
+; PF1-NEXT: </FUNCTION_BLOCK>
+
+; TD2: define void @AllocCastOpt() {
+; TD2-NEXT: %1 = alloca i8, i32 4, align 8
+; TD2-NEXT: %2 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %3 = bitcast [4 x i8]* @bytes to i32*
+; TD2-NEXT: store i32 %2, i32* %3, align 1
+; TD2-NEXT: %4 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %5 = bitcast [4 x i8]* @bytes to i32*
+; TD2-NEXT: store i32 %4, i32* %5, align 1
+; TD2-NEXT: ret void
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK>
+; PF2: </CONSTANTS_BLOCK>
+; PF2-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF2-NEXT: <INST_STORE op0=3 op1=1 op2=1/>
+; PF2-NEXT: <INST_STORE op0=3 op1=1 op2=1/>
+; PF2-NEXT: <INST_RET/>
+; PF2-NEXT: </FUNCTION_BLOCK>
+
+; ------------------------------------------------------
+
+; Show case where ptrtoint (and bitcast) for store are not immediately
+; before the store, the casts will be moved to the store.
+define void @AllocCastMove(i32) {
+ %2 = alloca i8, i32 4, align 8
+ %3 = bitcast [4 x i8]* @bytes to i32*
+ %4 = ptrtoint i8* %2 to i32
+ %5 = add i32 %0, 1
+ store i32 %4, i32* %3, align 1
+ ret void
+}
+
+; TD1: define void @AllocCastMove(i32) {
+; TD1-NEXT: %2 = alloca i8, i32 4, align 8
+; TD1-NEXT: %3 = bitcast [4 x i8]* @bytes to i32*
+; TD1-NEXT: %4 = ptrtoint i8* %2 to i32
+; TD1-NEXT: %5 = add i32 %0, 1
+; TD1-NEXT: store i32 %4, i32* %3, align 1
+; TD1-NEXT: ret void
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK>
+; PF1: </CONSTANTS_BLOCK>
+; PF1-NEXT: <INST_ALLOCA op0=2 op1=4/>
+; PF1-NEXT: <INST_CAST op0=5 op1=4 op2=11/>
+; PF1-NEXT: <INST_CAST op0=2 op1=0 op2=9/>
+; PF1-NEXT: <INST_BINOP op0=6 op1=4 op2=0/>
+; PF1-NEXT: <INST_STORE op0=3 op1=2 op2=1 op3=0/>
+; PF1-NEXT: <INST_RET/>
+; PF1-NEXT: </FUNCTION_BLOCK>
+
+; TD2: define void @AllocCastMove(i32) {
+; TD2-NEXT: %2 = alloca i8, i32 4, align 8
+; TD2-NEXT: %3 = add i32 %0, 1
+; TD2-NEXT: %4 = ptrtoint i8* %2 to i32
+; TD2-NEXT: %5 = bitcast [4 x i8]* @bytes to i32*
+; TD2-NEXT: store i32 %4, i32* %5, align 1
+; TD2-NEXT: ret void
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK>
+; PF2: </CONSTANTS_BLOCK>
+; PF2-NEXT: <INST_ALLOCA op0=2 op1=4/>
+; PF2-NEXT: <INST_BINOP op0=4 op1=2 op2=0/>
+; PF2-NEXT: <INST_STORE op0=6 op1=2 op2=1/>
+; PF2-NEXT: <INST_RET/>
+; PF2-NEXT: </FUNCTION_BLOCK>
+
+; ------------------------------------------------------
+
+; Show case where ptrtoint on global variable is merged in a store, and
+; order is kept.
+define void @StoreGlobal() {
+ %1 = alloca i8, i32 4, align 8
+ %2 = ptrtoint [4 x i8]* @bytes to i32
+ %3 = bitcast i8* %1 to i32*
+ store i32 %2, i32* %3, align 1
+ ret void
+}
+
+; TD1: define void @StoreGlobal() {
+; TD1-NEXT: %1 = alloca i8, i32 4, align 8
+; TD1-NEXT: %2 = ptrtoint [4 x i8]* @bytes to i32
+; TD1-NEXT: %3 = bitcast i8* %1 to i32*
+; TD1-NEXT: store i32 %2, i32* %3, align 1
+; TD1-NEXT: ret void
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK>
+; PF1: </CONSTANTS_BLOCK>
+; PF1-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF1-NEXT: <INST_CAST op0=3 op1=0 op2=9/>
+; PF1-NEXT: <INST_CAST op0=2 op1=4 op2=11/>
+; PF1-NEXT: <INST_STORE op0=1 op1=2 op2=1 op3=0/>
+; PF1-NEXT: <INST_RET/>
+; PF1-NEXT: </FUNCTION_BLOCK>
+
+; TD2: define void @StoreGlobal() {
+; TD2-NEXT: %1 = alloca i8, i32 4, align 8
+; TD2-NEXT: %2 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %3 = bitcast i8* %1 to i32*
+; TD2-NEXT: store i32 %2, i32* %3, align 1
+; TD2-NEXT: ret void
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK>
+; PF2: </CONSTANTS_BLOCK>
+; PF2-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF2-NEXT: <INST_STORE op0=1 op1=3 op2=1/>
+; PF2-NEXT: <INST_RET/>
+; PF2-NEXT: </FUNCTION_BLOCK>
+
+; ------------------------------------------------------
+
+; Same as above, but with cast order reversed.
+define void @StoreGlobalCastsReversed() {
+ %1 = alloca i8, i32 4, align 8
+ %2 = bitcast i8* %1 to i32*
+ %3 = ptrtoint [4 x i8]* @bytes to i32
+ store i32 %3, i32* %2, align 1
+ ret void
+}
+
+; TD1: define void @StoreGlobalCastsReversed() {
+; TD1-NEXT: %1 = alloca i8, i32 4, align 8
+; TD1-NEXT: %2 = bitcast i8* %1 to i32*
+; TD1-NEXT: %3 = ptrtoint [4 x i8]* @bytes to i32
+; TD1-NEXT: store i32 %3, i32* %2, align 1
+; TD1-NEXT: ret void
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK>
+; PF1: </CONSTANTS_BLOCK>
+; PF1-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF1-NEXT: <INST_CAST op0=1 op1=4 op2=11/>
+; PF1-NEXT: <INST_CAST op0=4 op1=0 op2=9/>
+; PF1-NEXT: <INST_STORE op0=2 op1=1 op2=1 op3=0/>
+; PF1-NEXT: <INST_RET/>
+; PF1-NEXT: </FUNCTION_BLOCK>
+
+; TD2: define void @StoreGlobalCastsReversed() {
+; TD2-NEXT: %1 = alloca i8, i32 4, align 8
+; TD2-NEXT: %2 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %3 = bitcast i8* %1 to i32*
+; TD2-NEXT: store i32 %2, i32* %3, align 1
+; TD2-NEXT: ret void
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK>
+; PF2: </CONSTANTS_BLOCK>
+; PF2-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF2-NEXT: <INST_STORE op0=1 op1=3 op2=1/>
+; PF2-NEXT: <INST_RET/>
+; PF2-NEXT: </FUNCTION_BLOCK>
+
+; ------------------------------------------------------
+
+; Show that we will move the ptrtoint of a global to the use.
+define i32 @StoreGlobalMovePtr2Int() {
+ %1 = ptrtoint [4 x i8]* @bytes to i32
+ %2 = alloca i8, i32 4, align 8
+ %3 = bitcast i8* %2 to i32*
+ store i32 %1, i32* %3, align 1
+ ret i32 0
+}
+
+; TD1: define i32 @StoreGlobalMovePtr2Int() {
+; TD1-NEXT: %1 = ptrtoint [4 x i8]* @bytes to i32
+; TD1-NEXT: %2 = alloca i8, i32 4, align 8
+; TD1-NEXT: %3 = bitcast i8* %2 to i32*
+; TD1-NEXT: store i32 %1, i32* %3, align 1
+; TD1-NEXT: ret i32 0
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK>
+; PF1: </CONSTANTS_BLOCK>
+; PF1-NEXT: <INST_CAST op0=3 op1=0 op2=9/>
+; PF1-NEXT: <INST_ALLOCA op0=3 op1=4/>
+; PF1-NEXT: <INST_CAST op0=1 op1=4 op2=11/>
+; PF1-NEXT: <INST_STORE op0=1 op1=3 op2=1 op3=0/>
+; PF1-NEXT: <INST_RET op0=4/>
+; PF1-NEXT: </FUNCTION_BLOCK>
+
+
+; TD2: define i32 @StoreGlobalMovePtr2Int() {
+; TD2-NEXT: %1 = alloca i8, i32 4, align 8
+; TD2-NEXT: %2 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %3 = bitcast i8* %1 to i32*
+; TD2-NEXT: store i32 %2, i32* %3, align 1
+; TD2-NEXT: ret i32 0
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK>
+; PF2: </CONSTANTS_BLOCK>
+; PF2-NEXT: <INST_ALLOCA op0=2 op1=4/>
+; PF2-NEXT: <INST_STORE op0=1 op1=4 op2=1/>
+; PF2-NEXT: <INST_RET op0=2/>
+; PF2-NEXT: </FUNCTION_BLOCK>
+
+; ------------------------------------------------------
+
+; Show that we handle add instructions with pointer casts.
+define void @CastAddAlloca() {
+ %1 = alloca i8, i32 4, align 8
+ %2 = ptrtoint i8* %1 to i32
+
+ ; Simple add.
+ %3 = add i32 1, 2
+
+ ; Cast first.
+ %4 = add i32 %2, 2
+
+ ; Cast second.
+ %5 = add i32 1, %2
+
+ ; Cast both.
+ %6 = add i32 %2, %2
+
+ ret void
+}
+
+; TD1: define void @CastAddAlloca() {
+; TD1-NEXT: %1 = alloca i8, i32 4, align 8
+; TD1-NEXT: %2 = ptrtoint i8* %1 to i32
+; TD1-NEXT: %3 = add i32 1, 2
+; TD1-NEXT: %4 = add i32 %2, 2
+; TD1-NEXT: %5 = add i32 1, %2
+; TD1-NEXT: %6 = add i32 %2, %2
+; TD1-NEXT: ret void
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK>
+; PF1: </CONSTANTS_BLOCK>
+; PF1-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF1-NEXT: <INST_CAST op0=1 op1=0 op2=9/>
+; PF1-NEXT: <INST_BINOP op0=5 op1=4 op2=0/>
+; PF1-NEXT: <INST_BINOP op0=2 op1=5 op2=0/>
+; PF1-NEXT: <INST_BINOP op0=7 op1=3 op2=0/>
+; PF1-NEXT: <INST_BINOP op0=4 op1=4 op2=0/>
+; PF1-NEXT: <INST_RET/>
+; PF1-NEXT: </FUNCTION_BLOCK>
+
+; TD2: define void @CastAddAlloca() {
+; TD2-NEXT: %1 = alloca i8, i32 4, align 8
+; TD2-NEXT: %2 = add i32 1, 2
+; TD2-NEXT: %3 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %4 = add i32 %3, 2
+; TD2-NEXT: %5 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %6 = add i32 1, %5
+; TD2-NEXT: %7 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %8 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %9 = add i32 %7, %8
+; TD2-NEXT: ret void
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK>
+; PF2: </CONSTANTS_BLOCK>
+; PF2-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF2-NEXT: <INST_BINOP op0=4 op1=3 op2=0/>
+; PF2-NEXT: <INST_BINOP op0=2 op1=4 op2=0/>
+; PF2-NEXT: <INST_BINOP op0=6 op1=3 op2=0/>
+; PF2-NEXT: <INST_BINOP op0=4 op1=4 op2=0/>
+; PF2-NEXT: <INST_RET/>
+; PF2-NEXT: </FUNCTION_BLOCK>
+
+; ------------------------------------------------------
+
+; Show that we handle add instructions with pointer casts.
+define void @CastAddGlobal() {
+ %1 = ptrtoint [4 x i8]* @bytes to i32
+
+ ; Simple Add.
+ %2 = add i32 1, 2
+
+ ; Cast first.
+ %3 = add i32 %1, 2
+
+ ; Cast Second.
+ %4 = add i32 1, %1
+
+ ; Cast both.
+ %5 = add i32 %1, %1
+ ret void
+}
+
+; TD1: define void @CastAddGlobal() {
+; TD1-NEXT: %1 = ptrtoint [4 x i8]* @bytes to i32
+; TD1-NEXT: %2 = add i32 1, 2
+; TD1-NEXT: %3 = add i32 %1, 2
+; TD1-NEXT: %4 = add i32 1, %1
+; TD1-NEXT: %5 = add i32 %1, %1
+; TD1-NEXT: ret void
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK>
+; PF1: </CONSTANTS_BLOCK>
+; PF1-NEXT: <INST_CAST op0=3 op1=0 op2=9/>
+; PF1-NEXT: <INST_BINOP op0=3 op1=2 op2=0/>
+; PF1-NEXT: <INST_BINOP op0=2 op1=3 op2=0/>
+; PF1-NEXT: <INST_BINOP op0=5 op1=3 op2=0/>
+; PF1-NEXT: <INST_BINOP op0=4 op1=4 op2=0/>
+; PF1-NEXT: <INST_RET/>
+; PF1-NEXT: </FUNCTION_BLOCK>
+
+; TD2: define void @CastAddGlobal() {
+; TD2-NEXT: %1 = add i32 1, 2
+; TD2-NEXT: %2 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %3 = add i32 %2, 2
+; TD2-NEXT: %4 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %5 = add i32 1, %4
+; TD2-NEXT: %6 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %7 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %8 = add i32 %6, %7
+; TD2-NEXT: ret void
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK>
+; PF2: </CONSTANTS_BLOCK>
+; PF2-NEXT: <INST_BINOP op0=2 op1=1 op2=0/>
+; PF2-NEXT: <INST_BINOP op0=4 op1=2 op2=0/>
+; PF2-NEXT: <INST_BINOP op0=4 op1=5 op2=0/>
+; PF2-NEXT: <INST_BINOP op0=6 op1=6 op2=0/>
+; PF2-NEXT: <INST_RET/>
+; PF2-NEXT: </FUNCTION_BLOCK>
+
+; ------------------------------------------------------
+
+; Show that we can handle pointer conversions for other scalar binary operators.
+define void @CastBinop() {
+ %1 = alloca i8, i32 4, align 8
+ %2 = ptrtoint i8* %1 to i32
+ %3 = ptrtoint [4 x i8]* @bytes to i32
+ %4 = sub i32 %2, %3
+ %5 = mul i32 %2, %3
+ %6 = udiv i32 %2, %3
+ %7 = urem i32 %2, %3
+ %8 = srem i32 %2, %3
+ %9 = shl i32 %2, %3
+ %10 = lshr i32 %2, %3
+ %11 = ashr i32 %2, %3
+ %12 = and i32 %2, %3
+ %13 = or i32 %2, %3
+ %14 = xor i32 %2, %3
+ ret void
+}
+
+; TD1: define void @CastBinop() {
+; TD1-NEXT: %1 = alloca i8, i32 4, align 8
+; TD1-NEXT: %2 = ptrtoint i8* %1 to i32
+; TD1-NEXT: %3 = ptrtoint [4 x i8]* @bytes to i32
+; TD1-NEXT: %4 = sub i32 %2, %3
+; TD1-NEXT: %5 = mul i32 %2, %3
+; TD1-NEXT: %6 = udiv i32 %2, %3
+; TD1-NEXT: %7 = urem i32 %2, %3
+; TD1-NEXT: %8 = srem i32 %2, %3
+; TD1-NEXT: %9 = shl i32 %2, %3
+; TD1-NEXT: %10 = lshr i32 %2, %3
+; TD1-NEXT: %11 = ashr i32 %2, %3
+; TD1-NEXT: %12 = and i32 %2, %3
+; TD1-NEXT: %13 = or i32 %2, %3
+; TD1-NEXT: %14 = xor i32 %2, %3
+; TD1-NEXT: ret void
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK>
+; PF1: </CONSTANTS_BLOCK>
+; PF1-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF1-NEXT: <INST_CAST op0=1 op1=0 op2=9/>
+; PF1-NEXT: <INST_CAST op0=4 op1=0 op2=9/>
+; PF1-NEXT: <INST_BINOP op0=2 op1=1 op2=1/>
+; PF1-NEXT: <INST_BINOP op0=3 op1=2 op2=2/>
+; PF1-NEXT: <INST_BINOP op0=4 op1=3 op2=3/>
+; PF1-NEXT: <INST_BINOP op0=5 op1=4 op2=5/>
+; PF1-NEXT: <INST_BINOP op0=6 op1=5 op2=6/>
+; PF1-NEXT: <INST_BINOP op0=7 op1=6 op2=7/>
+; PF1-NEXT: <INST_BINOP op0=8 op1=7 op2=8/>
+; PF1-NEXT: <INST_BINOP op0=9 op1=8 op2=9/>
+; PF1-NEXT: <INST_BINOP op0=10 op1=9 op2=10/>
+; PF1-NEXT: <INST_BINOP op0=11 op1=10 op2=11/>
+; PF1-NEXT: <INST_BINOP op0=12 op1=11 op2=12/>
+; PF1-NEXT: <INST_RET/>
+; PF1-NEXT: </FUNCTION_BLOCK>
+
+; TD2: define void @CastBinop() {
+; TD2-NEXT: %1 = alloca i8, i32 4, align 8
+; TD2-NEXT: %2 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %3 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %4 = sub i32 %2, %3
+; TD2-NEXT: %5 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %6 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %7 = mul i32 %5, %6
+; TD2-NEXT: %8 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %9 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %10 = udiv i32 %8, %9
+; TD2-NEXT: %11 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %12 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %13 = urem i32 %11, %12
+; TD2-NEXT: %14 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %15 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %16 = srem i32 %14, %15
+; TD2-NEXT: %17 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %18 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %19 = shl i32 %17, %18
+; TD2-NEXT: %20 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %21 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %22 = lshr i32 %20, %21
+; TD2-NEXT: %23 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %24 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %25 = ashr i32 %23, %24
+; TD2-NEXT: %26 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %27 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %28 = and i32 %26, %27
+; TD2-NEXT: %29 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %30 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %31 = or i32 %29, %30
+; TD2-NEXT: %32 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %33 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %34 = xor i32 %32, %33
+; TD2-NEXT: ret void
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK>
+; PF2: </CONSTANTS_BLOCK>
+; PF2-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF2-NEXT: <INST_BINOP op0=1 op1=3 op2=1/>
+; PF2-NEXT: <INST_BINOP op0=2 op1=4 op2=2/>
+; PF2-NEXT: <INST_BINOP op0=3 op1=5 op2=3/>
+; PF2-NEXT: <INST_BINOP op0=4 op1=6 op2=5/>
+; PF2-NEXT: <INST_BINOP op0=5 op1=7 op2=6/>
+; PF2-NEXT: <INST_BINOP op0=6 op1=8 op2=7/>
+; PF2-NEXT: <INST_BINOP op0=7 op1=9 op2=8/>
+; PF2-NEXT: <INST_BINOP op0=8 op1=10 op2=9/>
+; PF2-NEXT: <INST_BINOP op0=9 op1=11 op2=10/>
+; PF2-NEXT: <INST_BINOP op0=10 op1=12 op2=11/>
+; PF2-NEXT: <INST_BINOP op0=11 op1=13 op2=12/>
+; PF2-NEXT: <INST_RET/>
+; PF2-NEXT: </FUNCTION_BLOCK>
+
+; ------------------------------------------------------
+
+; Show that we handle (non-special) bitcasts by converting pointer
+; casts to integer.
+define void @TestCasts() {
+ %1 = alloca i8, i32 4, align 8
+ %2 = ptrtoint i8* %1 to i32
+
+ %3 = trunc i32 257 to i8
+ %4 = trunc i32 %2 to i8
+
+ %5 = zext i32 257 to i64
+ %6 = zext i32 %2 to i64
+
+ %7 = sext i32 -1 to i64
+ %8 = sext i32 %2 to i64
+
+ %9 = uitofp i32 1 to float
+ %10 = uitofp i32 %2 to float
+
+ %11 = sitofp i32 -1 to float
+ %12 = sitofp i32 %2 to float
+ ret void
+}
+
+; TD1: define void @TestCasts() {
+; TD1-NEXT: %1 = alloca i8, i32 4, align 8
+; TD1-NEXT: %2 = ptrtoint i8* %1 to i32
+; TD1-NEXT: %3 = trunc i32 257 to i8
+; TD1-NEXT: %4 = trunc i32 %2 to i8
+; TD1-NEXT: %5 = zext i32 257 to i64
+; TD1-NEXT: %6 = zext i32 %2 to i64
+; TD1-NEXT: %7 = sext i32 -1 to i64
+; TD1-NEXT: %8 = sext i32 %2 to i64
+; TD1-NEXT: %9 = uitofp i32 1 to float
+; TD1-NEXT: %10 = uitofp i32 %2 to float
+; TD1-NEXT: %11 = sitofp i32 -1 to float
+; TD1-NEXT: %12 = sitofp i32 %2 to float
+; TD1-NEXT: ret void
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK>
+; PF1: </CONSTANTS_BLOCK>
+; PF1-NEXT: <INST_ALLOCA op0=2 op1=4/>
+; PF1-NEXT: <INST_CAST op0=1 op1=0 op2=9/>
+; PF1-NEXT: <INST_CAST op0=6 op1=1 op2=0/>
+; PF1-NEXT: <INST_CAST op0=2 op1=1 op2=0/>
+; PF1-NEXT: <INST_CAST op0=8 op1=10 op2=1/>
+; PF1-NEXT: <INST_CAST op0=4 op1=10 op2=1/>
+; PF1-NEXT: <INST_CAST op0=9 op1=10 op2=2/>
+; PF1-NEXT: <INST_CAST op0=6 op1=10 op2=2/>
+; PF1-NEXT: <INST_CAST op0=9 op1=11 op2=5/>
+; PF1-NEXT: <INST_CAST op0=8 op1=11 op2=5/>
+; PF1-NEXT: <INST_CAST op0=13 op1=11 op2=6/>
+; PF1-NEXT: <INST_CAST op0=10 op1=11 op2=6/>
+; PF1-NEXT: <INST_RET/>
+; PF1-NEXT: </FUNCTION_BLOCK>
+
+; TD2: define void @TestCasts() {
+; TD2-NEXT: %1 = alloca i8, i32 4, align 8
+; TD2-NEXT: %2 = trunc i32 257 to i8
+; TD2-NEXT: %3 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %4 = trunc i32 %3 to i8
+; TD2-NEXT: %5 = zext i32 257 to i64
+; TD2-NEXT: %6 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %7 = zext i32 %6 to i64
+; TD2-NEXT: %8 = sext i32 -1 to i64
+; TD2-NEXT: %9 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %10 = sext i32 %9 to i64
+; TD2-NEXT: %11 = uitofp i32 1 to float
+; TD2-NEXT: %12 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %13 = uitofp i32 %12 to float
+; TD2-NEXT: %14 = sitofp i32 -1 to float
+; TD2-NEXT: %15 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %16 = sitofp i32 %15 to float
+; TD2-NEXT: ret void
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK>
+; PF2: </CONSTANTS_BLOCK>
+; PF2-NEXT: <INST_ALLOCA op0=2 op1=4/>
+; PF2-NEXT: <INST_CAST op0=5 op1=1 op2=0/>
+; PF2-NEXT: <INST_CAST op0=2 op1=1 op2=0/>
+; PF2-NEXT: <INST_CAST op0=7 op1=10 op2=1/>
+; PF2-NEXT: <INST_CAST op0=4 op1=10 op2=1/>
+; PF2-NEXT: <INST_CAST op0=8 op1=10 op2=2/>
+; PF2-NEXT: <INST_CAST op0=6 op1=10 op2=2/>
+; PF2-NEXT: <INST_CAST op0=8 op1=11 op2=5/>
+; PF2-NEXT: <INST_CAST op0=8 op1=11 op2=5/>
+; PF2-NEXT: <INST_CAST op0=12 op1=11 op2=6/>
+; PF2-NEXT: <INST_CAST op0=10 op1=11 op2=6/>
+; PF2-NEXT: <INST_RET/>
+; PF2-NEXT: </FUNCTION_BLOCK>
+
+; ------------------------------------------------------
+
+; Show that if a ptrtoint is used in something other than known scalar operations,
+; it gets copied to the bitcode file
+; TODO(kschimpf): Remove this once all scalar operations have been handled.
+define void @TestSavedPtrToInt() {
+ %1 = alloca i8, i32 4, align 8
+ %2 = ptrtoint i8* %1 to i32
+ %3 = add i32 %2, 0
+ %4 = call i32 @bar(i32 %2)
+ ret void
+}
+
+; TD1: define void @TestSavedPtrToInt() {
+; TD1-NEXT: %1 = alloca i8, i32 4, align 8
+; TD1-NEXT: %2 = ptrtoint i8* %1 to i32
+; TD1-NEXT: %3 = add i32 %2, 0
+; TD1-NEXT: %4 = call i32 @bar(i32 %2)
+; TD1-NEXT: ret void
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK>
+; PF1: </CONSTANTS_BLOCK>
+; PF1-NEXT: <INST_ALLOCA op0=2 op1=4/>
+; PF1-NEXT: <INST_CAST op0=1 op1=0 op2=9/>
+; PF1-NEXT: <INST_BINOP op0=1 op1=3 op2=0/>
+; PF1-NEXT: <INST_CALL op0=0 op1=22 op2=2/>
+; PF1-NEXT: <INST_RET/>
+; PF1-NEXT: </FUNCTION_BLOCK>
+
+; TD2: define void @TestSavedPtrToInt() {
+; TD2-NEXT: %1 = alloca i8, i32 4, align 8
+; TD2-NEXT: %2 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %3 = add i32 %2, 0
+; TD2-NEXT: %4 = call i32 @bar(i32 %2)
+; TD2-NEXT: ret void
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK>
+; PF2: </CONSTANTS_BLOCK>
+; PF2-NEXT: <INST_ALLOCA op0=2 op1=4/>
+; PF2-NEXT: <INST_CAST op0=1 op1=0 op2=9/>
+; PF2-NEXT: <INST_BINOP op0=1 op1=3 op2=0/>
+; PF2-NEXT: <INST_CALL op0=0 op1=22 op2=2/>
+; PF2-NEXT: <INST_RET/>
+; PF2-NEXT: </FUNCTION_BLOCK>
+
+; ------------------------------------------------------
+
+; Show that we can handle pointer conversions for icmp.
+define void @CastIcmp() {
+ %1 = alloca i8, i32 4, align 8
+ %2 = ptrtoint i8* %1 to i32
+ %3 = ptrtoint [4 x i8]* @bytes to i32
+ %4 = icmp eq i32 1, 2
+ %5 = icmp eq i32 %2, 2
+ %6 = icmp eq i32 1, %3
+ %7 = icmp eq i32 %2, %3
+ %8 = icmp eq i32 %3, %2
+ ret void
+}
+
+; TD1: define void @CastIcmp() {
+; TD1-NEXT: %1 = alloca i8, i32 4, align 8
+; TD1-NEXT: %2 = ptrtoint i8* %1 to i32
+; TD1-NEXT: %3 = ptrtoint [4 x i8]* @bytes to i32
+; TD1-NEXT: %4 = icmp eq i32 1, 2
+; TD1-NEXT: %5 = icmp eq i32 %2, 2
+; TD1-NEXT: %6 = icmp eq i32 1, %3
+; TD1-NEXT: %7 = icmp eq i32 %2, %3
+; TD1-NEXT: %8 = icmp eq i32 %3, %2
+; TD1-NEXT: ret void
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK>
+; PF1: </CONSTANTS_BLOCK>
+; PF1-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF1-NEXT: <INST_CAST op0=1 op1=0 op2=9/>
+; PF1-NEXT: <INST_CAST op0=6 op1=0 op2=9/>
+; PF1-NEXT: <INST_CMP2 op0=6 op1=5 op2=32/>
+; PF1-NEXT: <INST_CMP2 op0=3 op1=6 op2=32/>
+; PF1-NEXT: <INST_CMP2 op0=8 op1=3 op2=32/>
+; PF1-NEXT: <INST_CMP2 op0=5 op1=4 op2=32/>
+; PF1-NEXT: <INST_CMP2 op0=5 op1=6 op2=32/>
+; PF1-NEXT: <INST_RET/>
+; PF1-NEXT: </FUNCTION_BLOCK>
+
+; TD2: define void @CastIcmp() {
+; TD2-NEXT: %1 = alloca i8, i32 4, align 8
+; TD2-NEXT: %2 = icmp eq i32 1, 2
+; TD2-NEXT: %3 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %4 = icmp eq i32 %3, 2
+; TD2-NEXT: %5 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %6 = icmp eq i32 1, %5
+; TD2-NEXT: %7 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %8 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %9 = icmp eq i32 %7, %8
+; TD2-NEXT: %10 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %11 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %12 = icmp eq i32 %10, %11
+; TD2-NEXT: ret void
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK>
+; PF2: </CONSTANTS_BLOCK>
+; PF2-NEXT: <INST_ALLOCA op0=1 op1=4/>
+; PF2-NEXT: <INST_CMP2 op0=4 op1=3 op2=32/>
+; PF2-NEXT: <INST_CMP2 op0=2 op1=4 op2=32/>
+; PF2-NEXT: <INST_CMP2 op0=6 op1=7 op2=32/>
+; PF2-NEXT: <INST_CMP2 op0=4 op1=8 op2=32/>
+; PF2-NEXT: <INST_CMP2 op0=9 op1=5 op2=32/>
+; PF2-NEXT: <INST_RET/>
+; PF2-NEXT: </FUNCTION_BLOCK>
+
+; ------------------------------------------------------
+
+; Show that we can handle pointer conversions for Select.
+define void @CastSelect() {
+ %1 = alloca i8, i32 4, align 8
+ %2 = ptrtoint i8* %1 to i32
+ %3 = ptrtoint [4 x i8]* @bytes to i32
+ %4 = select i1 true, i32 1, i32 2
+ %5 = select i1 true, i32 %2, i32 2
+ %6 = select i1 true, i32 1, i32 %3
+ %7 = select i1 true, i32 %2, i32 %3
+ %8 = select i1 true, i32 %3, i32 %2
+ ret void
+}
+
+; TD1: define void @CastSelect() {
+; TD1-NEXT: %1 = alloca i8, i32 4, align 8
+; TD1-NEXT: %2 = ptrtoint i8* %1 to i32
+; TD1-NEXT: %3 = ptrtoint [4 x i8]* @bytes to i32
+; TD1-NEXT: %4 = select i1 true, i32 1, i32 2
+; TD1-NEXT: %5 = select i1 true, i32 %2, i32 2
+; TD1-NEXT: %6 = select i1 true, i32 1, i32 %3
+; TD1-NEXT: %7 = select i1 true, i32 %2, i32 %3
+; TD1-NEXT: %8 = select i1 true, i32 %3, i32 %2
+; TD1-NEXT: ret void
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK>
+; PF1: </CONSTANTS_BLOCK>
+; PF1-NEXT: <INST_ALLOCA op0=2 op1=4/>
+; PF1-NEXT: <INST_CAST op0=1 op1=0 op2=9/>
+; PF1-NEXT: <INST_CAST op0=7 op1=0 op2=9/>
+; PF1-NEXT: <INST_VSELECT op0=7 op1=6 op2=4/>
+; PF1-NEXT: <INST_VSELECT op0=3 op1=7 op2=5/>
+; PF1-NEXT: <INST_VSELECT op0=9 op1=3 op2=6/>
+; PF1-NEXT: <INST_VSELECT op0=5 op1=4 op2=7/>
+; PF1-NEXT: <INST_VSELECT op0=5 op1=6 op2=8/>
+; PF1-NEXT: <INST_RET/>
+; PF1-NEXT: </FUNCTION_BLOCK>
+
+; TD2: define void @CastSelect() {
+; TD2-NEXT: %1 = alloca i8, i32 4, align 8
+; TD2-NEXT: %2 = select i1 true, i32 1, i32 2
+; TD2-NEXT: %3 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %4 = select i1 true, i32 %3, i32 2
+; TD2-NEXT: %5 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %6 = select i1 true, i32 1, i32 %5
+; TD2-NEXT: %7 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %8 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %9 = select i1 true, i32 %7, i32 %8
+; TD2-NEXT: %10 = ptrtoint [4 x i8]* @bytes to i32
+; TD2-NEXT: %11 = ptrtoint i8* %1 to i32
+; TD2-NEXT: %12 = select i1 true, i32 %10, i32 %11
+; TD2-NEXT: ret void
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK>
+; PF2: </CONSTANTS_BLOCK>
+; PF2-NEXT: <INST_ALLOCA op0=2 op1=4/>
+; PF2-NEXT: <INST_VSELECT op0=5 op1=4 op2=2/>
+; PF2-NEXT: <INST_VSELECT op0=2 op1=5 op2=3/>
+; PF2-NEXT: <INST_VSELECT op0=7 op1=8 op2=4/>
+; PF2-NEXT: <INST_VSELECT op0=4 op1=9 op2=5/>
+; PF2-NEXT: <INST_VSELECT op0=10 op1=5 op2=6/>
+; PF2-NEXT: <INST_RET/>
+; PF2-NEXT: </FUNCTION_BLOCK>