diff options
-rw-r--r-- | include/llvm/Bitcode/NaCl/NaClLLVMBitCodes.h | 5 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Reader/NaClBitcodeHeader.cpp | 2 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp | 73 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Reader/NaClBitcodeReader.h | 11 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Writer/NaClBitcodeWriter.cpp | 41 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp | 57 | ||||
-rw-r--r-- | lib/Bitcode/NaCl/Writer/NaClValueEnumerator.h | 9 | ||||
-rw-r--r-- | test/NaCl/Bitcode/inttoptr-elide.ll | 180 | ||||
-rw-r--r-- | tools/pnacl-freeze/pnacl-freeze.cpp | 2 |
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(); |