Ejemplo n.º 1
0
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;
}