diff --git a/nautilus/include/nautilus/val.hpp b/nautilus/include/nautilus/val.hpp index 9a4db48b..0e828984 100644 --- a/nautilus/include/nautilus/val.hpp +++ b/nautilus/include/nautilus/val.hpp @@ -86,49 +86,67 @@ tracing::value_ref getState(T&& value) { } // namespace details -// val substitution for all arithmetic value type, integer, float, bool -template -class val { +template +class base_val { public: using raw_type = ValueType; using basic_type = ValueType; - #ifdef ENABLE_TRACING const tracing::value_ref state; - inline val() : state(tracing::traceConstant(0)) {}; - inline val(ValueType value) : state(tracing::traceConstant(value)), value(value) {}; + base_val() : state(tracing::traceConstant(0)) {}; + base_val(ValueType value) : state(tracing::traceConstant(value)), value(value) {}; // copy constructor - inline val(const val& other) : state(tracing::traceCopy(other.state)), value(other.value) {}; + base_val(const val& other) : state(tracing::traceCopy(other.state)), value(other.value) {}; // move constructor - inline val(const val&& other) noexcept : state(other.state), value(other.value) {}; - inline val(tracing::value_ref& tc) : state(tc), value() {}; + base_val(const val&& other) noexcept + : state(other.state), + value(other.value) { + // std::cout << "move con" << state.toString() << " = " << other.state.toString() << std::endl; + }; + base_val(tracing::value_ref& tc) : state(tc), value() {}; #else - val() {}; - val(ValueType value) : value(value) {}; + base_val() {}; + base_val(ValueType value) : value(value) {}; // copy constructor - val(const val& other) : value(other.value) {}; + base_val(const val& other) : value(other.value) {}; // move constructor - val(const val&& other) : value(other.value) {}; + base_val(const val&& other) : value(other.value) {}; #endif - ~val() { + virtual ~base_val() { + } + +protected: + friend ValueType details::getRawValue(val& left); + ValueType value; +}; +// val substitution for all arithmetic value type, integer, float, bool +template +class val : public base_val { +public: + + using base_val::base_val; + + // copy constructor + val(const val& other) : base_val(other) {} + // move constructor + val(const val&& other) : base_val(std::move(other)) {} + + val& operator=(const val&& other) { #ifdef ENABLE_TRACING if (tracing::inTracer()) { - - // tracing::getVarRefMap()[state.ref]--; - // if (tracing::getVarRefMap()[state.ref] == 0) { - // tracing::traceValueDestruction(state); - // std::cout << "destructor " << state << " - " << tag << std::endl; - // } + tracing::traceAssignment(this->state, other.state, tracing::to_type()); } #endif - } + this->value = other.value; + return *this; + }; val& operator=(const val& other) { #ifdef ENABLE_TRACING if (tracing::inTracer()) { - tracing::traceAssignment(state, other.state, tracing::to_type()); + tracing::traceAssignment(this->state, other.state, tracing::to_type()); } #endif this->value = other.value; @@ -141,11 +159,11 @@ class val { // cast if SHOULD_TRACE () { #ifdef ENABLE_TRACING - auto resultRef = tracing::traceCast(state, tracing::to_type()); + auto resultRef = tracing::traceCast(this->state, tracing::to_type()); return val(resultRef); #endif } - return val(value); + return val(this->value); } const val& operator++() { @@ -186,9 +204,6 @@ class val { } private: - friend ValueType details::getRawValue(val& left); - ValueType value; - template friend COMMON_RETURN_TYPE mul(val& left, val& right); @@ -245,41 +260,15 @@ class val { }; template <> -class val { +class val : public base_val { public: using raw_type = bool; using basic_type = bool; - -#ifdef ENABLE_TRACING - - tracing::value_ref state; - val() : state(tracing::traceConstant(0)), value(false) {}; - val(bool value) : state(tracing::traceConstant(value)), value(value) {}; + using base_val::base_val; // copy constructor - val(const val& other) : state(tracing::traceCopy(other.state)), value(other.value) {}; + val(const val& other) : base_val(other) {}; // move constructor - val(const val&& other) noexcept : state(other.state), value(other.value) {}; - val(tracing::value_ref& tc) : state(tc) {}; - -#else - val() {}; - val(bool value) : value(value) {}; - // copy constructor - val(const val& other) : value(other.value) {}; - // move constructor - val(const val&& other) : value(other.value) {}; -#endif - - ~val() { - if SHOULD_TRACE () { - - // tracing::getVarRefMap()[state.ref]--; - // if (tracing::getVarRefMap()[state.ref] == 0) { - // tracing::traceValueDestruction(state); - // std::cout << "destructor " << state << " - " << tag << std::endl; - // } - } - } + val(const val&& other) noexcept : base_val(std::move(other)) {}; val& operator=(const val& other) { @@ -302,8 +291,6 @@ class val { } return value; } - - bool value; }; template @@ -389,7 +376,8 @@ namespace details { auto&& lValue = cast_value(std::forward(left)); \ auto&& rValue = cast_value(std::forward(right)); \ if SHOULD_TRACE () { \ - auto tc = tracing::traceBinaryOp(details::getState(lValue), details::getState(rValue)); \ + auto tc = tracing::traceBinaryOp(details::getState(lValue), \ + details::getState(rValue)); \ return RES_TYPE(tc); \ } \ return RES_TYPE(getRawValue(lValue) OP getRawValue(rValue)); \ @@ -567,7 +555,7 @@ val inline lOr(val& left, val& right) { return val {tc}; } #endif - return left.value || right.value; + return getRawValue(left) || getRawValue(right); } val inline lAnd(val& left, val& right) { @@ -577,7 +565,7 @@ val inline lAnd(val& left, val& right) { return val {tc}; } #endif - return left.value && right.value; + return getRawValue(left) && getRawValue(right); } val inline lNot(val& arg) { @@ -587,7 +575,7 @@ val inline lNot(val& arg) { return val {tc}; } #endif - return !arg.value; + return !getRawValue(arg); } } // namespace details diff --git a/nautilus/src/nautilus/tracing/ExecutionTrace.cpp b/nautilus/src/nautilus/tracing/ExecutionTrace.cpp index 82dbb8d4..08e8b04c 100644 --- a/nautilus/src/nautilus/tracing/ExecutionTrace.cpp +++ b/nautilus/src/nautilus/tracing/ExecutionTrace.cpp @@ -11,14 +11,14 @@ ExecutionTrace::ExecutionTrace() : currentBlockIndex(0), currentOperationIndex(0 createBlock(); }; -bool ExecutionTrace::checkTag(Snapshot& snapshot) { +bool ExecutionTrace::checkTag(Snapshot& snapshot, std::vector& inputs) { // check if operation is in global map -> we have a repeating operation -> this is a control-flow merge // std::cout << "\n checkTag \n" << std::endl; // std::cout << *this << std::endl; auto globalTabIter = globalTagMap.find(snapshot); if (globalTabIter != globalTagMap.end()) { auto& ref = globalTabIter->second; - processControlFlowMerge(ref); + processControlFlowMerge(ref, inputs); return false; } @@ -27,7 +27,7 @@ bool ExecutionTrace::checkTag(Snapshot& snapshot) { // TODO #3500 Fix handling of repeated operations auto& ref = localTagIter->second; // add loop iteration to tag - processControlFlowMerge(ref); + processControlFlowMerge(ref, inputs); return false; } return true; @@ -145,7 +145,8 @@ uint16_t ExecutionTrace::createBlock() { return blocks.size() - 1; } -Block& ExecutionTrace::processControlFlowMerge(operation_identifier oi) { +Block& ExecutionTrace::processControlFlowMerge(operation_identifier oi, + [[maybe_unused]] std::vector& inputs) { if (oi.blockIndex == currentBlockIndex) { throw RuntimeException("Invalid trace. This is maybe caused by a constant loop."); } @@ -158,6 +159,10 @@ Block& ExecutionTrace::processControlFlowMerge(operation_identifier oi) { auto mergedBlockId = createBlock(); // perform a control flow merge and merge the current block with operations in some other block. auto& referenceBlock = blocks[oi.blockIndex]; + auto& referenceOp = referenceBlock.operations[oi.operationIndex]; + if (referenceOp.input.size() == inputs.size()) { + //for (referenceOp == ) + } auto& currentBlock = blocks[currentBlockIndex]; auto& mergeBlock = getBlock(mergedBlockId); diff --git a/nautilus/src/nautilus/tracing/ExecutionTrace.hpp b/nautilus/src/nautilus/tracing/ExecutionTrace.hpp index d426b2c2..3e27873b 100644 --- a/nautilus/src/nautilus/tracing/ExecutionTrace.hpp +++ b/nautilus/src/nautilus/tracing/ExecutionTrace.hpp @@ -29,7 +29,7 @@ class ExecutionTrace { void addReturn(Snapshot&, Type type, value_ref ref); - bool checkTag(Snapshot& snapshot); + bool checkTag(Snapshot& snapshot, std::vector& inputs); void resetExecution(); @@ -106,7 +106,7 @@ class ExecutionTrace { * @param operationIndex * @return Block& */ - Block& processControlFlowMerge(operation_identifier oi); + Block& processControlFlowMerge(operation_identifier oi, std::vector& inputs); /** * @brief Returns the return reference diff --git a/nautilus/src/nautilus/tracing/TraceContext.cpp b/nautilus/src/nautilus/tracing/TraceContext.cpp index 59d71852..d31215dd 100644 --- a/nautilus/src/nautilus/tracing/TraceContext.cpp +++ b/nautilus/src/nautilus/tracing/TraceContext.cpp @@ -56,7 +56,8 @@ value_ref TraceContext::traceLoad(value_ref src, Type resultType) { auto input = InputVariant(src); auto op = Op::LOAD; auto tag = recordSnapshot(); - if (executionTrace->checkTag(tag)) { + auto inputs = std::vector {input}; + if (executionTrace->checkTag(tag, inputs)) { auto resultRef = executionTrace->addOperationWithResult(tag, op, resultType, std::vector {input}); return resultRef; } @@ -72,7 +73,8 @@ void TraceContext::traceStore(value_ref target, value_ref src, Type valueType) { } auto op = Op::STORE; auto tag = recordSnapshot(); - if (executionTrace->checkTag(tag)) { + auto inputs = std::vector {src}; + if (executionTrace->checkTag(tag, inputs)) { executionTrace->addOperation(tag, op, valueType, target, src); return; } @@ -120,7 +122,9 @@ value_ref TraceContext::traceCopy(nautilus::tracing::value_ref ref) { return currentOperation.resultRef; } auto tag = recordSnapshot(); - if (executionTrace->checkTag(tag)) { + + auto inputs = std::vector {ref}; + if (executionTrace->checkTag(tag, inputs)) { auto resultRef = executionTrace->getNextValueRef(); executionTrace->addAssignmentOperation(tag, {resultRef, ref.type}, ref, ref.type); return {resultRef, ref.type}; @@ -139,7 +143,8 @@ value_ref TraceContext::traceCall(const std::string& functionName, void* fptn, T } auto tag = recordSnapshot(); - if (executionTrace->checkTag(tag)) { + auto inputs = std::vector {}; + if (executionTrace->checkTag(tag, inputs)) { auto functionArguments = InputVariant(FunctionCall { .functionName = functionName, .ptr = fptn, @@ -162,16 +167,19 @@ void TraceContext::traceAssignment(value_ref targetRef, value_ref sourceRef, Typ return; } auto tag = recordSnapshot(); - /* + auto found = executionTrace->globalTagMap.find(tag); if (found != executionTrace->globalTagMap.end()) { - auto currentOp = executionTrace->getBlock(found->second.blockIndex).operations[found->second.operationIndex]; - if(std::get(currentOp.input[0]) != sourceRef){ - executionTrace->addAssignmentOperation(tag, targetRef, sourceRef, resultType); + auto currentOp = executionTrace->getBlock(found->second.blockIndex).operations[found->second.operationIndex]; + if(std::get(currentOp.input[0]) != sourceRef){ + executionTrace->getCurrentBlock().operations.emplace_back(tag, ASSIGN, resultType, targetRef, std::vector {sourceRef}); return; - }; - }*/ - if (executionTrace->checkTag(tag)) { + //executionTrace->addAssignmentOperation(tag, targetRef, sourceRef, resultType); + //return; + }; + } + auto inputs = std::vector {sourceRef}; + if (executionTrace->checkTag(tag, inputs)) { executionTrace->addAssignmentOperation(tag, targetRef, sourceRef, resultType); return; } @@ -191,8 +199,10 @@ value_ref TraceContext::traceCast(value_ref state, Type resultType) { // we are in a know operation if the operation at the current block[currentOperationCounter] is equal to the // received operation. auto tag = recordSnapshot(); - if (executionTrace->checkTag(tag)) { - auto leftIV = InputVariant(state); + auto leftIV = InputVariant(state); + auto inputs = std::vector {leftIV}; + if (executionTrace->checkTag(tag, inputs)) { + auto op = Op::CAST; auto resultRef = executionTrace->addOperationWithResult(tag, op, resultType, std::vector {leftIV}); @@ -225,11 +235,12 @@ value_ref TraceContext::traceBinaryOperation(Op op, Type resultType, value_ref& } auto tag = recordSnapshot(); - if (executionTrace->checkTag(tag)) { - auto leftIV = InputVariant(leftRef); - auto rightIV = InputVariant(rightRef); - auto resultRef = - executionTrace->addOperationWithResult(tag, op, resultType, std::vector {leftIV, rightIV}); + + auto leftIV = InputVariant(leftRef); + auto rightIV = InputVariant(rightRef); + auto inputs = std::vector {leftIV, rightIV}; + if (executionTrace->checkTag(tag, inputs)) { + auto resultRef = executionTrace->addOperationWithResult(tag, op, resultType, std::move(inputs)); return resultRef; } throw TraceTerminationException(); @@ -244,7 +255,8 @@ bool TraceContext::traceCmp(value_ref targetRef) { } else { // record auto tag = recordSnapshot(); - if (executionTrace->checkTag(tag)) { + auto inputs = std::vector {}; + if (executionTrace->checkTag(tag, inputs)) { executionTrace->addCmpOperation(tag, targetRef); result = symbolicExecutionContext->record(tag); } else { diff --git a/nautilus/test/execution-tests/ExpressionFunctions.hpp b/nautilus/test/execution-tests/ExpressionFunctions.hpp index ca9ca2e6..40ae430b 100644 --- a/nautilus/test/execution-tests/ExpressionFunctions.hpp +++ b/nautilus/test/execution-tests/ExpressionFunctions.hpp @@ -33,6 +33,14 @@ val assignment5(val x) { return x; } +val assignmentSwap(val x) { + auto t = x; + x = 42; + x = t + x; + return x; +} + + val int8AddExpression(val x) { val y = (int8_t) 2; return y + x; diff --git a/nautilus/test/execution-tests/TracingTest.cpp b/nautilus/test/execution-tests/TracingTest.cpp index b2e13378..581c5334 100644 --- a/nautilus/test/execution-tests/TracingTest.cpp +++ b/nautilus/test/execution-tests/TracingTest.cpp @@ -136,6 +136,7 @@ TEST_CASE("Expression Trace Test") { {"assignment3", details::createFunctionWrapper(assignment3)}, {"assignment4", details::createFunctionWrapper(assignment4)}, {"assignment5", details::createFunctionWrapper(assignment5)}, + {"assignmentSwap", details::createFunctionWrapper(assignmentSwap)}, {"int8AddExpression", details::createFunctionWrapper(int8AddExpression)}, {"int16AddExpression", details::createFunctionWrapper(int16AddExpression)}, {"int32AddExpression", details::createFunctionWrapper(int32AddExpression)}, @@ -175,6 +176,7 @@ TEST_CASE("Control-flow Trace Test") { {"varyingComplexity", details::createFunctionWrapper(varyingComplexity)}, {"logicalXOR", details::createFunctionWrapper(logicalXOR)}, {"nestedIfElseDifferentLevels", details::createFunctionWrapper(nestedIfElseDifferentLevels)}, + }; runTraceTests(tests); }