aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Bitcode/NaCl/NaClLLVMBitCodes.h5
-rw-r--r--lib/Bitcode/NaCl/Reader/NaClBitcodeHeader.cpp2
-rw-r--r--lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp73
-rw-r--r--lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h11
-rw-r--r--lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp41
-rw-r--r--lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp57
-rw-r--r--lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h9
-rw-r--r--test/NaCl/Bitcode/inttoptr-elide.ll180
-rw-r--r--tools/pnacl-freeze/pnacl-freeze.cpp2
9 files changed, 351 insertions, 29 deletions
diff --git a/include/llvm/Bitcode/NaCl/NaClLLVMBitCodes.h b/include/llvm/Bitcode/NaCl/NaClLLVMBitCodes.h
index 5433ed5352..9b53e08ab8 100644
--- a/include/llvm/Bitcode/NaCl/NaClLLVMBitCodes.h
+++ b/include/llvm/Bitcode/NaCl/NaClLLVMBitCodes.h
@@ -286,7 +286,10 @@ namespace naclbitc {
// 17 is unused.
// 18 is unused.
FUNC_CODE_INST_ALLOCA = 19, // ALLOCA: [op, align]
- FUNC_CODE_INST_LOAD = 20, // LOAD: [op, align, vol]
+ FUNC_CODE_INST_LOAD = 20, // PNaCl version 1:
+ // LOAD: [op, align, vol]
+ // PNaCl version 2:
+ // LOAD: [op, align, vol, ty]
// 21 is unused.
// 22 is unused.
FUNC_CODE_INST_VAARG = 23, // Not used in PNaCl.
diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeHeader.cpp b/lib/Bitcode/NaCl/Reader/NaClBitcodeHeader.cpp
index 2dd2af5dc3..37b79ad3d8 100644
--- a/lib/Bitcode/NaCl/Reader/NaClBitcodeHeader.cpp
+++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeHeader.cpp
@@ -248,7 +248,7 @@ void NaClBitcodeHeader::InstallFields() {
}
if (PNaClVersion != 1) {
IsSupportedFlag = false;
- IsReadableFlag = false;
+ IsReadableFlag = (PNaClVersion == 2);
UpdatedUnsupportedMessage = true;
UnsupportedMessage.clear();
raw_string_ostream UnsupportedStream(UnsupportedMessage);
diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp
index 9c2f45ea56..40f8842b3b 100644
--- a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp
+++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp
@@ -1301,6 +1301,46 @@ bool NaClBitcodeReader::ParseBitcodeInto(Module *M) {
}
}
+// Returns true if error occured installing I into BB.
+bool NaClBitcodeReader::InstallInstruction(
+ BasicBlock *BB, Instruction *I) {
+ // Add instruction to end of current BB. If there is no current BB, reject
+ // this file.
+ if (BB == 0) {
+ delete I;
+ return Error("Invalid instruction with no BB");
+ }
+ BB->getInstList().push_back(I);
+ return false;
+}
+
+Value *NaClBitcodeReader::ConvertOpToType(Value *Op, Type *T, BasicBlock *BB) {
+ // Note: Currently only knows how to add inttoptr type conversion, since
+ // this is the only elided instruction in the bitcode writer.
+ // TODO(kschimpf): Generalize this as we expand elided conversions.
+ Value *Conversion = 0;
+ Type *OpTy = Op->getType();
+ if (OpTy == T) return Op;
+
+ // Following while loop is only run once. It is used to break on
+ // erroneous conditions.
+ while (true) {
+ if (!OpTy->isIntegerTy()) break;
+ if (!T->isPointerTy()) break;
+ Instruction *I = CastInst::Create(Instruction::IntToPtr, Op, T);
+ if (InstallInstruction(BB, I)) break;
+ Conversion = I;
+ break;
+ }
+ if (Conversion == 0) {
+ std::string Message;
+ raw_string_ostream StrM(Message);
+ StrM << "Can't convert " << *Op << " to type " << *T << "\n";
+ Error(StrM.str());
+ }
+ return Conversion;
+}
+
/// ParseFunctionBody - Lazily parse the specified function body block.
bool NaClBitcodeReader::ParseFunctionBody(Function *F) {
DEBUG(dbgs() << "-> ParseFunctionBody\n");
@@ -1602,13 +1642,29 @@ bool NaClBitcodeReader::ParseFunctionBody(Function *F) {
I = new AllocaInst(Type::getInt8Ty(Context), Size, (1 << Align) >> 1);
break;
}
- case naclbitc::FUNC_CODE_INST_LOAD: { // LOAD: [op, align, vol]
+ case naclbitc::FUNC_CODE_INST_LOAD: {
+ // PNaCl version 1: LOAD: [op, align, vol]
+ // PNaCl version 2: LOAD: [op, align, vol, ty]
unsigned OpNum = 0;
Value *Op;
- if (popValue(Record, &OpNum, NextValueNo, &Op) ||
- OpNum+2 != Record.size())
+ if (popValue(Record, &OpNum, NextValueNo, &Op))
return Error("Invalid LOAD record");
-
+ switch (GetPNaClVersion()) {
+ case 1:
+ if (Record.size() != 3)
+ return Error("Invalid LOAD record");
+ break;
+ case 2: {
+ if (Record.size() != 4)
+ return Error("Invalid LOAD record");
+ // Add pointer cast to op.
+ Type *T = getTypeByID(Record[3]);
+ if (T == 0)
+ return Error("Invalid type for load instruction");
+ Op = ConvertOpToType(Op, T->getPointerTo(), CurBB);
+ if (Op == 0) return true;
+ }
+ }
I = new LoadInst(Op, "", Record[OpNum+1], (1 << Record[OpNum]) >> 1);
break;
}
@@ -1677,13 +1733,8 @@ bool NaClBitcodeReader::ParseFunctionBody(Function *F) {
continue;
}
- // Add instruction to end of current BB. If there is no current BB, reject
- // this file.
- if (CurBB == 0) {
- delete I;
- return Error("Invalid instruction with no BB");
- }
- CurBB->getInstList().push_back(I);
+ if (InstallInstruction(CurBB, I))
+ return true;
// If this was a terminator instruction, move to the next block.
if (isa<TerminatorInst>(I)) {
diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h
index 849ca7e506..805bddf0b2 100644
--- a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h
+++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h
@@ -267,6 +267,17 @@ private:
return getFnValueByID(ValNo);
}
+ /// \brief Add instructions to cast Op to the given type T into block BB.
+ /// Follows rules for pointer conversion as defined in
+ /// llvm/lib/Transforms/NaCl/ReplacePtrsWithInts.cpp.
+ ///
+ /// Returns 0 if unable to generate conversion value (also generates
+ /// an appropriate error message and calls Error).
+ Value *ConvertOpToType(Value *Op, Type *T, BasicBlock *BB);
+
+ /// \brief Install instruction I into basic block BB.
+ bool InstallInstruction(BasicBlock *BB, Instruction *I);
+
bool ParseModule(bool Resume);
bool ParseTypeTable();
bool ParseTypeTableBody();
diff --git a/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp b/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp
index 9f3626557b..ac2a6a0acf 100644
--- a/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp
+++ b/lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp
@@ -811,8 +811,9 @@ static void pushValue(const Value *V, unsigned InstID,
SmallVector<unsigned, 64> &Vals,
NaClValueEnumerator &VE,
NaClBitstreamWriter &Stream) {
- EmitFnForwardTypeRef(V, InstID, VE, Stream);
- unsigned ValID = VE.getValueID(V);
+ const Value *VElided = VE.ElideCasts(V);
+ EmitFnForwardTypeRef(VElided, InstID, VE, Stream);
+ unsigned ValID = VE.getValueID(VElided);
// Make encoding relative to the InstID.
Vals.push_back(InstID - ValID);
}
@@ -821,8 +822,9 @@ static void pushValue64(const Value *V, unsigned InstID,
SmallVector<uint64_t, 128> &Vals,
NaClValueEnumerator &VE,
NaClBitstreamWriter &Stream) {
- EmitFnForwardTypeRef(V, InstID, VE, Stream);
- uint64_t ValID = VE.getValueID(V);
+ const Value *VElided = VE.ElideCasts(V);
+ EmitFnForwardTypeRef(VElided, InstID, VE, Stream);
+ uint64_t ValID = VE.getValueID(VElided);
Vals.push_back(InstID - ValID);
}
@@ -830,14 +832,16 @@ static void pushValueSigned(const Value *V, unsigned InstID,
SmallVector<uint64_t, 128> &Vals,
NaClValueEnumerator &VE,
NaClBitstreamWriter &Stream) {
- EmitFnForwardTypeRef(V, InstID, VE, Stream);
- unsigned ValID = VE.getValueID(V);
+ const Value *VElided = VE.ElideCasts(V);
+ EmitFnForwardTypeRef(VElided, InstID, VE, Stream);
+ unsigned ValID = VE.getValueID(VElided);
int64_t diff = ((int32_t)InstID - (int32_t)ValID);
emitSignedInt64(Vals, diff);
}
/// WriteInstruction - Emit an instruction to the specified stream.
-static void WriteInstruction(const Instruction &I, unsigned InstID,
+/// Returns true if instruction actually emitted.
+static bool WriteInstruction(const Instruction &I, unsigned InstID,
NaClValueEnumerator &VE,
NaClBitstreamWriter &Stream,
SmallVector<unsigned, 64> &Vals) {
@@ -848,6 +852,8 @@ static void WriteInstruction(const Instruction &I, unsigned InstID,
default:
if (Instruction::isCast(I.getOpcode())) {
// CAST: [opval, destty, castopc]
+ if (VE.IsElidedCast(&I))
+ return false;
Code = naclbitc::FUNC_CODE_INST_CAST;
AbbrevToUse = FUNCTION_INST_CAST_ABBREV;
pushValue(I.getOperand(0), InstID, Vals, VE, Stream);
@@ -965,7 +971,7 @@ static void WriteInstruction(const Instruction &I, unsigned InstID,
// Also do expected action - clear external Vals collection:
Vals.clear();
- return;
+ return true;
}
break;
case Instruction::Unreachable:
@@ -988,7 +994,7 @@ static void WriteInstruction(const Instruction &I, unsigned InstID,
// Emit a Vals64 vector and exit.
Stream.EmitRecord(Code, Vals64, AbbrevToUse);
Vals64.clear();
- return;
+ return true;
}
case Instruction::Alloca:
@@ -998,13 +1004,17 @@ static void WriteInstruction(const Instruction &I, unsigned InstID,
pushValue(I.getOperand(0), InstID, Vals, VE, Stream); // size.
Vals.push_back(Log2_32(cast<AllocaInst>(I).getAlignment())+1);
break;
-
case Instruction::Load:
+ // PNaCl Version 1: LOAD: [op, align, vol]
+ // PNaCl Version 2: LOAD: [op, align, vol, ty]
Code = naclbitc::FUNC_CODE_INST_LOAD;
- pushValue(I.getOperand(0), InstID, Vals, VE, Stream); // ptr
+ pushValue(I.getOperand(0), InstID, Vals, VE, Stream);
AbbrevToUse = FUNCTION_INST_LOAD_ABBREV;
Vals.push_back(Log2_32(cast<LoadInst>(I).getAlignment())+1);
Vals.push_back(cast<LoadInst>(I).isVolatile());
+ if (PNaClVersion == 2) {
+ Vals.push_back(VE.getTypeID(I.getType()));
+ }
break;
case Instruction::Store:
Code = naclbitc::FUNC_CODE_INST_STORE;
@@ -1047,6 +1057,7 @@ static void WriteInstruction(const Instruction &I, unsigned InstID,
Stream.EmitRecord(Code, Vals, AbbrevToUse);
Vals.clear();
+ return true;
}
// Emit names for globals/functions etc.
@@ -1133,9 +1144,8 @@ static void WriteFunction(const Function &F, NaClValueEnumerator &VE,
for (Function::const_iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
for (BasicBlock::const_iterator I = BB->begin(), E = BB->end();
I != E; ++I) {
- WriteInstruction(*I, InstID, VE, Stream, Vals);
-
- if (!I->getType()->isVoidTy())
+ if (WriteInstruction(*I, InstID, VE, Stream, Vals) &&
+ !I->getType()->isVoidTy())
++InstID;
}
@@ -1233,6 +1243,9 @@ static void WriteBlockInfo(const NaClValueEnumerator &VE,
Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 6)); // Ptr
Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 4)); // Align
Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::Fixed, 1)); // volatile
+ if (PNaClVersion == 2) {
+ Abbv->Add(NaClBitCodeAbbrevOp(NaClBitCodeAbbrevOp::VBR, 4)); // Typecast
+ }
if (Stream.EmitBlockInfoAbbrev(naclbitc::FUNCTION_BLOCK_ID,
Abbv) != FUNCTION_INST_LOAD_ABBREV)
llvm_unreachable("Unexpected abbrev ordering!");
diff --git a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp
index 3ad224a04f..7da01f005e 100644
--- a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp
+++ b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp
@@ -231,7 +231,11 @@ void NaClValueEnumerator::EnumerateValueSymbolTable(const ValueSymbolTable &VST)
EnumerateValue(VI->getValue());
}
-void NaClValueEnumerator::EnumerateValue(const Value *V) {
+void NaClValueEnumerator::EnumerateValue(const Value *VIn) {
+ // Skip over elided values.
+ const Value *V = ElideCasts(VIn);
+ if (V != VIn) return;
+
assert(!V->getType()->isVoidTy() && "Can't insert void values!");
assert(!isa<MDNode>(V) && !isa<MDString>(V) &&
"EnumerateValue doesn't handle Metadata!");
@@ -423,3 +427,54 @@ void NaClValueEnumerator::purgeFunction() {
BasicBlocks.clear();
FnForwardTypeRefs.clear();
}
+
+// Returns true if the bitcode writer can assume that the given
+// argument of the given operation can accept a normalized pointer.
+// 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) {
+ const Instruction *I = dyn_cast<Instruction>(V);
+ if (I == 0) return false;
+
+ // TODO(kschimpf) Expand this list to any operation that can handle
+ // normalized pointers. That is loads and stores, function calls, and
+ // instrinsic calls.
+ switch (I->getOpcode()) {
+ default:
+ return false;
+ case Instruction::Load:
+ return I->getOperand(0) == Arg;
+ }
+}
+
+// Returns true if the bitcode reader and writer can assume that the
+// uses of the given inttotpr I2P allow normalized pointers (as
+// defined in llvm/lib/Transforms/NaCl/ReplacePtrsWithInts.cpp).
+static bool IntToPtrUsesAllowEliding(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 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;
+}
+
+// Note: This function is based on the comments in
+// llvm/lib/Transforms/NaCl/ReplacePtrsWithInts.cpp.
+const Value *NaClValueEnumerator::ElideCasts(const Value *V) {
+ if (PNaClVersion == 1) return V;
+ // TODO(kschimpf): Expand this out to cover all cases.
+ if (const Instruction *I = dyn_cast<Instruction>(V)) {
+ switch (I->getOpcode()) {
+ default:
+ break;
+ case Instruction::IntToPtr:
+ if (IntToPtrUsesAllowEliding(I)) {
+ return ElideCasts(I->getOperand(0));
+ }
+ }
+ }
+ return V;
+}
diff --git a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h
index 3e71740f92..22de263c4b 100644
--- a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h
+++ b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h
@@ -135,6 +135,15 @@ public:
void incorporateFunction(const Function &F);
void purgeFunction();
+ /// \brief Returns the value after elided (cast) operations have been
+ /// removed. Returns V if unable to elide the cast.
+ const Value *ElideCasts(const Value *V);
+
+ /// \brief Returns true if value V is an elided (cast) operation.
+ bool IsElidedCast(const Value *V) {
+ return V != ElideCasts(V);
+ }
+
private:
void OptimizeTypes(const Module *M);
void OptimizeConstants(unsigned CstStart, unsigned CstEnd);
diff --git a/test/NaCl/Bitcode/inttoptr-elide.ll b/test/NaCl/Bitcode/inttoptr-elide.ll
new file mode 100644
index 0000000000..2f35389fa5
--- /dev/null
+++ b/test/NaCl/Bitcode/inttoptr-elide.ll
@@ -0,0 +1,180 @@
+; Test how we handle eliding inttoptr instructions.
+; TODO(kschimpf) Expand these tests as further CL's are added for issue 3544.
+
+; RUN: llvm-as < %s | pnacl-freeze --pnacl-version=1 | pnacl-bcanalyzer -dump \
+; 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 | pnacl-bcanalyzer -dump \
+; 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
+
+; ------------------------------------------------------
+
+; Test that we elide the simple case of inttoptr of a load.
+define void @SimpleLoad(i32 %i) {
+ %1 = inttoptr i32 %i to i32*
+ %2 = load i32* %1, align 4
+ ret void
+}
+
+; TD1: define void @SimpleLoad(i32 %i) {
+; TD1-NEXT: %1 = inttoptr i32 %i to i32*
+; TD1-NEXT: %2 = load i32* %1, align 4
+; TD1-NEXT: ret void
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK NumWords=6 BlockCodeSize=4>
+; PF1-NEXT: <DECLAREBLOCKS op0=1/>
+; PF1-NEXT: <INST_CAST abbrevid=7 op0=1 op1=1 op2=10/>
+; PF1-NEXT: <INST_LOAD abbrevid=4 op0=1 op1=3 op2=0/>
+; PF1-NEXT: <INST_RET abbrevid=8/>
+; PF1: </FUNCTION_BLOCK>
+
+; TD2: define void @SimpleLoad(i32 %i) {
+; TD2-NEXT: %1 = inttoptr i32 %i to i32*
+; TD2-NEXT: %2 = load i32* %1, align 4
+; TD2-NEXT: ret void
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK NumWords=5 BlockCodeSize=4>
+; PF2-NEXT: <DECLAREBLOCKS op0=1/>
+; PF2-NEXT: <INST_LOAD abbrevid=4 op0=1 op1=3 op2=0 op3=0/>
+; PF2-NEXT: <INST_RET abbrevid=8/>
+; PF2: </FUNCTION_BLOCK>
+
+; ------------------------------------------------------
+
+; Test that we don't elide an inttoptr if one of its uses is not a load.
+define i32* @NonsimpleLoad(i32 %i) {
+ %1 = inttoptr i32 %i to i32*
+ %2 = load i32* %1, align 4
+ ret i32* %1
+}
+
+; TD1: define i32* @NonsimpleLoad(i32 %i) {
+; TD1-NEXT: %1 = inttoptr i32 %i to i32*
+; TD1-NEXT: %2 = load i32* %1, align 4
+; TD1-NEXT: ret i32* %1
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK NumWords=6 BlockCodeSize=4>
+; PF1-NEXT: <DECLAREBLOCKS op0=1/>
+; PF1-NEXT: <INST_CAST abbrevid=7 op0=1 op1=1 op2=10/>
+; PF1-NEXT: <INST_LOAD abbrevid=4 op0=1 op1=3 op2=0/>
+; PF1-NEXT: <INST_RET abbrevid=9 op0=2/>
+; PF1: </FUNCTION_BLOCK>
+
+; TD2: define i32* @NonsimpleLoad(i32 %i) {
+; TD2-NEXT: %1 = inttoptr i32 %i to i32*
+; TD2-NEXT: %2 = load i32* %1, align 4
+; TD2-NEXT: ret i32* %1
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK NumWords=6 BlockCodeSize=4>
+; PF2-NEXT: <DECLAREBLOCKS op0=1/>
+; PF2-NEXT: <INST_CAST abbrevid=7 op0=1 op1=1 op2=10/>
+; PF2-NEXT: <INST_LOAD abbrevid=4 op0=1 op1=3 op2=0 op3=0/>
+; PF2-NEXT: <INST_RET abbrevid=9 op0=2/>
+; PF2: </FUNCTION_BLOCK>
+
+; ------------------------------------------------------
+
+; Test that we can handle multiple inttoptr of loads.
+define i32 @TwoLoads(i32 %i) {
+ %1 = inttoptr i32 %i to i32*
+ %2 = load i32* %1, align 4
+ %3 = inttoptr i32 %i to i32*
+ %4 = load i32* %3, align 4
+ %5 = add i32 %2, %4
+ ret i32 %5
+}
+
+; TD1: define i32 @TwoLoads(i32 %i) {
+; TD1-NEXT: %1 = inttoptr i32 %i to i32*
+; TD1-NEXT: %2 = load i32* %1, align 4
+; TD1-NEXT: %3 = inttoptr i32 %i to i32*
+; TD1-NEXT: %4 = load i32* %3, align 4
+; TD1-NEXT: %5 = add i32 %2, %4
+; TD1-NEXT: ret i32 %5
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK NumWords=8 BlockCodeSize=4>
+; PF1-NEXT: <DECLAREBLOCKS op0=1/>
+; PF1-NEXT: <INST_CAST abbrevid=7 op0=1 op1=1 op2=10/>
+; PF1-NEXT: <INST_LOAD abbrevid=4 op0=1 op1=3 op2=0/>
+; PF1-NEXT: <INST_CAST abbrevid=7 op0=3 op1=1 op2=10/>
+; PF1-NEXT: <INST_LOAD abbrevid=4 op0=1 op1=3 op2=0/>
+; PF1-NEXT: <INST_BINOP abbrevid=5 op0=3 op1=1 op2=0/>
+; PF1-NEXT: <INST_RET abbrevid=9 op0=1/>
+; PF1: </FUNCTION_BLOCK>
+
+; TD2: define i32 @TwoLoads(i32 %i) {
+; TD2-NEXT: %1 = inttoptr i32 %i to i32*
+; TD2-NEXT: %2 = load i32* %1, align 4
+; TD2-NEXT: %3 = inttoptr i32 %i to i32*
+; TD2-NEXT: %4 = load i32* %3, align 4
+; TD2-NEXT: %5 = add i32 %2, %4
+; TD2-NEXT: ret i32 %5
+; TD2-NEXT: }
+
+
+; PF2: <FUNCTION_BLOCK NumWords=7 BlockCodeSize=4>
+; PF2-NEXT: <DECLAREBLOCKS op0=1/>
+; PF2-NEXT: <INST_LOAD abbrevid=4 op0=1 op1=3 op2=0 op3=0/>
+; PF2-NEXT: <INST_LOAD abbrevid=4 op0=2 op1=3 op2=0 op3=0/>
+; PF2-NEXT: <INST_BINOP abbrevid=5 op0=2 op1=1 op2=0/>
+; PF2-NEXT: <INST_RET abbrevid=9 op0=1/>
+; PF2: </FUNCTION_BLOCK>
+
+; ------------------------------------------------------
+
+; Test how we duplicate inttoptrs, even if optimized in the input file.
+define i32 @TwoLoadOpt(i32 %i) {
+ %1 = inttoptr i32 %i to i32*
+ %2 = load i32* %1, align 4
+ %3 = load i32* %1, align 4
+ %4 = add i32 %2, %3
+ ret i32 %4
+}
+
+; TD1: define i32 @TwoLoadOpt(i32 %i) {
+; TD1-NEXT: %1 = inttoptr i32 %i to i32*
+; TD1-NEXT: %2 = load i32* %1, align 4
+; TD1-NEXT: %3 = load i32* %1, align 4
+; TD1-NEXT: %4 = add i32 %2, %3
+; TD1-NEXT: ret i32 %4
+; TD1-NEXT: }
+
+; PF1: <FUNCTION_BLOCK NumWords=7 BlockCodeSize=4>
+; PF1-NEXT: <DECLAREBLOCKS op0=1/>
+; PF1-NEXT: <INST_CAST abbrevid=7 op0=1 op1=1 op2=10/>
+; PF1-NEXT: <INST_LOAD abbrevid=4 op0=1 op1=3 op2=0/>
+; PF1-NEXT: <INST_LOAD abbrevid=4 op0=2 op1=3 op2=0/>
+; PF1-NEXT: <INST_BINOP abbrevid=5 op0=2 op1=1 op2=0/>
+; PF1-NEXT: <INST_RET abbrevid=9 op0=1/>
+; PF1: </FUNCTION_BLOCK>
+
+; TD2: define i32 @TwoLoadOpt(i32 %i) {
+; TD2-NEXT: %1 = inttoptr i32 %i to i32*
+; TD2-NEXT: %2 = load i32* %1, align 4
+; TD2-NEXT: %3 = inttoptr i32 %i to i32*
+; TD2-NEXT: %4 = load i32* %3, align 4
+; TD2-NEXT: %5 = add i32 %2, %4
+; TD2-NEXT: ret i32 %5
+; TD2-NEXT: }
+
+; PF2: <FUNCTION_BLOCK NumWords=7 BlockCodeSize=4>
+; PF2-NEXT: <DECLAREBLOCKS op0=1/>
+; PF2-NEXT: <INST_LOAD abbrevid=4 op0=1 op1=3 op2=0 op3=0/>
+; PF2-NEXT: <INST_LOAD abbrevid=4 op0=2 op1=3 op2=0 op3=0/>
+; PF2-NEXT: <INST_BINOP abbrevid=5 op0=2 op1=1 op2=0/>
+; PF2-NEXT: <INST_RET abbrevid=9 op0=1/>
+; PF2-NEXT: <VALUE_SYMTAB NumWords=1 BlockCodeSize=3>
+; PF2-NEXT: <ENTRY abbrevid=6 op0=4 op1=105/>
+; PF2-NEXT: </VALUE_SYMTAB>
+; PF2: </FUNCTION_BLOCK>
diff --git a/tools/pnacl-freeze/pnacl-freeze.cpp b/tools/pnacl-freeze/pnacl-freeze.cpp
index 297edb85a7..a3bc1a68e4 100644
--- a/tools/pnacl-freeze/pnacl-freeze.cpp
+++ b/tools/pnacl-freeze/pnacl-freeze.cpp
@@ -47,7 +47,7 @@ static void WriteOutputFile(const Module *M) {
exit(1);
}
- NaClWriteBitcodeToFile(M, Out->os());
+ NaClWriteBitcodeToFile(M, Out->os(), /* AcceptSupportedOnly = */ false);
// Declare success.
Out->keep();