diff --git a/include/retdec/bin2llvmir/optimizations/param_return/data_entries.h b/include/retdec/bin2llvmir/optimizations/param_return/data_entries.h index 3aa49d419..30bbdffe7 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/data_entries.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/data_entries.h @@ -165,6 +165,9 @@ class DataFlowEntry : public FunctionEntry void setCalledValue(llvm::Value* called); + std::size_t numberOfCalls() const; + bool hasBranches() const; + // Usage data. // public: diff --git a/src/bin2llvmir/optimizations/param_return/data_entries.cpp b/src/bin2llvmir/optimizations/param_return/data_entries.cpp index ded90528b..de5d2c850 100644 --- a/src/bin2llvmir/optimizations/param_return/data_entries.cpp +++ b/src/bin2llvmir/optimizations/param_return/data_entries.cpp @@ -421,6 +421,38 @@ void DataFlowEntry::setCalledValue(llvm::Value* called) _calledValue = called; } +std::size_t DataFlowEntry::numberOfCalls() const +{ + auto fnc = getFunction(); + if (fnc == nullptr) + return 0; + + std::size_t calls = 0; + for (auto& bb: *fnc) + for (auto& i: bb) + if (auto call = dyn_cast(&i)) { + auto* calledFnc = call->getCalledFunction(); + if (calledFnc && !calledFnc->isIntrinsic()) + calls++; + } + + return calls; +} + +bool DataFlowEntry::hasBranches() const +{ + auto fnc = getFunction(); + if (fnc == nullptr) + return false; + + for (auto& bb: *fnc) + for (auto& i: bb) + if (isa(i)) + return true; + + return false; +} + CallEntry* DataFlowEntry::createCallEntry(CallInst* call) { _calls.push_back(CallEntry(call, this)); diff --git a/src/bin2llvmir/optimizations/param_return/filter/filter.cpp b/src/bin2llvmir/optimizations/param_return/filter/filter.cpp index 31d5666af..5b07bc0fc 100644 --- a/src/bin2llvmir/optimizations/param_return/filter/filter.cpp +++ b/src/bin2llvmir/optimizations/param_return/filter/filter.cpp @@ -174,6 +174,10 @@ void Filter::filterCalls(DataFlowEntry* de) const retTempl = callRets.front(); } + /* When there is definition available we should + * use arguments from there. This is more reliable than + * constructing intersations of used arguments in file. + */ if (de->hasDefinition()) { FilterableLayout defArgs; @@ -191,12 +195,16 @@ void Filter::filterCalls(DataFlowEntry* de) const // below. filterArgsByKnownTypes(defArgs); } - else if (de->args().empty()) + else if (de->args().empty() && de->numberOfCalls() == 1 && !de->hasBranches()) { + // In this case it might be wrapper that + // takes arguments from call and do not modify them + // in definition. filterCallArgsByDefLayout(defArgs, argTempl); de->setArgs(createGroupedArgValues(defArgs)); } - else if (argTempl.stacks.size() > defArgs.stacks.size()) + else if (argTempl.stacks.size() > defArgs.stacks.size() + && de->numberOfCalls() == 1 && !de->hasBranches()) { if (argTempl.gpRegisters.size() == defArgs.gpRegisters.size() && argTempl.fpRegisters.size() == defArgs.fpRegisters.size() diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index e40da74f2..180c53591 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -579,6 +579,7 @@ void ParamReturn::dumpInfo(const DataFlowEntry& de) const LOG << "\t>|config f : " << (configFnc != nullptr) << std::endl; LOG << "\t>|debug f : " << (dbgFnc != nullptr) << std::endl; LOG << "\t>|wrapp c : " << llvmObjToString(wrappedCall) << std::endl; + LOG << "\t>|calls cnt: " << de.numberOfCalls() << std::endl; LOG << "\t>|type set : " << !de.argTypes().empty() << std::endl; LOG << "\t>|ret type : " << llvmObjToString(de.getRetType()) << std::endl; LOG << "\t>|ret value: " << llvmObjToString(de.getRetValue()) << std::endl;