const ReachingDefinitions &DataflowAnalyzer::computeReachingDefinitions(const Term *term, const MemoryLocation &memoryLocation, const ReachingDefinitions &definitions) { auto &termDefinitions = dataflow().getDefinitions(term); if (isTracked(memoryLocation)) { definitions.project(memoryLocation, termDefinitions); } else { termDefinitions.clear(); } return termDefinitions; }
static void resize( state_type &x1 , state_type x2 ) { //std::cout << "resizing..." << std::endl; // allocate required memory x1.resize( x2.size() ); for( size_t i=0 ; i < x2.size() ; ++i ) { x1[i] = dataflow( unwrap([]( shared_vec v2 ) { shared_vec tmp = std::allocate_shared<dvecvec>( std::allocator<dvecvec>() ); tmp->resize( v2->size() ); for( size_t n=0 ; n<v2->size() ; ++n ) (*tmp)[n].resize( (*v2)[n].size() ); return tmp; }) , x2[i] ); } //std::cout << "resizing complete" << std::endl; }
const MemoryLocation &DataflowAnalyzer::computeMemoryLocation(const Term *term, const ReachingDefinitions &definitions) { return dataflow().setMemoryLocation(term, [&]() -> MemoryLocation { switch (term->kind()) { case Term::MEMORY_LOCATION_ACCESS: { return term->asMemoryLocationAccess()->memoryLocation(); } case Term::DEREFERENCE: { auto dereference = term->asDereference(); auto addressValue = computeValue(dereference->address(), definitions); if (addressValue->abstractValue().isConcrete()) { if (dereference->domain() == MemoryDomain::MEMORY) { return MemoryLocation( dereference->domain(), addressValue->abstractValue().asConcrete().value() * CHAR_BIT, dereference->size()); } else { return MemoryLocation( dereference->domain(), addressValue->abstractValue().asConcrete().value(), dereference->size()); } } else if (addressValue->isStackOffset()) { return MemoryLocation(MemoryDomain::STACK, addressValue->stackOffset() * CHAR_BIT, dereference->size()); } else { return MemoryLocation(); } break; } default: { log_.warning(tr("%1: Term kind %2 cannot have a memory location.").arg(Q_FUNC_INFO).arg(term->kind())); return MemoryLocation(); } } }()); }
static typename util::detail::algorithm_result<ExPolicy, SegIter>::type segmented_for_each(Algo && algo, ExPolicy const& policy, SegIter first, SegIter last, F && f, Proj && proj, boost::mpl::false_) { typedef hpx::traits::segmented_iterator_traits<SegIter> traits; typedef typename traits::segment_iterator segment_iterator; typedef typename traits::local_iterator local_iterator_type; typedef util::detail::algorithm_result<ExPolicy, SegIter> result; typedef typename std::iterator_traits<SegIter>::iterator_category iterator_category; typedef typename boost::mpl::bool_<boost::is_same< iterator_category, std::input_iterator_tag >::value> forced_seq; segment_iterator sit = traits::segment(first); segment_iterator send = traits::segment(last); std::vector<future<local_iterator_type> > segments; segments.reserve(std::distance(sit, send)); if (sit == send) { // all elements are on the same partition local_iterator_type beg = traits::local(first); local_iterator_type end = traits::local(last); if (beg != end) { segments.push_back(dispatch_async(traits::get_id(sit), algo, policy, forced_seq(), beg, end, f, proj )); } } else { // handle the remaining part of the first partition local_iterator_type beg = traits::local(first); local_iterator_type end = traits::end(sit); if (beg != end) { segments.push_back(dispatch_async(traits::get_id(sit), algo, policy, forced_seq(), beg, end, f, proj )); } // handle all of the full partitions for (++sit; sit != send; ++sit) { beg = traits::begin(sit); end = traits::end(sit); if (beg != end) { segments.push_back(dispatch_async(traits::get_id(sit), algo, policy, forced_seq(), beg, end, f, proj )); } } // handle the beginning of the last partition beg = traits::begin(sit); end = traits::local(last); if (beg != end) { segments.push_back(dispatch_async(traits::get_id(sit), algo, policy, forced_seq(), beg, end, f, proj )); } } return result::get( dataflow( [=](std::vector<hpx::future<local_iterator_type> > && r) -> SegIter { // handle any remote exceptions, will throw on error std::list<boost::exception_ptr> errors; parallel::util::detail::handle_remote_exceptions< ExPolicy >::call(r, errors); return traits::compose(send, r.back().get()); }, std::move(segments))); }
void jacobi( size_t n , size_t iterations, size_t block_size, std::string output_filename) { hpx::util::high_resolution_timer t; vector< vector< vector< shared_future<block> > > > blockList(2); jacobi_init(blockList, n, block_size); size_t numBlocks = blockList[0].size(); for(size_t i = 1; i < iterations; ++i) { const size_t prev = i%2; const size_t curr = (i+1)%2; blockList[curr][0][0] = dataflow( jacobi_BL, blockList[prev][0][0], blockList[prev][0][1], blockList[prev][1][0] ); for(size_t j = 1; j < numBlocks - 1; j++) { blockList[curr][j][0] = dataflow( jacobi_left, blockList[prev][j ][0], blockList[prev][j ][1], blockList[prev][j-1][0], blockList[prev][j+1][0] ); } blockList[curr][numBlocks-1][0] = dataflow( jacobi_TL, blockList[prev][numBlocks-1][0], blockList[prev][numBlocks-1][1], blockList[prev][numBlocks-2][0] ); for(size_t j = 1; j < numBlocks - 1; j++) { blockList[curr][0][j] = dataflow( jacobi_bot, blockList[prev][0][j ], blockList[prev][0][j-1], blockList[prev][0][j+1], blockList[prev][1][j ] ); for(size_t k = 1; k < numBlocks - 1; k++) { blockList[curr][j][k] = dataflow( jacobi_op, blockList[prev][k ][j ], blockList[prev][k ][j-1], blockList[prev][k ][j+1], blockList[prev][k-1][j ], blockList[prev][k+1][j ]); } blockList[curr][numBlocks-1][j] = dataflow( jacobi_top, blockList[prev][numBlocks-1][j ], blockList[prev][numBlocks-1][j-1], blockList[prev][numBlocks-1][j+1], blockList[prev][numBlocks-2][j ] ); } blockList[curr][0][numBlocks-1] = dataflow( jacobi_BR, blockList[prev][0][numBlocks-1], blockList[prev][0][numBlocks-2], blockList[prev][1][numBlocks-1]); for(size_t j = 1; j < numBlocks - 1; j++) { blockList[curr][j][numBlocks-1] = dataflow( jacobi_left, blockList[prev][j ][numBlocks-1], blockList[prev][j ][numBlocks-2], blockList[prev][j-1][numBlocks-1], blockList[prev][j+1][numBlocks-1]); } blockList[curr][numBlocks-1][numBlocks-1] = dataflow( jacobi_TR, blockList[prev][numBlocks-1][numBlocks-1], blockList[prev][numBlocks-1][numBlocks-2], blockList[prev][numBlocks-2][numBlocks-1]); } for(int i = 0; i < blockList[(n-1)%2].size(); i++) { hpx::wait_all(blockList[(n-1)%2][i]); } report_timing(n, iterations, t.elapsed()); //output_grid(output_filename, *grid_old, n); }
static typename util::detail::algorithm_result<ExPolicy, SegIter>::type segmented_minormax(Algo && algo, ExPolicy const& policy, SegIter first, SegIter last, F && f, Proj && proj, std::false_type) { typedef hpx::traits::segmented_iterator_traits<SegIter> traits; typedef typename traits::segment_iterator segment_iterator; typedef typename traits::local_iterator local_iterator_type; typedef std::integral_constant<bool, !hpx::traits::is_forward_iterator<SegIter>::value > forced_seq; typedef util::detail::algorithm_result<ExPolicy, SegIter> result; segment_iterator sit = traits::segment(first); segment_iterator send = traits::segment(last); std::vector<future<SegIter> > segments; segments.reserve(std::distance(sit, send)); if (sit == send) { // all elements are on the same partition local_iterator_type beg = traits::local(first); local_iterator_type end = traits::local(last); if (beg != end) { segments.push_back( hpx::make_future<SegIter>( dispatch_async(traits::get_id(sit), algo, policy, forced_seq(), beg, end, f, proj), [send](local_iterator_type const& out) -> SegIter { return traits::compose(send, out); })); } } else { // handle the remaining part of the first partition local_iterator_type beg = traits::local(first); local_iterator_type end = traits::end(sit); if (beg != end) { segments.push_back( hpx::make_future<SegIter>( dispatch_async(traits::get_id(sit), algo, policy, forced_seq(), beg, end, f, proj), [sit](local_iterator_type const& out) -> SegIter { return traits::compose(sit, out); })); } // handle all of the full partitions for (++sit; sit != send; ++sit) { beg = traits::begin(sit); end = traits::end(sit); if (beg != end) { segments.push_back( hpx::make_future<SegIter>( dispatch_async(traits::get_id(sit), algo, policy, forced_seq(), beg, end, f, proj), [sit](local_iterator_type const& out) -> SegIter { return traits::compose(sit, out); })); } } // handle the beginning of the last partition beg = traits::begin(sit); end = traits::local(last); if (beg != end) { segments.push_back( hpx::make_future<SegIter>( dispatch_async(traits::get_id(sit), algo, policy, forced_seq(), beg, end, f, proj), [sit](local_iterator_type const& out) -> SegIter { return traits::compose(sit, out); })); } } return result::get( dataflow( [=](std::vector<hpx::future<SegIter> > && r) -> SegIter { // handle any remote exceptions, will throw on error std::list<boost::exception_ptr> errors; parallel::util::detail::handle_remote_exceptions< ExPolicy >::call(r, errors); std::vector<SegIter> res = hpx::util::unwrapped(std::move(r)); return Algo::sequential_minmax_element_ind( policy, res.begin(), res.size(), f, proj); }, std::move(segments))); }
static typename util::detail::algorithm_result<ExPolicy, T>::type segmented_transform_reduce(Algo && algo, ExPolicy const& policy, SegIter first, SegIter last, T && init, Reduce && red_op, Convert && conv_op, std::false_type) { typedef hpx::traits::segmented_iterator_traits<SegIter> traits; typedef typename traits::segment_iterator segment_iterator; typedef typename traits::local_iterator local_iterator_type; typedef util::detail::algorithm_result<ExPolicy, T> result; typedef std::integral_constant<bool, !hpx::traits::is_forward_iterator<SegIter>::value > forced_seq; segment_iterator sit = traits::segment(first); segment_iterator send = traits::segment(last); std::vector<shared_future<T> > segments; segments.reserve(std::distance(sit, send)); if (sit == send) { // all elements are on the same partition local_iterator_type beg = traits::local(first); local_iterator_type end = traits::local(last); if (beg != end) { segments.push_back( dispatch_async(traits::get_id(sit), algo, policy, forced_seq(), beg, end, init, red_op, conv_op) ); } } else { // handle the remaining part of the first partition local_iterator_type beg = traits::local(first); local_iterator_type end = traits::end(sit); if (beg != end) { segments.push_back( dispatch_async(traits::get_id(sit), algo, policy, forced_seq(), beg, end, init, red_op, conv_op) ); } // handle all of the full partitions for (++sit; sit != send; ++sit) { beg = traits::begin(sit); end = traits::end(sit); if (beg != end) { segments.push_back( dispatch_async(traits::get_id(sit), algo, policy, forced_seq(), beg, end, init, red_op, conv_op) ); } } // handle the beginning of the last partition beg = traits::begin(sit); end = traits::local(last); if (beg != end) { segments.push_back( dispatch_async(traits::get_id(sit), algo, policy, forced_seq(), beg, end, init, red_op, conv_op) ); } } return result::get( dataflow( [=](std::vector<shared_future<T> > && r) -> T { // handle any remote exceptions, will throw on error std::list<boost::exception_ptr> errors; parallel::util::detail::handle_remote_exceptions< ExPolicy >::call(r, errors); // VS2015RC bails out if red_op is capture by ref return std::accumulate( r.begin(), r.end(), init, [=](T const& val, shared_future<T>& curr) { return red_op(val, curr.get()); }); }, std::move(segments))); }
static typename util::detail::algorithm_result< ExPolicy, typename std::iterator_traits<SegIter>::difference_type >::type segmented_count(Algo && algo, ExPolicy const& policy, SegIter first, SegIter last, T const& value, std::false_type) { typedef hpx::traits::segmented_iterator_traits<SegIter> traits; typedef typename traits::segment_iterator segment_iterator; typedef typename traits::local_iterator local_iterator_type; typedef std::integral_constant<bool, !hpx::traits::is_forward_iterator<SegIter>::value > forced_seq; typedef typename std::iterator_traits<SegIter>::difference_type value_type; typedef util::detail::algorithm_result<ExPolicy, value_type> result; segment_iterator sit = traits::segment(first); segment_iterator send = traits::segment(last); std::vector<shared_future<value_type> > segments; segments.reserve(std::distance(sit, send)); if (sit == send) { // all elements are on the same partition local_iterator_type beg = traits::local(first); local_iterator_type end = traits::local(last); if (beg != end) { segments.push_back(dispatch_async(traits::get_id(sit), algo, policy, forced_seq(), beg, end, value)); } } else { // handle the remaining part of the first partition local_iterator_type beg = traits::local(first); local_iterator_type end = traits::end(sit); if (beg != end) { segments.push_back(dispatch_async(traits::get_id(sit), algo, policy, forced_seq(), beg, end, value)); } // handle all of the full partitions for (++sit; sit != send; ++sit) { beg = traits::begin(sit); end = traits::end(sit); if (beg != end) { segments.push_back(dispatch_async(traits::get_id(sit), algo, policy, forced_seq(), beg, end, value)); } } // handle the beginning of the last partition beg = traits::begin(sit); end = traits::local(last); if (beg != end) { segments.push_back(dispatch_async(traits::get_id(sit), algo, policy, forced_seq(), beg, end, value)); } } return result::get( dataflow( hpx::util::unwrapped([=](std::vector<value_type> && r) { return std::accumulate(r.begin(), r.end(), value_type()); }), segments)); }
void TypeAnalyzer::analyze(const BinaryOperator *binary) { /* Be careful: these pointers become kinda invalid after doing unionSet(). */ Type *type = types().getType(binary); Type *leftType = types().getType(binary->left()); Type *rightType = types().getType(binary->right()); const dflow::Value *value = dataflow().getValue(binary->left()); const dflow::Value *leftValue = dataflow().getValue(binary->left()); const dflow::Value *rightValue = dataflow().getValue(binary->right()); switch (binary->operatorKind()) { case BinaryOperator::ADD: if (leftType->isInteger() && rightType->isInteger()) { type->makeInteger(); } if ((leftType->isInteger() && rightType->isPointer()) || (leftType->isPointer() && rightType->isInteger())) { type->makePointer(); } if (type->isInteger()) { leftType->makeInteger(); rightType->makeInteger(); } if (type->isPointer()) { if (leftType->isInteger()) { rightType->makePointer(); } if (rightType->isInteger()) { leftType->makePointer(); } if (leftType->isPointer()) { rightType->makeInteger(); } if (rightType->isPointer()) { leftType->makeInteger(); } if (!leftType->isPointer() && !rightType->isPointer()) { if (leftValue->isMultiplication()) { rightType->makePointer(); } else if (rightValue->isMultiplication()) { leftType->makePointer(); } else if (leftValue->isConstant()) { if (leftValue->constantValue().value() < 4096) { leftType->makeInteger(); } else { leftType->makePointer(); } } else if (rightValue->isConstant()) { if (rightValue->constantValue().value() < 4096) { rightType->makeInteger(); } else { rightType->makePointer(); } } } } if (leftType->isUnsigned() || rightType->isUnsigned()) { type->makeUnsigned(); } if (leftType->isSigned() && rightType->isSigned()) { type->makeSigned(); } if (type->isSigned()) { leftType->makeSigned(); rightType->makeSigned(); } if (type->isUnsigned()) { if (leftType->isSigned()) { rightType->makeUnsigned(); } if (rightType->isSigned()) { rightType->makeUnsigned(); } } if (rightValue->isConstant()) { if (type == leftType) { type->updateFactor(rightValue->constantValue().absoluteValue()); } else { #ifdef NC_STRUCT_RECOVERY if (!value->isStackOffset()) { leftType->addOffset(rightValue->constantValue().signedValue(), type); } #endif } } if (leftValue->isConstant()) { if (type == rightType) { type->updateFactor(leftValue->constantValue().absoluteValue()); } else { #ifdef NC_STRUCT_RECOVERY if (!value->isStackOffset()) { rightType->addOffset(leftValue->constantValue().signedValue(), type); } #endif } } if (leftType->isPointer() && rightValue->isMultiplication()) { type->makePointer(leftType->pointee()); } if (rightType->isPointer() && leftValue->isMultiplication()) { type->makePointer(rightType->pointee()); } break; case BinaryOperator::SUB: if (leftType->isInteger() && rightType->isInteger()) { type->makeInteger(); } if (leftType->isPointer() && rightType->isInteger()) { type->makePointer(); } if (type->isPointer()) { leftType->makePointer(); rightType->makeInteger(); } if (leftType->isUnsigned() || rightType->isUnsigned()) { type->makeUnsigned(); } if (leftType->isSigned() && rightType->isSigned()) { type->makeSigned(); } if (type->isSigned()) { leftType->makeSigned(); rightType->makeSigned(); } if (type->isUnsigned()) { if (leftType->isSigned()) { rightType->makeUnsigned(); } if (rightType->isSigned()) { rightType->makeUnsigned(); } } if (rightValue->isConstant()) { if (type == leftType) { type->updateFactor(rightValue->constantValue().absoluteValue()); } else { #ifdef NC_STRUCT_RECOVERY if (!value->isStackOffset()) { leftType->addOffset(-rightValue->constantValue().signedValue(), type); } #endif } } if (leftType->isPointer() && rightValue->isMultiplication()) { type->makePointer(leftType->pointee()); } break; case BinaryOperator::MUL: type->makeInteger(); leftType->makeInteger(); rightType->makeInteger(); if (leftType->isUnsigned() || rightType->isUnsigned()) { type->makeUnsigned(); } if (leftType->isSigned() && rightType->isSigned()) { type->makeSigned(); } if (type->isSigned()) { leftType->makeSigned(); rightType->makeSigned(); } if (type->isUnsigned()) { if (leftType->isSigned()) { rightType->makeUnsigned(); } if (rightType->isSigned()) { rightType->makeUnsigned(); } } if (rightValue->isConstant()) { type->updateFactor(leftType->factor() * rightValue->constantValue().value()); } if (leftValue->isConstant()) { type->updateFactor(rightType->factor() * leftValue->constantValue().value()); } break; case BinaryOperator::SIGNED_DIV: leftType->makeInteger(); rightType->makeInteger(); type->makeInteger(); leftType->makeSigned(); rightType->makeSigned(); type->makeSigned(); break; case BinaryOperator::UNSIGNED_DIV: type->makeInteger(); leftType->makeInteger(); rightType->makeInteger(); if (leftType->isSigned()) { rightType->makeUnsigned(); } if (rightType->isUnsigned()) { leftType->makeSigned(); } type->makeUnsigned(); break; case BinaryOperator::SIGNED_REM: leftType->makeInteger(); rightType->makeInteger(); type->makeInteger(); leftType->makeSigned(); rightType->makeSigned(); type->makeSigned(); break; case BinaryOperator::UNSIGNED_REM: type->makeInteger(); leftType->makeInteger(); rightType->makeInteger(); if (leftType->isSigned()) { rightType->makeUnsigned(); } if (rightType->isUnsigned()) { leftType->makeSigned(); } type->makeUnsigned(); break; case BinaryOperator::BITWISE_AND: /* FALLTHROUGH */ case BinaryOperator::LOGICAL_AND: /* FALLTHROUGH */ case BinaryOperator::BITWISE_OR: /* FALLTHROUGH */ case BinaryOperator::LOGICAL_OR: /* FALLTHROUGH */ case BinaryOperator::BITWISE_XOR: leftType->makeInteger(); rightType->makeInteger(); type->makeInteger(); leftType->makeUnsigned(); rightType->makeUnsigned(); type->makeUnsigned(); break; case BinaryOperator::SHL: leftType->makeInteger(); rightType->makeInteger(); type->makeInteger(); rightType->makeUnsigned(); if (leftType->isSigned()) { type->makeSigned(); } if (leftType->isUnsigned()) { type->makeUnsigned(); } if (type->isSigned()) { leftType->makeSigned(); } if (type->isUnsigned()) { leftType->makeUnsigned(); } if (rightValue->isConstant()) { type->updateFactor(leftType->factor() * (ConstantValue(1) << rightValue->constantValue().value())); } break; case BinaryOperator::SHR: leftType->makeInteger(); rightType->makeInteger(); type->makeInteger(); leftType->makeUnsigned(); type->makeUnsigned(); break; case BinaryOperator::SAR: leftType->makeInteger(); rightType->makeInteger(); type->makeInteger(); leftType->makeSigned(); type->makeSigned(); break; case BinaryOperator::EQUAL: leftType->unionSet(rightType); break; case BinaryOperator::SIGNED_LESS: /* FALLTHROUGH */ case BinaryOperator::SIGNED_LESS_OR_EQUAL: /* FALLTHROUGH */ case BinaryOperator::SIGNED_GREATER: /* FALLTHROUGH */ case BinaryOperator::SIGNED_GREATER_OR_EQUAL: leftType->makeSigned(); rightType->makeSigned(); leftType->unionSet(rightType); break; case BinaryOperator::UNSIGNED_LESS: /* FALLTHROUGH */ case BinaryOperator::UNSIGNED_LESS_OR_EQUAL: /* FALLTHROUGH */ case BinaryOperator::UNSIGNED_GREATER: /* FALLTHROUGH */ case BinaryOperator::UNSIGNED_GREATER_OR_EQUAL: if (rightType->isSigned()) { leftType->makeUnsigned(); } else if (leftType->isSigned()) { rightType->makeUnsigned(); } else { leftType->makeUnsigned(); rightType->makeUnsigned(); } leftType->unionSet(rightType); break; default: unreachable(); break; } }
void DataflowAnalyzer::analyze(const CFG &cfg) { /* * Returns true if the given term does not cover given memory location. */ auto notCovered = [this](const MemoryLocation &mloc, const Term *term) -> bool { return !dataflow().getMemoryLocation(term).covers(mloc); }; /* Mapping of a basic block to the definitions reaching its end. */ boost::unordered_map<const BasicBlock *, ReachingDefinitions> outDefinitions; /* * Running abstract interpretation until reaching a fixpoint several times in a row. */ int niterations = 0; int nfixpoints = 0; while (nfixpoints++ < 3) { /* * Run abstract interpretation on all basic blocks. */ foreach (auto basicBlock, cfg.basicBlocks()) { ReachingDefinitions definitions; /* Merge reaching definitions from predecessors. */ foreach (const BasicBlock *predecessor, cfg.getPredecessors(basicBlock)) { definitions.merge(outDefinitions[predecessor]); } /* Remove definitions that do not cover the memory location that they define. */ definitions.filterOut(notCovered); /* Execute all the statements in the basic block. */ foreach (auto statement, basicBlock->statements()) { execute(statement, definitions); } /* Something has changed? */ ReachingDefinitions &oldDefinitions(outDefinitions[basicBlock]); if (oldDefinitions != definitions) { oldDefinitions = std::move(definitions); nfixpoints = 0; } } /* * Some terms might have changed their addresses. Filter again. */ foreach (auto &termAndDefinitions, dataflow().term2definitions()) { termAndDefinitions.second.filterOut(notCovered); } /* * Do we loop infinitely? */ if (++niterations >= 30) { log_.warning(tr("%1: Fixpoint was not reached after %2 iterations.").arg(Q_FUNC_INFO).arg(niterations)); break; } canceled_.poll(); } /* * Remove information about terms that disappeared. * Terms can disappear if e.g. a call is deinstrumented during the analysis. */ auto disappeared = [](const Term *term){ return term->statement()->basicBlock() == nullptr; }; std::vector<const Term *> disappearedTerms; foreach (auto &termAndDefinitions, dataflow().term2definitions()) { termAndDefinitions.second.filterOut([disappeared](const MemoryLocation &, const Term *term) { return disappeared(term); } ); } remove_if(dataflow().term2value(), disappeared); remove_if(dataflow().term2location(), disappeared); remove_if(dataflow().term2definitions(), disappeared); }
Value *DataflowAnalyzer::computeValue(const Term *term, const MemoryLocation &memoryLocation, const ReachingDefinitions &definitions) { assert(term); assert(term->isRead()); assert(memoryLocation || definitions.empty()); auto value = dataflow().getValue(term); if (definitions.empty()) { return value; } auto byteOrder = architecture()->getByteOrder(memoryLocation.domain()); /* * Merge abstract values. */ auto abstractValue = value->abstractValue(); foreach (const auto &chunk, definitions.chunks()) { assert(memoryLocation.covers(chunk.location())); /* * Mask of bits inside abstractValue which are covered by chunk's location. */ auto mask = bitMask<ConstantValue>(chunk.location().size()); if (byteOrder == ByteOrder::LittleEndian) { mask = bitShift(mask, chunk.location().addr() - memoryLocation.addr()); } else { mask = bitShift(mask, memoryLocation.endAddr() - chunk.location().endAddr()); } foreach (auto definition, chunk.definitions()) { auto definitionLocation = dataflow().getMemoryLocation(definition); assert(definitionLocation.covers(chunk.location())); auto definitionValue = dataflow().getValue(definition); auto definitionAbstractValue = definitionValue->abstractValue(); /* * Shift definition's abstract value to match term's location. */ if (byteOrder == ByteOrder::LittleEndian) { definitionAbstractValue.shift(definitionLocation.addr() - memoryLocation.addr()); } else { definitionAbstractValue.shift(memoryLocation.endAddr() - definitionLocation.endAddr()); } /* Project the value to the defined location. */ definitionAbstractValue.project(mask); /* Update term's value. */ abstractValue.merge(definitionAbstractValue); } } value->setAbstractValue(abstractValue.resize(term->size())); /* * Merge stack offset and product flags. * * Heuristic: merge information only from terms that define lower bits of the term's value. */ const std::vector<const Term *> *lowerBitsDefinitions = nullptr; if (byteOrder == ByteOrder::LittleEndian) { if (definitions.chunks().front().location().addr() == memoryLocation.addr()) { lowerBitsDefinitions = &definitions.chunks().front().definitions(); } } else { if (definitions.chunks().back().location().endAddr() == memoryLocation.endAddr()) { lowerBitsDefinitions = &definitions.chunks().back().definitions(); } } if (lowerBitsDefinitions) { foreach (auto definition, *lowerBitsDefinitions) { auto definitionValue = dataflow().getValue(definition); if (definitionValue->isNotStackOffset()) { value->makeNotStackOffset(); } else if (definitionValue->isStackOffset()) { value->makeStackOffset(definitionValue->stackOffset()); } if (definitionValue->isNotProduct()) { value->makeNotProduct(); } else if (definitionValue->isProduct()) { value->makeProduct(); } } } /* * Merge return address flag. */ if (definitions.chunks().front().location() == memoryLocation) { foreach (auto definition, definitions.chunks().front().definitions()) { auto definitionValue = dataflow().getValue(definition); if (definitionValue->isNotReturnAddress()) { value->makeNotReturnAddress(); } else if (definitionValue->isReturnAddress()) { value->makeReturnAddress(); } } }
Value *DataflowAnalyzer::computeValue(const Term *term, const ReachingDefinitions &definitions) { switch (term->kind()) { case Term::INT_CONST: { auto constant = term->asConstant(); Value *value = dataflow().getValue(constant); value->setAbstractValue(constant->value()); value->makeNotStackOffset(); value->makeNotProduct(); value->makeNotReturnAddress(); return value; } case Term::INTRINSIC: { auto intrinsic = term->asIntrinsic(); Value *value = dataflow().getValue(intrinsic); switch (intrinsic->intrinsicKind()) { case Intrinsic::UNKNOWN: /* FALLTHROUGH */ case Intrinsic::UNDEFINED: { value->setAbstractValue(AbstractValue(term->size(), -1, -1)); value->makeNotStackOffset(); value->makeNotProduct(); value->makeNotReturnAddress(); break; } case Intrinsic::ZERO_STACK_OFFSET: { value->setAbstractValue(AbstractValue(term->size(), -1, -1)); value->makeStackOffset(0); value->makeNotProduct(); value->makeNotReturnAddress(); break; } case Intrinsic::RETURN_ADDRESS: { value->setAbstractValue(AbstractValue(term->size(), -1, -1)); value->makeNotStackOffset(); value->makeNotProduct(); value->makeReturnAddress(); break; } default: { log_.warning(tr("%1: Unknown kind of intrinsic: %2.").arg(Q_FUNC_INFO).arg(intrinsic->intrinsicKind())); break; } } return value; } case Term::MEMORY_LOCATION_ACCESS: /* FALLTHROUGH */ case Term::DEREFERENCE: { const auto &memoryLocation = computeMemoryLocation(term, definitions); const auto &reachingDefinitions = computeReachingDefinitions(term, memoryLocation, definitions); return computeValue(term, memoryLocation, reachingDefinitions); } case Term::UNARY_OPERATOR: return computeValue(term->asUnaryOperator(), definitions); case Term::BINARY_OPERATOR: return computeValue(term->asBinaryOperator(), definitions); case Term::CHOICE: { auto choice = term->asChoice(); auto value = dataflow().getValue(choice); auto preferredValue = computeValue(choice->preferredTerm(), definitions); auto defaultValue = computeValue(choice->defaultTerm(), definitions); if (!dataflow().getDefinitions(choice->preferredTerm()).empty()) { *value = *preferredValue; } else { *value = *defaultValue; } return value; } default: { log_.warning(tr("%1: Unknown term kind: %2.").arg(Q_FUNC_INFO).arg(term->kind())); return dataflow().getValue(term); } } }
int main (int argc, char *argv[]) { int c, ret = 0; char *subopts; char *value; char *src_name = NULL; extern char *optarg; extern int optind; struct eq_lexer *lex = (struct eq_lexer *) malloc (sizeof (struct eq_lexer)); struct eq_parser *parser = (struct eq_parser *) malloc (sizeof (struct eq_parser)); init_global (); init_global_tree (); init_options (); progname = strrchr (argv[0], '/'); if (NULL == progname) progname = argv[0]; else progname++; while (-1 != (c = getopt (argc, argv, "B:P:V"))) switch (c) { case 'P': subopts = optarg; while (*subopts != '\0') switch (getsubopt (&subopts, p_opts, &value)) { case OPT_PRINT_PROGRAM: options.print_program = true; break; case OPT_PRINT_MATCHES: options.print_matches = true; break; case OPT_PRINT_TYPES: options.print_types = true; break; default: fprintf (stderr, "unknown -P suboption `%s'\n", value); goto cleanup; break; } break; case 'B': subopts = optarg; while (*subopts != '\0') switch (getsubopt (&subopts, b_opts, &value)) { case OPT_BREAK_PARSER: options.break_option = break_parser; break; case OPT_BREAK_TYPECHECK: options.break_option = break_typecheck; break; case OPT_BREAK_CONTROLFLOW: options.break_option = break_controlflow; case OPT_BREAK_DATAFLOW: options.break_option = break_dataflow; break; default: fprintf (stderr, "unknown -B suboption `%s'\n", value); goto cleanup; break; } break; case 'V': version (); goto cleanup; default: usage (); goto cleanup; } if (options.print_types && !(options.print_program || options.print_matches)) fprintf (stderr, "warning: 'types' flag is useless without either " "'program' flag or 'matches' flag\n"); argv += optind; /* FIXME: What if we have multiple files? */ if (NULL == *argv) { fprintf (stderr, "%s:error: filename argument required\n", progname); usage (); ret = -1; goto cleanup; } /* Initialize the lexer. */ if (!eq_lexer_init (lex, *argv)) { fprintf (stderr, "%s cannot create a lexer for file `%s'\n", progname, *argv); ret = -2; goto cleanup; } else { /* Discard extension from file to compile. */ char* start = strrchr (*argv, '/'); char* ext = strrchr (*argv, '.'); int size = 0; if (start == NULL) start = *argv; else start += 1; if (ext == NULL) size = strlen(start); else size = ext - start; src_name = strndup (start, size); } /* Initialize the parser. */ eq_parser_init (parser, lex); if ((ret += eq_parse (parser)) == 0 && options.break_option != break_parser) ret += typecheck (); /* printing debug routine. */ if (options.print_program) { xfile * xf = xfile_init_file_stdout (); printf ("\n######### Output ########\n"); print_program (xf); xfile_finalize (xf); } if (options.print_matches) { printf ("\n####### Transforms ########\n"); print_matches (); } if (options.break_option != break_typecheck && options.break_option != break_parser && !ret) controlflow (); if (options.break_option != break_controlflow && options.break_option != break_typecheck && options.break_option != break_parser && !ret) dataflow (); if (options.break_option != break_dataflow && options.break_option != break_controlflow && options.break_option != break_typecheck && options.break_option != break_parser && !ret) codegen (src_name); printf ("note: finished compiling.\n"); free (src_name); cleanup: eq_parser_finalize (parser); finalize_global_tree (); finalize_global (); /* That should be called at the very end. */ free_atomic_trees (); if (parser) free (parser); if (lex) free (lex); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; }