SizeOffsetType ObjectSizeOffsetVisitor::visitSelectInst(SelectInst &I) { SizeOffsetType TrueSide = compute(I.getTrueValue()); SizeOffsetType FalseSide = compute(I.getFalseValue()); if (bothKnown(TrueSide) && bothKnown(FalseSide)) { if (TrueSide == FalseSide) { return TrueSide; } APInt TrueResult = getSizeWithOverflow(TrueSide); APInt FalseResult = getSizeWithOverflow(FalseSide); if (TrueResult == FalseResult) { return TrueSide; } if (Options.EvalMode == ObjectSizeOpts::Mode::Min) { if (TrueResult.slt(FalseResult)) return TrueSide; return FalseSide; } if (Options.EvalMode == ObjectSizeOpts::Mode::Max) { if (TrueResult.sgt(FalseResult)) return TrueSide; return FalseSide; } } return unknown(); }
APInt IneqGraph::findShortestPathAt(Value *F, Value *T, BasicBlock *BB) { DEBUG(dbgs() << "IneqGraph: findShortestPathAt: " << *F << " ==> " << *T << " at " << BB->getName() << "\n"); Value *SigmaOrF = VS->getSigmaForAt(F, BB); Value *SigmaOrT = VS->getSigmaForAt(T, BB); APInt Shortest = findShortestPath(SigmaOrF, SigmaOrT); APInt Other = findShortestPath(F, SigmaOrT); return Other.slt(Shortest) ? Other : Shortest; }
APInt GraphNode::findShortestPath(GraphNode *Dest, SetVector<GraphNode*> Visited) { if (Dest == this) { DEBUG(dbgs() << "IneqGraph: Reached: " << *Dest->getValue() << "\n"); return APInt(64, 0, true); } DEBUG(dbgs() << "IneqGraph: Node: " << *V << "\n"); if (Visited.count(this)) { DEBUG(dbgs() << "IneqGraph: Visited\n"); return APInt::getSignedMaxValue(64); //(64, , true); } Visited.insert(this); APInt MayMin = APInt::getSignedMaxValue(64); for (may_iterator It = may_begin(), E = may_end(); It != E; ++It) { APInt Total = It->getToEdge()->findShortestPath(Dest, Visited); if (Total.slt(MayMin)) MayMin = Total + It->getWeight(); } //DEBUG(dbgs() << "IneqGraph: Node: " << *V << ", MayMin: " << MayMin << "\n"); APInt MustMax = APInt::getSignedMinValue(64); for (must_iterator It = must_begin(), E = must_end(); It != E; ++It) { APInt Total = It->getToEdge()->findShortestPath(Dest, Visited); if (MustMax.slt(Total)) MustMax = Total; } // DEBUG(dbgs() << "IneqGraph: Node: " << *V << ", MustMax: " << MustMax << "\n"); if (MustMax.isMinSignedValue()) { //DEBUG(dbgs() << "IneqGraph: Node: " << *V << ", Distance: " << MayMin << "\n"); DEBUG(dbgs() << "IneqGraph: Ret: " << MayMin << "\n"); return MayMin; } else { APInt Min = MustMax.slt(MayMin) ? MustMax : MayMin; //DEBUG(dbgs() << "IneqGraph: Node: " << *V << ", Distance: " << Min << "\n"); DEBUG(dbgs() << "IneqGraph: Ret: " << Min << "\n"); return Min; } }
/// FoldSPFofSPF - We have an SPF (e.g. a min or max) of an SPF of the form: /// SPF2(SPF1(A, B), C) Instruction *InstCombiner::FoldSPFofSPF(Instruction *Inner, SelectPatternFlavor SPF1, Value *A, Value *B, Instruction &Outer, SelectPatternFlavor SPF2, Value *C) { if (C == A || C == B) { // MAX(MAX(A, B), B) -> MAX(A, B) // MIN(MIN(a, b), a) -> MIN(a, b) if (SPF1 == SPF2) return ReplaceInstUsesWith(Outer, Inner); // MAX(MIN(a, b), a) -> a // MIN(MAX(a, b), a) -> a if ((SPF1 == SPF_SMIN && SPF2 == SPF_SMAX) || (SPF1 == SPF_SMAX && SPF2 == SPF_SMIN) || (SPF1 == SPF_UMIN && SPF2 == SPF_UMAX) || (SPF1 == SPF_UMAX && SPF2 == SPF_UMIN)) return ReplaceInstUsesWith(Outer, C); } if (SPF1 == SPF2) { if (ConstantInt *CB = dyn_cast<ConstantInt>(B)) { if (ConstantInt *CC = dyn_cast<ConstantInt>(C)) { APInt ACB = CB->getValue(); APInt ACC = CC->getValue(); // MIN(MIN(A, 23), 97) -> MIN(A, 23) // MAX(MAX(A, 97), 23) -> MAX(A, 97) if ((SPF1 == SPF_UMIN && ACB.ule(ACC)) || (SPF1 == SPF_SMIN && ACB.sle(ACC)) || (SPF1 == SPF_UMAX && ACB.uge(ACC)) || (SPF1 == SPF_SMAX && ACB.sge(ACC))) return ReplaceInstUsesWith(Outer, Inner); // MIN(MIN(A, 97), 23) -> MIN(A, 23) // MAX(MAX(A, 23), 97) -> MAX(A, 97) if ((SPF1 == SPF_UMIN && ACB.ugt(ACC)) || (SPF1 == SPF_SMIN && ACB.sgt(ACC)) || (SPF1 == SPF_UMAX && ACB.ult(ACC)) || (SPF1 == SPF_SMAX && ACB.slt(ACC))) { Outer.replaceUsesOfWith(Inner, A); return &Outer; } } } } return nullptr; }
APInt swift::constantFoldComparison(APInt lhs, APInt rhs, BuiltinValueKind ID) { bool result; switch (ID) { default: llvm_unreachable("Invalid integer compare kind"); case BuiltinValueKind::ICMP_EQ: result = lhs == rhs; break; case BuiltinValueKind::ICMP_NE: result = lhs != rhs; break; case BuiltinValueKind::ICMP_SLT: result = lhs.slt(rhs); break; case BuiltinValueKind::ICMP_SGT: result = lhs.sgt(rhs); break; case BuiltinValueKind::ICMP_SLE: result = lhs.sle(rhs); break; case BuiltinValueKind::ICMP_SGE: result = lhs.sge(rhs); break; case BuiltinValueKind::ICMP_ULT: result = lhs.ult(rhs); break; case BuiltinValueKind::ICMP_UGT: result = lhs.ugt(rhs); break; case BuiltinValueKind::ICMP_ULE: result = lhs.ule(rhs); break; case BuiltinValueKind::ICMP_UGE: result = lhs.uge(rhs); break; } return APInt(1, result); }
/* * function join * * Here we perform the join operation in the interval lattice, * using Cousot's widening operator. We join the current abstract state * with the new_abstract_state and update the current abstract state of * the node. * * This function returns true if the current abstract state has changed. */ bool llvm::RangeAnalysis::join(GraphNode* Node, Range new_abstract_state){ //Do not widen the range of a value that has an initial value if (!getInitialState(Node).isMaxRange()) { return false; } Range oldInterval = out_state[Node]; Range newInterval = new_abstract_state; APInt oldLower = oldInterval.getLower(); APInt oldUpper = oldInterval.getUpper(); APInt newLower = newInterval.getLower(); APInt newUpper = newInterval.getUpper(); if (oldInterval.isUnknown()) out_state[Node] = newInterval; else { if (widening_count[Node] < MaxIterationCount) { out_state[Node] = oldInterval.unionWith(newInterval); widening_count[Node]++; } else { //Widening APInt oldLower = oldInterval.getLower(); APInt oldUpper = oldInterval.getUpper(); APInt newLower = newInterval.getLower(); APInt newUpper = newInterval.getUpper(); if (newLower.slt(oldLower)) if (newUpper.sgt(oldUpper)) out_state[Node] = Range(Min, Max); else out_state[Node] = Range(Min, oldUpper); else if (newUpper.sgt(oldUpper)) out_state[Node] = Range(oldLower, Max); } } bool hasChanged = oldInterval != out_state[Node]; return hasChanged; }
/// MultiplyOverflows - True if the multiply can not be expressed in an int /// this size. static bool MultiplyOverflows(ConstantInt *C1, ConstantInt *C2, bool sign) { uint32_t W = C1->getBitWidth(); APInt LHSExt = C1->getValue(), RHSExt = C2->getValue(); if (sign) { LHSExt = LHSExt.sext(W * 2); RHSExt = RHSExt.sext(W * 2); } else { LHSExt = LHSExt.zext(W * 2); RHSExt = RHSExt.zext(W * 2); } APInt MulExt = LHSExt * RHSExt; if (!sign) return MulExt.ugt(APInt::getLowBitsSet(W * 2, W)); APInt Min = APInt::getSignedMinValue(W).sext(W * 2); APInt Max = APInt::getSignedMaxValue(W).sext(W * 2); return MulExt.slt(Min) || MulExt.sgt(Max); }
/// FoldSPFofSPF - We have an SPF (e.g. a min or max) of an SPF of the form: /// SPF2(SPF1(A, B), C) Instruction *InstCombiner::FoldSPFofSPF(Instruction *Inner, SelectPatternFlavor SPF1, Value *A, Value *B, Instruction &Outer, SelectPatternFlavor SPF2, Value *C) { if (C == A || C == B) { // MAX(MAX(A, B), B) -> MAX(A, B) // MIN(MIN(a, b), a) -> MIN(a, b) if (SPF1 == SPF2) return ReplaceInstUsesWith(Outer, Inner); // MAX(MIN(a, b), a) -> a // MIN(MAX(a, b), a) -> a if ((SPF1 == SPF_SMIN && SPF2 == SPF_SMAX) || (SPF1 == SPF_SMAX && SPF2 == SPF_SMIN) || (SPF1 == SPF_UMIN && SPF2 == SPF_UMAX) || (SPF1 == SPF_UMAX && SPF2 == SPF_UMIN)) return ReplaceInstUsesWith(Outer, C); } if (SPF1 == SPF2) { if (ConstantInt *CB = dyn_cast<ConstantInt>(B)) { if (ConstantInt *CC = dyn_cast<ConstantInt>(C)) { APInt ACB = CB->getValue(); APInt ACC = CC->getValue(); // MIN(MIN(A, 23), 97) -> MIN(A, 23) // MAX(MAX(A, 97), 23) -> MAX(A, 97) if ((SPF1 == SPF_UMIN && ACB.ule(ACC)) || (SPF1 == SPF_SMIN && ACB.sle(ACC)) || (SPF1 == SPF_UMAX && ACB.uge(ACC)) || (SPF1 == SPF_SMAX && ACB.sge(ACC))) return ReplaceInstUsesWith(Outer, Inner); // MIN(MIN(A, 97), 23) -> MIN(A, 23) // MAX(MAX(A, 23), 97) -> MAX(A, 97) if ((SPF1 == SPF_UMIN && ACB.ugt(ACC)) || (SPF1 == SPF_SMIN && ACB.sgt(ACC)) || (SPF1 == SPF_UMAX && ACB.ult(ACC)) || (SPF1 == SPF_SMAX && ACB.slt(ACC))) { Outer.replaceUsesOfWith(Inner, A); return &Outer; } } } } // ABS(ABS(X)) -> ABS(X) // NABS(NABS(X)) -> NABS(X) if (SPF1 == SPF2 && (SPF1 == SPF_ABS || SPF1 == SPF_NABS)) { return ReplaceInstUsesWith(Outer, Inner); } // ABS(NABS(X)) -> ABS(X) // NABS(ABS(X)) -> NABS(X) if ((SPF1 == SPF_ABS && SPF2 == SPF_NABS) || (SPF1 == SPF_NABS && SPF2 == SPF_ABS)) { SelectInst *SI = cast<SelectInst>(Inner); Value *NewSI = Builder->CreateSelect( SI->getCondition(), SI->getFalseValue(), SI->getTrueValue()); return ReplaceInstUsesWith(Outer, NewSI); } return nullptr; }
// caller must free returned value const EmuVal* eval_rexpr(const Expr* e){ errs() << "\nDEBUG: about to eval rexpr:\n"; e->dump(); if(isa<IntegerLiteral>(e)){ const IntegerLiteral *obj = (const IntegerLiteral*)e; APInt i = obj->getValue(); if(i.slt(EMU_MIN_INT) || i.sgt(EMU_MAX_INT)){ e->dump(); cant_handle(); } return new EmuNum<NUM_TYPE_INT>(i); } else if(isa<CharacterLiteral>(e)){ const CharacterLiteral *obj = (const CharacterLiteral*)e; unsigned int i = obj->getValue(); if(i > 127){ e->dump(); cant_handle(); } return new EmuNum<NUM_TYPE_CHAR>(new APInt(8, i, true)); } else if(isa<UnaryOperator>(e)){ const UnaryOperator *obj = (const UnaryOperator*)e; const Expr* sub = obj->getSubExpr(); const auto op = obj->getOpcode(); switch(op){ case UO_AddrOf: { lvalue arg = eval_lexpr(sub); return new EmuPtr(arg.ptr, e->getType()); } case UO_LNot: case UO_Minus: { const EmuVal* arg = eval_rexpr(sub); if(!arg->obj_type->isIntegerType()){ cant_cast(); } if(op == UO_LNot){ return ((const EmuNumGeneric*)arg)->lnot(); } else if (op == UO_Minus){ return ((const EmuNumGeneric*)arg)->neg(); } } case UO_Deref: case UO_Extension: case UO_Imag: case UO_Real: case UO_Not: case UO_PostInc: case UO_PostDec: case UO_PreInc: case UO_PreDec: case UO_Plus: default: llvm::errs() << "Got opcode " << obj->getOpcode() << "\n"; cant_handle(); } } else if(isa<BinaryOperator>(e)){ const BinaryOperator* ex = (const BinaryOperator*)e; BinaryOperatorKind op = ex->getOpcode(); // right always an rexpr const EmuVal *right = eval_rexpr(ex->getRHS()); switch(op){ case BO_Assign: { lvalue left = eval_lexpr(ex->getLHS()); const EmuVal* ans = right->cast_to(left.type); delete right; left.ptr.block->write(ans, left.ptr.offset); return ans; } case BO_LT: case BO_GT: case BO_LE: case BO_GE: case BO_EQ: case BO_NE: { const EmuVal *left = eval_rexpr(ex->getLHS()); QualType tl = left->obj_type.getCanonicalType(); QualType tr = right->obj_type.getCanonicalType(); if(tl != IntType || tr != IntType){ left->obj_type.dump(); right->obj_type.dump(); cant_handle(); } const llvm::APInt* lval = &((const EmuNum<NUM_TYPE_INT>*)left)->val; llvm::APInt rval = ((const EmuNum<NUM_TYPE_INT>*)right)->val; int ans; if(lval->isNegative()){ if(op == BO_LT) ans = (lval->slt(rval))?1:0; else if(op==BO_GT) ans = (lval->sgt(rval))?1:0; else if(op==BO_LE) ans = (lval->sle(rval))?1:0; else if(op==BO_GE) ans = (lval->sge(rval))?1:0; else if(op==BO_EQ) ans = (lval->eq( rval))?1:0; else if(op==BO_NE) ans = (lval->ne( rval))?1:0; } else if(rval.isNegative()){ if(op == BO_LT) ans = 0; else if(op==BO_GT) ans = 1; else if(op==BO_LE) ans = 0; else if(op==BO_GE) ans = 1; else if(op==BO_EQ) ans = 0; else if(op==BO_NE) ans = 1; } else { if(op == BO_LT) ans = (lval->ult(rval))?1:0; else if(op==BO_GT) ans = (lval->ugt(rval))?1:0; else if(op==BO_LE) ans = (lval->ule(rval))?1:0; else if(op==BO_GE) ans = (lval->uge(rval))?1:0; else if(op==BO_EQ) ans = (lval->eq( rval))?1:0; else if(op==BO_NE) ans = (lval->ne( rval))?1:0; } delete left; delete right; return new EmuNum<NUM_TYPE_INT>(APInt(32, apint_signed_repr(ans), true)); } case BO_AddAssign: case BO_SubAssign: { lvalue left = eval_lexpr(ex->getLHS()); QualType tl = left.type.getCanonicalType(); QualType tr = right->obj_type.getCanonicalType(); if(tl != IntType || tr != IntType){ left.type.dump(); right->obj_type.dump(); cant_handle(); } void* ptr = &((char*)left.ptr.block->data)[left.ptr.offset]; size_t space = left.ptr.block->size; if(space < 4 || space-4 < left.ptr.offset){ bad_memread(); } const EmuNum<NUM_TYPE_INT> value(ptr); const EmuNum<NUM_TYPE_INT>* result; if(op == BO_AddAssign) result = value.add((const EmuNum<NUM_TYPE_INT>*)right); else result = value.sub((const EmuNum<NUM_TYPE_INT>*)right); left.ptr.block->write(result, left.ptr.offset); delete right; return result; } case BO_Add: case BO_Sub: case BO_Mul: case BO_Div: case BO_And: case BO_Or: { const EmuVal* left = eval_rexpr(ex->getLHS()); if(!right->obj_type->isIntegerType()){ right->obj_type.dump(); cant_cast(); } const EmuNumGeneric* trueright = (const EmuNumGeneric*)right; const EmuVal* retval; QualType tl = left->obj_type; // special case: add integer to pointer if(tl->isPointerType()){ int n; if(op == BO_Add) n = trueright->val.getSExtValue(); else if(op == BO_Sub) n = -trueright->val.getSExtValue(); else err_exit("Undefined op on pointer"); QualType sub = tl->getAs<PointerType>()->getPointeeType(); int s = getSizeOf(sub); const EmuPtr* lp = (const EmuPtr*)left; retval = new EmuPtr(mem_ptr(lp->u.block,lp->offset+n*s), tl); } else if(tl->isIntegerType()){ const EmuNumGeneric* trueleft = (const EmuNumGeneric*)left; if(op == BO_Add) retval = trueleft->add(trueright); else if(op == BO_Sub) retval = trueleft->sub(trueright); else if(op == BO_Mul) retval = trueleft->mul(trueright); else if(op == BO_Div) retval = trueleft->div(trueright); else if(op == BO_Or) retval = trueleft->_or(trueright); else if(op == BO_And)retval = trueleft->_and(trueright); else cant_cast(); } else { tl.dump(); cant_cast(); } delete left; delete right; return retval; } case BO_PtrMemD: case BO_PtrMemI: case BO_Rem: case BO_Shl: case BO_Shr: case BO_LAnd: case BO_Xor: case BO_LOr: case BO_MulAssign: case BO_DivAssign: case BO_RemAssign: case BO_ShlAssign: case BO_ShrAssign: case BO_AndAssign: case BO_XorAssign: case BO_OrAssign: case BO_Comma: default: e->dump(); cant_handle(); } } else if(isa<CastExpr>(e)){ const CastExpr* expr = (const CastExpr*)e; const Expr* sub = expr->getSubExpr(); switch(expr->getCastKind()){ case CK_LValueToRValue: return from_lvalue(eval_lexpr(sub)); case CK_NoOp: return eval_rexpr(sub); case CK_BitCast: { if(isa<ExplicitCastExpr>(e)){ const ExplicitCastExpr* expr = (const ExplicitCastExpr*)e; return eval_rexpr(sub)->cast_to(expr->getTypeAsWritten()); } // else ImplicitCastExpr return eval_rexpr(sub)->cast_to(e->getType()); } case CK_IntegralCast: { return eval_rexpr(sub)->cast_to(expr->getType()); } case CK_FunctionToPointerDecay: { lvalue l = eval_lexpr(sub); if(!l.type->isFunctionType()){ e->dump(); cant_cast(); } return new EmuPtr(l.ptr, sources[curr_source]->getPointerType(l.type)); } case CK_ArrayToPointerDecay: { lvalue l = eval_lexpr(sub); const EmuVal* ans = new EmuPtr(l.ptr, expr->getType()); return ans; } case CK_BuiltinFnToFnPtr: { if(!isa<DeclRefExpr>(sub)){ err_exit("Don't know how to convert builtin function"); } std::string name = ((const DeclRefExpr*)sub)->getDecl()->getNameAsString(); const EmuFunc* f = get_external_func(name, sub->getType()); mem_block* ptr = new mem_block(MEM_TYPE_STATIC, f); delete f; return new EmuPtr(mem_ptr(ptr,0), expr->getType()); } case CK_NullToPointer: { return new EmuPtr(mem_ptr(nullptr,0), expr->getType()); } case CK_PointerToIntegral: { const EmuVal* ptr = eval_rexpr(sub); if(!ptr->obj_type->isPointerType()){ err_exit("Expected pointer"); } const EmuPtr* p = (const EmuPtr*)ptr; if(p->status != STATUS_DEFINED) cant_handle(); uint64_t segment; uint64_t offset = p->offset; if(p->u.block == nullptr){ segment = 0; } else { segment = p->u.block->id; } delete ptr; if((expr->getType()->getAs<BuiltinType>())->isSignedInteger()){ return new EmuNum<NUM_TYPE_LONGLONG>(APInt(64, (segment << 32) + offset, true)); } else { return new EmuNum<NUM_TYPE_ULONGLONG>(APInt(64, (segment << 32) + offset, false)); } } case CK_VectorSplat: case CK_IntegralToBoolean: case CK_IntegralToFloating: case CK_FloatingToIntegral: case CK_FloatingToBoolean: case CK_FloatingCast: case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: case CK_FloatingRealToComplex: case CK_FloatingComplexToReal: case CK_FloatingComplexToBoolean: case CK_FloatingComplexCast: case CK_FloatingComplexToIntegralComplex: case CK_IntegralRealToComplex: case CK_IntegralComplexToReal: case CK_IntegralComplexToBoolean: case CK_IntegralComplexCast: case CK_IntegralComplexToFloatingComplex: case CK_ARCProduceObject: case CK_ARCConsumeObject: case CK_ARCReclaimReturnedObject: case CK_ARCExtendBlockObject: case CK_AtomicToNonAtomic: case CK_NonAtomicToAtomic: case CK_CopyAndAutoreleaseBlockObject: case CK_ZeroToOCLEvent: case CK_AddressSpaceConversion: case CK_ReinterpretMemberPointer: case CK_UserDefinedConversion: case CK_ConstructorConversion: case CK_IntegralToPointer: case CK_PointerToBoolean: case CK_ToVoid: default: llvm::errs() << "\n\n"; e->dump(); cant_cast(); } } else if(isa<CallExpr>(e)){ const CallExpr* expr = (const CallExpr*)e; const Expr* const* args = expr->getArgs(); const Expr* callee = expr->getCallee(); llvm::errs() << "DOUG DEBUG: executing the following call:\n"; callee->dump(); const EmuVal* f = eval_rexpr(callee); if(f->status != STATUS_DEFINED || !f->obj_type->isFunctionPointerType()){ f->obj_type.dump(); err_exit("Calling an invalid function"); } const EmuPtr* p = (const EmuPtr*)f; if(p->u.block->memtype == MEM_TYPE_EXTERN){ err_exit("Tried to call an unimplemented function"); } const EmuFunc* func = (const EmuFunc*)from_lvalue(lvalue(p->u.block, ((const PointerType*)p->obj_type.getTypePtr())->getPointeeType(), p->offset)); uint32_t fid = func->func_id; const EmuVal* retval; add_stack_frame(); if(fid < NUM_EXTERNAL_FUNCTIONS){ if(is_lvalue_based_macro(fid)){ // special handling for va_args stuff for(unsigned int i=0; i < expr->getNumArgs(); i++){ const Expr* arg = args[i]; while(isa<ImplicitCastExpr>(arg)){ arg = ((const ImplicitCastExpr*)arg)->getSubExpr(); } if(!isa<DeclRefExpr>(arg)){ err_exit("Passed non-variable as lvalue to builtin macro"); } std::string name = ((const DeclRefExpr*)arg)->getDecl()->getNameAsString(); std::unordered_map<std::string,std::deque<std::pair<int,int> > >::const_iterator list = stack_var_map.find(name); if(list == stack_var_map.end()){ err_exit("Can't find appropriate lvalue for macro"); } const auto test = list->second; const auto item = test.back(); const EmuVal* val = new EmuStackPos(item.first, item.second); mem_block* storage = new mem_block(MEM_TYPE_STACK, val); add_stack_var("", lvalue(storage,val->obj_type,0)); delete val; } } else { // we are dealing with an external function for(unsigned int i=0; i < expr->getNumArgs(); i++){ const EmuVal* val = eval_rexpr(args[i]); mem_block* storage = new mem_block(MEM_TYPE_STACK, val); add_stack_var("", lvalue(storage,val->obj_type,0)); delete val; } } retval = call_external(fid); } else { const auto it = global_functions.find(fid); const FunctionDecl* defn = (const FunctionDecl*)it->second.second; for(unsigned int i=0; i < expr->getNumArgs(); i++){ const EmuVal* val = eval_rexpr(args[i]); mem_block* storage = new mem_block(MEM_TYPE_STACK, val); std::string name; if(i >= defn->getNumParams()){ name = ""; // relevant for later args of e.g. printf(char*, ...) } else { name = defn->getParamDecl(i)->getNameAsString(); } llvm::errs() << "DOUG DEBUG: adding stack variable "<<name<<" for arg "<<i<<" of internal function call (numparams="<< defn->getNumParams() <<")\n"; defn->dump(); add_stack_var(name, lvalue(storage,val->obj_type,0)); delete val; } int save = curr_source; curr_source = it->second.first; llvm::errs() << "DOUG DEBUG: actually executing:\n"; defn->getBody()->dump(); retval = exec_stmt(defn->getBody()); llvm::errs() << "DOUG DEBUG: call returned with retval at "<<((const void*)retval)<<"\n"; curr_source = save; } llvm::errs() << "DOUG DEBUG: popping frame leaving call\n"; pop_stack_frame(); return retval; } else if(isa<UnaryExprOrTypeTraitExpr>(e)){ const UnaryExprOrTypeTraitExpr* expr = (const UnaryExprOrTypeTraitExpr*)e; switch(expr->getKind()){ case UETT_SizeOf: { QualType qt = expr->getArgumentType(); const EmuVal* fake = from_lvalue(lvalue(nullptr, qt, 0)); uint64_t thesize = (uint64_t)fake->size(); delete fake; return new EmuNum<NUM_TYPE_ULONG>(APInt(32, thesize, false)); } case UETT_AlignOf: case UETT_VecStep: default: e->dump(); cant_handle(); } } else if(isa<InitListExpr>(e)){ const InitListExpr* expr = (const InitListExpr*)e; unsigned int n = expr->getNumInits(); QualType qt = expr->getType(); if(qt->isArrayType()){ const EmuPtr* array = (const EmuPtr*)from_lvalue(lvalue(nullptr, qt, 0)); if(array->status != STATUS_DEFINED) cant_handle(); size_t loc = 0; for(unsigned int i = 0; i < n; i++){ const EmuVal* curr = eval_rexpr(expr->getInit(i)); array->u.block->write(curr, loc); loc += curr->size(); delete curr; } return array; } else if(qt->isStructureType()){ unsigned int n = expr->getNumInits(); const EmuVal** arr = new const EmuVal*[n]; for(unsigned int i = 0; i < n; i++){ arr[i] = eval_rexpr(expr->getInit(i)); } return new EmuStruct(STATUS_DEFINED, qt, n, arr); } cant_handle(); } else if(isa<ImplicitValueInitExpr>(e)){ return zero_init(e->getType()); } else if(isa<ParenExpr>(e)){ return eval_rexpr(((const ParenExpr*)e)->getSubExpr()); } e->dump(); cant_handle(); }