Clause *CaptureConstraints::get_avoid_branch( const TerminatorInst *ti, unsigned i) const { assert(ti->getNumSuccessors() > 1); assert(isa<BranchInst>(ti) || isa<IndirectBrInst>(ti) || isa<InvokeInst>(ti) || isa<SwitchInst>(ti)); if (const BranchInst *bi = dyn_cast<BranchInst>(ti)) { assert(i == 0 || i == 1); const Value *cond = bi->getCondition(); assert(cond && cond->getType()->isIntegerTy(1)); if (!is_reachable_integer(cond)) return NULL; // i == 0 => avoid true branch => cond is 0 // i == 1 => avoid false branch => cond is 1 if (i == 0) { return new Clause(new BoolExpr( CmpInst::ICMP_EQ, new Expr(cond), new Expr(ConstantInt::getFalse(ti->getContext())))); } else { return new Clause(new BoolExpr( CmpInst::ICMP_EQ, new Expr(cond), new Expr(ConstantInt::getTrue(ti->getContext())))); } } else if (const SwitchInst *si = dyn_cast<SwitchInst>(ti)) { /* * switch (condition) { * case 0: * case 1: * ... * case k: * default: * } */ const Value *cond = si->getCondition(); assert(cond); if (!is_reachable_integer(cond)) return NULL; if (ti->getSuccessor(i) == si->getDefaultDest()) { // The condition is equal to one of the case values. Clause *disj = NULL; // Case 0 is the default branch. It doesn't have a case value. for (SwitchInst::ConstCaseIt iter = si->case_begin(); iter != si->case_end(); ++iter) { Clause *c = new Clause(new BoolExpr( CmpInst::ICMP_EQ, new Expr(cond), new Expr(iter.getCaseValue()))); if (!disj) disj = c; else disj = new Clause(Instruction::Or, disj, c); } assert(disj); return disj; } else { // The condition does not equal the particular case. return new Clause(new BoolExpr( CmpInst::ICMP_NE, new Expr(cond), new Expr(const_cast<SwitchInst *>(si)->findCaseDest(const_cast<BasicBlock *>(ti->getSuccessor(i)))))); } } else if (const IndirectBrInst *ii = dyn_cast<IndirectBrInst>(ti)) { errs() << *ii << "\n"; assert_not_supported(); } else { return NULL; } }
/// WriteInstruction - Emit an instruction to the specified stream. /// Returns true if instruction actually emitted. static bool WriteInstruction(const Instruction &I, unsigned InstID, NaClValueEnumerator &VE, NaClBitstreamWriter &Stream, SmallVector<unsigned, 64> &Vals) { unsigned Code = 0; unsigned AbbrevToUse = 0; VE.setInstructionID(&I); switch (I.getOpcode()) { 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); Vals.push_back(VE.getTypeID(I.getType())); unsigned Opcode = I.getOpcode(); Vals.push_back(GetEncodedCastOpcode(Opcode, I)); if (Opcode == Instruction::PtrToInt || Opcode == Instruction::IntToPtr || (Opcode == Instruction::BitCast && (I.getOperand(0)->getType()->isPointerTy() || I.getType()->isPointerTy()))) { ReportIllegalValue("(PNaCl ABI) pointer cast", I); } } else if (isa<BinaryOperator>(I)) { // BINOP: [opval, opval, opcode] Code = naclbitc::FUNC_CODE_INST_BINOP; AbbrevToUse = FUNCTION_INST_BINOP_ABBREV; pushValue(I.getOperand(0), InstID, Vals, VE, Stream); pushValue(I.getOperand(1), InstID, Vals, VE, Stream); Vals.push_back(GetEncodedBinaryOpcode(I.getOpcode(), I)); } else { ReportIllegalValue("instruction", I); } break; case Instruction::Select: Code = naclbitc::FUNC_CODE_INST_VSELECT; pushValue(I.getOperand(1), InstID, Vals, VE, Stream); pushValue(I.getOperand(2), InstID, Vals, VE, Stream); pushValue(I.getOperand(0), InstID, Vals, VE, Stream); break; case Instruction::ExtractElement: Code = naclbitc::FUNC_CODE_INST_EXTRACTELT; pushValue(I.getOperand(0), InstID, Vals, VE, Stream); pushValue(I.getOperand(1), InstID, Vals, VE, Stream); break; case Instruction::InsertElement: Code = naclbitc::FUNC_CODE_INST_INSERTELT; pushValue(I.getOperand(0), InstID, Vals, VE, Stream); pushValue(I.getOperand(1), InstID, Vals, VE, Stream); pushValue(I.getOperand(2), InstID, Vals, VE, Stream); break; case Instruction::ICmp: case Instruction::FCmp: // compare returning Int1Ty or vector of Int1Ty Code = naclbitc::FUNC_CODE_INST_CMP2; pushValue(I.getOperand(0), InstID, Vals, VE, Stream); pushValue(I.getOperand(1), InstID, Vals, VE, Stream); Vals.push_back(GetEncodedCmpPredicate(cast<CmpInst>(I))); break; case Instruction::Ret: { Code = naclbitc::FUNC_CODE_INST_RET; unsigned NumOperands = I.getNumOperands(); if (NumOperands == 0) AbbrevToUse = FUNCTION_INST_RET_VOID_ABBREV; else if (NumOperands == 1) { pushValue(I.getOperand(0), InstID, Vals, VE, Stream); AbbrevToUse = FUNCTION_INST_RET_VAL_ABBREV; } else { for (unsigned i = 0, e = NumOperands; i != e; ++i) pushValue(I.getOperand(i), InstID, Vals, VE, Stream); } } break; case Instruction::Br: { Code = naclbitc::FUNC_CODE_INST_BR; const BranchInst &II = cast<BranchInst>(I); Vals.push_back(VE.getValueID(II.getSuccessor(0))); if (II.isConditional()) { Vals.push_back(VE.getValueID(II.getSuccessor(1))); pushValue(II.getCondition(), InstID, Vals, VE, Stream); } } break; case Instruction::Switch: { // Redefine Vals, since here we need to use 64 bit values // explicitly to store large APInt numbers. SmallVector<uint64_t, 128> Vals64; Code = naclbitc::FUNC_CODE_INST_SWITCH; const SwitchInst &SI = cast<SwitchInst>(I); Vals64.push_back(VE.getTypeID(SI.getCondition()->getType())); pushValue64(SI.getCondition(), InstID, Vals64, VE, Stream); Vals64.push_back(VE.getValueID(SI.getDefaultDest())); Vals64.push_back(SI.getNumCases()); for (SwitchInst::ConstCaseIt i = SI.case_begin(), e = SI.case_end(); i != e; ++i) { // The PNaCl bitcode format has vestigial support for case // ranges, but we no longer support reading or writing them, // so the next two fields always have the same values. // See https://code.google.com/p/nativeclient/issues/detail?id=3758 Vals64.push_back(1/*NumItems = 1*/); Vals64.push_back(true/*IsSingleNumber = true*/); emitSignedInt64(Vals64, i.getCaseValue()->getSExtValue()); Vals64.push_back(VE.getValueID(i.getCaseSuccessor())); } Stream.EmitRecord(Code, Vals64, AbbrevToUse); // Also do expected action - clear external Vals collection: Vals.clear(); return true; } break; case Instruction::Unreachable: Code = naclbitc::FUNC_CODE_INST_UNREACHABLE; AbbrevToUse = FUNCTION_INST_UNREACHABLE_ABBREV; break; case Instruction::PHI: { const PHINode &PN = cast<PHINode>(I); Code = naclbitc::FUNC_CODE_INST_PHI; // With the newer instruction encoding, forward references could give // negative valued IDs. This is most common for PHIs, so we use // signed VBRs. SmallVector<uint64_t, 128> Vals64; Vals64.push_back(VE.getTypeID(PN.getType())); for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) { pushValueSigned(PN.getIncomingValue(i), InstID, Vals64, VE, Stream); Vals64.push_back(VE.getValueID(PN.getIncomingBlock(i))); } // Emit a Vals64 vector and exit. Stream.EmitRecord(Code, Vals64, AbbrevToUse); Vals64.clear(); return true; } case Instruction::Alloca: if (!cast<AllocaInst>(&I)->getAllocatedType()->isIntegerTy(8)) report_fatal_error("Type of alloca instruction is not i8"); Code = naclbitc::FUNC_CODE_INST_ALLOCA; pushValue(I.getOperand(0), InstID, Vals, VE, Stream); // size. Vals.push_back(Log2_32(cast<AllocaInst>(I).getAlignment())+1); break; case Instruction::Load: // LOAD: [op, align, ty] Code = naclbitc::FUNC_CODE_INST_LOAD; 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(VE.getTypeID(I.getType())); break; case Instruction::Store: // STORE: [ptr, val, align] Code = naclbitc::FUNC_CODE_INST_STORE; AbbrevToUse = FUNCTION_INST_STORE_ABBREV; pushValue(I.getOperand(1), InstID, Vals, VE, Stream); pushValue(I.getOperand(0), InstID, Vals, VE, Stream); Vals.push_back(Log2_32(cast<StoreInst>(I).getAlignment())+1); break; case Instruction::Call: { // CALL: [cc, fnid, args...] // CALL_INDIRECT: [cc, fnid, fnty, args...] const CallInst &Call = cast<CallInst>(I); const Value* Callee = Call.getCalledValue(); Vals.push_back((GetEncodedCallingConv(Call.getCallingConv()) << 1) | unsigned(Call.isTailCall())); pushValue(Callee, InstID, Vals, VE, Stream); if (Callee == VE.ElideCasts(Callee)) { // Since the call pointer has not been elided, we know that // the call pointer has the type signature of the called // function. This implies that the reader can use the type // signature of the callee to figure out how to add casts to // the arguments. Code = naclbitc::FUNC_CODE_INST_CALL; } else { // If the cast was elided, a pointer conversion to a pointer // was applied, meaning that this is an indirect call. For the // reader, this implies that we can't use the type signature // of the callee to resolve elided call arguments, since it is // not known. Hence, we must send the type signature to the // reader. Code = naclbitc::FUNC_CODE_INST_CALL_INDIRECT; Vals.push_back(VE.getTypeID(I.getType())); } for (unsigned I = 0, E = Call.getNumArgOperands(); I < E; ++I) { pushValue(Call.getArgOperand(I), InstID, Vals, VE, Stream); } break; } } Stream.EmitRecord(Code, Vals, AbbrevToUse); Vals.clear(); return true; }