[
  {
    "path": ".clang-format",
    "content": "---\nLanguage:        Cpp\n# BasedOnStyle:  LLVM\nAccessModifierOffset: -2\nAlignAfterOpenBracket: Align\nAlignConsecutiveMacros: false\nAlignConsecutiveAssignments: false\nAlignConsecutiveBitFields: false\nAlignConsecutiveDeclarations: false\nAlignEscapedNewlines: Right\nAlignOperands:   Align\nAlignTrailingComments: true\nAllowAllArgumentsOnNextLine: true\nAllowAllConstructorInitializersOnNextLine: true\nAllowAllParametersOfDeclarationOnNextLine: true\nAllowShortEnumsOnASingleLine: true\nAllowShortBlocksOnASingleLine: Empty\nAllowShortCaseLabelsOnASingleLine: false\nAllowShortFunctionsOnASingleLine: All\nAllowShortLambdasOnASingleLine: All\nAllowShortIfStatementsOnASingleLine: Never\nAllowShortLoopsOnASingleLine: false\nAlwaysBreakAfterDefinitionReturnType: None\nAlwaysBreakAfterReturnType: None\nAlwaysBreakBeforeMultilineStrings: false\nAlwaysBreakTemplateDeclarations: Yes\nBinPackArguments: true\nBinPackParameters: true\nBraceWrapping:\n  AfterCaseLabel:  false\n  AfterClass:      false\n  AfterControlStatement: Never\n  AfterEnum:       false\n  AfterFunction:   false\n  AfterNamespace:  false\n  AfterObjCDeclaration: false\n  AfterStruct:     false\n  AfterUnion:      false\n  AfterExternBlock: false\n  BeforeCatch:     false\n  BeforeElse:      false\n  BeforeLambdaBody: false\n  BeforeWhile:     false\n  IndentBraces:    false\n  SplitEmptyFunction: true\n  SplitEmptyRecord: true\n  SplitEmptyNamespace: true\nBreakBeforeBinaryOperators: None\nBreakBeforeBraces: Attach\nBreakBeforeInheritanceComma: false\nBreakInheritanceList: BeforeColon\nBreakBeforeTernaryOperators: true\nBreakConstructorInitializersBeforeComma: false\nBreakConstructorInitializers: BeforeColon\nBreakAfterJavaFieldAnnotations: false\nBreakStringLiterals: true\nColumnLimit:     80\nCompactNamespaces: false\nConstructorInitializerAllOnOneLineOrOnePerLine: false\nConstructorInitializerIndentWidth: 8\nContinuationIndentWidth: 8\nCpp11BracedListStyle: true\nDeriveLineEnding: false\nDerivePointerAlignment: false\nDisableFormat:   false\nFixNamespaceComments: true\nForEachMacros:\n  - foreach\n  - Q_FOREACH\n  - BOOST_FOREACH\nIncludeBlocks:   Preserve\nIndentCaseLabels: false\nIndentCaseBlocks: false\nIndentGotoLabels: false\nIndentPPDirectives: None\nIndentExternBlock: AfterExternBlock\nIndentWidth: 4\nIndentWrappedFunctionNames: false\nInsertTrailingCommas: None\nJavaScriptQuotes: Leave\nJavaScriptWrapImports: true\nKeepEmptyLinesAtTheStartOfBlocks: false\nMacroBlockBegin: ''\nMacroBlockEnd:   ''\nMaxEmptyLinesToKeep: 1\nNamespaceIndentation: None\nObjCBinPackProtocolList: Auto\nObjCBlockIndentWidth: 2\nObjCBreakBeforeNestedBlockParam: true\nObjCSpaceAfterProperty: false\nObjCSpaceBeforeProtocolList: true\nPenaltyBreakAssignment: 2\nPenaltyBreakBeforeFirstCallParameter: 19\nPenaltyBreakComment: 300\nPenaltyBreakFirstLessLess: 120\nPenaltyBreakString: 1000\nPenaltyBreakTemplateDeclaration: 10\nPenaltyExcessCharacter: 1000000\nPenaltyReturnTypeOnItsOwnLine: 60\nPointerAlignment: Right\nReflowComments:  true\nSortIncludes:    true\nSortUsingDeclarations: true\nSpaceAfterCStyleCast: true\nSpaceAfterLogicalNot: false\nSpaceAfterTemplateKeyword: true\nSpaceBeforeAssignmentOperators: true\nSpaceBeforeCpp11BracedList: false\nSpaceBeforeCtorInitializerColon: true\nSpaceBeforeInheritanceColon: true\nSpaceBeforeParens: ControlStatements\nSpaceBeforeRangeBasedForLoopColon: true\nSpaceInEmptyBlock: false\nSpaceInEmptyParentheses: false\nSpacesBeforeTrailingComments: 1\nSpacesInAngles:  false\nSpacesInConditionalStatement: false\nSpacesInContainerLiterals: true\nSpacesInCStyleCastParentheses: false\nSpacesInParentheses: false\nSpacesInSquareBrackets: false\nSpaceBeforeSquareBrackets: false\nStandard:        Latest\nTabWidth:        8\nUseCRLF:         false\nUseTab:          Never\n...\n"
  },
  {
    "path": ".clang-tidy",
    "content": "---\n# vim: syntax=yaml\n# we might want to enable llvm-namespace-comment in the future\nChecks:              'clang-diagnostic-*,clang-analyzer-*,modernize-*,-modernize-use-auto,-modernize-use-trailing-return-type,bugprone-*,llvm-*,-llvm-header-guard,-llvm-namespace-comment,misc-misplaced-const,misc-non-copyable-objects,misc-redundant-expression,misc-static-assert,misc-throw-by-value-catch-by-reference,misc-unconventional-assign-operator,misc-uniqueptr-reset-release,performace-*,readability-*,-readability-isolate-declaration,-readability-braces-around-statements,-readability-implicit-bool-conversion,-readability-static-accessed-through-instance,-readability-identifier-length'\nWarningsAsErrors:    ''\nHeaderFilterRegex:   'include/|lib/|tools/'\nAnalyzeTemporaryDtors: false\nFormatStyle:         file\nCheckOptions:\n  - key:             bugprone-argument-comment.CommentBoolLiterals\n    value:           '0'\n  - key:             bugprone-argument-comment.CommentCharacterLiterals\n    value:           '0'\n  - key:             bugprone-argument-comment.CommentFloatLiterals\n    value:           '0'\n  - key:             bugprone-argument-comment.CommentIntegerLiterals\n    value:           '0'\n  - key:             bugprone-argument-comment.CommentNullPtrs\n    value:           '0'\n  - key:             bugprone-argument-comment.CommentStringLiterals\n    value:           '0'\n  - key:             bugprone-argument-comment.CommentUserDefinedLiterals\n    value:           '0'\n  - key:             bugprone-argument-comment.IgnoreSingleArgument\n    value:           '0'\n  - key:             bugprone-argument-comment.StrictMode\n    value:           '0'\n  - key:             bugprone-assert-side-effect.AssertMacros\n    value:           assert\n  - key:             bugprone-assert-side-effect.CheckFunctionCalls\n    value:           'false'\n  - key:             bugprone-dangling-handle.HandleClasses\n    value:           'std::basic_string_view;std::experimental::basic_string_view'\n  - key:             bugprone-dynamic-static-initializers.HeaderFileExtensions\n    value:           ';h;hh;hpp;hxx'\n  - key:             bugprone-exception-escape.FunctionsThatShouldNotThrow\n    value:           ''\n  - key:             bugprone-exception-escape.IgnoredExceptions\n    value:           ''\n  - key:             bugprone-misplaced-widening-cast.CheckImplicitCasts\n    value:           'false'\n  - key:             bugprone-narrowing-conversions.PedanticMode\n    value:           'false'\n  - key:             bugprone-narrowing-conversions.WarnOnFloatingPointNarrowingConversion\n    value:           'true'\n  - key:             bugprone-not-null-terminated-result.WantToUseSafeFunctions\n    value:           'true'\n  - key:             bugprone-reserved-identifier.AggressiveDependentMemberLookup\n    value:           'false'\n  - key:             bugprone-reserved-identifier.AllowedIdentifiers\n    value:           ''\n  - key:             bugprone-reserved-identifier.Invert\n    value:           'false'\n  - key:             bugprone-signed-char-misuse.CharTypdefsToIgnore\n    value:           ''\n  - key:             bugprone-signed-char-misuse.DiagnoseSignedUnsignedCharComparisons\n    value:           'true'\n  - key:             bugprone-sizeof-expression.WarnOnSizeOfCompareToConstant\n    value:           'true'\n  - key:             bugprone-sizeof-expression.WarnOnSizeOfConstant\n    value:           'true'\n  - key:             bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression\n    value:           'false'\n  - key:             bugprone-sizeof-expression.WarnOnSizeOfThis\n    value:           'true'\n  - key:             bugprone-string-constructor.LargeLengthThreshold\n    value:           '8388608'\n  - key:             bugprone-string-constructor.WarnOnLargeLength\n    value:           'true'\n  - key:             bugprone-suspicious-enum-usage.StrictMode\n    value:           'false'\n  - key:             bugprone-suspicious-include.HeaderFileExtensions\n    value:           ';h;hh;hpp;hxx'\n  - key:             bugprone-suspicious-include.ImplementationFileExtensions\n    value:           'c;cc;cpp;cxx'\n  - key:             bugprone-suspicious-missing-comma.MaxConcatenatedTokens\n    value:           '5'\n  - key:             bugprone-suspicious-missing-comma.RatioThreshold\n    value:           '0.200000'\n  - key:             bugprone-suspicious-missing-comma.SizeThreshold\n    value:           '5'\n  - key:             bugprone-suspicious-string-compare.StringCompareLikeFunctions\n    value:           ''\n  - key:             bugprone-suspicious-string-compare.WarnOnImplicitComparison\n    value:           'true'\n  - key:             bugprone-suspicious-string-compare.WarnOnLogicalNotComparison\n    value:           'false'\n  - key:             bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit\n    value:           '16'\n  - key:             bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField\n    value:           'true'\n  - key:             bugprone-unused-return-value.CheckedFunctions\n    value:           '::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty;::std::back_inserter;::std::distance;::std::find;::std::find_if;::std::inserter;::std::lower_bound;::std::make_pair;::std::map::count;::std::map::find;::std::map::lower_bound;::std::multimap::equal_range;::std::multimap::upper_bound;::std::set::count;::std::set::find;::std::setfill;::std::setprecision;::std::setw;::std::upper_bound;::std::vector::at;::bsearch;::ferror;::feof;::isalnum;::isalpha;::isblank;::iscntrl;::isdigit;::isgraph;::islower;::isprint;::ispunct;::isspace;::isupper;::iswalnum;::iswprint;::iswspace;::isxdigit;::memchr;::memcmp;::strcmp;::strcoll;::strncmp;::strpbrk;::strrchr;::strspn;::strstr;::wcscmp;::access;::bind;::connect;::difftime;::dlsym;::fnmatch;::getaddrinfo;::getopt;::htonl;::htons;::iconv_open;::inet_addr;::isascii;::isatty;::mmap;::newlocale;::openat;::pathconf;::pthread_equal;::pthread_getspecific;::pthread_mutex_trylock;::readdir;::readlink;::recvmsg;::regexec;::scandir;::semget;::setjmp;::shm_open;::shmget;::sigismember;::strcasecmp;::strsignal;::ttyname'\n  - key:             cert-dcl16-c.NewSuffixes\n    value:           'L;LL;LU;LLU'\n  - key:             cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField\n    value:           '0'\n  - key:             cert-str34-c.DiagnoseSignedUnsignedCharComparisons\n    value:           '0'\n  - key:             cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors\n    value:           '1'\n  - key:             cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic\n    value:           '1'\n  - key:             google-readability-braces-around-statements.ShortStatementLines\n    value:           '1'\n  - key:             google-readability-function-size.StatementThreshold\n    value:           '800'\n  - key:             google-readability-namespace-comments.ShortNamespaceLines\n    value:           '10'\n  - key:             google-readability-namespace-comments.SpacesBeforeComments\n    value:           '2'\n  - key:             llvm-else-after-return.WarnOnConditionVariables\n    value:           'false'\n  - key:             llvm-else-after-return.WarnOnUnfixable\n    value:           'false'\n  - key:             llvm-header-guard.HeaderFileExtensions\n    value:           ';h;hh;hpp;hxx'\n  - key:             llvm-namespace-comment.ShortNamespaceLines\n    value:           '1'\n  - key:             llvm-namespace-comment.SpacesBeforeComments\n    value:           '1'\n  - key:             llvm-qualified-auto.AddConstToQualified\n    value:           'false'\n  - key:             misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic\n    value:           'false'\n  - key:             misc-non-private-member-variables-in-classes.IgnorePublicMemberVariables\n    value:           'false'\n  - key:             misc-throw-by-value-catch-by-reference.CheckThrowTemporaries\n    value:           'true'\n  - key:             misc-throw-by-value-catch-by-reference.WarnOnLargeObjects\n    value:           'false'\n  - key:             modernize-avoid-bind.PermissiveParameterList\n    value:           'false'\n  - key:             modernize-loop-convert.MaxCopySize\n    value:           '16'\n  - key:             modernize-loop-convert.MinConfidence\n    value:           reasonable\n  - key:             modernize-loop-convert.NamingStyle\n    value:           CamelCase\n  - key:             modernize-make-shared.IgnoreMacros\n    value:           'true'\n  - key:             modernize-make-shared.IncludeStyle\n    value:           llvm\n  - key:             modernize-make-shared.MakeSmartPtrFunction\n    value:           'std::make_shared'\n  - key:             modernize-make-shared.MakeSmartPtrFunctionHeader\n    value:           memory\n  - key:             modernize-make-unique.IgnoreMacros\n    value:           'true'\n  - key:             modernize-make-unique.IncludeStyle\n    value:           llvm\n  - key:             modernize-make-unique.MakeSmartPtrFunction\n    value:           'std::make_unique'\n  - key:             modernize-make-unique.MakeSmartPtrFunctionHeader\n    value:           memory\n  - key:             modernize-pass-by-value.IncludeStyle\n    value:           llvm\n  - key:             modernize-pass-by-value.ValuesOnly\n    value:           'false'\n  - key:             modernize-raw-string-literal.DelimiterStem\n    value:           lit\n  - key:             modernize-raw-string-literal.ReplaceShorterLiterals\n    value:           'false'\n  - key:             modernize-replace-auto-ptr.IncludeStyle\n    value:           llvm\n  - key:             modernize-replace-disallow-copy-and-assign-macro.MacroName\n    value:           DISALLOW_COPY_AND_ASSIGN\n  - key:             modernize-replace-random-shuffle.IncludeStyle\n    value:           llvm\n  - key:             modernize-use-bool-literals.IgnoreMacros\n    value:           'true'\n  - key:             modernize-use-default-member-init.IgnoreMacros\n    value:           'true'\n  - key:             modernize-use-default-member-init.UseAssignment\n    value:           'false'\n  - key:             modernize-use-emplace.ContainersWithPushBack\n    value:           '::std::vector;::std::list;::std::deque'\n  - key:             modernize-use-emplace.IgnoreImplicitConstructors\n    value:           'false'\n  - key:             modernize-use-emplace.SmartPointers\n    value:           '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr'\n  - key:             modernize-use-emplace.TupleMakeFunctions\n    value:           '::std::make_pair;::std::make_tuple'\n  - key:             modernize-use-emplace.TupleTypes\n    value:           '::std::pair;::std::tuple'\n  - key:             modernize-use-equals-default.IgnoreMacros\n    value:           'true'\n  - key:             modernize-use-equals-delete.IgnoreMacros\n    value:           'true'\n  - key:             modernize-use-nodiscard.ReplacementString\n    value:           '[[nodiscard]]'\n  - key:             modernize-use-noexcept.ReplacementString\n    value:           ''\n  - key:             modernize-use-noexcept.UseNoexceptFalse\n    value:           'true'\n  - key:             modernize-use-nullptr.NullMacros\n    value:           'NULL'\n  - key:             modernize-use-override.AllowOverrideAndFinal\n    value:           'false'\n  - key:             modernize-use-override.FinalSpelling\n    value:           final\n  - key:             modernize-use-override.IgnoreDestructors\n    value:           'false'\n  - key:             modernize-use-override.OverrideSpelling\n    value:           override\n  - key:             modernize-use-transparent-functors.SafeMode\n    value:           'false'\n  - key:             modernize-use-using.IgnoreMacros\n    value:           'true'\n  - key:             readability-braces-around-statements.ShortStatementLines\n    value:           '0'\n  - key:             readability-else-after-return.WarnOnConditionVariables\n    value:           'true'\n  - key:             readability-else-after-return.WarnOnUnfixable\n    value:           'true'\n  - key:             readability-function-size.BranchThreshold\n    value:           '4294967295'\n  - key:             readability-function-size.LineThreshold\n    value:           '4294967295'\n  - key:             readability-function-size.NestingThreshold\n    value:           '4294967295'\n  - key:             readability-function-size.ParameterThreshold\n    value:           '4294967295'\n  - key:             readability-function-size.StatementThreshold\n    value:           '800'\n  - key:             readability-function-size.VariableThreshold\n    value:           '4294967295'\n  - key:             readability-identifier-naming.AggressiveDependentMemberLookup\n    value:           'false'\n  - key:             readability-identifier-naming.IgnoreFailedSplit\n    value:           'false'\n  - key:             readability-identifier-naming.IgnoreMainLikeFunctions\n    value:           'false'\n  - key:             readability-implicit-bool-conversion.AllowIntegerConditions\n    value:           'true'\n  - key:             readability-implicit-bool-conversion.AllowPointerConditions\n    value:           'true'\n  - key:             readability-inconsistent-declaration-parameter-name.IgnoreMacros\n    value:           'true'\n  - key:             readability-inconsistent-declaration-parameter-name.Strict\n    value:           'false'\n  - key:             readability-magic-numbers.IgnoreAllFloatingPointValues\n    value:           'false'\n  - key:             readability-magic-numbers.IgnoreBitFieldsWidths\n    value:           'true'\n  - key:             readability-magic-numbers.IgnorePowersOf2IntegerValues\n    value:           'false'\n  - key:             readability-magic-numbers.IgnoredFloatingPointValues\n    value:           '1.0;100.0;'\n  - key:             readability-magic-numbers.IgnoredIntegerValues\n    value:           '1;2;3;4;'\n  - key:             readability-qualified-auto.AddConstToQualified\n    value:           'true'\n  - key:             readability-redundant-declaration.IgnoreMacros\n    value:           'true'\n  - key:             readability-redundant-member-init.IgnoreBaseInCopyConstructors\n    value:           'false'\n  - key:             readability-redundant-smartptr-get.IgnoreMacros\n    value:           'true'\n  - key:             readability-redundant-string-init.StringNames\n    value:           '::std::basic_string'\n  - key:             readability-simplify-boolean-expr.ChainedConditionalAssignment\n    value:           'false'\n  - key:             readability-simplify-boolean-expr.ChainedConditionalReturn\n    value:           'false'\n  - key:             readability-simplify-subscript-expr.Types\n    value:           '::std::basic_string;::std::basic_string_view;::std::vector;::std::array'\n  - key:             readability-static-accessed-through-instance.NameSpecifierNestingThreshold\n    value:           '3'\n  - key:             readability-uppercase-literal-suffix.IgnoreMacros\n    value:           'true'\n  - key:             readability-uppercase-literal-suffix.NewSuffixes\n    value:           ''\n...\n"
  },
  {
    "path": ".git-blame-ignore-revs",
    "content": "# Reformat the whole project\n2e60545c73a872b95d3c32a097e351ed9bfd8bf6\na69378f4f29a63d28cb79e0d6728d069353b19c8\n"
  },
  {
    "path": ".github/workflows/clang-format.yml",
    "content": "---\nname: Find unformatted files\n\non: [push, pull_request]\n\njobs:\n  Format:\n    name: Find unformatted files\n    runs-on: ubuntu-22.04\n    steps:\n      - name: Checkout DG\n        uses: actions/checkout@v3\n\n      - name: Install clang-format 14\n        run: |\n          sudo apt install clang-format-14\n\n      - name: Find unformatted files\n        # Based on https://rigtorp.se/notes/clang-format/.\n        run: |\n          set -o pipefail\n          find . -regextype posix-extended \\\n                 -iregex '\\./(include|lib|tests|tools)/.*\\.(h|c|cpp|hpp)' \\\n                 -o -iregex '\\./tests/catch2' -prune -type f | \\\n              xargs clang-format-14 --style=file --dry-run -Werror --color=true\n"
  },
  {
    "path": ".github/workflows/docker.yml",
    "content": "---\nname: Docker Image\n\non:\n  [push, pull_request]\n\njobs:\n  Docker:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout DG\n        uses: actions/checkout@v3\n\n      - name: Build the Docker image\n        run: |\n          docker build . --file Dockerfile \\\n                         --build-arg GIT_REF=$GITHUB_REF \\\n                         --build-arg GIT_REPO=$GITHUB_REPOSITORY \\\n                         --tag dg:$(date +%s)\n"
  },
  {
    "path": ".github/workflows/hash_map.yml",
    "content": "---\nname: DG + External Hash Maps\non: [push, pull_request]\n\njobs:\n  Ubuntu:\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-20.04]\n        compiler: [gcc, clang]\n        hashmap: [tsl-hopscotch]\n\n    runs-on: ${{matrix.os}}\n    env:\n      # for colours in ninja\n      CLICOLOR_FORCE: 1\n\n    steps:\n      - name: Checkout DG\n        uses: actions/checkout@v3\n\n      - name: Checkout TSL Hopscotch\n        uses: actions/checkout@v3\n        with:\n          repository: Tessil/hopscotch-map\n          path: tsl-hopscotch\n\n      - name: Install dependencies\n        run: |\n          sudo apt update\n          sudo apt install ccache cmake ninja-build clang-10 llvm-10-dev\n\n      - name: Set environment\n        id: env\n        run: |\n          # set expected name of selected hashmap\n          case \"${{matrix.hashmap}}\" in\n            \"tsl-hopscotch\") echo \"HASHMAP=TSL_HOPSCOTCH_DIR\" >> $GITHUB_ENV;;\n            *) echo \"Unknown hashmap selected.\" && exit 1;;\n          esac\n\n          if [[ \"${{matrix.compiler}}\" = \"clang\" ]]; then\n            echo \"CC=clang-10\" >> $GITHUB_ENV\n            echo \"CXX=clang++-10\" >> $GITHUB_ENV\n\n            # force coloured output\n            echo \"CFLAGS=$CFLAGS -fcolor-diagnostics\" >> $GITHUB_ENV\n            echo \"CXXFLAGS=$CXXFLAGS -fcolor-diagnostics\" >> $GITHUB_ENV\n          else\n            echo \"CC=gcc\" >> $GITHUB_ENV\n            echo \"CXX=g++\" >> $GITHUB_ENV\n\n            # force coloured output\n            echo \"CFLAGS=$CFLAGS -fdiagnostics-color=always\" >> $GITHUB_ENV\n            echo \"CXXFLAGS=$CXXFLAGS -fdiagnostics-color=always\" >> $GITHUB_ENV\n          fi\n\n          # set up ccache\n          sudo /usr/sbin/update-ccache-symlinks\n          echo \"/usr/lib/ccache\" >> $GITHUB_PATH\n\n          echo \"CCACHE_BASEDIR=$GITHUB_WORKSPACE\" >> $GITHUB_ENV\n          echo \"CCACHE_DIR=$GITHUB_WORKSPACE/.ccache\" >> $GITHUB_ENV\n          echo \"CCACHE_COMPRESS=true\" >> $GITHUB_ENV\n          echo \"CCACHE_COMPRESSLEVEL=6\" >> $GITHUB_ENV\n          echo \"CCACHE_MAXSIZE=400M\" >> $GITHUB_ENV\n\n          echo \"::set-output name=timestamp::$(date -u -Iseconds)\"\n\n      - name: Set up ccache\n        uses: actions/cache@v3\n        with:\n          path: .ccache\n          key: ${{matrix.os}}-${{matrix.hashmap}}-${{matrix.compiler}}-${{steps.env.outputs.timestamp}}\n          restore-keys: ${{matrix.os}}-${{matrix.hashmap}}-${{matrix.compiler}}\n\n      - name: Configure CMake project\n        run: |\n          cmake -S. \\\n                -B_build \\\n                -GNinja \\\n                -DUSE_SANITIZERS:BOOL=ON \\\n                -DLLVM_DIR:PATH=\"$(llvm-config-10 --cmakedir)\" \\\n                -D${HASHMAP}:PATH=\"$GITHUB_WORKSPACE/${{matrix.hashmap}}\"\n\n      - name: Build\n        run: cmake --build _build\n\n      - name: Run tests\n        # TODO: turn off the detection of leaks, we're working on it\n        run: ASAN_OPTIONS=detect_leaks=0 cmake --build _build --target check\n\n      - name: ccache statistics\n        run: ccache -s\n"
  },
  {
    "path": ".github/workflows/linux.yml",
    "content": "---\nname: Linux CI\non: [push, pull_request]\n\njobs:\n  build64:\n    name: Ubuntu 64-bit\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          # Linux with GCC\n          - {os: ubuntu-18.04, llvm: '3.9', compiler: gcc}\n          - {os: ubuntu-18.04, llvm: '4.0', compiler: gcc}\n          - {os: ubuntu-18.04, llvm: '5.0', compiler: gcc}\n          - {os: ubuntu-18.04, llvm: '6.0', compiler: gcc}\n          - {os: ubuntu-18.04, llvm: 7, compiler: gcc}\n          - {os: ubuntu-18.04, llvm: 8, compiler: gcc}\n          - {os: ubuntu-18.04, llvm: 9, compiler: gcc}\n          - {os: ubuntu-20.04, llvm: 10, compiler: gcc}\n          - {os: ubuntu-20.04, llvm: 11, compiler: gcc}\n          - {os: ubuntu-20.04, llvm: 12, compiler: gcc}\n          - {os: ubuntu-22.04, llvm: 13, compiler: gcc}\n          - {os: ubuntu-22.04, llvm: 14, compiler: gcc}\n          - {os: ubuntu-22.04, llvm: 14, compiler: gcc, type: Debug}\n\n          # Linux with Clang\n          - {os: ubuntu-18.04, llvm: '3.9', compiler: clang}\n          - {os: ubuntu-18.04, llvm: '4.0', compiler: clang}\n          - {os: ubuntu-18.04, llvm: '5.0', compiler: clang}\n          - {os: ubuntu-18.04, llvm: '6.0', compiler: clang}\n          - {os: ubuntu-18.04, llvm: 7, compiler: clang}\n          - {os: ubuntu-18.04, llvm: 8, compiler: clang}\n          - {os: ubuntu-18.04, llvm: 9, compiler: clang}\n          - {os: ubuntu-20.04, llvm: 10, compiler: clang}\n          - {os: ubuntu-20.04, llvm: 11, compiler: clang}\n          - {os: ubuntu-20.04, llvm: 12, compiler: clang}\n          - {os: ubuntu-22.04, llvm: 13, compiler: clang}\n          - {os: ubuntu-22.04, llvm: 14, compiler: clang}\n          - {os: ubuntu-22.04, llvm: 14, compiler: clang, type: Debug}\n\n    runs-on: ${{matrix.os}}\n    env:\n      # for colours in ninja\n      CLICOLOR_FORCE: 1\n\n    steps:\n      - name: Checkout DG\n        uses: actions/checkout@v3\n\n      - name: '[LLVM ${{matrix.llvm}}] Add repositories'\n        if: matrix.llvm >= 15\n        run: |\n          wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -\n          sudo apt-add-repository \"deb https://apt.llvm.org/jammy/ llvm-toolchain-jammy-${{matrix.llvm}} main\"\n\n      - name: Install dependencies\n        run: |\n          sudo apt update\n          sudo apt install ccache cmake ninja-build clang-${{matrix.llvm}} \\\n                           llvm-${{matrix.llvm}}-dev\n\n      - name: Set environment\n        id: env\n        run: |\n          if [[ \"${{matrix.compiler}}\" = \"clang\" ]]; then\n            echo \"CC=clang-${{matrix.llvm}}\" >> $GITHUB_ENV\n            echo \"CXX=clang++-${{matrix.llvm}}\" >> $GITHUB_ENV\n\n            # force coloured output\n            echo \"CFLAGS=$CFLAGS -fcolor-diagnostics\" >> $GITHUB_ENV\n            echo \"CXXFLAGS=$CXXFLAGS -fcolor-diagnostics\" >> $GITHUB_ENV\n          else\n            echo \"CC=gcc\" >> $GITHUB_ENV\n            echo \"CXX=g++\" >> $GITHUB_ENV\n\n            # force coloured output\n            echo \"CFLAGS=$CFLAGS -fdiagnostics-color=always\" >> $GITHUB_ENV\n            echo \"CXXFLAGS=$CXXFLAGS -fdiagnostics-color=always\" >> $GITHUB_ENV\n          fi\n\n          # set up ccache\n          sudo /usr/sbin/update-ccache-symlinks\n          echo \"/usr/lib/ccache\" >> $GITHUB_PATH\n\n          # Bionic does not create symlinks to versioned clang\n          sudo ln -sfr /usr/bin/ccache /usr/lib/ccache/clang-${{matrix.llvm}}\n          sudo ln -sfr /usr/bin/ccache /usr/lib/ccache/clang++-${{matrix.llvm}}\n\n          echo \"CCACHE_BASEDIR=$GITHUB_WORKSPACE\" >> $GITHUB_ENV\n          echo \"CCACHE_DIR=$GITHUB_WORKSPACE/.ccache\" >> $GITHUB_ENV\n          echo \"CCACHE_COMPRESS=true\" >> $GITHUB_ENV\n          echo \"CCACHE_COMPRESSLEVEL=6\" >> $GITHUB_ENV\n          echo \"CCACHE_MAXSIZE=400M\" >> $GITHUB_ENV\n\n          echo \"::set-output name=timestamp::$(date -u -Iseconds)\"\n\n      - name: Set up ccache\n        uses: actions/cache@v3\n        with:\n          path: .ccache\n          key: ${{matrix.os}}-${{matrix.llvm}}-${{matrix.compiler}}-${{matrix.type}}-${{steps.env.outputs.timestamp}}\n          restore-keys: ${{matrix.os}}-${{matrix.llvm}}-${{matrix.compiler}}-${{matrix.type}}\n\n      - name: '[Dynamic LLVM] Configure CMake project'\n        run: |\n          cmake -S. \\\n                -B_build \\\n                -GNinja \\\n                -DCMAKE_BUILD_TYPE:STRING=\"${{matrix.type}}\" \\\n                -DUSE_SANITIZERS:BOOL=ON \\\n                -DLLVM_DIR:PATH=\"/usr/lib/llvm-${{matrix.llvm}}/lib/cmake/llvm\"\n                # llvm-config-3.9 does not take --cmakedir yet!\n\n      - name: '[Dynamic LLVM] Build'\n        run: cmake --build _build\n\n      - name: '[Dynamic LLVM] Run tests'\n        # TODO: turn off the detection of leaks, we're working on it\n        run: ASAN_OPTIONS=detect_leaks=0 cmake --build _build --target check\n\n      - name: '[Static LLVM] Re-configure CMake project'\n        run: |\n          cmake -S. \\\n                -B_build \\\n                -DLLVM_LINK_DYLIB:BOOL=OFF\n          cmake --build _build --target clean\n\n      - name: '[Static LLVM] Build'\n        run: cmake --build _build\n\n      - name: '[Static LLVM] Run tests'\n        # TODO: turn off the detection of leaks, we're working on it\n        run: ASAN_OPTIONS=detect_leaks=0 cmake --build _build --target check\n\n      - name: ccache statistics\n        run: ccache -s\n\n# Warning: untested and incomplete\n#\n#  build32:\n#    name: Ubuntu 32-bit\n#    runs-on: ubuntu-20.04\n#    container: ubuntu:latest\n#\n#    strategy:\n#      fail-fast: false\n#      matrix:\n#        compiler: [gcc, clang]\n#        build_type: [Debug, Release]\n#\n#    steps:\n#      - uses: actions/checkout@v2\n#      - name: Install dependencies\n#        run: |\n#          dpkg --add-architecture i386\n#          apt update\n#          apt install -y cmake ninja-build clang:i386 llvm-dev:i386 libc-dev:i386\n#\n#      - name: Set environment\n#        run: |\n#          CFLAGS=\"$CFLAGS -m32\"\n#          CXXFLAGS=\"$CXXFLAGS -m32\"\n#\n#          if [[ \"${{matrix.compiler}}\" = \"clang\" ]]; then\n#            echo \"CC=clang\" >> $GITHUB_ENV\n#            echo \"CXX=clang++\" >> $GITHUB_ENV\n#\n#            # force coloured output\n#            echo \"CFLAGS=$CFLAGS -fcolor-diagnostics\" >> $GITHUB_ENV\n#            echo \"CXXFLAGS=$CXXFLAGS -fcolor-diagnostics\" >> $GITHUB_ENV\n#          else\n#            echo \"CC=gcc\" >> $GITHUB_ENV\n#            echo \"CXX=g++\" >> $GITHUB_ENV\n#\n#            # force coloured output\n#            echo \"CFLAGS=$CFLAGS -fdiagnostics-color\" >> $GITHUB_ENV\n#            echo \"CXXFLAGS=$CXXFLAGS -fdiagnostics-color\" >> $GITHUB_ENV\n#          fi\n#\n#      - name: Configure CMake project\n#        run: |\n#          cmake -Bbuild -S. \\\n#                -GNinja \\\n#                -DUSE_SANITIZERS=ON \\\n#                -DCMAKE_BUILD_TYPE='${{matrix.build_type}}'\n#\n#      - name: Build\n#        run: ninja -C build\n#\n#      - name: Run tests\n#        # TODO: turn off the detection of leaks, we're working on it\n#        run: ASAN_OPTIONS=detect_leaks=0 ninja check -C build\n"
  },
  {
    "path": ".github/workflows/mac.yml",
    "content": "---\nname: macOS CI\non: [push, pull_request]\n\njobs:\n  build:\n    name: macOS\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [macos-12]\n        build: [Debug, RelWithDebInfo]\n\n    runs-on: ${{matrix.os}}\n    env:\n      # for colours in ninja\n      CLICOLOR_FORCE: 1\n\n    steps:\n      - name: Checkout DG\n        uses: actions/checkout@v3\n\n      - name: Install dependencies\n        run: brew install ninja ccache llvm@14\n\n      - name: Set environment\n        id: env\n        run: |\n          echo \"CCACHE_BASEDIR=$GITHUB_WORKSPACE\" >> $GITHUB_ENV\n          echo \"CCACHE_DIR=$GITHUB_WORKSPACE/.ccache\" >> $GITHUB_ENV\n          echo \"CCACHE_COMPRESS=true\" >> $GITHUB_ENV\n          echo \"CCACHE_COMPRESSLEVEL=6\" >> $GITHUB_ENV\n          echo \"CCACHE_MAXSIZE=400M\" >> $GITHUB_ENV\n\n          echo \"/usr/local/opt/ccache/libexec\" >> $GITHUB_PATH\n\n          echo \"::set-output name=timestamp::$(date -u +%Y-%m-%dT%H:%M:%S%z)\"\n\n      - name: Set-up ccache\n        uses: actions/cache@v3\n        with:\n          path: .ccache\n          key: ${{matrix.os}}-${{matrix.build}}-${{steps.env.outputs.timestamp}}\n          restore-keys: ${{matrix.os}}-${{matrix.build}}\n\n      - name: Configure CMake project\n        run: |\n          cmake -S. \\\n                -B_build \\\n                -GNinja \\\n                -DCMAKE_BUILD_TYPE:STRING=${{matrix.build}} \\\n                -DUSE_SANITIZERS:BOOL=ON \\\n                -DLLVM_DIR:PATH=\"$($(brew --prefix llvm@14)/bin/llvm-config --cmakedir)\"\n        env:\n          # for coloured output\n          CFLAGS: -fcolor-diagnostics\n          CXXFLAGS: -fcolor-diagnostics\n\n      - name: Build\n        run: cmake --build _build\n\n      - name: Run tests\n        # TODO: turn off the detection of leaks, we're working on it\n        run: ASAN_OPTIONS=detect_leaks=0 cmake --build _build --target check\n\n      - name: ccache statistics\n        run: ccache -s\n"
  },
  {
    "path": ".github/workflows/svf.yml",
    "content": "---\nname: DG + SVF\non: [push, pull_request]\n\njobs:\n  Ubuntu:\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-22.04]\n        compiler: [gcc, clang]\n\n    runs-on: ${{matrix.os}}\n    env:\n      # for colours in ninja\n      CLICOLOR_FORCE: 1\n\n    steps:\n      - name: Checkout DG\n        uses: actions/checkout@v3\n\n      - name: Checkout SVF\n        uses: actions/checkout@v3\n        with:\n          ref: SVF-2.4\n          repository: SVF-tools/SVF\n          path: svf\n\n      - name: Checkout SVF test-suite\n        uses: actions/checkout@v3\n        with:\n          # ref corresponding to the SVF ref above\n          ref: 2338ede904c1f46293b64ccf32feb09b3904401f\n          repository: SVF-tools/Test-Suite\n          path: svf/Test-Suite\n\n      - name: Install dependencies\n        run: |\n          sudo apt update\n          sudo apt install ccache cmake ninja-build clang-13 llvm-13-dev \\\n                           libz3-dev\n\n      - name: Set environment\n        id: env\n        run: |\n          if [[ \"${{matrix.compiler}}\" = \"clang\" ]]; then\n            echo \"CC=clang-13\" >> $GITHUB_ENV\n            echo \"CXX=clang++-13\" >> $GITHUB_ENV\n\n            # force coloured output\n            echo \"CFLAGS=$CFLAGS -fcolor-diagnostics\" >> $GITHUB_ENV\n            echo \"CXXFLAGS=$CXXFLAGS -fcolor-diagnostics\" >> $GITHUB_ENV\n          else\n            echo \"CC=gcc\" >> $GITHUB_ENV\n            echo \"CXX=g++\" >> $GITHUB_ENV\n\n            # force coloured output\n            echo \"CFLAGS=$CFLAGS -fdiagnostics-color=always\" >> $GITHUB_ENV\n            echo \"CXXFLAGS=$CXXFLAGS -fdiagnostics-color=always\" >> $GITHUB_ENV\n          fi\n\n          # set up ccache\n          sudo /usr/sbin/update-ccache-symlinks\n          echo \"/usr/lib/ccache\" >> $GITHUB_PATH\n\n          echo \"CCACHE_BASEDIR=$GITHUB_WORKSPACE\" >> $GITHUB_ENV\n          echo \"CCACHE_DIR=$GITHUB_WORKSPACE/.ccache\" >> $GITHUB_ENV\n          echo \"CCACHE_COMPRESS=true\" >> $GITHUB_ENV\n          echo \"CCACHE_COMPRESSLEVEL=6\" >> $GITHUB_ENV\n          echo \"CCACHE_MAXSIZE=400M\" >> $GITHUB_ENV\n\n          echo \"::set-output name=timestamp::$(date -u -Iseconds)\"\n\n      - name: Set up ccache\n        uses: actions/cache@v3\n        with:\n          path: .ccache\n          key: ${{matrix.os}}-svf-${{matrix.compiler}}-${{steps.env.outputs.timestamp}}\n          restore-keys: ${{matrix.os}}-svf-${{matrix.compiler}}\n\n      - name: Build SVF\n        run: |\n          # Build directory name format is hard-coded in SVF tests...\n\n          # do not build with -Werror (needed for GCC 11.2.0)\n          sed -i 's/-Werror//' svf/CMakeLists.txt\n\n          # WARNING: DO NOT SET CMAKE_BUILD_TYPE! (except Debug)\n          # SVF expects that NDEBUG will never be defined!\n          cmake -Ssvf \\\n                -Bsvf/Release-build \\\n                -GNinja \\\n                -DLLVM_DIR:PATH=\"$(llvm-config-13 --cmakedir)\"\n\n          cmake --build svf/Release-build\n          (cd svf/Release-build && \\\n           PATH=\"$(llvm-config-13 --bindir):$PATH\" \\\n           ctest --progress --output-on-failure)\n\n      - name: '[Dynamic LLVM] Configure CMake project'\n        run: |\n          cmake -S. \\\n                -B_build \\\n                -GNinja \\\n                -DUSE_SANITIZERS:BOOL=ON \\\n                -DLLVM_DIR:PATH=\"$(llvm-config-13 --cmakedir)\" \\\n                -DSVF_DIR:PATH=\"$GITHUB_WORKSPACE/svf/Release-build\"\n\n      - name: '[Dynamic LLVM] Build'\n        run: cmake --build _build\n\n      - name: '[Dynamic LLVM] Run tests'\n        # TODO: turn off the detection of leaks, we're working on it\n        run: ASAN_OPTIONS=detect_leaks=0 cmake --build _build --target check\n\n      - name: '[Static LLVM] Re-configure CMake project'\n        run: |\n          cmake -S. \\\n                -B_build \\\n                -DLLVM_LINK_DYLIB:BOOL=OFF\n          cmake --build _build --target clean\n\n      - name: '[Static LLVM] Build'\n        run: cmake --build _build\n\n      - name: '[Static LLVM] Run tests'\n        # TODO: turn off the detection of leaks, we're working on it\n        run: ASAN_OPTIONS=detect_leaks=0 cmake --build _build --target check\n\n      - name: ccache statistics\n        run: ccache -s\n"
  },
  {
    "path": ".gitignore",
    "content": "# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Fortran module files\n*.mod\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n\n# Executables\n*.exe\n*.out\n*.app\n\n# cmake\n*.cmake\n*Makefile*\n\n# swp files\n*.swp\n*.swo\n*.swm\n\n# vim config files\n*.vimrc\n\ntags\n*/tags\n*/cscope.out\n\n*.swn\n*.dot\n*.ps\n\n# LLVM files\n*.bc\n*.sliced\n*.linked\n*.opt\n*.ll\n\n*.i\n\ntests/*-test\ntests/fuzzing/regressions/\n\n# clangd\n.cache\n.clangd\n\n# pycache\n__pycache__\n\n# C files in tools are test codes\ntools/*.c\ntools/*.bc\n\ntools/llvm-dg-dump\ntools/llvm-to-source\ntools/llvm-slicer\n\ngit-version.h\n\n# build directory\nbuild\n\n# sourcetrail files\ndg.srctrl*\n\ncompile_commands.json\n\nCMakeLists.txt.user*\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: cpp\nsudo: true\n\ndist: trusty\n\ngit:\n  depth: 1\n\naddons:\n  apt:\n    sources:\n      # newer gcc and clang\n      - ubuntu-toolchain-r-test\n      - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-4.0 main'\n        key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'\n      - sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-5.0 main'\n    packages:\n      - libz-dev\n\nenv:\n    - LLVM=3.8 BUILD_TYPE=Release\n    - LLVM=3.8 BUILD_TYPE=Debug\n    - LLVM=4.0 BUILD_TYPE=Release\n    - LLVM=4.0 BUILD_TYPE=Debug\n    - LLVM=5.0 BUILD_TYPE=Release\n    - LLVM=5.0 BUILD_TYPE=Debug\n\ncompiler:\n    - 'clang++'\n    - 'g++'\n    - 'g++-5'\n\ninstall:\n  - git clone --depth 1 https://github.com/tomsik68/travis-llvm.git\n  - cd travis-llvm\n  - chmod +x travis-llvm.sh\n  - ./travis-llvm.sh ${LLVM}\n  - cd ..\n\nscript:\n  - cmake -DCMAKE_BUILD_TYPE=\"$BUILD_TYPE\" -DUSE_SANITIZERS=ON .\n  - make -j2\n  # for now turn off the detection of leaks, we're working on it\n  - ASAN_OPTIONS=detect_leaks=0 make check -j2\n\nnotifications:\n    email: false\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.1)\n\n# FIXME: Unfortunately, C is (at least temporarily) required due to a bug\n# in LLVM 14.  See https://github.com/llvm/llvm-project/issues/53950.\nproject(dg LANGUAGES C CXX)\n\ninclude(CTest)\n\n# we need at least C++11 standard\nset(CMAKE_CXX_STANDARD 11)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\n\nOPTION(LLVM_DG \"Support for LLVM Dependency graph\" ON)\nOPTION(ENABLE_CFG \"Add support for CFG edges to the graph\" ON)\nOPTION(NO_EXCEPTIONS \"Compile with -fno-exceptions (ON by default)\" ON)\n\nif(NOT CMAKE_BUILD_TYPE)\n    message(STATUS \"Build type not set. Setting default.\")\n    set(CMAKE_BUILD_TYPE \"RelWithDebInfo\" CACHE STRING \"\" FORCE)\nendif()\nmessage(STATUS \"Build type: ${CMAKE_BUILD_TYPE}\")\nset_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS \"Debug\" \"RelWithDebInfo\"\n                                                     \"MinSizeRel\" \"Release\")\n\nif (LLVM_DG)\n\t# for llvm dg we need cfg and postdom edges\n\tif (NOT ENABLE_CFG)\n\t\tmessage(STATUS \"Enabling CFG edges due to llvm dg\")\n\tendif()\n\n\tset(ENABLE_CFG ON)\n\n\tfind_package(LLVM REQUIRED CONFIG)\n\n\tmessage(STATUS \"Found LLVM ${LLVM_PACKAGE_VERSION}\")\n\tmessage(STATUS \"Using LLVMConfig.cmake in: ${LLVM_DIR}\")\n\tmessage(STATUS \"LLVM binaries: ${LLVM_TOOLS_BINARY_DIR}\")\n\n\tset(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} \"${LLVM_DIR}\")\n\tinclude(LLVMConfig)\n\tinclude(AddLLVM)\n\n\tmessage(STATUS \"LLVM include dir: ${LLVM_INCLUDE_DIRS}\")\n\tmessage(STATUS \"LLVM libraries dir: ${LLVM_LIBRARY_DIRS}\")\n\tmessage(STATUS \"LLVM definitions: ${LLVM_DEFINITIONS}\")\n\n\t# if we were provided a path to custom sources\n\t# use that path\n\tif (LLVM_SRC_PATH)\n\t\tinclude_directories(SYSTEM ${LLVM_SRC_PATH}/include)\n\t\tmessage(STATUS \"Looking for headers in given: ${LLVM_SRC_PATH}/include\")\n\telse()\n\t\tinclude_directories(SYSTEM ${LLVM_INCLUDE_DIRS})\n\t\tmessage(STATUS \"Looking for headers in: ${LLVM_INCLUDE_DIRS}\")\n\tendif()\n\n\t# if we were provided a path to custom build directory\n\t# use that\n\tif (LLVM_BUILD_PATH)\n\t\tlink_directories(${LLVM_BUILD_PATH}/lib)\n\n\t\t# llvm-config.h\n\t\tinclude_directories(SYSTEM \"${LLVM_BUILD_PATH}/include\")\n\t\tmessage(STATUS \"Looking for libraries in given: ${LLVM_BUILD_PATH}/lib\")\n\telse()\n\t\tlink_directories(${LLVM_LIBRARY_DIRS})\n\t\tmessage(STATUS \"Looking for libraries in: ${LLVM_LIBRARY_DIRS}\")\n\tendif(LLVM_BUILD_PATH)\n\n\tadd_definitions(${LLVM_DEFINITIONS})\n\n\toption(LLVM_LINK_DYLIB \"Link with LLVM dynamically\" ON)\n\n\tif (LLVM_LINK_DYLIB)\n\t\tmessage(STATUS \"LLVM linking: dynamic\")\n\t\tif (${LLVM_PACKAGE_VERSION} VERSION_LESS \"3.8\")\n\t\t\tset(llvm LLVM-${LLVM_PACKAGE_VERSION})\n\t\telse()\n\t\t\t# only LLVM 3.8+ provide unversioned library\n\t\t\tset(llvm LLVM)\n\t\tendif()\n\telse()\n\t\tmessage(STATUS \"LLVM linking: static\")\n\t\tif (${LLVM_PACKAGE_VERSION} VERSION_GREATER \"3.4\")\n\t\t\tllvm_map_components_to_libnames(llvm_analysis analysis)\n\t\t\tllvm_map_components_to_libnames(llvm_irreader irreader)\n\t\t\tllvm_map_components_to_libnames(llvm_bitwriter bitwriter)\n\t\telse()\n\t\t\tllvm_map_components_to_libraries(llvm_irreader irreader)\n\t\t\tllvm_map_components_to_libraries(llvm_bitwriter bitwriter)\n\t\t\tllvm_map_components_to_libraries(llvm_analysis analysis)\n\t\tendif()\n\tendif()\n\n\t# LLVM 10 and newer require at least c++14 standard\n\tif (${LLVM_PACKAGE_VERSION} VERSION_GREATER \"9.0\")\n\t\tset(CMAKE_CXX_STANDARD 14)\n\t\toption(USE_CXX14 \"Use C++14 standard\" ON)\n\tendif()\nendif(LLVM_DG)\n\nif (SVF_DIR)\n\tset(HAVE_SVF ON)\n\tadd_definitions(-DHAVE_SVF)\n\tset(SVF_LIBDIR ${SVF_DIR}/lib)\n\n\tif (NOT SVF_INCLUDE)\n\t\tif (EXISTS \"${SVF_DIR}/include/WPA/Andersen.h\")\n\t\t\tset(SVF_INCLUDE ${SVF_DIR}/include)\n\t\telseif (EXISTS \"${SVF_DIR}/../include/WPA/Andersen.h\")\n\t\t\tset(SVF_INCLUDE ${SVF_DIR}/../include)\n\t\telse()\n\t\t\tmessage(FATAL_ERROR \"Did not find the directory with SVF headers\")\n\t\tendif()\n\tendif()\n\n\tset(SVF_LIBS Svf Cudd)\n\n\tinclude_directories(SYSTEM ${SVF_INCLUDE})\n\tlink_directories(${SVF_LIBDIR} ${SVF_LIBDIR}/CUDD)\n\n\tif (NOT LLVM_LINK_DYLIB)\n\t\tif (${LLVM_PACKAGE_VERSION} VERSION_GREATER \"3.4\")\n\t\t\tllvm_map_components_to_libnames(llvm_transformutils transformutils)\n\t\telse()\n\t\t\tllvm_map_components_to_libraries(llvm_transformutils transformutils)\n\t\tendif()\n\tendif()\n\n\tmessage(STATUS \"SVF dir: ${SVF_DIR}\")\n\tmessage(STATUS \"SVF libraries dir: ${SVF_LIBDIR}\")\n\tmessage(STATUS \"SVF include dir: ${SVF_INCLUDE}\")\n\tmessage(STATUS \"SVF libs: ${SVF_LIBS}\")\nendif(SVF_DIR)\n\nif (TSL_HOPSCOTCH_DIR)\n    set(HOPSCOTCH_DIR ${TSL_HOPSCOTCH_DIR}/include/)\n    if (NOT EXISTS \"${HOPSCOTCH_DIR}/tsl/hopscotch_map.h\")\n        message(FATAL_ERROR \"Tessil hopscotch map NOT FOUND in ${TSL_HOPSCOTCH_DIR}\" )\n    endif()\n\n    include_directories(SYSTEM ${HOPSCOTCH_DIR})\n    message(STATUS \"Found Tessil Hopscotch map in ${HOPSCOTCH_DIR}\" )\n    message(STATUS \"Adding include dir ${HOPSCOTCH_DIR}\")\n    add_definitions(-DHAVE_TSL_HOPSCOTCH)\nendif()\n\n\n\nif (ENABLE_CFG)\n\tadd_definitions(-DENABLE_CFG)\nendif()\n\nmessage(STATUS \"Using compiler: ${CMAKE_CXX_COMPILER}\")\n\n# --------------------------------------------------\n# Fuzzing\n# --------------------------------------------------\ninclude(CheckCXXCompilerFlag)\nset(CMAKE_REQUIRED_FLAGS \"-fsanitize=fuzzer\")\ncheck_cxx_source_compiles(\n   \"#include <cstddef>\n    extern \\\"C\\\" int LLVMFuzzerTestOneInput(const void *, size_t) { return 0; }\"\n    HAS_FUZZER)\nset(CMAKE_REQUIRED_FLAGS \"\")\n\noption(ENABLE_FUZZING \"Enable fuzzing tests\" ${HAS_FUZZER})\nif(NOT ENABLE_FUZZING)\n    message(STATUS \"Will NOT build fuzzing tests (requires Clang 6 or newer)\")\nendif()\n\n# --------------------------------------------------\n# clang-tidy\n# --------------------------------------------------\noption(USE_CLANG_TIDY \"Enable clang-tidy checks\" OFF)\nif(USE_CLANG_TIDY)\n    message(STATUS \"Clang-tidy build enabled\")\n    # read config from .clang-tidy\n    set(CMAKE_CXX_CLANG_TIDY \"clang-tidy;--config=\")\nendif()\n\n# --------------------------------------------------\n# Compiler flags\n# --------------------------------------------------\n# explicitly add -std=c++11 (-std=c++14) and -fno-rtti\n# we have CMAKE_CXX_STANDARD, but for some reason it does not\n# put the -std=c++11 (-std=c++14) or -std=gnu++11 (-std=gnu++14)\n# to the flags on some systems.\n# For the -fno-rtti: LLVM still got problems with turning RTTI off...\nif (USE_CXX14)\n\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++14\")\nelse()\n\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++11\")\nendif()\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -fno-rtti -Wall -Wextra\")\nif (NO_EXCEPTIONS)\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -fno-exceptions\")\nendif()\n\nif (USE_SANITIZERS)\n\tset(CMAKE_REQUIRED_FLAGS \"-fsanitize=undefined,address\") # for linker\n\tcheck_cxx_compiler_flag(\"-fsanitize=undefined,address\" sanitizers_work)\n\tset(CMAKE_REQUIRED_FLAGS \"\")\n\n\tif (sanitizers_work)\n\t\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -fsanitize=undefined,address\")\n\t\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -g -fno-omit-frame-pointer\")\n\t\tset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -fno-sanitize-recover=all\")\n\t\tadd_definitions(-DUSING_SANITIZERS)\n\telse()\n\t\tmessage(WARNING \"Used compiler does not support sanitizers or its support is incomplete.\")\n\tendif()\nendif()\n\n# Debug Release RelWithDebInfo MinSizeRel.\nif (CMAKE_BUILD_TYPE STREQUAL \"Debug\")\n\tadd_definitions(-DDEBUG_ENABLED)\n\tmessage(STATUS \"Using compilation flags: ${CMAKE_CXX_FLAGS_DEBUG}\")\nelseif (CMAKE_BUILD_TYPE STREQUAL \"Release\")\n\tmessage(STATUS \"Using compilation flags: ${CMAKE_CXX_FLAGS_RELEASE}\")\nelseif (CMAKE_BUILD_TYPE STREQUAL \"RelWithDebInfo\")\n\tmessage(STATUS\n\t\t\"Using compilation flags: ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}\")\nelseif (CMAKE_BUILD_TYPE STREQUAL \"MinSizeRel\")\n\tmessage(STATUS \"Using compilation flags: ${CMAKE_CXX_FLAGS_MINSIZEREL}\")\nendif ()\n\nmessage(STATUS \"Additional compilation flags: ${CMAKE_CXX_FLAGS}\")\n\ninclude(GNUInstallDirs)\nmessage(STATUS \"CMAKE_INSTALL_LIBDIR: \\\"${CMAKE_INSTALL_LIBDIR}\\\"\")\nmessage(STATUS \"CMAKE_INSTALL_INCLUDEDIR: \\\"${CMAKE_INSTALL_INCLUDEDIR}\\\"\")\n\ninclude_directories(include)\ninclude_directories(lib)\n\nadd_subdirectory(lib)\nadd_subdirectory(tools)\nadd_subdirectory(tests EXCLUDE_FROM_ALL)\n\nif(NOT LLVM_DG)\n  set(INSTALL_EXCLUDE_PATTERNS PATTERN \"llvm\" EXCLUDE)\nendif()\ninstall(DIRECTORY include/\n        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}\n        ${INSTALL_EXCLUDE_PATTERNS})\n"
  },
  {
    "path": "Changelog",
    "content": "-- 3. 10. 2018\n\n* The project was re-structured from src/ structure to lib/ and include/\n  structure. As a consequence, all public headers were moved to dg/\n  subdirectory, e.g. \"llvm/LLVMDependenceGraph.h\" is now\n  \"dg/llvm/LLVMDependenceGraph.h\"\n\n* Renamed files:\n- llvm/Slicer.h -> dg/llvm/LLVMSlicer.h\n- llvm/analysis/PointsTo/PointsTo.h -> dg/llvm/analysis/PointsTo/PointerAnalysis.h\n- analysis/PointsTo/PointsToFlowSensitive.h -> dg/analysis/PointsTo/PointerAnalysisFS.h\n- analysis/PointsTo/PointsToFlowInsensitive.h -> dg/analysis/PointsTo/PointerAnalysisFI.h\n- analysis/PointsTo/PointsToWithInvalidate.h -> dg/analysis/PointsTo/PointerAnalysisFSInv.h\n\n* A new library libDGAnalysis.so was added. You must link to this library\n  when linking with any dg library.\n"
  },
  {
    "path": "Dockerfile",
    "content": "# --------------------------------------------------\n# Base container\n# --------------------------------------------------\nFROM docker.io/ubuntu:jammy AS base\n\nRUN set -e\n\n# Install packages\nENV DEBIAN_FRONTEND=noninteractive\nRUN apt-get update\nRUN apt-get install -yq --no-install-recommends clang llvm\n\n# --------------------------------------------------\n# Build container\n# --------------------------------------------------\nFROM base as build\n\n# Can be used to specify which git ref to checkout\nARG GIT_REF=master\nARG GIT_REPO=mchalupa/dg\n\n# Install build dependencies\nRUN apt-get install -yq --no-install-recommends ca-certificates cmake git \\\n                                                ninja-build llvm-dev python3\n\n# Clone\nRUN git clone https://github.com/$GIT_REPO\nWORKDIR /dg\nRUN git fetch origin $GIT_REF:build\nRUN git checkout build\n\n# libfuzzer does not like the container environment\nRUN cmake -S. -GNinja -Bbuild -DCMAKE_INSTALL_PREFIX=/opt/dg \\\n          -DCMAKE_CXX_COMPILER=clang++ -DENABLE_FUZZING=OFF\nRUN cmake --build build\nRUN cmake --build build --target check\n\n# Install\nRUN cmake --build build --target install/strip\n\n# -------------------------------------------------\n# Release container\n# -------------------------------------------------\nFROM base AS release\n\nCOPY --from=build /opt/dg /opt/dg\nENV PATH=\"/opt/dg/bin:$PATH\"\nENV LD_LIBRARY_PATH=\"/opt/dg/lib\"\n\n# Verify it works\nRUN llvm-slicer --version\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2015-2020 Marek Chalupa\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice (including the\nnext paragraph) shall be included in all copies or substantial\nportions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\nBE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# DG\n\n[![Linux CI](https://github.com/mchalupa/dg/actions/workflows/linux.yml/badge.svg)](https://github.com/mchalupa/dg/actions/workflows/linux.yml)\n[![macOS CI](https://github.com/mchalupa/dg/actions/workflows/mac.yml/badge.svg)](https://github.com/mchalupa/dg/actions/workflows/mac.yml)\n\nDG is a library containing various bits for program analysis. However, the main motivation of this library is program slicing. The library contains implementation of a pointer analysis, data dependence analysis, control dependence analysis, and an analysis of relations between values in LLVM bitcode. All of the analyses target LLVM bitcode, but most of them are written in a generic way, so they are not dependent on LLVM in particular.\n\nFurther, DG contains an implementation of dependence graphs and a [static program slicer](doc/llvm-slicer.md) for LLVM bitcode. Some documentation can be found in the [doc/](doc/) directory.\n\n\n* [Downloading DG](doc/downloading.md)\n* [Compiling DG](doc/compiling.md)\n* [Using llvm-slicer](doc/llvm-slicer.md)\n* [Other tools](doc/tools.md)\n\n------------------------------------------------\n\nYou can find a high-level description of DG in [DG: a program analysis library](https://doi.org/10.1016/j.simpa.2020.100038) or [DG: Analysis and slicing of LLVM bitcode](https://www.fi.muni.cz/~xchalup4/dg_atva20_preprint.pdf) papers. More detailed information about dg is in the doc/ folder or in my [master thesis](http://is.muni.cz/th/396236/fi_m/thesis.pdf).\n\nYou can write e-mails with issues to <mchqwerty@gmail.com> (or file issue in github).\n"
  },
  {
    "path": "dg.spec.rpkg",
    "content": "# vim: syntax=spec\n\n# Do out-of-source build by default on Fedora\n%undefine __cmake_in_source_build\n\nName:       {{{ git_dir_name }}}\nVersion:    {{{ git_dir_version }}}\nRelease:    1%{?dist}\nSummary:    Analyses, construction of dependence graphs and slicing of LLVM bitcode\n\nLicense:    MIT\nURL:        https://github.com/mchalupa/dg\nVCS:        {{{ git_dir_vcs }}}\n\nSource:     {{{ git_dir_archive }}}\n\nBuildRequires: clang\nBuildRequires: cmake\nBuildRequires: gcc\nBuildRequires: gcc-c++\nBuildRequires: llvm-devel\nBuildRequires: make\nBuildRequires: ncurses-devel\nBuildRequires: python3\nBuildRequires: zlib-devel\n\nRequires: clang\nRequires: llvm\n\n%description\nDG is a library containing various bits for program analysis.  However, the\nmain motivation of this library is program slicing.  The library contains\nimplementation of a pointer analysis, data dependence analysis, control\ndependence analysis, and an analysis of relations between values in LLVM\nbitcode.  All of the analyses target LLVM bitcode, but most of them are written\nin a generic way, so they are not dependent on LLVM in particular.\n\n%prep\n{{{ git_dir_setup_macro }}}\n\n%build\nGIT_VERSION={{{ git rev-parse --short --sq HEAD }}}\n%cmake -DGIT_VERSION=\"$GIT_VERSION\"\n%cmake_build\n\n%install\n%cmake_install\n\n%check\n%if 0%{?suse_version}\n  %cmake_build -C %{__builddir} check\n%else\n  %if 0%{?epel}\n    %cmake_build check\n  %else\n    %cmake_build --target check\n  %endif\n%endif\n\n%files\n%license LICENSE\n%doc doc/*\n%{_bindir}/*\n%{_includedir}/%{name}\n%{_libdir}/*\n"
  },
  {
    "path": "doc/CDA.md",
    "content": "# Control Dependence Analysis\n\nIn DG, we implemented several algorithms for the computation of different control dependencies.\nThese  control dependencies are:\n\n - Standard (SCD) control dependence (Ferrante et al. [1])\n - Non-termination sensitive control dependence (NTSCD) (Ranangath et al.[2])\n - Decisive order dependence (DOD) (Ranangath et al.[2])\n - [experimental/WIP] Strong control closures (Strong CC) (Danicic et al.[3])\n\n\n## Public API\n\nThe class through which you can run and access the results of control dependence analysis\nis called `LLVMControlDependenceAnalysis` and is defined in\n[dg/llvm/ControlDependence/ControlDependence.h](../include/dg/llvm/ControlDependence/ControlDependence.h)\n\nThe class takes an instance of `LLVMControlDependenceAnalysisOptions` in constructor. This object\ndescribes which analysis to run and whether to compute also interprocedural dependencies (see below).\n\nThe public API of `LLVMControlDependenceAnalysis` contains several methods:\n\n* `run()` to run the analysis\n* `getDependencies()` to get dependencies of an instruction or a basic block (there are two polymorphic methods).\n   As we compute intraprocedural dependencies on basic block level, these two method return different things.\n   `getDependencies` for a basic block returns a set of values on which depend all the instructions in the basic\n   block. `getDependencies` for instruction then returns additional dependencies, e.g., interprocedural.\n   Therefore, if you want _all_ dependencies for an instruction, you should always query both, `getDependencies`\n   for the instruction and also `getDependencies` for the basic block of the instruction.\n   Note that the return value may be either an instruction or a basic block.\n   If a basic block is returned as a dependence, it means that the queried value depends on the terminator\n   instruction of the returned basic block.\n\n* `getDependent()` methods return values (instructions and blocks) that depend on the given instruction (block).\n   They work similarly as `getDependencies` methods, just return dependent values instead of dependencies.\n   If a block is returned, then all instructions of the block depend on the given value.\n\n* `getNoReturns()` return possibly no-returning points of the given function (those are usually calls to functions\n  that may not return). If interprocedural analysis is disabled, returns always an empty vector.\n\nThen there are methods for closure-based algorithms, but these are mostly unimplemented (in fact, the Strong CC algorithm\nworks, just these getter methods are not implemented yet).\n\n## Interprocedural dependencies\n\nDG supports the computation of control dependencies that arise due to e.g., calling `abort()` from inside of a procedure.\nConsider this example:\n\n```C\nvoid foo(int x) { if (x < 0) abort(); }\n\nint main() {\n    int a = input();\n    foo();\n    assert(a > 0);\n}\n```\n\nIn the example above, the assertion cannot be violated, because for values of `a` that would violate the\nassert the program is killed by the call to `abort`. That is, the assertion in fact depends on the if statement\nin the `foo` function. Such control dependencies between procedures are omitted by the classical algorithms.\nIn DG, compute these dependencies by a standalone analysis that runs after computing intraprocedural control dependencies.\nResults of the interprocedural analysis are returned by `getDependencies` and `getDependent` along with\nresults of the intraprocedural analysis (of course, only if interprocedural analysis is enabled by the options\nobject).\n\nAlso, NTSCD and DOD algorithms can be executed on interprocedural (inlined) CFG (ICFG).\nThat is, a one big CFG that contains nodes for all basic blocks/instructions of the\nprogram and there are regular intraprocedural edges and also interprocedural\nedges going between calls and entry blocks/instructions and from returns to return-sites.\nFor this functionality, use -cda-icfg.\n\n## Tools\n\nThere is the `llvm-cda-dump` tool that dumps the results of control dependence analysis.\nBy default, it shows the results directly on LLVM bitcode. You can you the `-ir`switch to see the internal\nrepresentation from the analyses. To select the analysis to run, use the `-cda` switch with one of these options:\n\n|opt             | description                           |\n|----------------|---------------------------------------|\n|`scd`             | standard CD (the default)             |\n|`standard`        | an alias for stanard                  |\n|`classic`         | an alias for standard                 |\n|`ntscd`           | non-termination sensitive CD          |\n|`ntscd2`          | NTSCD (a different implementation)    |\n|`ntscd-ranganath` | Ranganath et al's algorithm for NTSCD (warning: it is incorrect) |\n|`dod`             | Standalone DOD computation            |\n|`dod-ranganath`   | Ranganath et al's algorithm (the original algorithm was incorrect, this is a fixed version) |\n|`dod+ntscd`       | NTSCD + DOD                           |\n|`scc`             | Strong control closures               |\n\n\nNote that `llvm-slicer` takes the very same options.\n\nThere are also tools `llvm-ntscd-dump` specialized for showing internals and results of the NTSCD analysis,\n`llvm-cda-bench` that benchmarks a given list of analyses (the list is given without the `-cda` switch,\ne.g., `-ntscd -ntscd2 -dod`, see the help message) on a given program, and `llvm-cda-stress`\nthat works like `llvm-cda-bench` with the difference that it generates and uses a random control flow graph\nand it works with only a subset of analyses (all except SCD).\n\n## Other notes\n\nThe algorithm for computing standard control dependencies does not have a generic implementation in DG\nas we heavily rely on LLVM in computation of post dominators.\n\n\n\n[1] Jeanne Ferrante, Karl J. Ottenstein, Joe D. Warren: The Program Dependence Graph and Its Use in Optimization.\n    ACM Trans. Program. Lang. Syst. 9(3): 319-349 (1987)\n\n\n[2] Venkatesh Prasad Ranganath, Torben Amtoft, Anindya Banerjee, Matthew B. Dwyer, John Hatcliff:\n    A New Foundation for Control-Dependence and Slicing for Modern Program Structures. ESOP 2005: 77-93\n\n[3] Sebastian Danicic, Richard W.Barraclough, Mark Harman, John D.Howroyd, Ákos Kiss, Michael R.Laurence: A unifying theory of control dependence and its application to arbitrary program structures. Theoretical Computer Science, Volume 412, Issue 49, 2011, Pages 6809-6842\n"
  },
  {
    "path": "doc/DDA.md",
    "content": "# Data Dependence Analysis\n\nDG contains the analysis of data dependencies (also called value-flow)\nbased on constructing memory SSA form of the program.\n\n## Public API\n\nThe data dependence analysis class for LLVM is `LLVMDataDependenceAnalysis`.\nIts constructor takes the LLVM module, results of pointer analysis and optionally an instance of\n`LLVMDataDependenceAnalysisOptions`.\n\nRelevant methods from the public API are two polymorphic methods `getLLVMDefinitions`.\n\nOne takes LLVM value which is required to read memory (can be checked by `isUse` method)\nand returns a vector of LLVM values that may have possibly written the values read\nby the given value.\n\nThe other takes parameters `where`, `mem`, `off`, and `len` and returns all LLVM values that\nmay write to the memory allocated by instruction or global variable `mem` at bytes from `off`\nto `off + len - 1` and the written value may be read at `where` (i.e., it has not been surely\noverwritten at `where` yet).\n\n## Modeling external (undefined) functions\n\nThe class `LLVMDataDependenceAnalysisOptions` has the possibility of registering\nmodels for functions. If the analysis then hits a call of the given function,\nit uses this model instead of calling the function (if the function is defined\nin the module) or instead of assuming that the function may do anything.\n\nThe methods that take care of registering models of functions are\n`functionModelAddDef` and `functionModelAddUse`.\nThese methods take the name of the modelled function and a tripple `(argidx, offset, len)`\nwhich means that the function defines/uses the memory pointed by the `argidx`-th argument\n(beginning at 0) and define `len` bytes from the memory beginning at `argidx + offset`.\nIf `len` (`offset`, resp.) are of type `Offset`, these are interpreted as constant numbers.\nHowever, if those are of type `unsigned`, those are interpreted as indexes of arguments\n(the same as `argidx`) meaning that the real number of bytes and offset is given\nby the argument of the called function. If the argument is not a constant,\nit is taken as UNKNOWN. For example,\n\n```C\nfunctionModelAddUse(\"memset\", {0, Offset(0), 2})`\n```\n\ntell the analysis that `memset` function defines the memory pointed by the first argument\n(with index 0) and this memory is defined from the byte where the first argument points.\nAlso, only the number of bytes specified by the third argument (with index 2) are used.\nFor the code\n\n```C\nint array[10];\nmemset(array + 2, 0, 20);\n```\n\nThe analysis will create a model that tells that this call to `memset` defines bytes 8 - 27 of `array`\n(given that the size of int is 4 bytes).Another examples of using these functions can be found in\n[LLVMDataDependenceAnalysisOptions.h](../include/dg/llvm/DataDependence/LLVMDataDependenceAnalysisOptions.h).\n\n\n## Tools\n\nThere is `llvm-dda-dump` that dumps the results of data dependence analysis. If dumped to .dot file\n(`-dot` option) the computed memory SSA along with def-use chains is shown.\n"
  },
  {
    "path": "doc/PTA.md",
    "content": "# Pointer Analysis in DG\n\nPointer analysis (PTA) implementation in DG consists of a general part and LLVM\npart.  The general part include a program representation (graph) and the\npointer analysis algorithm that runs on the graph.  The LLVM part takes care of\nbuilding the pointer graph from the LLVM module and translating results from\nthe analysis to consumers of LLVM bitcode (i.e., if we ask for points-to set of\na LLVM value, we get a set of LLVM values and not the analysi's internal\nnodes).\n\nThe program representation (`PointerGraph`) is a graph whose nodes (`PSNode`)\ncontain information about pointer handlings, e.g., casts, storing and loading\nto/from memory, shifting, etc.  Further, the graph is subdivided into subgraphs\n(`PointerSubgraph`) that correspond to procedures.\n\nOnce we build the pointer graph, we can run an analysis on it.  In DG, the\npointer analysis class has virtual `getMemoryObjects` method whose definition\nchanges the behavior of the analysis (along with auxiliary `processefore` and\n`processAfter`).  Once the `run` method of pointer analysis is invoked, the\nanalysis computes points-to sets of nodes (that correspond to top-level values\nin LLVM) until fixpoint is reached.\n\nWe have implemented flow-sensitive (data-flow) and flow-insensitive\n(Andersen's-like) pointer analysis (this one is used by default).\n\n## LLVM pointer analysis\n\nFiles from [dg/llvm/PointerAnalysis/](../include/dg/llvm/PointerAnalysis/)\n\nThe pointer analysis for LLVM is provided by the `LLVMPointerAnalysis` class.\nThis class can have different implementations, all of them complying with a\nbasic public API:\n\n##### `hasPointsTo`\n\nreturns true if\n  1) PTA has any points-to set for the given value\n  2) the points-to set is non-empty```\n\n##### `getLLVMPointsTo`\n\nreturns points-to set (object of the class `LLVMPointsToSet`, see below) for the given value.\nIf `hasPointsTo` would be false for the given value, points-to set containging the only\nelement `unknown` is returned.\n\n##### `getLLVMPointsToChecked`\n\nreturns points-to set (object of the class `LLVMPointsToSet`) for the given value\nand a bool which corresponds with the result of `hasPointsTo`.   \nThe boolean returned is good for checking whether the `unknown` pointer in the points-to set\n(if any) is a result of the analysis (e.g., a pointer returned from an undefined function) or\nis there because the analysis has no information about the queried value.\n\n##### `getAccessedMemory`\n\nis a wrapper around getLLVMPointsTo that returns `LLVMMemoryRegionSet`.\nThis object represents a set of tripples (memory, offset, length) describing the regions\nof memory accessed by the given instruction (e.g., store or load).\n\n\n`LLVMPointsToSet` is an object that yields `LLVMPointer` objects upon\niteration.  Each `LLVMPointer` object is a pair of LLVM `Value` and `Offset`\ncontaining the allocation that allocated the pointed memory and the offset into\nthe memory.  `LLVMPointsToSet` has also methods `hasUnknown`, `hasNull`, and\n`hasInvalidated` that return true if the points-to set contains `unknown`,\n`null`, or `invalidated` (i.e., pointing to freed or destroyed memory) element.\nNote that these elements are not physically present in the points-to set as\nthere are no LLVM Values that would represent them (and thus could be returned\nin LLVMPointer).\n\n## Tools\n\nResults of pointer analysis can be dumped by the `llvm-pta-dump` tool which can be found in `tools/` directory.\nPossible options are:\n\nOption                | Values      | Description\n----------------------|-------------|-------------\n`-pta`                | fi, fs, inv, svf | Type of analysis - flow-insensitive, flow-sensitive,                                     flow-sensitive with tracking invalidated memory, and SVF (if available)\n`-pta-field-sensitive` | BYTES       | Set field sensitivity: how many bytes to track on each object\n`-callgraph`          |             | Dump also call graph\n`-callgraph-only`     |             | Dump only call graph\n`-iteration`          | NUM         | How many iterations to perform (for debugging)\n`-graph-only`         |             | Do not run PTA, just build and dump the pointer graph\n`-stats`              |             | Dump statistics\n`-entry`              | FUN         | Set entry function to FUN\n`-dbg`                |             | Show debugging messages\n`-ir`                 |             | Dump internal representation of the analysis\n`-c-lines`            |             | Dump output on the level of C lines (needs debug info)\n`-dot`                |             | Dump IR and results of the analysis to .dot file\n`-v` `-vv`            |             | Verbose output\n\nFurther, there is the tool `llvm-pta-ben` for evaulation of files annotated according to the [PTABen](https://github.com/SVF-tools/PTABen) project, and `llvm-pta-compare` that compares results different pointer analyses.\n"
  },
  {
    "path": "doc/README.md",
    "content": "# DG library\n\nDG is a C++ library containing bits for building various static program\nanalyses.  The main part of the library aims at building dependence graph and\nprogram slicing. In particular, DG contains an implementation of static program\nslicer for LLVM bitcode.\n\n#### Supported operating systems\n\nWe develop and target DG on GNU/Linux. The project should be compilable on OSX,\nthough there were some issues in the past (issue [#230](https://github.com/mchalupa/dg/issues/230)).\nThere were also some unresolved attempts to compile DG on Windows.\nAlthough the code does not use any compiler-specific\nor non-portable features, so it should be compilable on Windows,\nthe compilation was failing due to problems with linking to LLVM libraries\n(issues [#196](https://github.com/mchalupa/dg/issues/196) and\n[#315](https://github.com/mchalupa/dg/issues/315)).\n\n## Analyses\n - [Pointer analysis](PTA.md)\n - [Data dependence analysis](DDA.md)\n - [Control dependence analysis](CDA.md)\n - [Value-relations analysis](VRA.md)\n\n## Tools\n - [llvm-slicer](llvm-slicer.md)\n - [Other tools](tools.md)\n\n## External Libraries\n - [SVF](SVF.md)\n"
  },
  {
    "path": "doc/SVF.md",
    "content": "# Integration of SVF into DG\n\nDG can use pointer anlysis from the SVF project.  This analysis should scale\nmuch more better than ours, however, our analysis can be more precise in some\ncases.\n\n\n## Building DG with SVF\n\nTo use SVF with DG, you first needs a build of\n[SVF](https://github.com/SVF-tools/SVF).  Build the project according its\ninstructions.  To configure DG with SVF, setup `SVF_DIR` variable to point\nto the build of SVF:\n\n```\ncmake . -DSVF_DIR=/path/to/svf/build\n```\n\nDuring configuration, cmake should inform you about the found SVF build:\n\n```cmake\n-- SVF dir: /home/user/SVF/Debug-build\n-- SVF libraries dir: /home/user/SVF/Debug-build/lib\n-- SVF include dir: /home/user/SVF/Debug-build/../include\n-- SVF libs: LLVMSvf;LLVMCudd\n```\n\nIn cases of out-of-source build of SVF you may want to manually specify\nthe varable for include directory:\n\n```\ncmake . -DSVF_DIR=/path/to/svf/build -DSVF_INCLUDE=/path/to/svf/include\n```\n\n`SVF_DIR` must point to a directory that contains the `lib` subdirectory with\nlibraries. `SVF_INCLUDE` must point to directly to a directory that contains\nthe header files.\n\n## Using DG with SVF\n\nDG now integrates only pointer analysis from SVF. To use SVF from C++ API,\njust specify in the `LLVMPointerAnalysisOptions` object\nthat the analysis is of type `LLVMPointerAnalysisOptions::AnalysisType::svf`.\n\nFor tools, the switch that turns on SVF pointer analysis is `-pta svf`,\nfor example:\n\n```\ntools/llvm-slicer -c foo -pta svf test.ll\n```\n"
  },
  {
    "path": "doc/compiling.md",
    "content": "# Compiling DG from sources\n\n## Requirements\n\nDG needs LLVM 3.4 or higher. Further requirements are `cmake`, `make`, `g++` or `clang++`\nin a version that supports at least C++11 standard.\nAnd, of course, `git` for downloading the project. On some systems,\nalso `zlib` is required. For compilation of files into LLVM, we need also `clang`\ncompiler. To run slicing tests and some of the tools, you need also an installation\nof `python`.\n\nOn Ubuntu, you install the dependencies with:\n\n```\napt install git cmake make llvm zlib1g-dev clang g++ python3\n```\n\nOn ArchLinux, the command for installing the dependencies is the following:\n\n```\npacman -S git cmake make llvm clang gcc python\n```\n\nOn CentOS/RHEL/Fedora, the command for installing the dependencies is the following:\n\n```\ndnf install git cmake make zlib-devel llvm-devel gcc-c++ ncurses-devel\n```\n\nYou can use also LLVM compiled from sources (see below).\n\n## Building docker image\n\nThe DG repository contains a prepared Dockerfile that\nbuilds DG under Ubuntu 20.04. To build the docker image,\ngo into the top-level project's directory (the one containing\nDockerfile) and run:\n\n```\ndocker build . --tag dg:latest\ndocker run -ti dg:latest\n```\n\nThe Dockerfile installs only the prerequisities for dg.\nIf you need anything else to try out dg (e.g., vim or emacs), you must install\nit manually inside the image.\n\n## Compiling DG\n\nThe first step is to clone the repository to your machine:\n\n```\ngit clone https://github.com/mchalupa/dg\ncd dg\n```\n\nOnce you have the project cloned, you need to configure it.\nWhen LLVM is installed on your system in standard paths,\nthe configuration should be as easy as calling `cmake`:\n\n```\ncmake .\n```\nor\n```\nmkdir build\ncd build\ncmake ..\n```\n\nHowever, if you have LLVM installed in non-standard paths, or you have several\nversions of LLVM and want to use a particular one, you must manually specify\npath to the installation:\n\n```\ncmake -DLLVM_SRC_PATH=/path/to/src -DLLVM_BUILD_PATH=/path/to/build -DLLVM_DIR=path/to/llvm/share/llvm/cmake .\n```\n\nLLVM\\_DIR is an environment variable used by LLVM to find cmake config files\n(it points to the build or install directory), LLVM\\_SRC\\_DIR is a variable\nthat tells cmake where to look for llvm's sources and it is used to override\ninclude paths. The same holds for LLVM\\_BUILD\\_PATH that is used to override\nlibrary paths. Usually, you don't need to specify all these variables:\nLLVM\\_DIR variable is useful if there is any collision (i.e. there are more\nversions of LLVM installed) and you want to use a particular build of LLVM. In\nthat case, define the LLVM\\_DIR variable to point to the directory where are\nthe config files of the desired version (`$PREFIX/share/llvm/cmake` or\n`$PREFIX/lib/cmake/llvm/` for newer versions of LLVM -- for system\ninstallations, `PREFIX` is usually set to `/usr`).  If you have LLVM compiled\nfrom sources but not installed anywhere, you may need to use LLVM\\_SRC\\_PATH\nand LLVM\\_BUILD\\_PATH variables to specify the directory with sources and\nbuild.  As an example, suppose you have LLVM built in /home/user/llvm-build\nfrom sources in /home/user/llvm-src. Then the following configuration should\nwork:\n\n```\ncmake -DLLVM_SRC_PATH=/home/user/llvm-src -DLLVM_BUILD_PATH=/home/user/llvm-build -DLLVM_DIR=/home/user/llvm-build/share/llvm/cmake .\n```\n\nThe LLVM is linked dynamically by default. This behaviour can be toggled by\nturning the `LLVM_LINK_DYLIB` option `OFF`. Note that some additional packages\nmight be required than those listed above when linking statically.\n\nIf you want to build the project with debugging information and assertions, you\nmay specify the build type by adding `-DCMAKE_BUILD_TYPE=Debug` during\nconfiguration. Also, you may enable building with sanitizers by adding\n`-DUSE_SANITIZERS=ON`.\n\nAfter configuring the project, usual `make` takes place:\n\n```\nmake -j4\n```\n\nIn this documentation, you can find also some reports of how we compiled DG on\ndifferent Linux systems with the system LLVM packages. These documents describe\njust the one-time experience and are not maintained. Therefore,\nthe reports may be out-of-date:\n\n- [Compiling on Ubuntu Trusty](compiling_ubuntu_trusty.md)\n- [Compiling on Ubuntu Xenial](compiling_ubuntu_xenial.md)\n\n\n## Building with SVF support\n\nIf you want to build DG with the support of the\n[SVF](https://github.com/SVF-tools/SVF) library, you must specify `SVF_DIR`\nvariable to point to the build of SVF. For more information, see [documentation\nfor SVF](SVF.md).\n\n## Testing\n\nYou can run tests with `make check`. The command runs unit tests and also tests\nof slicing LLVM bitcode in several different configurations, so it may take a\nwhile. If your compiler supports `libFuzzer`, fuzzing tests are compiled and\nrun as well.\n"
  },
  {
    "path": "doc/compiling_ubuntu_trusty.md",
    "content": "# The experience with compiling DG on Ubuntu Trusty\n\nThis is my experience with compiling DG on (a clean installation of) Ubuntu Trusty for different versions of LLVM.\nTo summarize, compiling DG with a custom build of LLVM goes fine on Ubuntu Trusty.\nUsing system LLVM packages does not work at all. The only way how to compile DG without compiling also LLVM\nis to use our packages that we use in CI.\n\nIf LLVM is compiled from sources, it should be enough to set `LLVM_DIR` (and possibly\n`LLVM_SRC_DIR` and `LLVM_BUILD_DIR` to the right directories.\n\nThe LLVM 3.4-3.8 packages from the system repositories unfortunately contain broken cmake files.\nNot only the config file is named `LLVM-Config.cmake` instead of `LLVMConfig.cmake`\nfor some LLVM version,but there is also broken the mapping to LLVM libraries.\n\nThe configuration with system LLVM 3.9 goes smoothly, but the compilation fails with this error:\n\n```\n/usr/lib/llvm-3.9/lib/libLLVMCore.a(AsmWriter.cpp.o): unrecognized relocation (0x2a) in section `.text._ZN4llvm24AssemblyAnnotationWriterD2Ev'\n\n```\n\nGreater versions of LLVM are not available from the repositories.\n\n## Building with LLVM package from our CI\n\nIf you do not want to compile LLVM from sources, \nfor LLVM 3.8, 4, and 5 you can use the packages that we use in our CI:\n\n\n```\ngit clone --depth 1 https://github.com/tomsik68/travis-llvm.git\ncd travis-llvm\nchmod +x travis-llvm.sh\n./travis-llvm.sh 3.8  # change 3.8 to 4 or 5 if wanted\n```\n\nNow we can proceed normally with configuration and compilation:\n\n```\ncd dg\ncmake . -DLLVM_DIR=/usr/share/llvm-3.8/cmake\nmake -j4\n```\n"
  },
  {
    "path": "doc/compiling_ubuntu_xenial.md",
    "content": "# The experience with compiling DG on Ubuntu Trusty\n\nThis is my experience with compiling DG on (a clean installation of) Ubuntu Xenial for different versions of LLVM.\nCompiling DG with LLVM built from sources should work fine, so here I focus only on the compilation\nwith LLVM from the repositories packages.\n\n\nFirst of all, install the dependencies.\n\n```\napt update\napt install git cmake make zlib1g-dev clang g++ python3\n```\n\n## LLVM 3.8\n\nThe default LLVM is 3.8 which you can install with:\n\n```\napt install llvm\n```\n\nUnfortunately, it still suffers from the broken cmake files as in Ubuntu Trusty\n(the files are in `/usr/share/llvm-3.8/cmake/`, but cmake is instructed to look\nfor the configuration files in `/usr/share/llvm/cmake/`. So for LLVm 3.8, the\nonly option is to build LLVM from sources or use our CI package\n(see [Compiling on Ubuntu Trusty](compiling_ubuntu_trusty.md) page).\n\n## LLVM >= 3.9\n\nCompiling DG with system LLVM 3.9 and higher (Xenial has packages\nfor LLVM 3.9, 4.0, 5.0, 6.0, and 8.0) should work out of the box.\nAfter the installation of prerequisities, just install LLVM, configure DG\nand compile (replace `-3.9` with the desired version of LLVM):\n\n```\napt install llvm-3.9\ncmake .                # you may need to use -DLLVM_DIR=/usr/lib/llvm-3.9/cmake\nmake -j2\n```\n\nDon't forget to compile source code to LLVM with the right version of clang:\n\n```\napt install clang-3.9\n```\n\nThe binaries `clang`, `llvm-link`, `opt`, and `lli` (for running slicing tests) may have the suffix `-3.9`,\nso you may need to create symbolic links with names without the suffix to successfully run tests.\n\n"
  },
  {
    "path": "doc/downloading.md",
    "content": "# Getting pre-compiled DG\n\nYou can obtain pre-compiled DG project in several forms.\n\n## Docker image\n\nYou can download the image from [Docker Hub](https://hub.docker.com/r/mchalupa/dg). The image\ncontains, apart from DG, also vim and emacs editors and clang, so that you can try dg out.\n(Note that this image is not being updated regularly).\nAlternatively, the root folder of dg contains a Dockerfile which allows you to build\na docker image with dg installed. Just run these commands from the dg's root directory:\n\n```\ndocker build . --tag dg:latest\ndocker run -ti dg:latest\n```\n\nNote that the locally built image does not contain either vim or emacs, so you must\ninstall one of them if you need.\n\n## Binary Packages\n\nWe have packed DG for several systems. The packages contain only the library and `llvm-slicer`. Other tools are not included.\n\n### Ubuntu package\n\nA binary package for Ubuntu 18.04 can be found in [Releases](https://github.com/mchalupa/dg/releases/tag/v0.9-pre).\n\n\n### Archlinux AUR package\n\nThere is also the [dg-git](https://aur.archlinux.org/packages/dg-git/) AUR package for Archlinux users.\n"
  },
  {
    "path": "doc/llvm-slicer.md",
    "content": "# llvm-slicer\n\nDG project contains a static slicer for LLVM bitcode. The slicer supports backward and forward (experimental) slicing.\nIt is designed and tested on slicing code generated from sequential C programs. However, there is an experimental\nsupport for parallel programs and it should handle bitcode generated from other languages in many cases.\nThere is a section on using the slicer with bitcode generated from C++ at the end of this file.\n\n### Using the llvm-slicer\n\nThe compiled `llvm-slicer` can be found in the `tools/` subdirectory. First, you need to compile your\nprogram into LLVM IR (make sure you are using the correct version of LLVM binaries if you have more than one):\n\n```\nclang -c -emit-llvm source.c -o bitcode.bc\n```\n\nIf the program is split into more source files (exactly one of them must contain main),\nyou must compile each of them separately (as above) and then link the bitcodes together using `llvm-link`:\n\n```\nllvm-link bitcode1.bc bitcode2.bc ... -o bitcode.bc\n```\n\nNow, you're ready to slice the program:\n\n```\n./llvm-slicer -c slicing_criterion bitcode.bc\n```\n\nThe `slicing_criterion` is either a call-site of a function or `ret` to slice\nwith respect to the return value of the main function. Alternatively, if the program was compiled with the `-g` option,\nyou can also use `line:variable` as slicing criterion. Slicer will then try to find a use of the variable\non the provided line and mark this use, if found, as a slicing criterion.\nIf no line is provided (e.g. `:x`), then the variable is considered to be global variable.\nYou can provide a comma-separated list of slicing criterions, e.g.: `-c crit1,crit2,crit3`.\nMore about specifying slicing criteria can be found [later](#slicing-criteria) in this document.\n\nYou can view the dependence graph that was used to slice the bitcode by exporting it into .dot file.\nTo achieve this, use `-dump-dg` switch with `llvm-slicer` or a stand-alone tool like\n`llvm-dg-dump` (this one is deprecated, but should still work):\n\n```\n./llvm-dg-dump bitcode.bc > file.dot\n```\n\nYou can highlight nodes from the dependence graph that will be in the slice using the `-mark` switch:\n\n```\n./llvm-dg-dump -mark slicing_criterion bitcode.bc > file.dot\n```\n\nWhen using `-dump-dg` with `llvm-slicer`, the nodes should be already highlighted.\nAlso a .dot file with the sliced dependence graph is generated (similar behaviour\ncan be achieved with `llvm-dg-dump` using the `-slice` switch).\n\nIf the dependence graph is too big to be displayed using .dot files, you can debug/see the slice right from\nthe LLVM language. Just pass `-annotate` option to the `llvm-slicer` and it will store readable annotated LLVM in `file-debug.ll`\n(where `file.bc` is the name of file being sliced). There are more options (try `llvm-slicer -help` for show all of them),\nbut the most interesting is probably the `-annotate slice`:\n\n```\n./llvm-slicer -c crit -annotate slice code.bc\n```\n\nThe content of `code-debug.ll` will look like this:\n\n```LLVM\n; <label>:25                                      ; preds = %20\n  ; x   call void @llvm.dbg.value(metadata !{i32* %i}, i64 0, metadata !151), !dbg !164\n  %26 = load i32* %i, align 4, !dbg !164\n  %27 = add nsw i32 %26, 1, !dbg !164\n  ; x   call void @llvm.dbg.value(metadata !{i32 %27}, i64 0, metadata !151), !dbg !164\n  store i32 %27, i32* %i, align 4, !dbg !164\n  ; x   call void @llvm.dbg.value(metadata !{i32* %j}, i64 0, metadata !153), !dbg !161\n  ; x   %28 = load i32* %j, align 4, !dbg !161\n  ; x   %29 = add nsw i32 %28, 1, !dbg !161\n  ; x   call void @llvm.dbg.value(metadata !{i32 %29}, i64 0, metadata !153), !dbg !161\n  ; x   br label %20, !dbg !165\n\n.critedge:                                        ; preds = %20\n  ; x   call void @llvm.dbg.value(metadata !{i32* %j}, i64 0, metadata !153), !dbg !166\n  ; x   %30 = load i32* %j, align 4, !dbg !166\n  ; x   %31 = icmp sgt i32 %30, 99, !dbg !166\n  ; x   br i1 %31, label %19, label %32, !dbg !166\n```\n\nOther options for `-annotate` are `pta`, `dd`, `cd`, `memacc` to annotate points-to information,\ndata dependencies, control dependencies or memory accessed by instructions.\nYou can provide comma-separated list of multiple options (`-annotate cd,slice,dd`)\n\n### Example\n\nWe can try slicing, for example, this program (with respect to the assertion):\n\n```C\n#include <assert.h>\n#include <stdio.h>\n\nlong int fact(int x)\n{\n\tlong int r = x;\n\twhile (--x >=2)\n\t\tr *= x;\n\n\treturn r;\n}\n\nint main(void)\n{\n\tint a, b, c = 7;\n\n\twhile (scanf(\"%d\", &a) > 0) {\n\t\tassert(a > 0);\n\t\tprintf(\"fact: %lu\\n\", fact(a));\n\t}\n\n\treturn 0;\n}\n```\n\nLet's say the program is stored in a file `fact.c`. We translate it into LLVM bitcode and then slice it:\n\n```\n$ cd tools\n$ clang -c -emit-llvm fact.c -o fact.bc\n$ ./llvm-slicer -c __assert_fail fact.bc\n```\n\nThe output is in `fact.sliced`, we can look at the result using `llvm-dis` or `sliced-diff.sh` script:\n\n```LLVM\n; Function Attrs: nounwind uwtable\ndefine i32 @main() #0 {\n  %a = alloca i32, align 4\n  br label %1\n\n; <label>:1                                       ; preds = %4, %0\n  %2 = call i32 (i8*, ...) @__isoc99_scanf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i32* %a)\n  %3 = icmp sgt i32 %2, 0\n  br i1 %3, label %4, label %safe_return\n\n; <label>:4                                       ; preds = %1\n  %5 = load i32, i32* %a, align 4\n  %6 = icmp sgt i32 %5, 0\n  br i1 %6, label %1, label %7\n\n; <label>:7                                       ; preds = %4\n  call void @__assert_fail(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str1, i32 0, i32 0), ... [truncated])\n  unreachable\n\nsafe_return:                                      ; preds = %1\n  ret i32 0\n}\n\n```\n\n### Slicing criteria (the -c and -2c options)\n\nThe `slicing_criterion` is either a call-site of a function or `ret` to slice\nwith respect to the return value of the main function. Alternatively, if the program was compiled with the `-g` option,\nyou can also use `line:variable` as slicing criterion. Slicer will then try to find a use of the variable\non the provided line and mark this use, if found, as a slicing criterion. `llvm-slicer` should then inform you\nthat it matched a slicing criterion with a given instruction.\nIf no line is provided (e.g. `:x`), then the variable is considered to be a global variable.\nYou can provide a comma-separated list of slicing criteria, e.g.: `-c crit1,crit2,crit3`.\n\nFor example, consider this program:\n```C\n1. int main() {\n2.   int a = 8, b = input();\n3.   while (a > b) {\n4.     ++b;\n5.   }\n6.   check(a == b);\n7.   check2();\n8.   print(a)\n}\n```\nAssuming that the slicing criteria are calls to function `check` (`-c check`),\ntherefore the slicer will detect the calls to `check` and slice the code w.r.t. these calls\n(including their arguments, as the arguments are used by the calls).\nTherefore, the slice w.r.t. `-c check` would correspond to (if mapped back to C):\n\n```C\n1. int main() {\n2.   int a = 8, b = input();\n3.   while (a > b) {\n4.     ++b;\n5.   }\n6.   check(a == b);\n}\n```\n\nThe same way you can specify the slicing criteria are calls to `check2`, in which case the slice would be just:\n```C\n7. check2();\n```\nas `check2` does not use any variables and therefore has no dependencies\n(well, this is not true with non-termination sensitive control dependence).\n\nAlternatively, if you compile the program to LLVM with debugging information (`-g` option),\nyou can specify a line and variable that should be used as slicing criterion. In our example, if you use `-c 8:a`,\nthen the program is sliced w.r.t accesses to variable `a` on line 8, so the slice would be:\n\n```C\n1. int main() {\n2.   int a = 8;\n8.  // read of a will stay in LLVM here\n}\n```\nHere is a restriction that the specified variable must be used at the given line.\nJust to fill in the details, a slicing criterion is always a node of a dependence graph.\nIf you dump the dependence graph of the program (`-dump-dg`), then you can see what nodes are there and therefore\nwhat can be a slicing criterion. Alternatively, nodes in dep. graph correspond to instructions,\nso a slicing criterion is always an instruction in LLVM (check `-annotate slice` option,\nwhich generates `-debug.ll` file with information about sliced instructions; slicing criteria are marked in the file too).\n\n### Secondary slicing criteria\n\n`llvm-slicer` supports also something that we call a _secondary_ slicing critera. A secondary slicing criterion\nis a node (instruction) that is taken as slicing criterion only if it is on a path into a regular slicing criterion.\nTake, for example this small program:\n\n```C\nint x  = nondet();\nassume(x > 0);\ncheck(x > 0);\n```\n\nIn the example above, if we just set `check` to be the slicing criterion (`-c check`), the `assume` gets sliced away\nbecause it does not modify `x`. Therefore, we can say that calls to `assume` are secondary slicing criteria\n(`-2c assume`) and therefore any `assume` that appears on a path into `check` is set as a slicing criterion too\nand is preserved.\n\nSecondary slicing criteria does not bring any additional power to slicing. Indeed, we can either say the slicer that\n`assume` modifies `x`, or add control dependence from `assume` to nodes reachable from the call (as `assume` may in fact\nterminate the execution). However, with secondary slicing criteria, we save edges.\n\nFurther, we can specify that a secondary slicing criterion is a _data_ secondary slicing criterion, which means\nthat it is considered as a slicing criterion only if it is on a path into a regular slicing criterion and\nat the same time it uses the same memory as the regular slicing criterion. In `llvm-slicer`, we do that by adding\n`()` after the secondary slicing criterion, e.g., `-2c assume()`.\n\n### Slicing criteria (the -sc option)\n\n`llvm-slicer` supports specifying slicing criteria also with `-sc` option, which is designed for further extensions\nfor C++ and allows to bind a secondary slicing criterion to every primary slicing criterion.\n`-sc` takes a list of semi-colon-separated slicing criteria pairs, i.e.,\n`-sc 'S;S;S;...'` where `S` describes a primary-secondary slicing criteria pair. A pair is divided by `|`, i.e.\nthe pair is in the form: `X|Y`. Either the primary or the secondary criterion can be empty (not both, though).\nIf the primary criterion is empty, the secondary slicing criterion is attached to all primary slicing criteria.\n\nFinally, `X` and `Y` are in the form `file#function#line#obj`.\nThe fields `file`, `function`, `line`, and `obj` can be empty and the prefix of `###..` can be left out.\nThe `obj` field matches either a call of a function or a use of a variable (given that the program is\ncompiled with debugging information) and can be further specified to be a (global) variable or a function call:\n`[&][@]obj[()]`. For example, `&x` means variable `x`, `fun()` means call of `fun` and `@g` (or `&@g`) means\nglobal variable `g`.\n\nExamples:\n\n```\n'fun()|&x'           -- matches calls of fun() as primary SC and instructions using variable x as secondary SC\n'x|f'                -- matches calls of function x or uses of variable x as primary SC and the same with f as secondary SC\n'file.c###fun()|&x'  -- matches calls of fun() in file file.c as primary SC and instructions using variable x as secondary SC\n'#8#|main#7#'        -- matches all instruction on line 8 (in any file) as primary SC and instructions in (any)\n                        function main on line 7 as secondary SC\n'foo();boo();|fun()' -- matches calls of functions foo and boo as primary SC and calls of fun as secondary SC for both foo and boo\n'foo();boo()|fun()'  -- matches calls of functions foo as primary SC and boo as primary SC with calls of fun as secondary SC\n```\n\nNote that the matching is performed in approximation manner, i.e., if the slicer lacks information about an instruction,\nit assume it matches the slicing criterion.\n\n### Options\n\nA set of useful options is:\n\nOption             | Arguments        | Description\n-------------------|------------------|--------------------------------------------\n`-c`               | crit1,crit2,...  | A comma-separated list of slicing criteria\n`-2c`              | crit1,crit2,...  | A comma-separated list of secondary slicing criteria\n`-annotate`        | val1,val2,...    | Generate annotated bitcode. The argument is a comma-separated list of `slice`,`pta`,`dd`,`cd`,`memacc`\n`-allocation-funs` | func:type,...    | Treat the given functions as allocations. `type` is one of `malloc`, `calloc`, `realloc`\n`-pta`             | fi, fs, svf       | Set PTA type to flow-insensitive, flow-sensitive, or SVF (if supported)\n`-cda`             | standard, ntscd  | Set the type of used control dependencies (termination insensitive or sensitive)\n`-interproc-cd`    |                  | Take into account also not returning from function calls (on by default)\n`-dump-dg`         |                  | Dump dependence graph to .dot file\n`-entry`           | FUN              | Set entry function to FUN\n`-forward`         |                  | Perform forward slicing\n`-statistics`      |                  | Dump statistics about bitcode before and after slicing\n`-undefined-funs`   | {read,write}-{args,any}, pure | Set how to handle calls to undefined functions\n`-o`               | FILE             | Output the sliced bitcode into FILE\n`-help`            |                  | Show all possible options\n\n\n## Using slicer on C++ bitcode\n\nDG is not made for analysing C++ bitcode. At least not yet. However, in many cases it should be able to sucessfully analyze and slice\nsuch a bitcode. Unsupported are instructions like `invoke` and `landingpad` that are used in code that uses exceptions.\nIn some cases, you can use `-lowerinvoke` pass to get rid of these.\n\nAnother issue is names mangling. C++ compilers mangle the names, so for example it changes the name of function `f` with the type `void (*)(int *, int)`\nto `_Z1fPii`. This can be confusing when specifying slicing criteria. Instead of `-sc 'f##x'` to slice w.r.t uses of `x` in function `f` one must use\n`-sc '_Z1fPii##x'`.\n"
  },
  {
    "path": "doc/tools.md",
    "content": "## Tools\n\nIn the `tools/` directory, there are a few scripts for convenient manipulation\nwith sliced bitcode. First is a `sliced-diff.sh`. This script takes file and shows\ndifferences after slicing. It uses `meld` or `kompare` or just `diff` program\nto display the results (the first that is available on the system, in this order)\n\n```\n./llvm-slicer -c crit code.bc\n./slicer-diff.sh code.bc\n```\n\nIf the program was compiled with `-g`, you can use `llvm-to-source sliced-bitcode.bc source.c` to see the original lines of the source that stayed in the sliced program. Note that this program just dumps the lines of the original code that are present in the sliced bitcode, it does not produce a syntactically valid C program.\n\nAnother script is a wrapper around the `llvm-dg-dump`. It uses `xdot` or `evince` or `okular` (or `xdg-open`).\nIt takes exactly the same arguments as the `llvm-dg-dump`:\n\n```\n./llvmdg-show -mark crit code.bc\n```\n\n### All tools\n\nThe tools subdirectory contains a set of useful programs for debugging\nand playing with the llvm bitcode. Except for the `llvm-slicer` you can find there:\n\n* `llvm-dg-dump`      - Dump the dependence graph for given program to graphviz format (to stdout)\n* `llvm-pta-dump`     - dump pointer subgraph and results of the points-to analysis to stdout\n* `llvm-dda-dump`     - display data dependencies between instructions in a llvm bitcode\n* `llvm-cda-dump`     - display control dependencies between instructions in a llvm bitcode\n* `llvm-cg-dump`      - dump call graph of the given LLVM bitcode (based on pointer analysis)\n* `llvmdg-show`       - wrapper for llvm-dg-dump that displays the dependence graph in dot\n* `llvmdda-dump`      - wrapper for llvm-dda-dump that displays data dependencies in dot\n* `pta-show`          - wrapper for llvm-pta-dump that prints the PS in grapviz to pdf\n* `llvm-to-source`    - find lines from the source code that are in given file\n* `dgtool`            - a wrapper around clang that compiles code and passes it to a specified tool\n\nAll these programs take as an input llvm bitcode, for example:\n\n```\n./pta-show code.bc\n```\n\nwill show the pointer state subgraph for code.bc and the results of points-to analysis.\nSome useful switches for all programs are `-pta fs` and `-pta fi` that switch between flow-sensitive\nand flow-insensitive points-to analysis within all these programs that use points-to analysis.\nSome of these tools support the `-c-lines` switch that dumps the output on the level of\nC file (where an instruction is represented as the line:column pair). For this switch to work,\nthe program must be compiled with debugging information (`-g`).\n\n### dgtool\n\n`dgtool` is a wrapper around clang that compiles given files (C or LLVM bitcode or a mix),\nlinks them together and then calls the program given as an argument on the bitcode.\nFor example,\n\n```\ndgtool llvm-slicer -c __assert_fail -cda ntscd main.c foo.c\n```\n\nYou can pass arguments to clang if you preceed them with `-Xclang`, the same way, you can pass arguments to\n`dgtool` itself when using `-Xdg`, for example:\n\n```\ndgtool -Xclang -O3 -Xclang -fno-discard-value-names -Xdg dbg llvm-dda-dump test.c\n```\n"
  },
  {
    "path": "include/dg/ADT/Bits.h",
    "content": "#ifndef _DG_SPARSE_BITS_H_\n#define _DG_SPARSE_BITS_H_\n\n#include <cassert>\n#include <cstddef> // size_t\n#include <cstdint>\n\nnamespace dg {\nnamespace ADT {\n\n// an element that holds a sequence of bits (up to 64 bits usually)\n// along with offset. So this class can represent a sequence\n// of [S, S(+sizeof(InnerT)*8)] bits. (E.g. 100th, 101th, ..., 163th bit)\ntemplate <typename InnerT = uint64_t, typename ShiftT = uint64_t>\nclass ShiftedBits {\n    InnerT _bits{0};\n    ShiftT _shift;\n\n  public:\n    ShiftedBits(ShiftT shift) : _shift(shift) {}\n\n    static size_t bitsNum() { return sizeof(InnerT) * 8; }\n    bool operator==(const ShiftedBits &rhs) const {\n        return _bits == rhs._bits && _shift == rhs._shift;\n    }\n    bool operator!=(const ShiftedBits &rhs) const { return !operator==(rhs); }\n\n    bool mayContain(size_t i) const {\n        return i >= _shift && i - _shift < bitsNum();\n    }\n\n    size_t size() const {\n        size_t num = 0;\n        for (size_t i = 0; i < bitsNum(); ++i)\n            if (_bits & (static_cast<InnerT>(1) << i))\n                ++num;\n\n        return num;\n    }\n\n    bool empty() const { return _bits == 0; }\n\n    bool get(size_t i) const {\n        if (!mayContain(i))\n            return false;\n\n        assert(i - _shift < bitsNum());\n        return _bits & (static_cast<InnerT>(1) << (i - _shift));\n    }\n\n    // return the previous value\n    bool set(size_t i) {\n        assert(mayContain(i));\n        bool ret = get(i);\n        _bits |= (static_cast<InnerT>(1) << (i - _shift));\n        return ret;\n    }\n\n    class const_iterator {\n        const ShiftedBits *bits{nullptr};\n        size_t pos{0};\n\n        bool isEnd() const { return pos == ShiftedBits::bitsNum(); }\n\n        void _findNext() {\n            assert(pos < ShiftedBits::bitsNum());\n            while (!(bits->_bits & (static_cast<InnerT>(1) << pos))) {\n                ++pos;\n\n                if (isEnd())\n                    return;\n            }\n        }\n\n        const_iterator(const ShiftedBits *bits, size_t pos = 0)\n                : bits(bits), pos(pos) {\n            assert(bits && \"No bits given\");\n            // start at the first element\n            if (!isEnd() && !(bits->_bits & 1))\n                operator++();\n        }\n\n      public:\n        const_iterator() = default;\n        const_iterator(const const_iterator &) = default;\n        const_iterator &operator=(const const_iterator &) = default;\n\n        const_iterator &operator++() {\n            ++pos;\n            if (!isEnd())\n                _findNext();\n            return *this;\n        }\n\n        const_iterator operator++(int) {\n            auto tmp = *this;\n            operator++();\n            return tmp;\n        }\n\n        size_t operator*() const {\n            assert(pos < ShiftedBits::bitsNum());\n            assert(bits->mayContain(bits->_shift + pos));\n            return bits->_shift + pos;\n        }\n\n        bool operator==(const const_iterator &rhs) const {\n            return pos == rhs.pos && bits == rhs.bits;\n        }\n\n        bool operator!=(const const_iterator &rhs) const {\n            return !operator==(rhs);\n        }\n\n        friend class ShiftedBits;\n    };\n\n    const_iterator begin() const { return const_iterator(this); }\n    const_iterator end() const { return const_iterator(this, bitsNum()); }\n\n    friend class const_iterator;\n};\n\n// a set of bits with 0 offset. This is a special case\n// of ShiftedBits with _shift = 0\ntemplate <typename InnerT = uint64_t>\nclass Bits {\n    InnerT _bits{0};\n\n  public:\n    static size_t bitsNum() { return sizeof(InnerT) * 8; }\n    bool operator==(const Bits &rhs) const { return _bits == rhs._bits; }\n    bool operator!=(const Bits &rhs) const { return !operator==(rhs); }\n\n    bool empty() const { return _bits == 0; }\n    bool mayContain(size_t i) const { return i < bitsNum(); }\n\n    size_t size() const {\n        size_t num = 0;\n        for (size_t i = 0; i < bitsNum(); ++i)\n            if (_bits & (static_cast<InnerT>(1) << i))\n                ++num;\n\n        return num;\n    }\n\n    bool get(size_t i) const {\n        if (!mayContain(i))\n            return false;\n\n        assert(i < bitsNum());\n        return _bits & (static_cast<InnerT>(1) << i);\n    }\n\n    // return the previous value\n    bool set(size_t i) {\n        assert(mayContain(i));\n        bool ret = get(i);\n        _bits |= (static_cast<InnerT>(1) << i);\n        return ret;\n    }\n\n    class const_iterator {\n        const Bits *bits{nullptr};\n        size_t pos{0};\n\n        bool isEnd() const { return pos == Bits::bitsNum(); }\n\n        void _findNext() {\n            assert(pos < Bits::bitsNum());\n            while (!(bits->_bits & (static_cast<InnerT>(1) << pos))) {\n                ++pos;\n\n                if (isEnd())\n                    return;\n            }\n        }\n\n        const_iterator(const Bits *bits, size_t pos = 0)\n                : bits(bits), pos(pos) {\n            assert(bits && \"No bits given\");\n            // start at the first element\n            if (!isEnd() && !(bits->_bits & 1))\n                operator++();\n        }\n\n      public:\n        const_iterator() = default;\n        const_iterator(const const_iterator &) = default;\n        const_iterator &operator=(const const_iterator &) = default;\n\n        const_iterator &operator++() {\n            ++pos;\n            if (!isEnd())\n                _findNext();\n            return *this;\n        }\n\n        const_iterator operator++(int) {\n            auto tmp = *this;\n            operator++();\n            return tmp;\n        }\n\n        size_t operator*() const {\n            assert(pos < Bits::bitsNum());\n            assert(bits->mayContain(pos));\n            return pos;\n        }\n\n        bool operator==(const const_iterator &rhs) const {\n            return pos == rhs.pos && bits == rhs.bits;\n        }\n\n        bool operator!=(const const_iterator &rhs) const {\n            return !operator==(rhs);\n        }\n\n        friend class Bits;\n    };\n\n    const_iterator begin() const { return const_iterator(this); }\n    const_iterator end() const { return const_iterator(this, bitsNum()); }\n\n    friend class const_iterator;\n};\n\n} // namespace ADT\n} // namespace dg\n\n#endif // _DG_SPARSE_BITS_H_\n"
  },
  {
    "path": "include/dg/ADT/Bitvector.h",
    "content": "#ifndef DG_SPARSE_BITVECTOR_H_\n#define DG_SPARSE_BITVECTOR_H_\n\n#include <cassert>\n#include <cstdint>\n\n#include \"HashMap.h\"\n#include \"Map.h\"\n\nnamespace dg {\nnamespace ADT {\n\nusing std::size_t;\n\ntemplate <typename BitsT = uint64_t, typename ShiftT = uint64_t,\n          typename IndexT = uint64_t, size_t SCALE = 1,\n          typename BitsContainerT = dg::Map<ShiftT, BitsT>>\nclass SparseBitvectorImpl {\n    // mapping from shift to bits\n    BitsContainerT _bits{};\n\n    static const size_t BITS_IN_BYTE = 8;\n    static const size_t BITS_IN_BUCKET = sizeof(BitsT) * BITS_IN_BYTE;\n    static ShiftT _shift(IndexT i) { return i - (i % BITS_IN_BUCKET); }\n\n    static size_t _countBits(BitsT bits) {\n        size_t num = 0;\n        while (bits) {\n            if (bits & 0x1)\n                ++num;\n\n            bits = bits >> 1;\n        }\n\n        return num;\n    }\n\n    void _addBit(IndexT i) {\n        // for now we just push it back,\n        // but we would rather do it somehow\n        // more smartly (probably not using the vector)\n        auto sft = _shift(i);\n        _bits.emplace(sft, BitsT{1} << (i - sft));\n    }\n\n  public:\n    SparseBitvectorImpl() = default;\n    SparseBitvectorImpl(IndexT i) { _addBit(i); } // singleton ctor\n\n    SparseBitvectorImpl(const SparseBitvectorImpl &) = default;\n    SparseBitvectorImpl(SparseBitvectorImpl &&) = default;\n\n    void reset() { _bits.clear(); }\n    bool empty() const { return _bits.empty(); }\n    void swap(SparseBitvectorImpl &oth) { _bits.swap(oth._bits); }\n\n    // TODO: use SFINAE to define empty body if a class without\n    // reserve() is used...\n    void reserve(size_t n) { _bits.reserve(n); }\n\n    bool get(IndexT i) const {\n        auto sft = _shift(i);\n        assert(sft % BITS_IN_BUCKET == 0);\n\n        auto it = _bits.find(sft);\n        if (it == _bits.end()) {\n            return false;\n        }\n\n        return (it->second & (BitsT{1} << (i - sft)));\n    }\n\n    // returns the previous value of the i-th bit\n    bool set(IndexT i) {\n        auto sft = _shift(i);\n        auto &B = _bits[sft];\n\n        bool prev = B & (BitsT{1} << (i - sft));\n        B |= BitsT{1} << (i - sft);\n\n        return prev;\n    }\n\n    // union operation\n    bool set(const SparseBitvectorImpl &rhs) {\n        bool changed = false;\n        for (auto &pair : rhs._bits) {\n            auto &B = _bits[pair.first];\n            auto old = B;\n            B |= pair.second;\n            changed |= old != B;\n        }\n\n        return changed;\n    }\n\n    // returns the previous value of the i-th bit\n    bool unset(IndexT i) {\n        auto sft = _shift(i);\n        auto it = _bits.find(sft);\n        if (it == _bits.end()) {\n            assert(get(i) == 0);\n            return false;\n        }\n\n        // FIXME: use this implementation only for hash map\n        // which returns read-only object and\n        // modify directly it->second in other cases (for std::map)\n        auto res = it->second & ~(BitsT{1} << (i - sft));\n        if (res == 0) {\n            _bits.erase(it);\n            // tests that size() = 0 <=> empty()\n            assert(((size() != 0) ^ empty()) && \"Inconsistence\");\n        } else {\n            _bits[sft] = res;\n        }\n\n        assert(get(i) == 0 && \"Failed removing\");\n        return true;\n    }\n\n    // FIXME: track the number of elements\n    // in a variable, to avoid this search...\n    size_t size() const {\n        size_t num = 0;\n        for (auto &it : _bits)\n            num += _countBits(it.second);\n\n        return num;\n    }\n\n    class const_iterator {\n        typename BitsContainerT::const_iterator container_it;\n        typename BitsContainerT::const_iterator container_end;\n        size_t pos{0};\n\n        const_iterator(const BitsContainerT &cont, bool end = false)\n                : container_it(end ? cont.end() : cont.begin()),\n                  container_end(cont.end()) {\n            // set-up the initial position\n            if (!end && !cont.empty())\n                _findClosestBit();\n        }\n\n        void _findClosestBit() {\n            assert(pos < BITS_IN_BUCKET);\n            while (!(container_it->second & (BitsT{1} << pos))) {\n                if (++pos == BITS_IN_BUCKET)\n                    return;\n            }\n        }\n\n      public:\n        const_iterator() = default;\n        const_iterator &operator++() {\n            // shift to the next bit in the current bits\n            assert(pos < BITS_IN_BUCKET);\n            assert(container_it != container_end && \"operator++ called on end\");\n            if (++pos != BITS_IN_BUCKET)\n                _findClosestBit();\n\n            if (pos == BITS_IN_BUCKET) {\n                ++container_it;\n                pos = 0;\n                if (container_it != container_end) {\n                    assert(container_it->second != 0 &&\n                           \"Empty bucket in a bitvector\");\n                    _findClosestBit();\n                }\n            }\n            return *this;\n        }\n\n        const_iterator operator++(int) {\n            auto tmp = *this;\n            operator++();\n            return tmp;\n        }\n\n        IndexT operator*() const { return container_it->first + pos; }\n\n        bool operator==(const const_iterator &rhs) const {\n            return pos == rhs.pos && container_it == rhs.container_it;\n        }\n\n        bool operator!=(const const_iterator &rhs) const {\n            return !operator==(rhs);\n        }\n\n        friend class SparseBitvectorImpl;\n    };\n\n    const_iterator begin() const { return const_iterator(_bits); }\n    const_iterator end() const { return const_iterator(_bits, true /* end */); }\n\n    friend class const_iterator;\n};\n\nusing SparseBitvectorMapImpl =\n        SparseBitvectorImpl<uint64_t, uint64_t, uint64_t, 1,\n                            dg::Map<uint64_t, uint64_t>>;\nusing SparseBitvectorHashImpl =\n        SparseBitvectorImpl<uint64_t, uint64_t, uint64_t, 1,\n                            dg::HashMap<uint64_t, uint64_t>>;\nusing SparseBitvector = SparseBitvectorMapImpl;\n\n} // namespace ADT\n} // namespace dg\n\n#endif // DG_SPARSE_BITVECTOR_H_\n"
  },
  {
    "path": "include/dg/ADT/DGContainer.h",
    "content": "#ifndef DG_CONTAINER_H_\n#define DG_CONTAINER_H_\n\n#include <algorithm>\n#include <cassert>\n#include <set>\n\nnamespace dg {\n\n/// ------------------------------------------------------------------\n// - DGContainer\n//\n//   This is basically just a wrapper for real container, so that\n//   we have the container defined on one place for all edges.\n//   It may have more implementations depending on available features\n/// ------------------------------------------------------------------\ntemplate <typename ValueT, unsigned int EXPECTED_ELEMENTS_NUM = 8>\nclass DGContainer {\n  public:\n    // XXX use llvm ADTs when available, or BDDs?\n    using ContainerT = typename std::set<ValueT>;\n    using iterator = typename ContainerT::iterator;\n    using const_iterator = typename ContainerT::const_iterator;\n    using size_type = typename ContainerT::size_type;\n\n    iterator begin() { return container.begin(); }\n    const_iterator begin() const { return container.begin(); }\n    iterator end() { return container.end(); }\n    const_iterator end() const { return container.end(); }\n\n    size_type size() const { return container.size(); }\n\n    bool insert(ValueT n) { return container.insert(n).second; }\n\n    bool contains(ValueT n) const { return container.count(n) != 0; }\n\n    size_t erase(ValueT n) { return container.erase(n); }\n\n    void clear() { container.clear(); }\n\n    bool empty() { return container.empty(); }\n\n    void swap(DGContainer<ValueT, EXPECTED_ELEMENTS_NUM> &oth) {\n        container.swap(oth.container);\n    }\n\n    void intersect(const DGContainer<ValueT, EXPECTED_ELEMENTS_NUM> &oth) {\n        DGContainer<ValueT, EXPECTED_ELEMENTS_NUM> tmp;\n\n        std::set_intersection(\n                container.begin(), container.end(), oth.container.begin(),\n                oth.container.end(),\n                std::inserter(tmp.container, tmp.container.begin()));\n\n        // swap containers\n        container.swap(tmp.container);\n    }\n\n    bool\n    operator==(const DGContainer<ValueT, EXPECTED_ELEMENTS_NUM> &oth) const {\n        if (container.size() != oth.size())\n            return false;\n\n        // the sets are ordered, so this will work\n        iterator snd = oth.container.begin();\n        for (iterator fst = container.begin(), efst = container.end();\n             fst != efst; ++fst, ++snd)\n            if (*fst != *snd)\n                return false;\n\n        return true;\n    }\n\n    bool\n    operator!=(const DGContainer<ValueT, EXPECTED_ELEMENTS_NUM> &oth) const {\n        return !operator==(oth);\n    }\n\n  private:\n    ContainerT container;\n};\n\n// Edges are pointers to other nodes\ntemplate <typename NodeT, unsigned int EXPECTED_EDGES_NUM = 4>\nclass EdgesContainer : public DGContainer<NodeT *, EXPECTED_EDGES_NUM> {};\n\n} // namespace dg\n\n#endif // DG_CONTAINER_H_\n"
  },
  {
    "path": "include/dg/ADT/DisjunctiveIntervalMap.h",
    "content": "#ifndef DG_DISJUNCTIVE_INTERVAL_MAP_H_\n#define DG_DISJUNCTIVE_INTERVAL_MAP_H_\n\n#include <algorithm>\n#include <cassert>\n#include <map>\n#include <set>\n#include <vector>\n\n#ifndef NDEBUG\n#include <iostream>\n#endif\n\n#include \"dg/Offset.h\"\n\nnamespace dg {\nnamespace ADT {\n\ntemplate <typename T = int64_t>\nstruct DiscreteInterval {\n    using ValueT = T;\n\n    T start;\n    T end;\n\n    DiscreteInterval(T s, T e) : start(s), end(e) {\n        assert(s <= e && \"Invalid interval\");\n    }\n\n    T length() const {\n        // +1 as the intervals are discrete\n        // (interval |0|1|2|3|  has length 4)\n        return end - start + 1;\n    }\n\n    // total order on intervals so that we can insert them\n    // to std containers. We want to compare them only\n    // according to the start value.\n    bool operator<(const DiscreteInterval &I) const { return start < I.start; }\n\n    bool operator==(const DiscreteInterval &I) const {\n        return start == I.start && end == I.end;\n    }\n\n    bool operator!=(const DiscreteInterval &I) const { return !operator==(I); }\n\n    bool overlaps(const DiscreteInterval &I) const {\n        return (start <= I.start && end >= I.start) || I.end >= start;\n    }\n\n    bool covers(const DiscreteInterval &I) const {\n        return (start <= I.start && end >= I.end);\n    }\n\n    bool overlaps(T rhs_start, T rhs_end) const {\n        return overlaps(DiscreteInterval(rhs_start, rhs_end));\n    }\n\n    bool covers(T rhs_start, T rhs_end) const {\n        return covers(DiscreteInterval(rhs_start, rhs_end));\n    }\n\n#ifndef NDEBUG\n    void dump() const;\n#endif\n};\n\n///\n// Mapping of disjunctive discrete intervals of values\n// to sets of ValueT.\ntemplate <typename ValueT, typename IntervalValueT = Offset>\nclass DisjunctiveIntervalMap {\n  public:\n    using IntervalT = DiscreteInterval<IntervalValueT>;\n    using ValuesT = std::set<ValueT>;\n    using MappingT = std::map<IntervalT, ValuesT>;\n    using iterator = typename MappingT::iterator;\n    using const_iterator = typename MappingT::const_iterator;\n\n    ///\n    // Return true if the mapping is updated anyhow\n    // (intervals split, value added).\n    bool add(const IntervalValueT start, const IntervalValueT end,\n             const ValueT &val) {\n        return add(IntervalT(start, end), val);\n    }\n\n    bool add(const IntervalT &I, const ValueT &val) {\n        return _add(I, val, false);\n    }\n\n    template <typename ContT>\n    bool add(const IntervalT &I, const ContT &vals) {\n        bool changed = false;\n        for (const ValueT &val : vals) {\n            changed |= _add(I, val, false);\n        }\n        return changed;\n    }\n\n    bool update(const IntervalValueT start, const IntervalValueT end,\n                const ValueT &val) {\n        return update(IntervalT(start, end), val);\n    }\n\n    bool update(const IntervalT &I, const ValueT &val) {\n        return _add(I, val, true);\n    }\n\n    template <typename ContT>\n    bool update(const IntervalT &I, const ContT &vals) {\n        bool changed = false;\n        for (const ValueT &val : vals) {\n            changed |= _add(I, val, true);\n        }\n        return changed;\n    }\n\n    // add the value 'val' to all intervals\n    bool addAll(const ValueT &val) {\n        bool changed = false;\n        for (auto &it : _mapping) {\n            changed |= it.second.insert(val).second;\n        }\n        return changed;\n    }\n\n    // return true if some intervals from the map\n    // has a overlap with I\n    bool overlaps(const IntervalT &I) const {\n        if (_mapping.empty())\n            return false;\n\n        auto ge = _find_ge(I);\n        if (ge == _mapping.end()) {\n            auto last = _get_last();\n            return last->first.end >= I.start;\n        }\n        return ge->first.start <= I.end;\n    }\n\n    bool overlaps(IntervalValueT start, IntervalValueT end) const {\n        return overlaps(IntervalT(start, end));\n    }\n\n    // return true if the map has an entry for\n    // each single byte from the interval I\n    bool overlapsFull(const IntervalT &I) const {\n        if (_mapping.empty()) {\n            return false;\n        }\n\n        auto ge = _find_ge(I);\n        if (ge == _mapping.end()) {\n            auto last = _get_last();\n            return last->first.end >= I.end;\n        }\n        if (ge->first.start > I.start) {\n            if (ge == _mapping.begin())\n                return false;\n            auto prev = ge;\n            --prev;\n            if (prev->first.end != ge->first.start - 1)\n                return false;\n        }\n\n        IntervalValueT last_end = ge->first.end;\n        while (ge->first.end < I.end) {\n            ++ge;\n            if (ge == _mapping.end())\n                return false;\n\n            if (ge->first.start != last_end + 1)\n                return false;\n\n            last_end = ge->first.end;\n        }\n\n        // full overlap means that there are not uncovered bytes\n        assert(uncovered(I).empty());\n        return true;\n    }\n\n    bool overlapsFull(IntervalValueT start, IntervalValueT end) const {\n        return overlapsFull(IntervalT(start, end));\n    }\n\n    DisjunctiveIntervalMap\n    intersection(const DisjunctiveIntervalMap &rhs) const {\n        DisjunctiveIntervalMap tmp;\n        // FIXME: this could be done more efficiently\n        auto it = _mapping.begin();\n        for (auto &rhsit : rhs._mapping) {\n            while (it->first.end < rhsit.first.start) {\n                if (it == _mapping.end()) {\n                    return tmp;\n                }\n            }\n            if (it->first.overlaps(rhsit.first)) {\n                decltype(rhsit.second) vals;\n                std::set_intersection(it->second.begin(), it->second.end(),\n                                      rhsit.second.begin(), rhsit.second.end(),\n                                      std::inserter(vals, vals.begin()));\n                tmp.add(IntervalT{std::max(it->first.start, rhsit.first.start),\n                                  std::min(it->first.end, rhsit.first.end)},\n                        vals);\n            }\n        }\n        return tmp;\n    }\n\n    ///\n    // Gather all values that are covered by the interval I\n    std::set<ValueT> gather(IntervalValueT start, IntervalValueT end) const {\n        return gather(IntervalT(start, end));\n    }\n\n    std::set<ValueT> gather(const IntervalT &I) const {\n        std::set<ValueT> ret;\n\n        auto it = le(I);\n        if (it == end())\n            return ret;\n\n        assert(it->first.overlaps(I) && \"The found interval should overlap\");\n        while (it != end() && it->first.overlaps(I)) {\n            ret.insert(it->second.begin(), it->second.end());\n            ++it;\n        }\n\n        return ret;\n    }\n\n    std::vector<IntervalT> uncovered(IntervalValueT start,\n                                     IntervalValueT end) const {\n        return uncovered(IntervalT(start, end));\n    }\n\n    std::vector<IntervalT> uncovered(const IntervalT &I) const {\n        if (_mapping.empty())\n            return {I};\n\n        auto it = le(I);\n        if (it == end())\n            return {I};\n\n        std::vector<IntervalT> ret;\n        IntervalT cur = I;\n\n        if (cur.start > it->first.start) {\n            // the first interval covers the whole I?\n            if (it->first.end >= I.end) {\n                return {};\n            }\n\n            assert(cur == I);\n            cur.start = it->first.end + 1;\n            assert(cur.end == I.end);\n            assert(I.end > it->first.end);\n            // we handled this interval, move further\n            ++it;\n\n            // nothing else to handle...\n            if (it == _mapping.end()) {\n                if (cur.start <= cur.end)\n                    return {cur};\n            }\n        }\n\n        while (true) {\n            assert(cur.start <= it->first.start);\n            if (cur.start != it->first.start && cur.start < it->first.start) {\n                assert(it->first.start != 0 && \"Underflow\");\n                ret.push_back(IntervalT{cur.start, it->first.start - 1});\n            }\n            // does the rest of the interval covers all?\n            if (it->first.end >= I.end)\n                break;\n\n            assert(it->first.end != (~static_cast<IntervalValueT>(0)) &&\n                   \"Overflow\");\n            cur.start = it->first.end + 1;\n            assert(cur.end == I.end);\n\n            ++it;\n            if (it == end()) {\n                if (cur.start <= cur.end)\n                    ret.push_back(cur);\n                // we're done here\n                break;\n            }\n        }\n\n        return ret;\n    }\n\n    bool empty() const { return _mapping.empty(); }\n    size_t size() const { return _mapping.size(); }\n\n    iterator begin() { return _mapping.begin(); }\n    const_iterator begin() const { return _mapping.begin(); }\n    iterator end() { return _mapping.end(); }\n    const_iterator end() const { return _mapping.end(); }\n\n    bool operator==(\n            const DisjunctiveIntervalMap<ValueT, IntervalValueT> &rhs) const {\n        return _mapping == rhs._mapping;\n    }\n\n    // return the iterator to an element that is the first\n    // that overlaps the interval I or end() if there is\n    // no such interval\n    iterator le(const IntervalT &I) { return _shift_le(_find_ge(I), I); }\n\n    const_iterator le(const IntervalT &I) const {\n        return _shift_le(_find_ge(I), I);\n    }\n\n    iterator le(const IntervalValueT start, const IntervalValueT end) {\n        return le(IntervalT(start, end));\n    }\n\n    const_iterator le(const IntervalValueT start,\n                      const IntervalValueT end) const {\n        return le(IntervalT(start, end));\n    }\n\n#ifndef NDEBUG\n    friend std::ostream &\n    operator<<(std::ostream &os,\n               const DisjunctiveIntervalMap<ValueT, IntervalValueT> &map) {\n        os << \"{\";\n        for (const auto &pair : map) {\n            if (pair.second.empty())\n                continue;\n\n            os << \"{ \";\n            os << pair.first.start << \"-\" << pair.first.end;\n            os << \": \" << *pair.second.begin();\n            os << \" }, \";\n        }\n        os << \"}\";\n        return os;\n    }\n\n    void dump() const { std::cout << *this << \"\\n\"; }\n#endif\n\n#if 0\n    friend llvm::raw_ostream& operator<<(llvm::raw_ostream& os, const DisjunctiveIntervalMap<ValueT, IntervalValueT>& map) {\n        os << \"{\";\n        for (const auto& pair : map) {\n            if (pair.second.empty())\n                continue;\n\n            os << \"{ \";\n            os << *pair.first.start << \"-\" << *pair.first.end;\n            os << \": \" << *pair.second.begin();\n            os << \" }, \";\n        }\n        os << \"}\";\n        return os;\n    }\n\n#endif\n\n  private:\n    // shift the iterator such that it will point to the\n    // first element that overlaps with I, or to end\n    // if there is no such interval\n    template <typename IteratorT>\n    IteratorT _shift_le(const IteratorT &startge, const IntervalT &I) const {\n        // find the element that starts at the same value\n        // as I or later (i.e. I.start >= it.start)\n        if (startge == end()) {\n            auto last = _get_last();\n            if (last->first.end >= I.start) {\n                assert(last->first.overlaps(I));\n                return last;\n            }\n\n            return end();\n        }\n\n        assert(startge->first.start >= I.start);\n\n        // check whether there's\n        // an previous interval with an overlap\n        if (startge != begin()) {\n            auto tmp = startge;\n            --tmp;\n            if (tmp->first.end >= I.start) {\n                assert(tmp->first.overlaps(I));\n                return tmp;\n            }\n            // fall-through\n        }\n\n        // starge is the first interval or the\n        // previous interval does not overlap.\n        // Just check whether this interval overlaps\n        if (startge->first.start > I.end)\n            return end();\n\n        assert(startge->first.overlaps(I));\n        return startge;\n    }\n\n    // Split interval [a,b] to two intervals [a, where] and [where + 1, b].\n    // Each of the new intervals has a copy of the original set associated\n    // to the original interval.\n    // Returns the new lower interval\n    // XXX: could we pass just references to the iterator?\n    template <typename IteratorT, typename HintIteratorT>\n    IteratorT splitIntervalHint(IteratorT I, IntervalValueT where,\n                                HintIteratorT hint) {\n        auto interval = I->first;\n        auto values = std::move(I->second);\n\n        assert(interval.start != interval.end && \"Cannot split such interval\");\n        assert(interval.start <= where && where <= interval.end &&\n               \"Value 'where' must lie inside the interval\");\n        assert(where < interval.end && \"The second interval would be empty\");\n\n        // remove the original interval and replace it with\n        // two splitted intervals\n        _mapping.erase(I);\n        auto ret = _mapping.emplace_hint(hint, IntervalT(interval.start, where),\n                                         values);\n        _mapping.emplace_hint(hint, IntervalT(where + 1, interval.end),\n                              std::move(values));\n        return ret;\n    }\n\n    bool splitExtBorders(const IntervalT &I) {\n        assert(!_mapping.empty());\n        bool changed = false;\n\n        auto ge = _mapping.lower_bound(I);\n        if (ge == _mapping.end()) {\n            // the last interval must start somewhere to the\n            // left from our new interval\n            auto last = _get_last();\n            assert(last->first.start < I.start);\n\n            if (last->first.end > I.end) {\n                last = splitIntervalHint(last, I.end, ge);\n                changed |= true;\n            }\n\n            if (last->first.end >= I.start) {\n                splitIntervalHint(last, I.start - 1, ge);\n                changed |= true;\n            }\n            return changed;\n        }\n\n        // we found an interval starting at I.start\n        // or later\n        assert(ge->first.start >= I.start);\n        // FIXME: optimize this...\n        //  add _find_le to find the \"closest\" interval from the right\n        //  (maybe iterating like this is faster, though)\n        auto it = ge;\n        while (it->first.start <= I.end) {\n            if (it->first.end > I.end) {\n                it = splitIntervalHint(it, I.end, _mapping.end());\n                changed = true;\n                break;\n            }\n            ++it;\n            if (it == _mapping.end())\n                break;\n        }\n\n        // we may have also overlap from the previous interval\n        if (changed)\n            ge = _mapping.lower_bound(I);\n        if (ge != _mapping.begin()) {\n            auto prev = ge;\n            --prev;\n            auto prev_end = prev->first.end;\n            if (prev_end >= I.start) {\n                ge = splitIntervalHint(prev, I.start - 1, ge);\n                changed = true;\n            }\n            // is the new interval entirely covered by the previous?\n            if (prev_end > I.end) {\n                // get the higher of the new intervals\n                ++ge;\n                assert(ge != _mapping.end());\n                assert(ge->first.end == prev_end);\n#ifndef NDEBUG\n                auto check =\n#endif\n                        splitIntervalHint(ge, I.end, _mapping.end());\n                assert(check->first == I);\n                changed = true;\n            }\n        }\n\n        return changed;\n    }\n\n    template <typename IteratorT>\n    bool _addValue(IteratorT I, ValueT val, bool update) {\n        if (update) {\n            if (I->second.size() == 1 && I->second.count(val) > 0)\n                return false;\n\n            I->second.clear();\n            I->second.insert(val);\n            return true;\n        }\n\n        return I->second.insert(val).second;\n    }\n\n    // If the boolean 'update' is set to true, the value\n    // is not added, but rewritten\n    bool _add(const IntervalT &I, const ValueT &val, bool update = false) {\n        if (_mapping.empty()) {\n            _mapping.emplace(I, ValuesT{val});\n            return true;\n        }\n\n        // fast path\n        // auto fastit = _mapping.lower_bound(I);\n        // if (fastit != _mapping.end() &&\n        //    fastit->first == I) {\n        //    return _addValue(fastit, val, update);\n        //}\n\n        // XXX: pass the lower_bound iterator from the fast path\n        // so that we do not search the mapping again\n        bool changed = splitExtBorders(I);\n        _check();\n\n        // splitExtBorders() arranged the intervals such\n        // that some interval starts with ours\n        // and some interval ends with ours.\n        // Now we just create new intervals in the gaps\n        // and add values to the intervals that we have\n\n        // FIXME: splitExtBorders() can return the iterator,\n        // so that we do not need to search the map again.\n        auto it = _find_ge(I);\n        assert(!changed || it != _mapping.end());\n\n        // we do not have any overlapping interval\n        if (it == _mapping.end() || I.end < it->first.start) {\n            assert(!overlaps(I) && \"Bug in add() or in overlaps()\");\n            _mapping.emplace(I, ValuesT{val});\n            return true;\n        }\n\n        auto rest = I;\n        assert(rest.end >= it->first.start); // we must have some overlap here\n        while (it != _mapping.end()) {\n            if (rest.start < it->first.start) {\n                // add the gap interval\n                _mapping.emplace_hint(\n                        it, IntervalT(rest.start, it->first.start - 1),\n                        ValuesT{val});\n                rest.start = it->first.start;\n                changed = true;\n            } else {\n                // update the existing interval and shift\n                // to the next interval\n                assert(rest.start == it->first.start);\n                changed |= _addValue(it, val, update);\n                if (it->first.end == rest.end)\n                    break;\n\n                rest.start = it->first.end + 1;\n                ++it;\n\n                // our interval spans to the right\n                // after the last covered interval\n                if (it == _mapping.end() || it->first.start > rest.end) {\n                    _mapping.emplace_hint(it, rest, ValuesT{val});\n                    changed = true;\n                    break;\n                }\n            }\n        }\n\n        _check();\n        return changed;\n    }\n\n    // find the elements starting at\n    // or right to the interval\n    typename MappingT::iterator _find_ge(const IntervalT &I) {\n        // lower_bound = lower upper bound\n        return _mapping.lower_bound(I);\n    }\n\n    typename MappingT::const_iterator _find_ge(const IntervalT &I) const {\n        return _mapping.lower_bound(I);\n    }\n\n    typename MappingT::iterator _get_last() {\n        assert(!_mapping.empty());\n        return (--_mapping.end());\n    }\n\n    typename MappingT::const_iterator _get_last() const {\n        assert(!_mapping.empty());\n        return (--_mapping.end());\n    }\n\n    void _check() const {\n#ifndef NDEBUG\n        // check that the keys are disjunctive\n        auto it = _mapping.begin();\n        auto last = it->first;\n        ++it;\n        while (it != _mapping.end()) {\n            assert(last.start <= last.end);\n            // this one is nontrivial (the other assertions\n            // should be implied by the Interval and std::map propertis)\n            assert(last.end < it->first.start);\n            assert(it->first.start <= it->first.end);\n\n            last = it->first;\n            ++it;\n        }\n#endif // NDEBUG\n    }\n\n    MappingT _mapping;\n};\n\n} // namespace ADT\n} // namespace dg\n\n#endif // _DG_DISJUNCTIVE_INTERVAL_MAP_H_\n"
  },
  {
    "path": "include/dg/ADT/HashMap.h",
    "content": "#ifndef DG_HASH_MAP_H_\n#define DG_HASH_MAP_H_\n\n#ifdef HAVE_TSL_HOPSCOTCH\n#include \"TslHopscotchHashMap.h\"\nnamespace dg {\ntemplate <typename Key, typename Val>\nusing HashMap = HopscotchHashMap<Key, Val>;\n}\n#else\n#include \"STLHashMap.h\"\nnamespace dg {\ntemplate <typename Key, typename Val>\nusing HashMap = STLHashMap<Key, Val>;\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "include/dg/ADT/HashMapImpl.h",
    "content": "#ifndef DG_HASH_MAP_IMPL_H_\n#define DG_HASH_MAP_IMPL_H_\n\nnamespace dg {\n\ntemplate <typename Key, typename Val, typename Impl>\nclass HashMapImpl : public Impl {\n  public:\n    using iterator = typename Impl::iterator;\n    using const_iterator = typename Impl::const_iterator;\n\n    bool put(const Key &k, Val v) {\n        auto it = this->insert(std::make_pair(k, v));\n        return it.second;\n    }\n\n    const Val *get(const Key &k) const {\n        auto it = this->find(k);\n        if (it != this->end())\n            return &it->second;\n        return nullptr;\n    }\n\n    Val *get(Key &k) {\n        auto it = this->find(k);\n        if (it != this->end())\n            return &it->second;\n        return nullptr;\n    }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/ADT/IntervalsList.h",
    "content": "#ifndef DG_INTERVALS_LIST_H_\n#define DG_INTERVALS_LIST_H_\n\n#include \"dg/Offset.h\"\n#include <cassert>\n#include <list>\n\nnamespace dg {\nnamespace dda {\n\nclass IntervalsList {\n    struct Interval {\n        Offset start;\n        Offset end;\n\n        Interval(Offset s, Offset e) : start(s), end(e) {\n            assert(start <= end);\n        }\n\n        Interval(const std::pair<Offset, Offset> &I)\n                : Interval(I.first, I.second) {}\n\n        bool overlaps(const Interval &I) const {\n            return start <= I.end && end >= I.start;\n        }\n        Offset length() const { return end - start + 1; }\n    };\n\n    std::list<Interval> intervals;\n\n    template <typename Iterator>\n    void _replace_overlapping(const Interval &I, Iterator it, Iterator to) {\n        assert(it->overlaps(I) && to->overlaps(I));\n        assert(it != intervals.end());\n        assert(to != intervals.end());\n        it->start = std::min(it->start, I.start);\n        it->end = std::max(to->end, I.end);\n\n        ++it;\n        ++to;\n        if (it != intervals.end()) {\n            intervals.erase(it, to);\n        } else {\n            assert(to == intervals.end());\n        }\n    }\n\n#ifndef NDEBUG\n    bool _check() {\n        auto it = intervals.begin();\n        if (it != intervals.end()) {\n            assert(it->start < it->end);\n            auto last = it++;\n            while (it != intervals.end()) {\n                assert(last->start < last->end);\n                assert(last->end < it->start);\n                assert(it->start < it->end);\n            }\n        }\n        return true;\n    }\n#endif // NDEBUG\n\n  public:\n    void add(Offset start, Offset end) { add({start, end}); }\n\n    void add(const Interval &I) {\n        if (intervals.empty())\n            intervals.push_back(I);\n\n        auto it = intervals.begin();\n        auto end = intervals.end();\n\n        while (it != end) {\n            if (I.overlaps(*it)) {\n                auto to = ++it;\n                while (to != end && I.overlaps(*to)) {\n                    ++to;\n                }\n                if (to == end) {\n                    --to;\n                }\n                _replace_overlapping(I, it, to);\n                break;\n            }\n            if (it->start > I.end) {\n                intervals.insert(it, I);\n                break;\n            }\n\n            ++it;\n        }\n\n        if (it == end) {\n            intervals.push_back(I);\n        }\n        assert(_check());\n    }\n\n    IntervalsList &intersectWith(const IntervalsList &rhs) {\n        if (intervals.empty())\n            return *this;\n\n        auto it = intervals.begin();\n        for (const auto &RI : rhs.intervals) {\n            while (it->end < RI.start) {\n                auto tmp = it++;\n                intervals.erase(tmp);\n                if (it == intervals.end()) {\n                    return *this;\n                }\n            }\n            if (it->overlaps(RI)) {\n                it->start = std::max(it->start, RI.start);\n                it->end = std::min(it->end, RI.end);\n            }\n        }\n\n        return *this;\n    }\n\n    auto begin() -> decltype(intervals.begin()) { return intervals.begin(); }\n    auto begin() const -> decltype(intervals.begin()) {\n        return intervals.begin();\n    }\n    auto end() -> decltype(intervals.end()) { return intervals.end(); }\n    auto end() const -> decltype(intervals.end()) { return intervals.end(); }\n};\n\n} // namespace dda\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/ADT/Map.h",
    "content": "#ifndef DG_MAP_IMPL_H_\n#define DG_MAP_IMPL_H_\n\n#include <cstddef>\n#include <map>\n\nnamespace dg {\n\n// an ordered map with a unified API\ntemplate <typename Key, typename Val, typename Impl>\nclass MapImpl : public Impl {\n  public:\n    using iterator = typename Impl::iterator;\n    using const_iterator = typename Impl::const_iterator;\n\n    bool put(const Key &k, Val v) {\n        auto it = this->insert(std::make_pair(k, v));\n        return it.second;\n    }\n\n    const Val *get(const Key &k) const {\n        auto it = this->find(k);\n        if (it != this->end())\n            return &it->second;\n        return nullptr;\n    }\n\n    Val *get(Key &k) {\n        auto it = this->find(k);\n        if (it != this->end())\n            return &it->second;\n        return nullptr;\n    }\n\n    void reserve(size_t /*unused*/) {\n        // so that we can exchangabily use with HashMap\n    }\n};\n\ntemplate <typename Key, typename Val>\nusing Map = MapImpl<Key, Val, std::map<Key, Val>>;\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/ADT/NumberSet.h",
    "content": "#ifndef _DG_NUMBER_SET_H_\n#define _DG_NUMBER_SET_H_\n\n#include \"Bits.h\"\n#include \"Bitvector.h\"\n\nnamespace dg {\nnamespace ADT {\n\n// this is just a wrapper around sparse bitvector\n// that translates the bitvector methods to a new methods.\n// There is no possibility to remove elements from the set.\nclass BitvectorNumberSet {\n    using NumT = uint64_t;\n    using ContainerT = SparseBitvectorImpl<uint64_t, NumT>;\n\n    ContainerT _bitvector;\n\n  public:\n    using const_iterator = typename ContainerT::const_iterator;\n\n    BitvectorNumberSet() = default;\n    BitvectorNumberSet(size_t n) : _bitvector(n){};\n    BitvectorNumberSet(BitvectorNumberSet &&) = default;\n\n    bool add(NumT n) { return !_bitvector.set(n); }\n    bool has(NumT n) const { return _bitvector.get(n); }\n    bool empty() const { return _bitvector.empty(); }\n    size_t size() const { return _bitvector.size(); }\n    void swap(BitvectorNumberSet &oth) { oth._bitvector.swap(_bitvector); }\n\n    const_iterator begin() const { return _bitvector.begin(); }\n    const_iterator end() const { return _bitvector.end(); }\n};\n\n// This class is a container for a set of numbers\n// that is optimized for holding small values\n// (values less than sizeof(NumT)*8*SmallElemNum)).\n// If a greater value is inserted, the whole container\n// is lifted to a normal set.\n// There is no possibility to remove elements from the set.\nclass SmallNumberSet {\n    using NumT = uint64_t;\n    // NOTE: if we change this to something that\n    // has non-trivial ctors/dtors, we must reflect it in the code!\n    using SmallSetT = Bits<NumT>;\n    using BigSetT = BitvectorNumberSet;\n\n    bool is_small{true};\n\n    union SetT {\n        SmallSetT small;\n        BigSetT big;\n\n        SetT() : small() {}\n        ~SetT() {}\n    } _set;\n\n    void _lift(NumT n) {\n        assert(is_small);\n\n        auto S = BigSetT(n);\n        for (auto x : _set.small)\n            S.add(x);\n\n        // initialize the big-set\n        new (&_set.big) BigSetT();\n        S.swap(_set.big);\n\n        is_small = false;\n    }\n\n  public:\n    ~SmallNumberSet() {\n        // if we used the big set, call its destructor\n        // (for smalls set there's nothing to do)\n        if (!is_small)\n            _set.big.~BigSetT();\n    }\n\n    bool add(NumT n) {\n        if (is_small) {\n            if (_set.small.mayContain(n))\n                return !_set.small.set(n);\n            _lift(n);\n            return true;\n\n        } else\n            return _set.big.add(n);\n    }\n\n    bool has(NumT n) const {\n        return is_small ? _set.small.get(n) : _set.big.has(n);\n    }\n\n    bool empty() const {\n        return is_small ? _set.small.empty() : _set.big.empty();\n    }\n\n    size_t size() const {\n        return is_small ? _set.small.size() : _set.big.size();\n    }\n\n    class const_iterator {\n        const bool is_small;\n\n        union ItT {\n            SmallSetT::const_iterator small_it;\n            BigSetT::const_iterator big_it;\n            ItT() {}\n            ~ItT() {}\n        } _it;\n\n      public:\n        const_iterator(const SmallNumberSet &S, bool end = false)\n                : is_small(S.is_small) {\n            if (is_small) {\n                if (end)\n                    _it.small_it = S._set.small.end();\n                else\n                    _it.small_it = S._set.small.begin();\n            } else {\n                if (end)\n                    _it.big_it = S._set.big.end();\n                else\n                    _it.big_it = S._set.big.begin();\n            }\n        }\n\n        const_iterator(const const_iterator &) = default;\n\n        const_iterator &operator++() {\n            if (is_small)\n                ++_it.small_it;\n            else\n                ++_it.big_it;\n\n            return *this;\n        }\n\n        const_iterator operator++(int) {\n            auto tmp = *this;\n            operator++();\n            return tmp;\n        }\n\n        size_t operator*() const {\n            if (is_small)\n                return *_it.small_it;\n            return *_it.big_it;\n        }\n\n        bool operator==(const const_iterator &rhs) const {\n            if (is_small != rhs.is_small)\n                return false;\n\n            if (is_small)\n                return _it.small_it == rhs._it.small_it;\n            return _it.big_it == rhs._it.big_it;\n        }\n\n        bool operator!=(const const_iterator &rhs) const {\n            return !operator==(rhs);\n        }\n    };\n\n    const_iterator begin() const { return const_iterator(*this); }\n    const_iterator end() const { return const_iterator(*this, true /* end */); }\n\n    friend class const_iterator;\n};\n\n#if 0\n// This class is a container for a set of numbers\n// that is optimized for holding small values\n// (values less than sizeof(NumT)*8*SmallElemNum)).\n// If a greater value is inserted, the whole container\n// is lifted to a normal set.\n// There is no possibility to remove elements from the set.\ntemplate <typename NumT = uint64_t,\n          typename BigSetT = BitvectorNumberSet,\n          size_t SmallElemNum = 1>\nclass SmallNumberSet {\n    NumT[SmallElemNum] _smallNums{};\n    std::unique_ptr<BigSetT> _bigSet;\n\n    static size_t smallSetElemSize() { return sizeof(NumT)*8; }\n    static size_t smallSetSize() { return smallSetElemSize*SmallElemNum; }\n    static bool isInSmallSet(NumT n) { return n < smallSetSize(); }\n\n    // split a number from small set to offset to _smallNums\n    // and a bit of the element\n    std::pair<size_t, NumT> _split(NumT n) {\n        assert(!_bigSet);\n\n        size_t pos = 0;\n        while (n >= smallSetElemSize()) {\n            n =>> smallSetElemSize() - 1;\n            ++pos;\n        }\n\n        assert(pos < SmallElemNum);\n        return {pos, n};\n    }\n\n    // add a number\n    bool _add(NumT n) {\n        if (isInSmallSet(n)) {\n            size_t pos;\n            std::tie(pos, n) = _getSmallPos(n);\n            if (_smallNums[pos] & (1UL << num)) {\n                return false;\n            } else {\n                _smallNums[pos] |= (1UL << num);\n                return true;\n            }\n        } else {\n            assert(!_bigSet);\n            auto S = std::unique_ptr<BigSetT>(new BigSetT(n));\n            // copy the elements from small set to the big set\n            for (auto x : *this)\n                S.add(x);\n\n            // set the big set\n            _bigSet = std::move(S);\n\n            return true;\n        }\n    };\n\n    size_t _sizeSmall() const {\n        assert(!_bigSet);\n        size_t n;\n        for (auto x : _smallNums) {\n            while(x) {\n                if (x & 0x1)\n                    ++n;\n                x >>= 1;\n            }\n        }\n\n        return n;\n    }\n\n    bool _emptySmall() const { return _sizeSmall() == 0; }\n\n    bool _hasSmall(NumT n) const {\n        std::tie(pos, n) = _getSmallPos(n);\n        assert(pos < smallSetSize());\n        assert(n < smallSetElemSize());\n\n        auto pos = _getSmallPos(n);\n        return _smallNums[pos] & (1UL << num);\n    }\n\npublic:\n    bool add(NumT n) { return _bigSet ? _bigSet->add(n) : _add(n); }\n    bool has(NumT n) const { return _bigSet ? _bigSet.has(n) : _hasSmall(n); }\n    bool empty() const { return _bigSet ? _bigSet.empty() : _emptySmall(); }\n    size_t size() const { return _bigSet ? _bigSet.size() : _sizeSmall(); }\n\n    /*\n    const_iterator begin() const { return _bitvector.begin(); }\n    const_iterator end() const { return _bitvector.end(); }\n    */\n}\n#endif\n\n/*\n// this is just a wrapper around std::set\ntemplate <typename NumT = uint64_t>\nclass SimpleNumberSet {\n    using ContainerT = std::set<NumT>;\n}\n*/\n\n} // namespace ADT\n} // namespace dg\n\n#endif // _DG_NUMBER_SET_H_\n"
  },
  {
    "path": "include/dg/ADT/Queue.h",
    "content": "#ifndef DG_ADT_QUEUE_H_\n#define DG_ADT_QUEUE_H_\n\n#include <queue>\n#include <set>\n#include <stack>\n\nnamespace dg {\nnamespace ADT {\n\ntemplate <typename ValueT>\nclass QueueLIFO {\n    using ContainerT = std::stack<ValueT>;\n\n  public:\n    using ValueType = ValueT;\n\n    ValueT pop() {\n        ValueT ret = Container.top();\n        Container.pop();\n\n        return ret;\n    }\n\n    ValueT &top() { return Container.top(); }\n\n    void push(const ValueT &what) { Container.push(what); }\n\n    bool empty() const { return Container.empty(); }\n\n    typename ContainerT::size_type size() const { return Container.size(); }\n\n    void swap(QueueLIFO<ValueT> &oth) { Container.swap(oth.Container); }\n\n  private:\n    ContainerT Container;\n};\n\ntemplate <typename ValueT>\nclass QueueFIFO {\n    using ContainerT = std::queue<ValueT>;\n\n  public:\n    using ValueType = ValueT;\n\n    ValueT pop() {\n        ValueT ret = Container.front();\n        Container.pop();\n\n        return ret;\n    }\n\n    ValueT &top() { return Container.top(); }\n\n    void push(const ValueT &what) { Container.push(what); }\n\n    bool empty() const { return Container.empty(); }\n\n    typename ContainerT::size_type size() const { return Container.size(); }\n\n    void swap(QueueFIFO<ValueT> &oth) { Container.swap(oth.Container); }\n\n  private:\n    ContainerT Container;\n};\n\ntemplate <typename ValueT, typename Comp>\nclass PrioritySet {\n    using ContainerT = std::set<ValueT, Comp>;\n\n  public:\n    using ValueType = ValueT;\n\n    ValueT pop() {\n        ValueT ret = *(Container.begin());\n        Container.erase(Container.begin());\n\n        return ret;\n    }\n\n    void push(const ValueT &what) { Container.insert(what); }\n\n    bool empty() const { return Container.empty(); }\n\n    typename ContainerT::size_type size() const { return Container.size(); }\n\n  private:\n    ContainerT Container;\n};\n\n} // namespace ADT\n} // namespace dg\n\n#endif // DG_ADT_QUEUE_H_\n"
  },
  {
    "path": "include/dg/ADT/STLHashMap.h",
    "content": "#ifndef DG_STL_HASH_MAP_H_\n#define DG_STL_HASH_MAP_H_\n\n#include <unordered_map>\n\n#include \"HashMapImpl.h\"\n\nnamespace dg {\n\ntemplate <typename Key, typename Val>\nclass STLHashMap : public HashMapImpl<Key, Val, std::unordered_map<Key, Val>> {\n};\n\n// unordered_map that caches last several accesses\n// XXX: use a different implementation than std::unordered_map\ntemplate <typename Key, typename T, unsigned CACHE_SIZE = 4U>\nclass CachingHashMap : public std::unordered_map<Key, T> {\n    std::pair<Key, T *> _cache[CACHE_SIZE];\n    unsigned _insert_pos{0};\n    unsigned _last{0};\n\n    T *_get_from_cache(const Key &key) {\n        if (_last > 0) {\n            for (unsigned i = 0; i < _last; ++i) {\n                if (_cache[i].first == key)\n                    return _cache[i].second;\n            }\n        }\n        return nullptr;\n    }\n\n    void _insert_to_cache(const Key &key, T *v) {\n        _last = std::min(_last + 1, CACHE_SIZE);\n        _cache[_insert_pos] = {key, v};\n        _insert_pos = (_insert_pos + 1) % CACHE_SIZE;\n\n        assert(_insert_pos < CACHE_SIZE);\n        assert(_last <= CACHE_SIZE);\n    }\n\n    void _invalidate_cache() {\n        _last = 0;\n        _insert_pos = 0;\n    }\n\n  public:\n    using iterator = typename std::unordered_map<Key, T>::iterator;\n    using const_iterator = typename std::unordered_map<Key, T>::const_iterator;\n\n    T &operator[](const Key &key) {\n        if (auto *v = _get_from_cache(key)) {\n            return *v;\n        }\n\n        auto &ret = std::unordered_map<Key, T>::operator[](key);\n        _insert_to_cache(key, &ret);\n        return ret;\n    }\n\n    iterator erase(const_iterator pos) {\n        _invalidate_cache();\n        return std::unordered_map<Key, T>::erase(pos);\n    }\n\n    iterator erase(const_iterator first, const_iterator last) {\n        _invalidate_cache();\n        return std::unordered_map<Key, T>::erase(first, last);\n    }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/ADT/SetQueue.h",
    "content": "#ifndef DG_ADT_SET_QUEUE_H_\n#define DG_ADT_SET_QUEUE_H_\n\n#include \"Queue.h\"\n#include <set>\n\nnamespace dg {\nnamespace ADT {\n\n// A queue where each element can be queued only once\ntemplate <typename QueueT>\nclass SetQueue {\n    std::set<typename QueueT::ValueType> _queued;\n    QueueT _queue;\n\n  public:\n    using ValueType = typename QueueT::ValueType;\n\n    ValueType pop() { return _queue.pop(); }\n    ValueType &top() { return _queue.top(); }\n    bool empty() const { return _queue.empty(); }\n    size_t size() const { return _queue.size(); }\n\n    void push(const ValueType &what) {\n        if (_queued.insert(what).second)\n            _queue.push(what);\n    }\n\n    void swap(SetQueue<QueueT> &oth) {\n        _queue.swap(oth._queue);\n        _queued.swap(oth._queued);\n    }\n};\n\n} // namespace ADT\n} // namespace dg\n\n#endif // DG_ADT_QUEUE_H_\n"
  },
  {
    "path": "include/dg/ADT/TslHopscotchHashMap.h",
    "content": "#ifndef DG_TSL_HOPSCOTCH_MAP_H_\n#define DG_TSL_HOPSCOTCH_MAP_H_\n\n#include <tsl/hopscotch_map.h>\n\n#include \"HashMapImpl.h\"\n\nnamespace dg {\n\ntemplate <typename Key, typename Val>\nclass HopscotchHashMap\n        : public HashMapImpl<Key, Val, tsl::hopscotch_map<Key, Val>> {};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/AnalysisOptions.h",
    "content": "#ifndef DG_ANALYSIS_OPTIONS_H_\n#define DG_ANALYSIS_OPTIONS_H_\n\n#include <cassert>\n#include <map>\n#include <string>\n\n#include \"Offset.h\"\n\nnamespace dg {\n\n///\n// Enumeration for functions that are known to\n// return freshly allocated memory.\nenum class AllocationFunction {\n    NONE,    // not an allocation function\n    MALLOC,  // function behaves like malloc\n    CALLOC,  // function behaves like calloc\n    ALLOCA,  // function behaves like alloca\n    REALLOC, // function behaves like realloc\n    MALLOC0, // function behaves like malloc,\n             // but cannot return NULL\n    CALLOC0, // function behaves like calloc,\n             // but cannot return NULL\n};\n\nstruct AnalysisOptions {\n    // Number of bytes in objects to track precisely\n    Offset fieldSensitivity{Offset::UNKNOWN};\n\n    AnalysisOptions &setFieldSensitivity(Offset o) {\n        fieldSensitivity = o;\n        return *this;\n    }\n\n    std::map<const std::string, AllocationFunction> allocationFunctions = {\n            {\"malloc\", AllocationFunction::MALLOC},\n            {\"calloc\", AllocationFunction::CALLOC},\n            {\"alloca\", AllocationFunction::ALLOCA},\n            {\"realloc\", AllocationFunction::REALLOC},\n    };\n\n    void addAllocationFunction(const std::string &name, AllocationFunction F) {\n#ifndef NDEBUG\n        auto ret =\n#endif\n                allocationFunctions.emplace(name, F);\n        assert(ret.second && \"Already have this allocation function\");\n    }\n\n    AllocationFunction getAllocationFunction(const std::string &name) const {\n        auto it = allocationFunctions.find(name);\n        if (it == allocationFunctions.end())\n            return AllocationFunction::NONE;\n        return it->second;\n    }\n\n    bool isAllocationFunction(const std::string &name) const {\n        return getAllocationFunction(name) != AllocationFunction::NONE;\n    }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/BBlock.h",
    "content": "#ifndef BBLOCK_H_\n#define BBLOCK_H_\n\n#include <cassert>\n#include <list>\n\n#include \"ADT/DGContainer.h\"\n#include \"dg/util/iterators.h\"\n#include \"legacy/Analysis.h\"\n\nnamespace dg {\n\n/// ------------------------------------------------------------------\n// - BBlock\n//     Basic block structure for dependence graph\n/// ------------------------------------------------------------------\ntemplate <typename NodeT>\nclass BBlock {\n  public:\n    using BBlockLabelTy = uint8_t;\n    static const BBlockLabelTy ARTIFICIAL_BBLOCK_LABEL = 255;\n    static const BBlockLabelTy MAX_BBLOCK_LABEL = ARTIFICIAL_BBLOCK_LABEL;\n    using KeyT = typename NodeT::KeyType;\n    using DependenceGraphT = typename NodeT::DependenceGraphType;\n\n    struct BBlockEdge {\n        BBlockEdge(BBlock<NodeT> *t, uint8_t label = 0)\n                : target(t), label(label) {}\n\n        BBlock<NodeT> *target;\n        // we'll have just numbers as labels now.\n        // We can change it if there's a need\n        BBlockLabelTy label;\n\n        bool operator==(const BBlockEdge &oth) const {\n            return target == oth.target && label == oth.label;\n        }\n\n        bool operator!=(const BBlockEdge &oth) const { return operator==(oth); }\n\n        bool operator<(const BBlockEdge &oth) const {\n            return target == oth.target ? label < oth.label\n                                        : target < oth.target;\n        }\n    };\n\n    BBlock<NodeT>(NodeT *head = nullptr, DependenceGraphT *dg = nullptr)\n            : key(KeyT()), dg(dg), ipostdom(nullptr) {\n        if (head) {\n            append(head);\n            assert(!dg || head->getDG() == nullptr || dg == head->getDG());\n        }\n    }\n\n    ~BBlock<NodeT>() {\n        if (delete_nodes_on_destr) {\n            for (NodeT *nd : nodes)\n                delete nd;\n        }\n    }\n\n    using BBlockContainerT = EdgesContainer<BBlock<NodeT>>;\n    // we don't need labels with predecessors\n    using PredContainerT = EdgesContainer<BBlock<NodeT>>;\n    using SuccContainerT = DGContainer<BBlockEdge>;\n\n    SuccContainerT &successors() { return nextBBs; }\n    const SuccContainerT &successors() const { return nextBBs; }\n\n    PredContainerT &predecessors() { return prevBBs; }\n    const PredContainerT &predecessors() const { return prevBBs; }\n\n    const BBlockContainerT &controlDependence() const { return controlDeps; }\n    const BBlockContainerT &revControlDependence() const {\n        return revControlDeps;\n    }\n\n    // similary to nodes, basic blocks can have keys\n    // they are not stored anywhere, it is more due to debugging\n    void setKey(const KeyT &k) { key = k; }\n    const KeyT &getKey() const { return key; }\n\n    // XXX we should do it a common base with node\n    // to not duplicate this - something like\n    // GraphElement that would contain these attributes\n    void setDG(DependenceGraphT *d) { dg = d; }\n    DependenceGraphT *getDG() const { return dg; }\n\n    const std::list<NodeT *> &getNodes() const { return nodes; }\n    std::list<NodeT *> &getNodes() { return nodes; }\n    bool empty() const { return nodes.empty(); }\n    size_t size() const { return nodes.size(); }\n\n    void append(NodeT *n) {\n        assert(n && \"Cannot add null node to BBlock\");\n\n        n->setBasicBlock(this);\n        nodes.push_back(n);\n    }\n\n    void prepend(NodeT *n) {\n        assert(n && \"Cannot add null node to BBlock\");\n\n        n->setBasicBlock(this);\n        nodes.push_front(n);\n    }\n\n    bool hasControlDependence() const { return !controlDeps.empty(); }\n\n    // return true if all successors point\n    // to the same basic block (not considering labels,\n    // just the targets)\n    bool successorsAreSame() const {\n        if (nextBBs.size() < 2)\n            return true;\n\n        typename SuccContainerT::const_iterator start, iter, end;\n        iter = nextBBs.begin();\n        end = nextBBs.end();\n\n        BBlock<NodeT> *block = iter->target;\n        // iterate over all successor and\n        // check if they are all the same\n        for (++iter; iter != end; ++iter)\n            if (iter->target != block)\n                return false;\n\n        return true;\n    }\n\n    // return true if all successors point\n    // to the same basic block (not considering labels,\n    // just the targets)\n    bool hasSuccessor(BBlock<NodeT> *B) const {\n        return dg::any_of(successors(), [B](const BBlockEdge &succB) {\n            return succB.target == B;\n        });\n    }\n\n    // remove all edges from/to this BB and reconnect them to\n    // other nodes\n    void isolate() {\n        // take every predecessor and reconnect edges from it\n        // to successors\n        for (BBlock<NodeT> *pred : prevBBs) {\n            // find the edge that is going to this node\n            // and create new edges to all successors. The new edges\n            // will have the same label as the found one\n            DGContainer<BBlockEdge> new_edges;\n            for (auto I = pred->nextBBs.begin(), E = pred->nextBBs.end();\n                 I != E;) {\n                auto cur = I++;\n                if (cur->target == this) {\n                    // create edges that will go from the predecessor\n                    // to every successor of this node\n                    for (const BBlockEdge &succ : nextBBs) {\n                        // we cannot create an edge to this bblock (we're\n                        // isolating _this_ bblock), that would be incorrect. It\n                        // can occur when we're isolatin a bblock with self-loop\n                        if (succ.target != this)\n                            new_edges.insert(\n                                    BBlockEdge(succ.target, cur->label));\n                    }\n\n                    // remove the edge from predecessor\n                    pred->nextBBs.erase(*cur);\n                }\n            }\n\n            // add newly created edges to predecessor\n            for (const BBlockEdge &edge : new_edges) {\n                assert(edge.target != this &&\n                       \"Adding an edge to a block that is being isolated\");\n                pred->addSuccessor(edge);\n            }\n        }\n\n        removeSuccessors();\n\n        // NOTE: nextBBs were cleared in removeSuccessors()\n        prevBBs.clear();\n\n        // remove reverse edges to this BB\n        for (BBlock<NodeT> *B : controlDeps) {\n            // we don't want to corrupt the iterator\n            // if this block is control dependent on itself.\n            // We're gonna clear it anyway\n            if (B == this)\n                continue;\n\n            B->revControlDeps.erase(this);\n        }\n\n        // clear also cd edges that blocks have\n        // to this block\n        for (BBlock<NodeT> *B : revControlDeps) {\n            if (B == this)\n                continue;\n\n            B->controlDeps.erase(this);\n        }\n\n        revControlDeps.clear();\n        controlDeps.clear();\n    }\n\n    void remove(bool with_nodes = true) {\n        // do not leave any dangling reference\n        isolate();\n\n        if (dg) {\n#ifndef NDEBUG\n            bool ret =\n#endif\n                    dg->removeBlock(key);\n            assert(ret && \"BUG: block was not in DG\");\n            if (dg->getEntryBB() == this)\n                dg->setEntryBB(nullptr);\n        }\n\n        if (with_nodes) {\n            for (NodeT *n : nodes) {\n                // we must set basic block to nullptr\n                // otherwise the node will try to remove the\n                // basic block again if it is of size 1\n                n->setBasicBlock(nullptr);\n\n                // remove dependency edges, let be CFG edges\n                // as we'll destroy all the nodes\n                n->removeCDs();\n                n->removeDDs();\n                // remove the node from dg\n                assert(n->getDG());\n                n->getDG()->removeNode(n);\n\n                delete n;\n            }\n        }\n\n        delete this;\n    }\n\n    void removeNode(NodeT *n) { nodes.remove(n); }\n\n    size_t successorsNum() const { return nextBBs.size(); }\n    size_t predecessorsNum() const { return prevBBs.size(); }\n\n    bool addSuccessor(const BBlockEdge &edge) {\n        bool ret = nextBBs.insert(edge);\n        edge.target->prevBBs.insert(this);\n\n        return ret;\n    }\n\n    bool addSuccessor(BBlock<NodeT> *b, uint8_t label = 0) {\n        return addSuccessor(BBlockEdge(b, label));\n    }\n\n    void removeSuccessors() {\n        // remove references to this node from successors\n        for (const BBlockEdge &succ : nextBBs) {\n            // This assertion does not hold anymore, since if we have\n            // two edges with different labels to the same successor,\n            // and we remove the successor, then we remove 'this'\n            // from prevBBs twice. If we'll add labels even to predecessors,\n            // this assertion must hold again\n            // bool ret = succ.target->prevBBs.erase(this);\n            // assert(ret && \"Did not have this BB in successor's pred\");\n            succ.target->prevBBs.erase(this);\n        }\n\n        nextBBs.clear();\n    }\n\n    bool hasSelfLoop() { return nextBBs.contains(this); }\n\n    void removeSuccessor(const BBlockEdge &succ) {\n        succ.target->prevBBs.erase(this);\n        nextBBs.erase(succ);\n    }\n\n    unsigned removeSuccessorsTarget(BBlock<NodeT> *target) {\n        unsigned removed = 0;\n        SuccContainerT tmp;\n        // approx\n        for (auto &edge : nextBBs) {\n            if (edge.target != target)\n                tmp.insert(edge);\n            else\n                ++removed;\n        }\n\n        nextBBs.swap(tmp);\n        return removed;\n    }\n\n    void removePredecessors() {\n        for (BBlock<NodeT> *BB : prevBBs)\n            BB->nextBBs.erase(this);\n\n        prevBBs.clear();\n    }\n\n    bool addControlDependence(BBlock<NodeT> *b) {\n        bool ret;\n#ifndef NDEBUG\n        bool ret2;\n#endif\n\n        ret = controlDeps.insert(b);\n#ifndef NDEBUG\n        ret2 =\n#endif\n                b->revControlDeps.insert(this);\n\n        // we either have both edges or none\n        assert(ret == ret2);\n\n        return ret;\n    }\n\n    // get first node from bblock\n    // or nullptr if the block is empty\n    NodeT *getFirstNode() const {\n        if (nodes.empty())\n            return nullptr;\n\n        return nodes.front();\n    }\n\n    // get last node from block\n    // or nullptr if the block is empty\n    NodeT *getLastNode() const {\n        if (nodes.empty())\n            return nullptr;\n\n        return nodes.back();\n    }\n\n    // XXX: do this optional?\n    BBlockContainerT &getPostDomFrontiers() { return postDomFrontiers; }\n    const BBlockContainerT &getPostDomFrontiers() const {\n        return postDomFrontiers;\n    }\n\n    bool addPostDomFrontier(BBlock<NodeT> *BB) {\n        return postDomFrontiers.insert(BB);\n    }\n\n    bool addDomFrontier(BBlock<NodeT> *DF) { return domFrontiers.insert(DF); }\n\n    BBlockContainerT &getDomFrontiers() { return domFrontiers; }\n    const BBlockContainerT &getDomFrontiers() const { return domFrontiers; }\n\n    void setIPostDom(BBlock<NodeT> *BB) {\n        assert(!ipostdom && \"Already has the immedate post-dominator\");\n        ipostdom = BB;\n        BB->postDominators.insert(this);\n    }\n\n    BBlock<NodeT> *getIPostDom() { return ipostdom; }\n    const BBlock<NodeT> *getIPostDom() const { return ipostdom; }\n\n    BBlockContainerT &getPostDominators() { return postDominators; }\n    const BBlockContainerT &getPostDominators() const { return postDominators; }\n\n    void setIDom(BBlock<NodeT> *BB) {\n        assert(!idom && \"Already has immediate dominator\");\n        idom = BB;\n        BB->addDominator(this);\n    }\n\n    void addDominator(BBlock<NodeT> *BB) {\n        assert(BB && \"need dominator bblock\");\n        dominators.insert(BB);\n    }\n\n    BBlock<NodeT> *getIDom() { return idom; }\n    const BBlock<NodeT> *getIDom() const { return idom; }\n\n    BBlockContainerT &getDominators() { return dominators; }\n    const BBlockContainerT &getDominators() const { return dominators; }\n\n    unsigned int getDFSOrder() const { return analysisAuxData.dfsorder; }\n\n    // in order to fasten up interprocedural analyses,\n    // we register all the call sites in the BBlock\n    unsigned int getCallSitesNum() const { return callSites.size(); }\n\n    const std::set<NodeT *> &getCallSites() { return callSites; }\n\n    bool addCallsite(NodeT *n) {\n        assert(n->getBBlock() == this &&\n               \"Cannot add callsite from different BB\");\n\n        return callSites.insert(n).second;\n    }\n\n    bool removeCallSite(NodeT *n) {\n        assert(n->getBBlock() == this && \"Removing callsite from different BB\");\n\n        return callSites.erase(n) != 0;\n    }\n\n    void setSlice(uint64_t sid) { slice_id = sid; }\n\n    uint64_t getSlice() const { return slice_id; }\n\n    void deleteNodesOnDestruction(bool v = true) { delete_nodes_on_destr = v; }\n\n  private:\n    // optional key\n    KeyT key;\n\n    // reference to dg if needed\n    DependenceGraphT *dg;\n\n    // nodes contained in this bblock\n    std::list<NodeT *> nodes;\n\n    SuccContainerT nextBBs;\n    PredContainerT prevBBs;\n\n    // when we have basic blocks, we do not need\n    // to keep control dependencies in nodes, because\n    // all nodes in block has the same control dependence\n    BBlockContainerT controlDeps;\n    BBlockContainerT revControlDeps;\n\n    // post-dominator frontiers\n    BBlockContainerT postDomFrontiers;\n    BBlock<NodeT> *ipostdom;\n    // the post-dominator tree edges\n    // (reverse to immediate post-dominator)\n    BBlockContainerT postDominators;\n\n    // parent of @this in dominator tree\n    BBlock<NodeT> *idom = nullptr;\n    // BB.dominators = all children in dominator tree\n    BBlockContainerT dominators;\n    // dominance frontiers\n    BBlockContainerT domFrontiers;\n\n    // is this block in some slice?\n    uint64_t slice_id{0};\n\n    // delete nodes on destruction of the block\n    bool delete_nodes_on_destr = false;\n\n    // auxiliary data for analyses\n    std::set<NodeT *> callSites;\n\n    // auxiliary data for different analyses\n    legacy::AnalysesAuxiliaryData analysisAuxData;\n    friend class legacy::BBlockAnalysis<NodeT>;\n};\n\n} // namespace dg\n\n#endif // _BBLOCK_H_\n"
  },
  {
    "path": "include/dg/BBlockBase.h",
    "content": "#ifndef DG_BBLOCK_BASE_H_\n#define DG_BBLOCK_BASE_H_\n\n#include <list>\n#include <vector>\n\nnamespace dg {\n\nclass ElemId {\n    static unsigned idcnt;\n    unsigned id;\n\n  public:\n    ElemId() : id(++idcnt) {}\n    unsigned getID() const { return id; }\n};\n\ntemplate <typename ElemT>\nclass ElemWithEdges {\n    using EdgesT = std::vector<ElemT *>;\n\n  protected:\n    EdgesT _successors;\n    EdgesT _predecessors;\n\n  public:\n    auto succ_begin() -> decltype(_successors.begin()) {\n        return _successors.begin();\n    }\n    auto succ_end() -> decltype(_successors.begin()) {\n        return _successors.end();\n    }\n    auto pred_begin() -> decltype(_predecessors.begin()) {\n        return _predecessors.begin();\n    }\n    auto pred_end() -> decltype(_predecessors.begin()) {\n        return _predecessors.end();\n    }\n    auto succ_begin() const -> decltype(_successors.begin()) {\n        return _successors.begin();\n    }\n    auto succ_end() const -> decltype(_successors.begin()) {\n        return _successors.end();\n    }\n    auto pred_begin() const -> decltype(_predecessors.begin()) {\n        return _predecessors.begin();\n    }\n    auto pred_end() const -> decltype(_predecessors.begin()) {\n        return _predecessors.end();\n    }\n\n    const EdgesT &successors() const { return _successors; }\n    const EdgesT &predecessors() const { return _predecessors; }\n\n    bool hasSuccessors() const { return !_successors.empty(); }\n    bool hasPredecessors() const { return !_predecessors.empty(); }\n\n    void addSuccessor(ElemT *s) {\n        for (auto *succ : _successors) {\n            if (succ == s)\n                return;\n        }\n\n        _successors.push_back(s);\n\n        for (auto *pred : s->_predecessors) {\n            if (pred == this)\n                return;\n        }\n        s->_predecessors.push_back(static_cast<ElemT *>(this));\n    }\n\n    ElemT *getSinglePredecessor() {\n        return _predecessors.size() == 1 ? _predecessors.back() : nullptr;\n    }\n\n    ElemT *getSingleSuccessor() {\n        return _successors.size() == 1 ? _successors.back() : nullptr;\n    }\n};\n\ntemplate <typename ElemT>\nclass CFGElement : public ElemId, public ElemWithEdges<ElemT> {};\n\ntemplate <typename ElemT, typename NodeT>\nclass BBlockBase : public CFGElement<ElemT> {\n    using NodesT = std::list<NodeT *>;\n\n    NodesT _nodes;\n\n  public:\n    void append(NodeT *n) {\n        _nodes.push_back(n);\n        n->setBBlock(static_cast<ElemT *>(this));\n    }\n    void prepend(NodeT *n) {\n        _nodes.push_front(n);\n        n->setBBlock(static_cast<ElemT *>(this));\n    }\n\n    void insertBefore(NodeT *n, NodeT *before) {\n        assert(!_nodes.empty());\n\n        auto it = _nodes.begin();\n        while (it != _nodes.end()) {\n            if (*it == before)\n                break;\n            ++it;\n        }\n        assert(it != _nodes.end() && \"Did not find 'before' node\");\n\n        _nodes.insert(it, n);\n        n->setBBlock(static_cast<ElemT *>(this));\n    }\n\n    // FIXME: rename to nodes()\n    const NodesT &getNodes() const { return _nodes; }\n    NodesT &getNodes() { return _nodes; }\n    // FIXME: rename to first/front(), last/back()\n    NodeT *getFirst() { return _nodes.empty() ? nullptr : _nodes.front(); }\n    NodeT *getLast() { return _nodes.empty() ? nullptr : _nodes.back(); }\n    const NodeT *getFirst() const {\n        return _nodes.empty() ? nullptr : _nodes.front();\n    }\n    const NodeT *getLast() const {\n        return _nodes.empty() ? nullptr : _nodes.back();\n    }\n\n    bool empty() const { return _nodes.empty(); }\n    auto size() const -> decltype(_nodes.size()) { return _nodes.size(); }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/BBlocksBuilder.h",
    "content": "#ifndef DG_BBLOCKS_BUILDER_H_\n#define DG_BBLOCKS_BUILDER_H_\n\n#include <cassert>\n#include <memory>\n\n#include \"dg/ADT/Queue.h\"\n\nnamespace dg {\n\n///\n// Generate basic blocks from nodes with successors.\ntemplate <typename BBlockT>\nclass BBlocksBuilder {\n    using NodeT = typename BBlockT::NodeT;\n\n    std::vector<std::unique_ptr<BBlockT>> _blocks;\n\n    // FIXME: use bitvector?\n    std::set<unsigned> _processed;\n    ADT::QueueFIFO<NodeT *> _queue;\n\n    bool enqueue(NodeT *n) {\n        // the id 0 is reserved for invalid nodes\n        assert(n->getID() != 0 && \"Queued invalid node\");\n\n        if (!static_cast<bool>(_processed.insert(n->getID()).second))\n            return false; // we already queued this node\n\n        _queue.push(n);\n        assert(enqueue(n) == false);\n        return true;\n    }\n\n    void setNewBlock(NodeT *cur) {\n        auto *blk = new BBlockT();\n        _blocks.emplace_back(blk);\n        blk->append(cur);\n        cur->setBBlock(blk);\n    }\n\n    void addToBlock(NodeT *cur, BBlockT *blk) {\n        cur->setBBlock(blk);\n        blk->append(cur);\n    }\n\n    void setBlock(NodeT *cur) {\n        if (cur->predecessorsNum() == 0      // root node\n            || cur->predecessorsNum() > 1) { // join\n            setNewBlock(cur);\n            return;\n        }\n\n        assert(cur->predecessorsNum() == 1);\n        // if we are the entry node after branching,\n        // we create a new block\n        if (cur->getSinglePredecessor()->successorsNum() > 1) {\n            setNewBlock(cur);\n            return;\n        }\n\n        // We are inside a block, set the block from\n        // the predecessor\n        assert(cur->getSinglePredecessor()->getBBlock());\n        addToBlock(cur, cur->getSinglePredecessor()->getBBlock());\n    }\n\n  public:\n    void buildBlocks(NodeT *root) {\n        enqueue(root);\n\n        while (!_queue.empty()) {\n            NodeT *cur = _queue.pop();\n            assert(cur->getBBlock() == nullptr);\n\n            setBlock(cur);\n\n            // queue successors for processing\n            for (NodeT *succ : cur->successors()) {\n                enqueue(succ);\n            }\n        }\n    }\n\n    std::vector<std::unique_ptr<BBlockT>> &getBlocks() { return _blocks; }\n\n    std::vector<std::unique_ptr<BBlockT>> &&buildAndGetBlocks(NodeT *root) {\n        buildBlocks(root);\n        return std::move(_blocks);\n    }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/BFS.h",
    "content": "#ifndef DG_BFS_H_\n#define DG_BFS_H_\n\n#include \"dg/ADT/Queue.h\"\n#include \"dg/NodesWalk.h\"\n\nusing dg::ADT::QueueFIFO;\n\nnamespace dg {\n\ntemplate <typename Node, typename VisitTracker = SetVisitTracker<Node>,\n          typename EdgeChooser = SuccessorsEdgeChooser<Node>>\nstruct BFS\n        : public NodesWalk<Node, QueueFIFO<Node *>, VisitTracker, EdgeChooser> {\n    BFS() = default;\n    BFS(EdgeChooser chooser)\n            : NodesWalk<Node, QueueFIFO<Node *>, VisitTracker, EdgeChooser>(\n                      std::move(chooser)) {}\n    BFS(VisitTracker tracker)\n            : NodesWalk<Node, QueueFIFO<Node *>, VisitTracker, EdgeChooser>(\n                      std::move(tracker)) {}\n    BFS(VisitTracker tracker, EdgeChooser chooser)\n            : NodesWalk<Node, QueueFIFO<Node *>, VisitTracker, EdgeChooser>(\n                      std::move(tracker), std::move(chooser)) {}\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/CallGraph/CallGraph.h",
    "content": "#ifndef DG_GENERIC_CALLGRAPH_H_\n#define DG_GENERIC_CALLGRAPH_H_\n\n#include <map>\n#include <vector>\n\n#include \"dg/util/iterators.h\"\n\nnamespace dg {\n\ntemplate <typename ValueT>\nclass GenericCallGraph {\n  public:\n    class FuncNode {\n        unsigned _id;\n        unsigned _scc_id{0};\n        std::vector<FuncNode *> _calls;\n        std::vector<FuncNode *> _callers;\n\n        template <typename Cont>\n        bool _contains(const FuncNode *x, const Cont &C) const {\n            return dg::any_of(C, [x](FuncNode *s) { return s == x; });\n        }\n\n      public:\n        const ValueT value;\n\n        FuncNode(unsigned id, const ValueT &nd) : _id(id), value(nd){};\n        FuncNode(FuncNode &&) = default;\n\n        bool calls(const FuncNode *x) const { return _contains(x, _calls); }\n        bool isCalledBy(FuncNode *x) const { return _contains(x, _callers); }\n\n        unsigned getID() const { return _id; }\n        unsigned getSCCId() const { return _scc_id; }\n        void setSCCId(unsigned id) { _scc_id = id; }\n\n        bool addCall(FuncNode *x) {\n            if (calls(x))\n                return false;\n            _calls.push_back(x);\n            if (!x->isCalledBy(this))\n                x->_callers.push_back(this);\n            return true;\n        }\n\n        const std::vector<FuncNode *> &getCalls() const { return _calls; }\n        // alias for getCalls()\n        const std::vector<FuncNode *> &successors() const { return getCalls(); }\n        const std::vector<FuncNode *> &getCallers() const { return _callers; }\n\n        const ValueT &getValue() const { return value; };\n    };\n\n  private:\n    unsigned last_id{0};\n\n    FuncNode *getOrCreate(const ValueT &v) {\n        auto it = _mapping.find(v);\n        if (it == _mapping.end()) {\n            auto newIt = _mapping.emplace(v, FuncNode(++last_id, v));\n            return &newIt.first->second;\n        }\n        return &it->second;\n    }\n\n    std::map<const ValueT, FuncNode> _mapping;\n\n  public:\n    // just create a node for the value\n    // (e.g., the entry node)\n    FuncNode *createNode(const ValueT &a) { return getOrCreate(a); }\n\n    // a calls b\n    bool addCall(const ValueT &a, const ValueT &b) {\n        auto A = getOrCreate(a);\n        auto B = getOrCreate(b);\n        return A->addCall(B);\n    }\n\n    const FuncNode *get(const ValueT &v) const {\n        auto it = _mapping.find(v);\n        if (it == _mapping.end()) {\n            return nullptr;\n        }\n        return &it->second;\n    }\n\n    FuncNode *get(const ValueT &v) {\n        auto it = _mapping.find(v);\n        if (it == _mapping.end()) {\n            return nullptr;\n        }\n        return &it->second;\n    }\n\n    bool empty() const { return _mapping.empty(); }\n\n    auto begin() -> decltype(_mapping.begin()) { return _mapping.begin(); }\n    auto end() -> decltype(_mapping.end()) { return _mapping.end(); }\n    auto begin() const -> decltype(_mapping.begin()) {\n        return _mapping.begin();\n    }\n    auto end() const -> decltype(_mapping.end()) { return _mapping.end(); }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/ControlDependence/ControlDependenceAnalysisOptions.h",
    "content": "#ifndef DG_CDA_OPTIONS_H_\n#define DG_CDA_OPTIONS_H_\n\n#include \"dg/AnalysisOptions.h\"\n\nnamespace dg {\n\nstruct ControlDependenceAnalysisOptions : AnalysisOptions {\n    // FIXME: add options class for CD\n    enum class CDAlgorithm {\n        STANDARD,\n        NTSCD_LEGACY,\n        NTSCD2,\n        NTSCD_RANGANATH,      // fixed version of Ranganath's alg.\n        NTSCD_RANGANATH_ORIG, // original (wrong) version of Ranaganath's alg.\n        NTSCD,\n        DOD_RANGANATH,\n        DOD,\n        DODNTSCD, // DOD + NTSCD\n        STRONG_CC\n    } algorithm;\n\n    // take into account interprocedural control dependencies\n    // (raising e.g., from calls to exit() which terminates the program)\n    bool interprocedural{true};\n\n    bool standardCD() const { return algorithm == CDAlgorithm::STANDARD; }\n    bool ntscdCD() const { return algorithm == CDAlgorithm::NTSCD; }\n    bool ntscd2CD() const { return algorithm == CDAlgorithm::NTSCD2; }\n    bool ntscdRanganathCD() const {\n        return algorithm == CDAlgorithm::NTSCD_RANGANATH;\n    }\n    bool ntscdRanganathOrigCD() const {\n        return algorithm == CDAlgorithm::NTSCD_RANGANATH_ORIG;\n    }\n    bool ntscdLegacyCD() const {\n        return algorithm == CDAlgorithm::NTSCD_LEGACY;\n    }\n    bool dodRanganathCD() const {\n        return algorithm == CDAlgorithm::DOD_RANGANATH;\n    }\n    bool dodCD() const { return algorithm == CDAlgorithm::DOD; }\n    bool dodntscdCD() const { return algorithm == CDAlgorithm::DODNTSCD; }\n    bool strongCC() const { return algorithm == CDAlgorithm::STRONG_CC; }\n    bool interproceduralCD() const { return interprocedural; }\n\n    ///\n    // Return true if the computed control dependencies\n    // contain NTSCD dependencies\n    bool isNonterminationSensitive() const {\n        // DOD is for infinite loops, but it is not what we\n        // want when asking for non-termination sensitive...\n        return !standardCD() && !dodCD() && !dodRanganathCD();\n    }\n};\n\n} // namespace dg\n#endif\n"
  },
  {
    "path": "include/dg/DFS.h",
    "content": "#ifndef DG_DFS_H_\n#define DG_DFS_H_\n\n#include \"dg/ADT/Queue.h\"\n#include \"dg/NodesWalk.h\"\n\nusing dg::ADT::QueueLIFO;\n\nnamespace dg {\n\ntemplate <typename Node, typename VisitTracker = SetVisitTracker<Node>,\n          typename EdgeChooser = SuccessorsEdgeChooser<Node>>\nstruct DFS\n        : public NodesWalk<Node, QueueLIFO<Node *>, VisitTracker, EdgeChooser> {\n    DFS() = default;\n    DFS(EdgeChooser chooser)\n            : NodesWalk<Node, QueueLIFO<Node *>, VisitTracker, EdgeChooser>(\n                      std::move(chooser)) {}\n    DFS(VisitTracker tracker)\n            : NodesWalk<Node, QueueLIFO<Node *>, VisitTracker, EdgeChooser>(\n                      std::move(tracker)) {}\n    DFS(VisitTracker tracker, EdgeChooser chooser)\n            : NodesWalk<Node, QueueLIFO<Node *>, VisitTracker, EdgeChooser>(\n                      std::move(tracker), std::move(chooser)) {}\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/DG2Dot.h",
    "content": "#ifndef DG_2_DOT_H_\n#define DG_2_DOT_H_\n\n#include <fstream>\n#include <iostream>\n#include <set>\n\n#include \"dg/DFS.h\"\n#include \"dg/DependenceGraph.h\"\n\nnamespace dg {\nnamespace debug {\n\nenum dg2dot_options {\n    PRINT_NONE = 0, // print no edges\n    PRINT_CFG = 1 << 0,\n    PRINT_REV_CFG = 1 << 1,\n    PRINT_DD = 1 << 2,\n    PRINT_REV_DD = 1 << 3,\n    PRINT_USE = 1 << 4,\n    PRINT_USER = 1 << 5,\n    PRINT_CD = 1 << 6,\n    PRINT_REV_CD = 1 << 7,\n    PRINT_ID = 1 << 8,\n    PRINT_REV_ID = 1 << 9,\n    PRINT_CALL = 1 << 10,\n    PRINT_POSTDOM = 1 << 11,\n    PRINT_ALL = 0xfff\n};\n\nstruct Indent {\n    int ind;\n    Indent(int ind = 1) : ind(ind) {}\n    friend std::ostream &operator<<(std::ostream &os, const Indent &ind);\n};\n\nstd::ostream &operator<<(std::ostream &os, const Indent &ind) {\n    for (int i = 0; i < ind.ind; ++i)\n        os << \"\\t\";\n\n    return os;\n}\n\ntemplate <typename NodeT>\nclass DG2Dot {\n    std::set<const typename DependenceGraph<NodeT>::ContainerType *>\n            dumpedGlobals;\n    // slicing criteria\n    std::set<NodeT *> criteria;\n\n  public:\n    using KeyT = typename NodeT::KeyType;\n\n    DG2Dot<NodeT>(DependenceGraph<NodeT> *dg,\n                  uint32_t opts = PRINT_CFG | PRINT_DD | PRINT_CD | PRINT_USE,\n                  const char *file = nullptr)\n            : options(opts), dg(dg), file(file) {\n        // if a graph has no global nodes, this will forbid trying to print them\n        dumpedGlobals.insert(nullptr);\n        reopen(file);\n    }\n\n    void setSlicingCriteria(const std::set<NodeT *> &crit) { criteria = crit; }\n\n    bool open(const char *new_file) {\n        if (out.is_open()) {\n            std::cerr << \"File already opened (\" << file << \")\" << std::endl;\n            return false;\n        }\n        reopen(new_file);\n    }\n\n    virtual std::ostream &printKey(std::ostream &os, KeyT key) {\n        os << key;\n        return os;\n    }\n\n    // \\return - error state: true if there's an error, false otherwise\n    virtual bool checkNode(std::ostream &os, NodeT *node) {\n        bool err = false;\n\n        if (!node->getBBlock()) {\n            err = true;\n            os << \"\\\\nERR: no BB\";\n        }\n\n        return err;\n    }\n\n    bool ensureFile(const char *fl) {\n        if (fl)\n            reopen(fl);\n\n        if (!out.is_open()) {\n            std::cerr << \"File '\" << file << \"' not opened\" << std::endl;\n            return false;\n        }\n\n        return true;\n    }\n\n    virtual bool dump(const char *new_file = nullptr,\n                      const char *only_functions = nullptr) {\n        (void) only_functions;\n\n        if (!ensureFile(new_file))\n            return false;\n\n        start();\n\n#ifdef ENABLE_CFG\n        dumpBBs(dg);\n#endif\n\n        // even when we have printed nodes while\n        // going through BBs, print nodes again,\n        // so that we'll see if there are any nodes\n        // that are not in BBs\n        dump_nodes();\n        dump_edges();\n\n        // print subgraphs once we printed all the nodes\n        if (!subgraphs.empty())\n            out << \"\\n\\t/* ----------- SUBGRAPHS ---------- */\\n\\n\";\n        for (auto sub : subgraphs) {\n            dump_subgraph(sub);\n        }\n\n        end();\n\n        out.close();\n        return true;\n    }\n\n    /* if user want's manual printing, he/she can */\n\n    void start() {\n        out << \"digraph \\\"DependenceGraph\\\" {\\n\";\n        out << \"\\tcompound=true label=\\\"Graph \" << dg << \" has \" << dg->size()\n            << \" nodes\\\\n\\n\"\n            << \"\\tdd edges color: \" << dd_color << \"\\n\"\n            << \"\\tuse edges color: \" << use_color << \", dashed\\n\"\n            << \"\\tcd edges color: \" << cd_color << \"\\n\"\n            << \"\\tcfg edges color: \" << cfg_color << \"\\\"\\n\\n\";\n    }\n\n    void end() { out << \"}\\n\"; }\n\n    void dumpSubgraphStart(DependenceGraph<NodeT> *sub,\n                           const char *name = nullptr) {\n        out << \"\\t/* subgraph \" << sub << \" nodes */\\n\";\n        out << \"\\tsubgraph cluster_\" << sub << \" {\\n\";\n        out << \"\\t\\tstyle=\\\"filled, rounded\\\" fillcolor=gray95\\n\";\n        out << \"\\t\\tlabel=\\\"Subgraph \";\n        if (name)\n            out << name << \" \";\n\n        out << \"[\" << sub << \"]\"\n            << \"\\\\nhas \" << sub->size() << \" nodes\\n\";\n\n        uint64_t slice_id = sub->getSlice();\n        if (slice_id != 0)\n            out << \"\\\\nslice: \" << slice_id;\n\n        out << \"\\\"\\n\";\n\n        // dump BBs of the formal parameters\n        dump_parameters(sub, 2);\n    }\n\n    void dumpSubgraphEnd(DependenceGraph<NodeT> *sub, bool with_nodes = true) {\n        if (with_nodes) {\n            // dump all nodes, to get it without BBlocks\n            // (we may not have BBlocks or we just don't want\n            // to print them\n            for (auto &I : *sub) {\n                dump_node(I.second, 2);\n                dump_node_edges(I.second, 2);\n            }\n\n            if (dumpedGlobals.insert(sub->getGlobalNodes().get()).second) {\n                for (auto &I : *sub->getGlobalNodes()) {\n                    dump_node(I.second, 2, \"GLOB\");\n                    dump_node_edges(I.second, 2);\n                }\n            }\n        }\n\n        out << \"\\t}\\n\";\n    }\n\n    void dumpSubgraph(DependenceGraph<NodeT> *sub) {\n        dumpSubgraphStart(sub);\n        dumpSubgraphEnd(sub);\n    }\n\n    void dumpBBlock(BBlock<NodeT> *BB, int ind = 2) { dumpBB(BB, ind); }\n\n    void dumpBBlockEdges(BBlock<NodeT> *BB, int ind = 1) {\n        dumpBBedges(BB, ind);\n    }\n\n  private:\n    // what all to print?\n    uint32_t options;\n\n    void reopen(const char *new_file) {\n        if (!new_file)\n            new_file = \"/dev/stdout\";\n\n        if (out.is_open())\n            out.close();\n\n        out.open(new_file);\n        file = new_file;\n    }\n\n    void dumpBB(const BBlock<NodeT> *BB, int indent) {\n        Indent Ind(indent);\n\n        out << Ind << \"/* Basic Block \";\n        printKey(out, BB->getKey());\n        out << \" [\" << BB << \"] */\\n\";\n        out << Ind << \"subgraph cluster_bb_\" << BB << \" {\\n\";\n        out << Ind << \"\\tstyle=filled fillcolor=white\\n\";\n        out << Ind << \"\\tlabel=\\\"\";\n\n        printKey(out, BB->getKey());\n        out << \" [\" << BB << \"]\";\n\n        unsigned int dfsorder = BB->getDFSOrder();\n        if (dfsorder != 0)\n            out << Ind << \"\\\\ndfs order: \" << dfsorder;\n\n        uint64_t slice_id = BB->getSlice();\n        if (slice_id != 0)\n            out << \"\\\\nslice: \" << slice_id;\n\n        out << \"\\\"\\n\";\n\n        for (NodeT *n : BB->getNodes()) {\n            // print nodes in BB, edges will be printed later\n            out << Ind << \"\\tNODE\" << n << \" [shape=rect label=\\\"\"\n                << n->getKey() << \"\\\"]\\n\";\n        }\n\n        out << Ind << \"} /* cluster_bb_\" << BB << \" */\\n\\n\";\n    }\n\n    void dumpBBedges(BBlock<NodeT> *BB, int indent) {\n        Indent Ind(indent);\n\n        if (options & PRINT_CFG) {\n            for (auto S : BB->successors()) {\n                NodeT *lastNode = BB->getLastNode();\n                NodeT *firstNode = S.target->getFirstNode();\n\n                out << Ind << \"NODE\" << lastNode << \" -> \"\n                    << \"NODE\" << firstNode << \" [penwidth=2 label=\\\"\"\n                    << static_cast<int>(S.label) << \"\\\"\"\n                    << \"  ltail=cluster_bb_\" << BB << \"  lhead=cluster_bb_\"\n                    << S.target << \"  color=\\\"\" << cfg_color << \"\\\"\"\n                    << \"]\\n\";\n            }\n        }\n\n        if (options & PRINT_REV_CFG) {\n            for (auto S : BB->predecessors()) {\n                NodeT *lastNode = S->getLastNode();\n                NodeT *firstNode = BB->getFirstNode();\n\n                out << Ind << \"NODE\" << firstNode << \" -> \"\n                    << \"NODE\" << lastNode << \" [penwidth=2 color=\\\"\"\n                    << cfg_color << \"\\\" dashed\"\n                    << \"  ltail=cluster_bb_\" << BB << \"  lhead=cluster_bb_\" << S\n                    << \" constraint=false]\\n\";\n            }\n        }\n\n        if (options & PRINT_CD) {\n            for (auto S : BB->controlDependence()) {\n                NodeT *lastNode = BB->getLastNode();\n                NodeT *firstNode = S->getFirstNode();\n\n                out << Ind << \"NODE\" << lastNode << \" -> \"\n                    << \"NODE\" << firstNode << \" [penwidth=2 color=blue\"\n                    << \"  ltail=cluster_bb_\" << BB << \"  lhead=cluster_bb_\" << S\n                    << \"]\\n\";\n            }\n\n            for (BBlock<NodeT> *S : BB->getPostDomFrontiers()) {\n                NodeT *start = BB->getFirstNode();\n                NodeT *end = S->getLastNode();\n\n                out << Ind << \"/* post-dominance frontiers */\\n\"\n                    << \"NODE\" << start << \" -> \"\n                    << \"NODE\" << end << \" [penwidth=3 color=green\"\n                    << \"  ltail=cluster_bb_\" << BB << \"  lhead=cluster_bb_\" << S\n                    << \" constraint=false]\\n\";\n            }\n        }\n\n        if (options & PRINT_POSTDOM) {\n            BBlock<NodeT> *ipd = BB->getIPostDom();\n            if (ipd) {\n                NodeT *firstNode = BB->getFirstNode();\n                NodeT *lastNode = ipd->getLastNode();\n\n                out << Ind << \"NODE\" << lastNode << \" -> \"\n                    << \"NODE\" << firstNode << \" [penwidth=3 color=purple\"\n                    << \"  ltail=cluster_bb_\" << BB << \"  lhead=cluster_bb_\"\n                    << ipd << \" constraint=false]\\n\";\n            }\n        }\n    }\n\n    void dump_parameters(NodeT *node, int ind) {\n        DGParameters<NodeT> *params = node->getParameters();\n\n        if (params) {\n            dump_parameters(params, ind, false);\n        }\n    }\n\n    void dump_parameters(DependenceGraph<NodeT> *g, int ind) {\n        DGParameters<NodeT> *params = g->getParameters();\n\n        if (params) {\n            dump_parameters(params, ind, true);\n        }\n    }\n\n    void dump_parameters(DGParameters<NodeT> *params, int ind, bool formal) {\n        Indent Ind(ind);\n\n        // FIXME\n        // out << Ind << \"/* Input parameters */\\n\";\n        // dumpBB(params->getBBIn(), data);\n        // out << Ind << \"/* Output parameters */\\n\";\n        // dumpBB(params->getBBOut(), data);\n\n        // dump all the nodes again to get the names\n        for (auto it : *params) {\n            auto &p = it.second;\n            if (p.in) {\n                dump_node(p.in, ind, formal ? \"[f] IN ARG\" : \"IN ARG\");\n                dump_node_edges(p.in, ind);\n            } else\n                out << \"NO IN ARG\";\n\n            if (p.out) {\n                dump_node(p.out, ind, formal ? \"[f] OUT ARG\" : \"OUT ARG\");\n                dump_node_edges(p.out, ind);\n            } else\n                out << \"NO OUT ARG\";\n        }\n\n        for (auto I = params->global_begin(), E = params->global_end(); I != E;\n             ++I) {\n            auto &p = I->second;\n            if (p.in) {\n                dump_node(p.in, ind, formal ? \"[f] GLOB IN\" : \"GLOB IN\");\n                dump_node_edges(p.in, ind);\n            } else\n                out << \"NO GLOB IN ARG\";\n\n            if (p.out) {\n                dump_node(p.out, ind, formal ? \"[f] GLOB OUT\" : \"GLOB OUT\");\n                dump_node_edges(p.out, ind);\n            } else\n                out << \"NO GLOB OUT ARG\";\n        }\n\n        auto p = params->getVarArg();\n        if (p) {\n            if (p->in) {\n                dump_node(p->in, ind, \"[va] IN ARG\");\n                dump_node_edges(p->in, ind);\n            } else\n                out << \"NO IN va ARG\";\n\n            if (p->out) {\n                dump_node(p->out, ind, \"[va] OUT ARG\");\n                dump_node_edges(p->out, ind);\n            } else\n                out << \"NO OUT ARG\";\n        }\n\n        if (auto *noret = params->getNoReturn()) {\n            dump_node(noret, ind, \"[noret]\");\n            dump_node_edges(noret, ind);\n        }\n    }\n\n    void dump_subgraph(DependenceGraph<NodeT> *sub) {\n        dumpSubgraphStart(sub);\n\n#ifdef ENABLE_CFG\n        // dump BBs in the subgraph\n        dumpBBs(sub, 2);\n#endif\n\n        // dump all nodes again, if there is any that is\n        // not in any BB\n        for (auto &I : *sub)\n            dump_node(I.second, 2);\n        // dump edges between nodes\n        for (auto &I : *sub)\n            dump_node_edges(I.second, 2);\n\n        dumpSubgraphEnd(sub);\n    }\n\n    void dumpBBs(DependenceGraph<NodeT> *graph, int ind = 1) {\n        for (auto it : graph->getBlocks())\n            dumpBB(it.second, ind);\n\n        // print CFG edges between BBs\n        if (options & (PRINT_CFG | PRINT_REV_CFG)) {\n            out << Indent(ind) << \"/* CFG edges */\\n\";\n            for (auto it : graph->getBlocks())\n                dumpBBedges(it.second, ind);\n        }\n    }\n\n    void dump_node(NodeT *node, int ind = 1, const char *prefix = nullptr) {\n        bool err = false;\n        unsigned int dfsorder = node->getDFSOrder();\n        unsigned int bfsorder = node->getDFSOrder();\n        uint32_t slice_id = node->getSlice();\n        Indent Ind(ind);\n\n        out << Ind << \"NODE\" << node << \" [label=\\\"\";\n\n        if (prefix)\n            out << prefix << \" \";\n\n        printKey(out, node->getKey());\n\n        if (node->hasSubgraphs())\n            out << \"\\\\nsubgraphs: \" << node->subgraphsNum();\n        if (dfsorder != 0)\n            out << \"\\\\ndfs order: \" << dfsorder;\n        if (bfsorder != 0)\n            out << \"\\\\nbfs order: \" << bfsorder;\n\n        if (slice_id != 0)\n            out << \"\\\\nslice: \" << slice_id;\n\n        // check if the node is OK, and if not\n        // highlight it\n        err = checkNode(out, node);\n\n        // end of label\n        out << \"\\\" \";\n\n        if (err) {\n            out << \"style=filled fillcolor=red\";\n        } else if (criteria.count(node) > 0) {\n            out << \"style=filled fillcolor=orange\";\n        } else if (slice_id != 0)\n            out << \"style=filled fillcolor=greenyellow\";\n        else\n            out << \"style=filled fillcolor=white\";\n\n        out << \"]\\n\";\n\n        dump_parameters(node, ind);\n        if (node->hasSubgraphs() && (options & PRINT_CALL)) {\n            // add call-site to callee edges\n            for (auto subgraph : node->getSubgraphs()) {\n                out << Ind << \"NODE\" << node << \" -> NODE\"\n                    << subgraph->getEntry() << \" [label=\\\"call\\\"\"\n                    << \"  lhead=cluster_\" << subgraph\n                    << \" penwidth=3 style=dashed]\\n\";\n            }\n        }\n    }\n\n    void dump_nodes() {\n        out << \"\\t/* nodes */\\n\";\n        for (auto &I : *dg) {\n            auto *node = I.second;\n\n            dump_node(node);\n\n            for (auto subgraph : node->getSubgraphs()) {\n                subgraphs.insert(subgraph);\n            }\n        }\n\n        if (dumpedGlobals.insert(dg->getGlobalNodes().get()).second)\n            for (auto &I : *dg->getGlobalNodes())\n                dump_node(I.second, 1, \"GL\");\n    }\n\n    void dump_edges() {\n        for (auto &I : *dg) {\n            dump_node_edges(I.second);\n        }\n\n        if (dumpedGlobals.insert(dg->getGlobalNodes().get()).second)\n            for (auto &I : *dg->getGlobalNodes())\n                dump_node_edges(I.second);\n    }\n\n    void dump_node_edges(NodeT *n, int ind = 1) {\n        Indent Ind(ind);\n\n        out << Ind << \"/* -- node \" << n->getKey() << \"\\n\"\n            << Ind << \" * ------------------------------------------- */\\n\";\n\n        if (options & PRINT_DD) {\n            out << Ind << \"/* DD edges */\\n\";\n            for (auto II = n->data_begin(), EE = n->data_end(); II != EE; ++II)\n                out << Ind << \"NODE\" << n << \" -> NODE\" << *II << \" [color=\\\"\"\n                    << dd_color << \"\\\" rank=max]\\n\";\n        }\n\n        if (options & PRINT_REV_DD) {\n            out << Ind << \"/* reverse DD edges */\\n\";\n            for (auto II = n->rev_data_begin(), EE = n->rev_data_end();\n                 II != EE; ++II)\n                out << Ind << \"NODE\" << n << \" -> NODE\" << *II << \" [color=\\\"\"\n                    << dd_color << \"\\\" style=\\\"dashed\\\"  constraint=false]\\n\";\n        }\n\n        if (options & PRINT_USE) {\n            out << Ind << \"/* USE edges */\\n\";\n            for (auto II = n->use_begin(), EE = n->use_end(); II != EE; ++II)\n                out << Ind << \"NODE\" << n << \" -> NODE\" << *II << \" [color=\\\"\"\n                    << use_color << \"\\\" rank=max style=\\\"dashed\\\"]\\n\";\n        }\n\n        if (options & PRINT_USER) {\n            out << Ind << \"/* user edges */\\n\";\n            for (auto II = n->user_begin(), EE = n->user_end(); II != EE; ++II)\n                out << Ind << \"NODE\" << n << \" -> NODE\" << *II << \" [color=\\\"\"\n                    << use_color << \"\\\" style=\\\"dashed\\\"  constraint=false]\\n\";\n        }\n\n        if (options & PRINT_CD) {\n            out << Ind << \"/* CD edges */\\n\";\n            for (auto II = n->control_begin(), EE = n->control_end(); II != EE;\n                 ++II)\n                out << Ind << \"NODE\" << n << \" -> NODE\" << *II << \" [color=\\\"\"\n                    << cd_color << \"\\\"]\\n\";\n        }\n\n        if (options & PRINT_REV_CD) {\n            out << Ind << \"/* reverse CD edges */\\n\";\n            for (auto II = n->rev_control_begin(), EE = n->rev_control_end();\n                 II != EE; ++II)\n                out << Ind << \"NODE\" << n << \" -> NODE\" << *II << \" [color=\\\"\"\n                    << cd_color << \"\\\" style=\\\"dashed\\\" constraint=false]\\n\";\n        }\n\n        if (options & PRINT_ID) {\n            out << Ind << \"/* ID edges */\\n\";\n            for (auto II = n->interference_begin(), EE = n->interference_end();\n                 II != EE; ++II)\n                out << Ind << \"NODE\" << n << \" -> NODE\" << *II\n                    << \" [color=\\\"red\\\" constraint=false]\\n\";\n        }\n\n        if (options & PRINT_REV_ID) {\n            out << Ind << \"/* reverse ID edges */\\n\";\n            for (auto II = n->rev_interference_begin(),\n                      EE = n->rev_interference_end();\n                 II != EE; ++II)\n                out << Ind << \"NODE\" << n << \" -> NODE\" << *II\n                    << \" [color=\\\"orange\\\" constraint=false]\\n\";\n        }\n    }\n\n    const char *dd_color = \"cyan4\";\n    const char *use_color = \"black\";\n    const char *cd_color = \"blue\";\n    const char *cfg_color = \"gray\";\n\n    DependenceGraph<NodeT> *dg;\n    const char *file;\n    std::set<DependenceGraph<NodeT> *> subgraphs;\n\n  protected:\n    std::ofstream out;\n};\n\n} // namespace debug\n} // namespace dg\n\n#endif // DG_2_DOT_H_\n"
  },
  {
    "path": "include/dg/DGParameters.h",
    "content": "#ifndef DG_PARAMETERS_H_\n#define DG_PARAMETERS_H_\n\n#include <map>\n#include <memory>\n#include <utility>\n\n#include \"BBlock.h\"\n\nnamespace dg {\n\ntemplate <typename NodeT>\nstruct DGParameterPair {\n    DGParameterPair<NodeT>(NodeT *v1, NodeT *v2) : in(v1), out(v2) {}\n\n    // input value of parameter\n    NodeT *in;\n    // output value of parameter\n    NodeT *out;\n\n    void removeIn() {\n        if (in) {\n            in->isolate();\n            delete in;\n            in = nullptr;\n        }\n    }\n\n    void removeOut() {\n        if (out) {\n            out->isolate();\n            delete out;\n            out = nullptr;\n        }\n    }\n};\n\n// --------------------------------------------------------\n// --- Parameters of functions\n//\n//  DGParameters keep list of function parameters (arguments).\n//  Each parameter is a pair - input and output value and is\n//  represented as a node in the dependence graph.\n//  Moreover, there are BBlocks for input and output parameters\n//  so that the parameters can be used in BBlock analysis\n// --------------------------------------------------------\ntemplate <typename NodeT>\nclass DGParameters {\n  public:\n    using KeyT = typename NodeT::KeyType;\n    using ContainerType = std::map<KeyT, DGParameterPair<NodeT>>;\n    using iterator = typename ContainerType::iterator;\n    using const_iterator = typename ContainerType::const_iterator;\n\n    DGParameters<NodeT>(NodeT *cs = nullptr)\n            : BBIn(new BBlock<NodeT>), BBOut(new BBlock<NodeT>), callSite(cs) {}\n\n    ~DGParameters<NodeT>() {\n        // delete the parameters itself\n        for (const auto &par : *this) {\n            delete par.second.in;\n            delete par.second.out;\n        }\n\n        // delete globals parameters\n        for (const auto &gl : globals) {\n            delete gl.second.in;\n            delete gl.second.out;\n        }\n\n#ifdef ENABLE_CFG\n        // delete auxiliary basic blocks\n        delete BBIn;\n        delete BBOut;\n#endif\n    }\n\n    DGParameterPair<NodeT> *operator[](KeyT k) { return find(k); }\n    const DGParameterPair<NodeT> *operator[](KeyT k) const { return find(k); }\n\n    template <typename... Args>\n    std::pair<NodeT *, NodeT *> construct(KeyT k, Args... args) {\n        auto *in = new NodeT(args...);\n        auto *out = new NodeT(args...);\n        add(k, in, out, &params);\n        return {in, out};\n    }\n\n    template <typename... Args>\n    std::pair<NodeT *, NodeT *> constructGlobal(KeyT k, Args... args) {\n        auto *in = new NodeT(args...);\n        auto *out = new NodeT(args...);\n        add(k, in, out, &globals);\n        return {in, out};\n    }\n\n    DGParameterPair<NodeT> *findGlobal(KeyT k) { return find(k, &globals); }\n\n    DGParameterPair<NodeT> *findParameter(KeyT k) { return find(k, &params); }\n\n    DGParameterPair<NodeT> *find(KeyT k) {\n        auto ret = findParameter(k);\n        if (!ret)\n            return findGlobal(k);\n\n        return ret;\n    }\n\n    const DGParameterPair<NodeT> *findParameter(KeyT k) const {\n        return findParameter(k);\n    }\n\n    const DGParameterPair<NodeT> *findGlobal(KeyT k) const {\n        return findGlobal(k);\n    }\n    const DGParameterPair<NodeT> *find(KeyT k) const { return find(k); }\n\n    void remove(KeyT k) { params.erase(k); }\n\n    void removeIn(KeyT k) {\n        auto p = find(k);\n        if (!p)\n            return;\n\n        p->removeIn();\n\n        // if we do not have the other, just remove whole param\n        if (!p->out)\n            params.erase(k);\n    }\n\n    void removeOut(KeyT k) {\n        auto p = find(k);\n        if (!p)\n            return;\n\n        p->removeOut();\n\n        // if we do not have the other, just remove whole param\n        if (!p->in)\n            params.erase(k);\n    }\n\n    size_t paramsNum() const { return params.size(); }\n    size_t globalsNum() const { return globals.size(); }\n    size_t size() const { return params.size() + globals.size(); }\n\n    iterator begin() { return params.begin(); }\n    const_iterator begin() const { return params.begin(); }\n    iterator end() { return params.end(); }\n    const_iterator end() const { return params.end(); }\n\n    iterator global_begin() { return globals.begin(); }\n    const_iterator global_begin() const { return globals.begin(); }\n    iterator global_end() { return globals.end(); }\n    const_iterator global_end() const { return globals.end(); }\n\n    const BBlock<NodeT> *getBBIn() const { return BBIn; }\n    const BBlock<NodeT> *getBBOut() const { return BBOut; }\n    BBlock<NodeT> *getBBIn() { return BBIn; }\n    BBlock<NodeT> *getBBOut() { return BBOut; }\n\n    DGParameterPair<NodeT> *getVarArg() { return vararg.get(); }\n    const DGParameterPair<NodeT> *getVarArg() const { return vararg.get(); }\n    bool setVarArg(NodeT *in, NodeT *out) {\n        assert(!vararg && \"Already has a vararg parameter\");\n\n        vararg.reset(new DGParameterPair<NodeT>(in, out));\n        return true;\n    }\n\n    NodeT *getNoReturn() { return noret.get(); }\n    const NodeT *getNoReturn() const { return noret.get(); }\n    bool addNoReturn(NodeT *n) {\n        assert(!noret && \"Already has the noret parameter\");\n\n        noret.reset(n);\n        return true;\n    }\n\n    const NodeT *getCallSite() const { return callSite; }\n    NodeT *getCallSite() { return callSite; }\n    void setCallSite(NodeT *n) { return callSite = n; }\n\n  private:\n    // globals represented as a parameter\n    ContainerType globals;\n    // usual parameters\n    ContainerType params;\n\n    // this is parameter that represents\n    // formal vararg parameters. It is only one, because without\n    // any further analysis, we cannot tell apart the formal varargs\n    std::unique_ptr<DGParameterPair<NodeT>> vararg{};\n    // node representing that the function may not return\n    // -- we can add control dependencies to this node\n    std::unique_ptr<NodeT> noret{};\n\n    BBlock<NodeT> *BBIn;\n    BBlock<NodeT> *BBOut;\n    NodeT *callSite;\n\n    DGParameterPair<NodeT> *find(KeyT k, ContainerType *C) {\n        iterator it = C->find(k);\n        if (it == C->end())\n            return nullptr;\n\n        return &(it->second);\n    }\n\n    bool add(KeyT k, NodeT *val_in, NodeT *val_out, ContainerType *C) {\n        auto v = std::make_pair(k, DGParameterPair<NodeT>(val_in, val_out));\n        if (!C->insert(v).second)\n            // we already has param with this key\n            return false;\n\n        BBIn->append(val_in);\n        BBOut->append(val_out);\n\n        return true;\n    }\n};\n\n} // namespace dg\n\n#endif // DG_PARAMETERS_H_\n"
  },
  {
    "path": "include/dg/DataDependence/DataDependence.h",
    "content": "#ifndef DG_DATA_DEPENDENCE_ANALYSIS_H_\n#define DG_DATA_DEPENDENCE_ANALYSIS_H_\n\n#include <cassert>\n#include <memory>\n\n#include \"dg/DataDependence/DataDependenceAnalysisImpl.h\"\n#include \"dg/DataDependence/DataDependenceAnalysisOptions.h\"\n#include \"dg/MemorySSA/MemorySSA.h\"\n#include \"dg/Offset.h\"\n#include \"dg/ReadWriteGraph/ReadWriteGraph.h\"\n\n#include \"dg/util/debug.h\"\n\nnamespace dg {\nnamespace dda {\n\n// here the types are for type-checking (optional - user can do it\n// when building the graph) and for later optimizations\n\nclass DataDependenceAnalysis {\n    // the implementation either uses reaching definitions\n    // or transformation to SSA\n    std::unique_ptr<DataDependenceAnalysisImpl> _impl;\n\n    static DataDependenceAnalysisImpl *\n    createAnalysis(ReadWriteGraph &&graph,\n                   const DataDependenceAnalysisOptions &opts) {\n        assert(opts.isSSA() && \"Unsupported analysis\");\n        return new MemorySSATransformation(std::move(graph), opts);\n    }\n\n    const DataDependenceAnalysisOptions &_options;\n\n  public:\n    DataDependenceAnalysis(ReadWriteGraph &&graph,\n                           const DataDependenceAnalysisOptions &opts)\n            : _impl(createAnalysis(std::move(graph), opts)), _options(opts) {}\n\n    DataDependenceAnalysis(ReadWriteGraph &&graph)\n            : DataDependenceAnalysis(std::move(graph), {}) {}\n\n    ReadWriteGraph *getGraph() { return _impl->getGraph(); }\n    const ReadWriteGraph *getGraph() const { return _impl->getGraph(); }\n\n    // run the analysis\n    void run() { _impl->run(); }\n\n    // return the reaching definitions of ('mem', 'off', 'len')\n    // at the location 'where'\n    std::vector<RWNode *> getDefinitions(RWNode *where, RWNode *mem,\n                                         const Offset &off, const Offset &len) {\n        return _impl->getDefinitions(where, mem, off, len);\n    }\n\n    // return reaching definitions of a node that represents\n    // the given use\n    std::vector<RWNode *> getDefinitions(RWNode *use) {\n        return _impl->getDefinitions(use);\n    }\n\n    const DataDependenceAnalysisOptions &getOptions() const { return _options; }\n\n    DataDependenceAnalysisImpl *getImpl() { return _impl.get(); }\n    const DataDependenceAnalysisImpl *getImpl() const { return _impl.get(); }\n};\n\n} // namespace dda\n} // namespace dg\n\n#endif // DG_DATA_DEPENDENCE_ANALYSIS_H_\n"
  },
  {
    "path": "include/dg/DataDependence/DataDependenceAnalysisImpl.h",
    "content": "#ifndef DG_DATA_DEPENDENCE_ANALYSIS_IMPL_H_\n#define DG_DATA_DEPENDENCE_ANALYSIS_IMPL_H_\n\n#include <cassert>\n#include <utility>\n\n#include \"dg/DataDependence/DataDependenceAnalysisOptions.h\"\n#include \"dg/Offset.h\"\n#include \"dg/ReadWriteGraph/ReadWriteGraph.h\"\n\n#include \"dg/util/debug.h\"\n\nnamespace dg {\nnamespace dda {\n\n// here the types are for type-checking (optional - user can do it\n// when building the graph) and for later optimizations\n\nclass DataDependenceAnalysisImpl {\n  protected:\n    ReadWriteGraph graph;\n\n    const DataDependenceAnalysisOptions options;\n\n  public:\n    DataDependenceAnalysisImpl(ReadWriteGraph &&graph,\n                               DataDependenceAnalysisOptions opts)\n            : graph(std::move(graph)), options(std::move(opts)) {\n        assert(this->graph.getEntry() && \"Graph has no entry\");\n    }\n\n    DataDependenceAnalysisImpl(ReadWriteGraph &&graph)\n            : DataDependenceAnalysisImpl(std::move(graph), {}) {}\n\n    virtual ~DataDependenceAnalysisImpl() = default;\n\n    ReadWriteGraph *getGraph() { return &graph; }\n    const ReadWriteGraph *getGraph() const { return &graph; }\n    const RWSubgraph *getEntry() const { return graph.getEntry(); }\n    // FIXME: rename to getEntryNode();\n    // RWNode *getRoot() { return graph.getEntry()->getRoot(); }\n    const RWNode *getRoot() const { return graph.getEntry()->getRoot(); }\n\n    virtual void run() = 0;\n\n    // return the reaching definitions of ('mem', 'off', 'len')\n    // at the location 'where'\n    virtual std::vector<RWNode *> getDefinitions(RWNode *where, RWNode *mem,\n                                                 const Offset &off,\n                                                 const Offset &len) = 0;\n\n    // return reaching definitions of a node that represents\n    // the given use\n    virtual std::vector<RWNode *> getDefinitions(RWNode *use) = 0;\n};\n\n} // namespace dda\n} // namespace dg\n\n#endif // DG_DATA_DEPENDENCE_ANALYSIS_IMPL_H_\n"
  },
  {
    "path": "include/dg/DataDependence/DataDependenceAnalysisOptions.h",
    "content": "#ifndef DG_DATA_DEPENDENCE_ANALYSIS_OPTIONS_H_\n#define DG_DATA_DEPENDENCE_ANALYSIS_OPTIONS_H_\n\n#include <cassert>\n#include <map>\n#include <utility>\n\n#include \"dg/AnalysisOptions.h\"\n#include \"dg/Offset.h\"\n\nnamespace dg {\n\nstruct FunctionModel {\n    std::string name;\n\n    struct OperandValue {\n        enum class Type { OFFSET, OPERAND } type{Type::OFFSET};\n\n        union {\n            Offset offset;\n            unsigned operand;\n        } value{0};\n\n        bool isOffset() const { return type == Type::OFFSET; }\n        bool isOperand() const { return type == Type::OPERAND; }\n        Offset getOffset() const {\n            assert(isOffset());\n            return value.offset;\n        }\n        unsigned getOperand() const {\n            assert(isOperand());\n            return value.operand;\n        }\n\n        OperandValue(Offset offset) { value.offset = offset; }\n        OperandValue(unsigned operand) : type(Type::OPERAND) {\n            value.operand = operand;\n        }\n        OperandValue(const OperandValue &) = default;\n        OperandValue(OperandValue &&) = default;\n        OperandValue &operator=(const OperandValue &rhs) {\n            type = rhs.type;\n            if (rhs.isOffset())\n                value.offset = rhs.value.offset;\n            else\n                value.operand = rhs.value.operand;\n            return *this;\n        }\n    };\n\n    struct Operand {\n        unsigned operand;\n        OperandValue from, to;\n\n        Operand(unsigned operand, OperandValue from, OperandValue to)\n                : operand(operand), from(std::move(from)), to(std::move(to)) {}\n        Operand(Operand &&) = default;\n        Operand(const Operand &) = default;\n        Operand &operator=(const Operand &rhs) = default;\n    };\n\n    void addDef(unsigned operand, OperandValue from, OperandValue to) {\n        _defines.emplace(operand, Operand{operand, from, to});\n    }\n\n    void addUse(unsigned operand, OperandValue from, OperandValue to) {\n        _uses.emplace(operand, Operand{operand, from, to});\n    }\n\n    void addDef(const Operand &op) { _defines.emplace(op.operand, op); }\n    void addUse(const Operand &op) { _uses.emplace(op.operand, op); }\n\n    const Operand *defines(unsigned operand) const {\n        auto it = _defines.find(operand);\n        return it == _defines.end() ? nullptr : &it->second;\n    }\n\n    const Operand *uses(unsigned operand) const {\n        auto it = _uses.find(operand);\n        return it == _uses.end() ? nullptr : &it->second;\n    }\n\n    bool handles(unsigned i) const { return defines(i) || uses(i); }\n\n  private:\n    std::map<unsigned, Operand> _defines;\n    std::map<unsigned, Operand> _uses;\n};\n\nnamespace dda {\nenum UndefinedFunsBehavior {\n    PURE = 0,\n    WRITE_ANY = 1,\n    READ_ANY = 1 << 1,\n    WRITE_ARGS = 1 << 2,\n    READ_ARGS = 1 << 3,\n};\n} // namespace dda\n\nstruct DataDependenceAnalysisOptions : AnalysisOptions {\n    // default one\n    enum class AnalysisType { ssa } analysisType{AnalysisType::ssa};\n\n    bool isSSA() const { return analysisType == AnalysisType::ssa; }\n\n    dda::UndefinedFunsBehavior undefinedFunsBehavior{dda::READ_ARGS};\n\n    // Does the analysis track concrete bytes\n    // or just objects?\n    bool fieldInsensitive{false};\n\n    bool undefinedArePure() const { return undefinedFunsBehavior == dda::PURE; }\n    bool undefinedFunsWriteAny() const {\n        return undefinedFunsBehavior & dda::WRITE_ANY;\n    }\n    bool undefinedFunsReadAny() const {\n        return undefinedFunsBehavior & dda::READ_ANY;\n    }\n    bool undefinedFunsWriteArgs() const {\n        return undefinedFunsBehavior & dda::WRITE_ARGS;\n    }\n    bool undefinedFunsReadArgs() const {\n        return undefinedFunsBehavior & dda::READ_ARGS;\n    }\n\n    DataDependenceAnalysisOptions &setFieldInsensitive(bool b) {\n        fieldInsensitive = b;\n        return *this;\n    }\n\n    std::map<const std::string, FunctionModel> functionModels;\n\n    const FunctionModel *getFunctionModel(const std::string &name) const {\n        auto it = functionModels.find(name);\n        return it == functionModels.end() ? nullptr : &it->second;\n    }\n\n    void functionModelAddDef(const std::string &name,\n                             const FunctionModel::Operand &def) {\n        auto &M = functionModels[name];\n        if (M.name.empty())\n            M.name = name;\n        M.addDef(def);\n    }\n\n    void functionModelAddUse(const std::string &name,\n                             const FunctionModel::Operand &def) {\n        auto &M = functionModels[name];\n        if (M.name.empty())\n            M.name = name;\n        M.addUse(def);\n    }\n};\n\n} // namespace dg\n\n#endif // DG_DATA_DEPENDENCE_ANALYSIS_OPTIONS_H_\n"
  },
  {
    "path": "include/dg/DependenceGraph.h",
    "content": "#ifndef DEPENDENCE_GRAPH_H_\n#define DEPENDENCE_GRAPH_H_\n\n#include <cassert>\n#include <map>\n#include <memory>\n#include <queue>\n#include <utility>\n\n#include \"ADT/DGContainer.h\"\n#include \"BBlock.h\"\n#include \"Node.h\"\n\nnamespace dg {\n\n// non-template class representing a generic dependence graph\nclass DependenceGraphBase {\n    // how many nodes keeps pointer to this graph?\n    int refcount{1};\n\n    // is the graph in some slice?\n    uint64_t slice_id{0};\n\n  public:\n    virtual ~DependenceGraphBase() = default;\n    // dependence graph can be shared between more call-sites that\n    // has references to this graph. When destroying graph, we\n    // must be sure do delete it just once, so count references\n    // This is up to concrete DG implementation if it uses\n    // ref()/unref() methods or handle these stuff some other way\n    int ref() {\n        ++refcount;\n        return refcount;\n    }\n\n    // unref graph and delete if refrences drop to 0\n    // destructor calls this on subgraphs\n    int unref(bool deleteOnZero = true) {\n        --refcount;\n\n        if (deleteOnZero && refcount == 0) {\n            delete this;\n            return 0;\n        }\n\n        assert(refcount >= 0 && \"Negative refcount\");\n        return refcount;\n    }\n\n    // set that this graph (if it is subgraph)\n    // will be left in a slice. It is virtual, because the graph\n    // may want to override the function and take some action,\n    // if it is in a graph\n    // XXX: could we get rid of the virtual??\n    virtual void setSlice(uint64_t sid) { slice_id = sid; }\n\n    uint64_t getSlice() const { return slice_id; }\n};\n\n// -------------------------------------------------------------------\n//  -- DependenceGraph\n//\n//  This is a base template for a dependence graphs. Every concrete\n//  dependence graph will inherit from instance of this template.\n//  Dependece graph has a map of nodes that it contains (each node\n//  is required to have a unique key). Actually, there are two maps.\n//  One for nodes that are local to the graph and one for nodes that\n//  are global and can be shared between graphs.\n//  Concrete dependence graph may not use all attributes of this class\n//  and it is free to use them as it needs (e.g. it may use only\n//  global nodes and thus share them between all graphs)\n// -------------------------------------------------------------------\ntemplate <typename NodeT>\nclass DependenceGraph : public DependenceGraphBase {\n  public:\n    // type of key that is used in nodes\n    using KeyT = typename NodeT::KeyType;\n    // type of this dependence graph - so that we can refer to it in the code\n    using DependenceGraphT = typename NodeT::DependenceGraphType;\n\n    using ContainerType = std::map<KeyT, NodeT *>;\n    using iterator = typename ContainerType::iterator;\n    using const_iterator = typename ContainerType::const_iterator;\n#ifdef ENABLE_CFG\n    using BBlocksMapT = std::map<KeyT, BBlock<NodeT> *>;\n#endif\n\n  private:\n    // entry and exit nodes of the graph\n    NodeT *entryNode;\n    NodeT *exitNode;\n\n    // Formal parameters of the graph. Every graph is a graph of some function\n    // and formal parameters are parameters from its prototype, i. e. for\n    // foo(int a, int b) we have formal parameters 'a' and 'b'. Actual\n    // parameters are the values that are passed to function call, so for foo(3,\n    // x) the actual parameters are '3' and 'x'. Actual parameters are stored in\n    // the call node. Graph can have none or one formal parameters.\n    DGParameters<NodeT> *formalParameters;\n\n    // call-sites (nodes) that are calling this graph\n    DGContainer<NodeT *> callers;\n\n#ifdef ENABLE_CFG\n    // blocks contained in this graph\n    BBlocksMapT _blocks;\n\n    // if we want to keep CFG information in the dependence graph,\n    // these are entry and exit basic blocks\n    BBlock<NodeT> *entryBB;\n    BBlock<NodeT> *exitBB;\n\n    // root of post-dominator tree\n    BBlock<NodeT> *PDTreeRoot;\n#endif // ENABLE_CFG\n\n  protected:\n    // nodes contained in this dg. They are protected, so that\n    // child classes can access them directly\n    ContainerType nodes;\n    // container that can be shared accross the graphs\n    // (therefore it is a pointer)\n    std::shared_ptr<ContainerType> global_nodes;\n\n  public:\n    DependenceGraph<NodeT>()\n            : entryNode(nullptr), exitNode(nullptr), formalParameters(nullptr)\n#ifdef ENABLE_CFG\n              ,\n              entryBB(nullptr), exitBB(nullptr), PDTreeRoot(nullptr)\n#endif\n    {\n    }\n\n    ~DependenceGraph<NodeT>() override {\n#ifdef ENABLE_CFG\n#ifdef ENABLE_DEBUG\n        bool deleted_entry = false;\n        bool deleted_exit = false;\n#endif // ENABLE_DEBUG\n        for (auto &it : _blocks) {\n#ifdef ENABLE_DEBUG\n            if (it.second == entryBB)\n                deleted_entry = true;\n            else if (it.second == exitBB)\n                ;\n            deleted_exit = true;\n#endif // ENABLE_DEBUG\n            delete it.second;\n        }\n\n#ifdef ENABLE_DEBUG\n        assert(deleted_entry && \"Did not have entry in _blocks\");\n        assert(deleted_exit && \"Did not have exit in _blocks\");\n#endif // ENABLE_DEBUG\n#endif\n    }\n\n    // iterators for local nodes\n    iterator begin() { return nodes.begin(); }\n    const_iterator begin() const { return nodes.begin(); }\n    iterator end() { return nodes.end(); }\n    const_iterator end() const { return nodes.end(); }\n\n    // operator [] for local nodes\n    NodeT *operator[](KeyT k) { return nodes[k]; }\n    const NodeT *operator[](KeyT k) const { return nodes[k]; }\n\n    // reference getter for fast include-if-null operation\n    NodeT *&getRef(KeyT k) { return nodes[k]; }\n\n    // do we have a local node with this key?\n    bool contains(KeyT k) const { return nodes.count(k) != 0; }\n\n    // get iterator to a local node with key 'k'. If there is no\n    // such a node, return end()\n    iterator find(KeyT k) { return nodes.find(k); }\n    const_iterator find(KeyT k) const { return nodes.find(k); }\n\n    // get formal parameters of this graph\n    DGParameters<NodeT> *getParameters() { return formalParameters; }\n    DGParameters<NodeT> *getParameters() const { return formalParameters; }\n\n    // set new parameters of this graph.\n    void setParameters(DGParameters<NodeT> *p) {\n        assert(!formalParameters && \"Already have formal parameters\");\n        formalParameters = p;\n    }\n\n    // Get node from graph for key. The function searches in nodes,\n    // formal parameters and global nodes (in this order)\n    // Return nullptr if no such node exists\n    template <typename T>\n    NodeT *_getNode(T k) {\n        auto it = nodes.find(k);\n        if (it != nodes.end())\n            return it->second;\n\n        if (formalParameters) {\n            auto p = formalParameters->find(k);\n            if (p)\n                return p->in;\n        }\n\n        return getGlobalNode(k);\n    }\n\n    NodeT *getNode(KeyT k) { return _getNode(k); }\n    const NodeT *getNode(const KeyT k) const { return _getNode(k); }\n\n    // get global node with given key or null if there's\n    // not such node\n    template <typename T>\n    NodeT *_getGlobalNode(T k) {\n        if (global_nodes) {\n            auto it = global_nodes->find(k);\n            if (it != global_nodes->end())\n                return it->second;\n        }\n\n        return nullptr;\n    }\n\n    NodeT *getGlobalNode(KeyT k) { return _getGlobalNode(k); }\n    const NodeT *getGlobalNode(const KeyT k) const { return _getGlobalNode(k); }\n\n    // number of local nodes\n    size_t size() const { return nodes.size(); }\n\n    NodeT *setEntry(NodeT *n) {\n        NodeT *oldEnt = entryNode;\n        entryNode = n;\n\n        return oldEnt;\n    }\n\n    NodeT *setExit(NodeT *n) {\n        NodeT *oldExt = exitNode;\n        exitNode = n;\n\n        return oldExt;\n    }\n\n    NodeT *getEntry() const { return entryNode; }\n    NodeT *getExit() const { return exitNode; }\n\n    void setGlobalNodes(const std::shared_ptr<ContainerType> &ngn) {\n        global_nodes = ngn;\n    }\n\n    // allocate new global nodes\n    void allocateGlobalNodes() {\n        assert(!global_nodes && \"Already contains global nodes\");\n        // std::make_shared returned unaligned pointer for some reason...\n        global_nodes = std::shared_ptr<ContainerType>(new ContainerType());\n    }\n\n    ContainerType *getNodes() { return &nodes; }\n\n    const ContainerType *getNodes() const { return &nodes; }\n\n    std::shared_ptr<ContainerType> getGlobalNodes() { return global_nodes; }\n\n    const std::shared_ptr<ContainerType> &getGlobalNodes() const {\n        return global_nodes;\n    }\n\n    // add a node to this graph. The DependenceGraph is something like\n    // a namespace for nodes, since every node has unique key and we can\n    // have another node with same key in another graph.\n    // So we can have two nodes for the same value but in different\n    // graphs. The edges can be between arbitrary nodes and do not\n    // depend on graphs the nodes are in.\n    bool addNode(KeyT k, NodeT *n) {\n        bool ret = nodes.insert(std::make_pair(k, n)).second;\n        if (ret) {\n            assert(n->getDG() == nullptr &&\n                   \"A node can not belong to more graphs\");\n            n->setDG(static_cast<DependenceGraphT *>(this));\n        }\n\n        return ret;\n    }\n\n    // make it virtual? We don't need it now, but\n    // in the future it may be handy.\n    bool addNode(NodeT *n) {\n        // NodeT is a class derived from\n        // dg::Node, so it must have getKey() method\n        return addNode(n->getKey(), n);\n    }\n\n    bool addGlobalNode(KeyT k, NodeT *n) {\n        assert(global_nodes && \"Need a container for global nodes first\");\n        return global_nodes->insert(std::make_pair(k, n)).second;\n    }\n\n    bool addGlobalNode(NodeT *n) { return addGlobalNode(n->getKey(), n); }\n\n    NodeT *removeNode(KeyT k) { return _removeNode(k, &nodes); }\n\n    NodeT *removeNode(NodeT *n) { return removeNode(n->getKey()); }\n\n    NodeT *removeNode(iterator &it) { return _removeNode(it, &nodes); }\n\n    NodeT *removeGlobalNode(KeyT k) {\n        if (!global_nodes)\n            return nullptr;\n\n        return _removeNode(k, global_nodes);\n    }\n\n    NodeT *removeGlobalNode(NodeT *n) { return removeGlobalNode(n->getKey()); }\n\n    NodeT *removeGlobalNode(iterator &it) {\n        if (!global_nodes)\n            return nullptr;\n\n        return _removeNode(it, global_nodes);\n    }\n\n    bool deleteNode(NodeT *n) { return deleteNode(n->getKey()); }\n\n    bool deleteNode(KeyT k) {\n        NodeT *n = removeNode(k);\n        delete n;\n\n        return n != nullptr;\n    }\n\n    bool deleteNode(iterator &it) {\n        NodeT *n = removeNode(it);\n        delete n;\n\n        return n != nullptr;\n    }\n\n    bool deleteGlobalNode(KeyT k) {\n        NodeT *n = removeGlobalNode(k);\n        delete n;\n\n        return n != nullptr;\n    }\n\n    bool deleteGlobalNode(NodeT *n) { return deleteGlobalNode(n->getKey()); }\n\n    bool deleteGlobalNode(iterator &it) {\n        NodeT *n = removeGlobalNode(it);\n        delete n;\n\n        return n != nullptr;\n    }\n\n    DGContainer<NodeT *> &getCallers() { return callers; }\n    const DGContainer<NodeT *> &getCallers() const { return callers; }\n    bool addCaller(NodeT *sg) { return callers.insert(sg); }\n\n#ifdef ENABLE_CFG\n    // get blocks contained in this graph\n    BBlocksMapT &getBlocks() { return _blocks; }\n    const BBlocksMapT &getBlocks() const { return _blocks; }\n    // add block to this graph\n    bool addBlock(KeyT key, BBlock<NodeT> *B) {\n        return _blocks.emplace(key, B).second;\n    }\n\n    bool removeBlock(KeyT key) { return _blocks.erase(key) == 1; }\n\n    BBlock<NodeT> *getPostDominatorTreeRoot() const { return PDTreeRoot; }\n    void setPostDominatorTreeRoot(BBlock<NodeT> *r) {\n        assert(!PDTreeRoot && \"Already has a post-dominator tree root\");\n        PDTreeRoot = r;\n    }\n\n    BBlock<NodeT> *getEntryBB() const { return entryBB; }\n    BBlock<NodeT> *getExitBB() const { return exitBB; }\n\n    BBlock<NodeT> *setEntryBB(BBlock<NodeT> *nbb) {\n        BBlock<NodeT> *old = entryBB;\n        entryBB = nbb;\n\n        return old;\n    }\n\n    BBlock<NodeT> *setExitBB(BBlock<NodeT> *nbb) {\n        BBlock<NodeT> *old = exitBB;\n        exitBB = nbb;\n\n        return old;\n    }\n\n#endif // ENABLE_CFG\n\n  private:\n    NodeT *_removeNode(iterator &it, ContainerType *cont) {\n        NodeT *n = it->second;\n        n->isolate();\n        cont->erase(it);\n\n        return n;\n    }\n\n    NodeT *_removeNode(KeyT k, ContainerType *cont) {\n        iterator it = cont->find(k);\n        if (it == cont->end())\n            return nullptr;\n\n        // remove and re-connect edges\n        return _removeNode(it, cont);\n    }\n};\n\n} // namespace dg\n\n#endif // DEPENDENCE_GRAPH_H_\n"
  },
  {
    "path": "include/dg/Dominators/DominanceFrontiers.h",
    "content": "#ifndef DG_DOMINANCE_FRONTIERS_H_\n#define DG_DOMINANCE_FRONTIERS_H_\n\n#include <vector>\n\n#include \"BBlock.h\"\n#include \"BFS.h\"\n\nnamespace dg {\n\n///\n// Compute dominance frontiers\n//\n// \\param root   root of dominators tree\n//\n// This algorithm takes dominator tree\n// (edges of the tree are in BBlocks) and computes\n// dominance frontiers for every node\n//\n// The algorithm is due:\n//\n// R. Cytron, J. Ferrante, B. K. Rosen, M. N. Wegman, and F. K. Zadeck. 1989.\n// An efficient method of computing static single assignment form.\n// In Proceedings of the 16th ACM SIGPLAN-SIGACT symposium on Principles of\n// programming languages (POPL '89), CORPORATE New York, NY Association for\n// Computing Machinery (Ed.). ACM, New York, NY, USA, 25-35.\n// DOI=http://dx.doi.org/10.1145/75277.75280\n//\ntemplate <typename NodeT>\nclass DominanceFrontiers {\n    static void queueDomBBs(BBlock<NodeT> *BB,\n                            std::vector<BBlock<NodeT> *> *blocks) {\n        blocks->push_back(BB);\n    }\n\n    void computeDFrontiers(BBlock<NodeT> *X) {\n        // DF_local\n        for (const auto &edge : X->successors()) {\n            BBlock<NodeT> *Y = edge.target;\n            if (Y->getIDom() != X) {\n                X->addDomFrontier(Y);\n            }\n        }\n\n        // DF_up\n        for (BBlock<NodeT> *Z : X->getDominators()) {\n            for (BBlock<NodeT> *Y : Z->getDomFrontiers()) {\n                if (Y->getIDom() != X) {\n                    X->addDomFrontier(Y);\n                }\n            }\n        }\n    }\n\n  public:\n    void compute(BBlock<NodeT> *root) {\n        std::vector<BBlock<NodeT> *> blocks;\n        BBlockBFS<NodeT> bfs(BFS_BB_DOM);\n\n        // get BBs in the order of dom tree edges (BFS),\n        // so that we process it bottom-up\n        bfs.run(root, queueDomBBs, &blocks);\n\n        // go bottom-up the dom tree and compute domninance frontiers\n        for (int i = blocks.size() - 1; i >= 0; --i)\n            computeDFrontiers(blocks[i]);\n    }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/Dominators/PostDominanceFrontiers.h",
    "content": "#ifndef DG_POST_DOMINANCE_FRONTIERS_H_\n#define DG_POST_DOMINANCE_FRONTIERS_H_\n\n#include <vector>\n\n#include \"dg/BBlock.h\"\n#include \"dg/BFS.h\"\n\nnamespace dg {\nnamespace legacy {\n\n///\n// Compute post-dominance frontiers\n//\n// \\param root   root of post-dominators tree\n//\n// This algorithm takes post-dominator tree\n// (edges of the tree are in BBlocks) and computes\n// post-dominator frontiers for every node\n//\n// The algorithm is due:\n//\n// R. Cytron, J. Ferrante, B. K. Rosen, M. N. Wegman, and F. K. Zadeck. 1989.\n// An efficient method of computing static single assignment form.\n// In Proceedings of the 16th ACM SIGPLAN-SIGACT symposium on Principles of\n// programming languages (POPL '89), CORPORATE New York, NY Association for\n// Computing Machinery (Ed.). ACM, New York, NY, USA, 25-35.\n// DOI=http://dx.doi.org/10.1145/75277.75280\n//\ntemplate <typename NodeT, typename BBlockT>\nclass PostDominanceFrontiers {\n    void computePDFrontiers(BBlockT *BB, bool add_cd) {\n        // compute DFlocal\n        for (auto *pred : BB->predecessors()) {\n            auto *ipdom = pred->getIPostDom();\n            if (ipdom && ipdom != BB) {\n                BB->addPostDomFrontier(pred);\n\n                // pd-frontiers are the reverse control dependencies\n                if (add_cd)\n                    pred->addControlDependence(BB);\n            }\n        }\n\n        for (auto *pdom : BB->getPostDominators()) {\n            for (auto *df : pdom->getPostDomFrontiers()) {\n                auto *ipdom = df->getIPostDom();\n                if (ipdom && ipdom != BB && df != BB) {\n                    BB->addPostDomFrontier(df);\n\n                    if (add_cd)\n                        df->addControlDependence(BB);\n                }\n            }\n        }\n    }\n\n  public:\n    void compute(BBlockT *root, bool add_cd = false) {\n        std::vector<BBlockT *> blocks;\n\n        struct EdgeChooser {\n            class range {\n                BBlockT *_blk;\n\n              public:\n                range(BBlockT *blk) : _blk(blk) {}\n\n                auto begin() -> decltype(_blk->getPostDominators().begin()) {\n                    return _blk->getPostDominators().begin();\n                }\n\n                auto end() -> decltype(_blk->getPostDominators().end()) {\n                    return _blk->getPostDominators().end();\n                }\n            };\n\n            range operator()(BBlockT *b) const { return range(b); }\n        };\n\n        EdgeChooser chooser;\n        BFS<BBlockT, SetVisitTracker<BBlockT>, EdgeChooser> bfs(chooser);\n\n        // get BBs in the order of post-dom tree edges (BFS),\n        // so that we process it bottom-up\n        bfs.run(root, [&blocks](BBlockT *b) { blocks.push_back(b); });\n\n        // go bottom-up the post-dom tree and compute post-domninance frontiers\n        for (int i = blocks.size() - 1; i >= 0; --i)\n            computePDFrontiers(blocks[i], add_cd);\n    }\n};\n\n} // namespace legacy\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/MemorySSA/Definitions.h",
    "content": "#ifndef DG_MEMORY_SSA_DEFINITIONS_H_\n#define DG_MEMORY_SSA_DEFINITIONS_H_\n\n#include <set>\n#include <vector>\n\n#include \"dg/MemorySSA/DefinitionsMap.h\"\n#include \"dg/Offset.h\"\n#include \"dg/ReadWriteGraph/RWNode.h\"\n\nnamespace dg {\nnamespace dda {\n\n// information about definitions associated to each bblock\nstruct Definitions {\n    bool _processed{false};\n\n    // definitions gathered at the end of this bblock\n    // (if you find the sought memory here,\n    // you got all definitions from this block)\n    DefinitionsMap<RWNode> definitions;\n    // all memory that is overwritten by this block (strong update)\n    // FIXME: we should have just a mapping from memory to disjunctive intervals\n    // as data structure here (if you find the sought memory here, you can\n    // terminate the search)\n    DefinitionsMap<RWNode> kills;\n\n    // writes to unknown memory in this block\n    std::vector<RWNode *> unknownWrites;\n\n    void swap(Definitions &rhs) {\n        definitions.swap(rhs.definitions);\n        kills.swap(rhs.kills);\n        unknownWrites.swap(rhs.unknownWrites);\n    }\n\n    void addUnknownWrite(RWNode *n) { unknownWrites.push_back(n); }\n\n    const std::vector<RWNode *> &getUnknownWrites() const {\n        return unknownWrites;\n    }\n\n    ///\n    /// get the definition-sites for the given 'ds'\n    ///\n    std::set<RWNode *> get(const DefSite &ds) {\n        auto retval = definitions.get(ds);\n        if (retval.empty()) {\n            retval.insert(unknownWrites.begin(), unknownWrites.end());\n        }\n        return retval;\n    }\n\n    // update this Definitions by definitions from 'node'.\n    // I.e., as if node would be executed when already\n    // having the definitions we have\n    void update(RWNode *node, RWNode *defnode = nullptr);\n    // Join another definitions to this Definitions\n    // (as if on  a joint point in a CFG)\n    void join(const Definitions &rhs);\n\n    auto uncovered(const DefSite &ds) const\n            -> decltype(kills.undefinedIntervals(ds)) {\n        return kills.undefinedIntervals(ds);\n    }\n\n    // for on-demand analysis\n    // once isProcessed is true, the Defiitions contain\n    // summarized all the information that one needs\n    // (may be then altered just only by adding a phi node definitions)\n    bool isProcessed() const { return _processed; }\n    void setProcessed() { _processed = true; }\n\n#ifndef NDEBUG\n    void dump() const;\n#endif\n};\n\n} // namespace dda\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/MemorySSA/DefinitionsMap.h",
    "content": "#ifndef DG_DEFINITIONS_MAP_H_\n#define DG_DEFINITIONS_MAP_H_\n\n#include <set>\n#include <unordered_map>\n#include <vector>\n#ifndef NDEBUG\n#include <iostream>\n#endif\n\n#include \"dg/ADT/DisjunctiveIntervalMap.h\"\n#include \"dg/Offset.h\"\n#include \"dg/ReadWriteGraph/DefSite.h\"\n\nnamespace dg {\nnamespace dda {\n\nclass RWNode;\nclass ReachingDefinitionsAnalysis;\n\n/// A data structure that represents a mapping\n/// DefSite -> RWNode, that is, it stores which memory (DefSite)\n/// was defined where.\ntemplate <typename NodeT = RWNode>\nclass DefinitionsMap {\n  public:\n    using OffsetsT = ADT::DisjunctiveIntervalMap<NodeT *>;\n    using IntervalT = typename OffsetsT::IntervalT;\n\n  private:\n    std::unordered_map<NodeT *, OffsetsT> _definitions{};\n\n    // transform (offset, lenght) from a DefSite into the interval\n    static std::pair<Offset, Offset> getInterval(const DefSite &ds) {\n        // if the offset is unknown, stretch the interval over all possible\n        // bytes\n        if (ds.offset.isUnknown())\n            return {0, Offset::UNKNOWN};\n\n        return {ds.offset, ds.offset + (ds.len - 1)};\n    }\n\n  public:\n    void clear() { _definitions.clear(); }\n    void swap(DefinitionsMap &rhs) { _definitions.swap(rhs._definitions); }\n    bool empty() const { return _definitions.empty(); }\n\n    bool add(const DefSite &ds, NodeT *node) {\n        // if the offset is unknown, make it 0, so that the\n        // definition get stretched over all possible offsets\n        Offset start, end;\n        std::tie(start, end) = getInterval(ds);\n        return _definitions[ds.target].add(start, end, node);\n    }\n\n    bool addAll(NodeT *node) {\n        bool changed = false;\n        for (auto &it : _definitions) {\n            changed |= it.second.addAll(node);\n        }\n        return changed;\n    }\n\n    bool update(const DefSite &ds, NodeT *node) {\n        Offset start, end;\n        std::tie(start, end) = getInterval(ds);\n        return _definitions[ds.target].update(start, end, node);\n    }\n\n    template <typename ContainerT>\n    bool add(const DefSite &ds, const ContainerT &nodes) {\n        bool changed = false;\n        for (auto *n : nodes)\n            changed |= add(ds, n);\n        return changed;\n    }\n\n    template <typename ContainerT>\n    bool add(const ContainerT &defsites, NodeT *n) {\n        bool changed = false;\n        for (auto &ds : defsites)\n            changed |= add(ds, n);\n        return changed;\n    }\n\n    bool add(NodeT *target, const OffsetsT &elems) {\n        bool changed = false;\n        for (auto &it : elems)\n            changed |= _definitions[target].add(it.first, it.second);\n        return changed;\n    }\n\n    bool add(const DefinitionsMap<NodeT> &rhs) {\n        bool changed = false;\n        for (auto &it : rhs) {\n            changed |= add(it.first, it.second);\n        }\n        return changed;\n    }\n\n    bool update(const DefSite &ds, const std::vector<NodeT *> &nodes) {\n        bool changed = false;\n        for (auto n : nodes)\n            changed |= update(ds, n);\n        return changed;\n    }\n\n    ///\n    // Get definitions of the memory described by 'ds'\n    std::set<NodeT *> get(const DefSite &ds) {\n        auto it = _definitions.find(ds.target);\n        if (it == _definitions.end())\n            return {};\n\n        Offset start, end;\n        std::tie(start, end) = getInterval(ds);\n        return it->second.gather(start, end);\n    }\n\n    ///\n    // Return intervals of bytes from 'ds' that are not defined by this map\n    std::vector<IntervalT> undefinedIntervals(const DefSite &ds) const {\n        auto it = _definitions.find(ds.target);\n        if (it == _definitions.end())\n            return {IntervalT(ds.offset, ds.offset + (ds.len - 1))};\n\n        Offset start, end;\n        std::tie(start, end) = getInterval(ds);\n        return it->second.uncovered(start, end);\n    }\n\n    bool definesTarget(NodeT *target) const {\n        return _definitions.find(target) != _definitions.end();\n    }\n\n    /*\n    template <typename KeyFilt, typename SetFilt>\n    DefinitionsMap<NodeT> filter(KeyFilt keyfilt, SetFilt setfilt) {\n        DefinitionsMap<NodeT> tmp;\n        for (auto& it : _definitions) {\n            if (keyfilt(it.first) && setfilt(it.second)) {\n                tmp._definitions.emplace(it.first, it.second);\n            }\n        }\n        return tmp;\n    }\n    */\n\n    template <typename FiltFun>\n    DefinitionsMap<NodeT> filter(FiltFun filt) {\n        DefinitionsMap<NodeT> tmp;\n        for (auto &it : _definitions) {\n            if (filt(it.first)) {\n                tmp._definitions.emplace(it.first, it.second);\n            }\n        }\n        return tmp;\n    }\n\n    DefinitionsMap<NodeT> intersect(const DefinitionsMap<NodeT> &rhs) {\n        DefinitionsMap<NodeT> retval;\n        for (auto &it : _definitions) {\n            auto rhsit = rhs._definitions.find(it.first);\n            if (rhsit != rhs._definitions.end()) {\n                retval.add(it.first, it.second.intersection(rhsit->second));\n            }\n        }\n        return retval;\n    }\n\n    // FIXME: do that as iterators\n    std::set<NodeT *> values() const {\n        std::set<NodeT *> ret;\n        for (auto &it : _definitions) {\n            for (auto &it2 : it.second) {\n                ret.insert(it2.second.begin(), it2.second.end());\n            }\n        }\n        return ret;\n    }\n\n    auto begin() const -> decltype(_definitions.begin()) {\n        return _definitions.begin();\n    }\n\n    auto end() const -> decltype(_definitions.end()) {\n        return _definitions.end();\n    }\n\n    bool operator==(const DefinitionsMap<NodeT> &oth) const {\n        return _definitions == oth._definitions;\n    }\n\n    size_t size() const { return _definitions.size(); }\n\n#ifndef NDEBUG\n    void dump() const {\n        for (auto &it : _definitions) {\n            it.first->dump();\n            std::cout << \" defined at \";\n            it.second.dump();\n        }\n    }\n#endif\n};\n\n} // namespace dda\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/MemorySSA/MemorySSA.h",
    "content": "#ifndef DG_MEMORY_SSA_H_\n#define DG_MEMORY_SSA_H_\n\n#include <cassert>\n#include <set>\n#include <unordered_map>\n#include <vector>\n\n#include \"dg/Offset.h\"\n\n#include \"dg/DataDependence/DataDependenceAnalysisImpl.h\"\n#include \"dg/DataDependence/DataDependenceAnalysisOptions.h\"\n#include \"dg/MemorySSA/DefinitionsMap.h\"\n\n#include \"dg/ReadWriteGraph/ReadWriteGraph.h\"\n\n#include \"dg/ADT/Queue.h\"\n#include \"dg/util/debug.h\"\n\n#include \"Definitions.h\"\n#include \"ModRef.h\"\n\nnamespace dg {\nnamespace dda {\n\nclass MemorySSATransformation : public DataDependenceAnalysisImpl {\n    class BBlockInfo {\n        Definitions definitions{};\n        RWNodeCall *call{nullptr};\n\n      public:\n        void setCallBlock(RWNodeCall *c) { call = c; }\n        bool isCallBlock() const { return call != nullptr; }\n        RWNodeCall *getCall() { return call; }\n        const RWNodeCall *getCall() const { return call; }\n\n        Definitions &getDefinitions() { return definitions; }\n        const Definitions &getDefinitions() const { return definitions; }\n    };\n\n    class SubgraphInfo {\n        std::unordered_map<RWBBlock *, BBlockInfo> _bblock_infos;\n\n        class Summary {\n          public:\n            // phi nodes representing reads/writes to memory that is\n            // external to the procedure\n            DefinitionsMap<RWNode> inputs;\n            DefinitionsMap<RWNode> outputs;\n\n            Summary() = default;\n            Summary(Summary &&) = default;\n            Summary(const Summary &) = delete;\n\n            void addInput(const DefSite &ds, RWNode *n) { inputs.add(ds, n); }\n            void addOutput(const DefSite &ds, RWNode *n) { outputs.add(ds, n); }\n\n            RWNode *getUnknownPhi() {\n                // FIXME: optimize this, we create std::set for nothing...\n                auto S = inputs.get({UNKNOWN_MEMORY, 0, Offset::UNKNOWN});\n                if (S.empty()) {\n                    return nullptr;\n                }\n                assert(S.size() == 1);\n                return *(S.begin());\n            }\n\n            std::set<RWNode *> getOutputs(const DefSite &ds) {\n                return outputs.get(ds);\n            }\n            auto getUncoveredOutputs(const DefSite &ds) const\n                    -> decltype(outputs.undefinedIntervals(ds)) {\n                return outputs.undefinedIntervals(ds);\n            }\n        } summary;\n\n        // sumarized information about visible external\n        // effects of the procedure\n        ModRefInfo modref;\n\n        SubgraphInfo(RWSubgraph *s);\n\n        friend class MemorySSATransformation;\n\n      public:\n        SubgraphInfo() = default;\n\n        Summary &getSummary() { return summary; }\n        const Summary &getSummary() const { return summary; }\n        BBlockInfo &getBBlockInfo(RWBBlock *b) { return _bblock_infos[b]; }\n        const BBlockInfo *getBBlockInfo(RWBBlock *b) const {\n            auto it = _bblock_infos.find(b);\n            return it == _bblock_infos.end() ? nullptr : &it->second;\n        }\n    };\n\n    void initialize();\n\n    ////\n    // LVN\n    ///\n    // Perform LVN up to a certain point and search only for a certain memory.\n    // XXX: we could avoid this by (at least virtually) splitting blocks on\n    // uses.\n    static Definitions findDefinitionsInBlock(RWNode *to,\n                                              const RWNode *mem = nullptr);\n    static Definitions findEscapingDefinitionsInBlock(RWNode *to);\n    static void performLvn(Definitions & /*D*/, RWBBlock * /*block*/);\n    void updateDefinitions(Definitions &D, RWNode *node);\n\n    ///\n    // Find definitions of the def site and return def-use edges.\n    // For the uncovered bytes create phi nodes (which are also returned\n    // as the definitions).\n    std::vector<RWNode *> findDefinitions(RWBBlock * /*block*/,\n                                          const DefSite & /*ds*/);\n    std::vector<RWNode *> findDefinitions(RWNode *node, const DefSite &ds);\n\n    // Find definitions for the given node (which is supposed to be a use)\n    std::vector<RWNode *> findDefinitions(RWNode *node);\n\n    std::vector<RWNode *> findDefinitionsInPredecessors(RWBBlock *block,\n                                                        const DefSite &ds);\n\n    void findDefinitionsInMultiplePredecessors(RWBBlock *block,\n                                               const DefSite &ds,\n                                               std::vector<RWNode *> &defs);\n\n    void addUncoveredFromPredecessors(RWBBlock *block, Definitions &D,\n                                      const DefSite &ds,\n                                      std::vector<RWNode *> &defs);\n\n    void findPhiDefinitions(RWNode *phi);\n\n    ///\n    // Search call C for definitions of ds and store the results into D.\n    // Used to implement on-demand search inside procedures.\n    void fillDefinitionsFromCall(Definitions &D, RWNodeCall *C,\n                                 const DefSite &ds);\n    ///\n    // Search call C for all definitions that may be visible after the call.\n    // After the call to this method, D is completely filled with all\n    // information, similarly as when we perform LVN for non-call bblock.\n    void fillDefinitionsFromCall(Definitions &D, RWNodeCall *C);\n\n    void findDefinitionsFromCalledFun(RWNode *phi, RWSubgraph *subg,\n                                      const DefSite &ds);\n\n    void addDefsFromUndefCall(Definitions &D, RWNode *defs, RWNode *call,\n                              bool isstrong);\n\n    template <typename Iterable>\n    void findPhiDefinitions(RWNode *phi, const Iterable &I) {\n        std::set<RWNode *> defs;\n\n        assert(phi->getOverwrites().size() == 1);\n        const auto &ds = *(phi->getOverwrites().begin());\n        // we handle this case separately\n        assert(!ds.target->isUnknown() && \"PHI for unknown memory\");\n\n        for (auto *block : I) {\n            auto tmpdefs = findDefinitions(block, ds);\n            defs.insert(tmpdefs.begin(), tmpdefs.end());\n        }\n\n        phi->addDefUse(defs);\n    }\n\n    /// Finding definitions for unknown memory\n    // Must be called after LVN proceeded - ideally only when the client is\n    // getting the definitions\n    std::vector<RWNode *> findAllDefinitions(RWNode *from);\n    Definitions collectAllDefinitions(RWNode *from);\n    /// if escaping is set to true, collect only definitions of escaping memory\n    // (optimization for searching definitions in callers)\n    void collectAllDefinitions(RWNode *from, Definitions &defs,\n                               bool escaping = false);\n    void collectAllDefinitions(Definitions &defs, RWBBlock *from,\n                               std::set<RWBBlock *> &visitedBlocks,\n                               bool escaping);\n\n    void collectAllDefinitionsInCallers(Definitions &defs, RWSubgraph *subg);\n\n    void findDefinitionsInSubgraph(RWNode *phi, RWNodeCall *C,\n                                   const DefSite &ds, RWSubgraph *subg);\n\n    void addDefinitionsFromCalledValue(RWNode *phi, RWNodeCall *C,\n                                       const DefSite &ds, RWNode *calledValue);\n\n    void computeModRef(RWSubgraph *subg, SubgraphInfo &si);\n    bool callMayDefineTarget(RWNodeCall *C, RWNode *target);\n\n    RWNode *createPhi(const DefSite &ds, RWNodeType type = RWNodeType::PHI);\n    RWNode *createPhi(Definitions &D, const DefSite &ds,\n                      RWNodeType type = RWNodeType::PHI);\n    RWNode *createAndPlacePhi(RWBBlock *block, const DefSite &ds);\n\n    // insert a (temporary) use into the graph before the node 'where'\n    RWNode *insertUse(RWNode *where, RWNode *mem, const Offset &off,\n                      const Offset &len);\n\n    std::vector<RWNode *> _phis;\n    dg::ADT::QueueLIFO<RWNode> _queue;\n    std::unordered_map<const RWSubgraph *, SubgraphInfo> _subgraphs_info;\n\n    Definitions &getBBlockDefinitions(RWBBlock *b, const DefSite *ds = nullptr);\n\n    SubgraphInfo &getSubgraphInfo(const RWSubgraph *s) {\n        return _subgraphs_info[s];\n    }\n    const SubgraphInfo *getSubgraphInfo(const RWSubgraph *s) const {\n        auto it = _subgraphs_info.find(s);\n        return it == _subgraphs_info.end() ? nullptr : &it->second;\n    }\n    BBlockInfo &getBBlockInfo(RWBBlock *b) {\n        return getSubgraphInfo(b->getSubgraph()).getBBlockInfo(b);\n    }\n\n    const BBlockInfo *getBBlockInfo(RWBBlock *b) const {\n        const auto *si = getSubgraphInfo(b->getSubgraph());\n        if (si) {\n            return si->getBBlockInfo(b);\n        }\n        return nullptr;\n    }\n\n    SubgraphInfo::Summary &getSubgraphSummary(const RWSubgraph *s) {\n        return getSubgraphInfo(s).getSummary();\n    }\n\n  public:\n    MemorySSATransformation(ReadWriteGraph &&graph,\n                            const DataDependenceAnalysisOptions &opts)\n            : DataDependenceAnalysisImpl(std::move(graph), opts) {}\n\n    MemorySSATransformation(ReadWriteGraph &&graph)\n            : DataDependenceAnalysisImpl(std::move(graph)) {}\n\n    void run() override;\n\n    // compute definitions for all uses at once\n    // (otherwise the definitions are computed on demand\n    // when calling getDefinitions())\n    void computeAllDefinitions();\n\n    // return the reaching definitions of ('mem', 'off', 'len')\n    // at the location 'where'\n    std::vector<RWNode *> getDefinitions(RWNode *where, RWNode *mem,\n                                         const Offset &off,\n                                         const Offset &len) override;\n\n    std::vector<RWNode *> getDefinitions(RWNode *use) override;\n\n    const Definitions *getDefinitions(RWBBlock *b) const {\n        const auto *bi = getBBlockInfo(b);\n        return bi ? &bi->getDefinitions() : nullptr;\n    }\n\n    const SubgraphInfo::Summary *getSummary(const RWSubgraph *s) const {\n        const auto *si = getSubgraphInfo(s);\n        if (!si)\n            return nullptr;\n        return &si->getSummary();\n    }\n};\n\n} // namespace dda\n} // namespace dg\n\n#endif // DG_MEMORY_SSA_H_\n"
  },
  {
    "path": "include/dg/MemorySSA/ModRef.h",
    "content": "#ifndef DG_MOD_REF_H_\n#define DG_MOD_REF_H_\n\n#include \"dg/Offset.h\"\n\n#include \"dg/MemorySSA/DefinitionsMap.h\"\n#include \"dg/ReadWriteGraph/RWNode.h\"\n\nnamespace dg {\nnamespace dda {\n\n// sumarized information about visible external\n// effects of the procedure\nclass ModRefInfo {\n    // to distinguish between empty and non-computed modref information\n    bool _initialized{false};\n\n  public:\n    // the set of memory that is defined in this procedure\n    // and is external to the subgraph or is local but its address is taken\n    // In other words, memory whose definitions can be \"visible\"\n    // outside the procedure.\n    // FIXME: we should keep only sets of DefSites\n    DefinitionsMap<RWNode> maydef;\n    // external or local address-taken memory that can be\n    // used inside the procedure\n    // FIXME: we should keep only sets of DefSites\n    DefinitionsMap<RWNode> mayref;\n    // memory that must be defined in this procedure\n    // (on every path through the procedure)\n    DefinitionsMap<RWNode> mustdef;\n\n    void addMayDef(const DefSite &ds, RWNode *def) {\n        // FIXME: do not store def, it is useless. Just takes memory...\n        maydef.add(ds, def);\n    }\n\n    template <typename C>\n    void addMayDef(const C &c, RWNode *def) {\n        for (auto &ds : c) {\n            maydef.add(ds, def);\n        }\n    }\n\n    void addMayRef(const DefSite &ds, RWNode *ref) {\n        // FIXME: do not store ref, it is useless. Just takes memory...\n        mayref.add(ds, ref);\n    }\n\n    template <typename C>\n    void addMayRef(const C &c, RWNode *ref) {\n        for (auto &ds : c) {\n            mayref.add(ds, ref);\n        }\n    }\n\n    void addMustDef(const DefSite &ds, RWNode *def) {\n        // FIXME: do not store def, it is useless. Just takes memory...\n        mustdef.add(ds, def);\n    }\n\n    template <typename C>\n    void addMustDef(const C &c, RWNode *def) {\n        for (auto &ds : c) {\n            mustdef.add(ds, def);\n        }\n    }\n\n    void add(const ModRefInfo &oth) {\n        maydef.add(oth.maydef);\n        mayref.add(oth.mayref);\n        mustdef.add(oth.mustdef);\n    }\n\n    ///\n    // Check whether the procedure may define 'n' (ignoring writes\n    // to unknown memory, \\see mayDefineOrUnknown())\n    bool mayDefine(RWNode *n) const { return maydef.definesTarget(n); }\n    bool mayDefineUnknown() const { return mayDefine(UNKNOWN_MEMORY); }\n\n    ///\n    // Check whether the procedure may define 'n', taking into\n    // account also writes to unknown memory\n    bool mayDefineOrUnknown(RWNode *n) const {\n        return mayDefine(n) or mayDefineUnknown();\n    }\n\n    auto getMayDef(RWNode *n) -> decltype(maydef.get(n)) {\n        return maydef.get(n);\n    }\n\n    void setInitialized() { _initialized = true; }\n    bool isInitialized() const { return _initialized; }\n};\n\n} // namespace dda\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/MemoryState.h",
    "content": "#ifndef DG_MEMORY_STATE_H_\n#define DG_MEMORY_STATE_H_\n\n#include \"dg/util/cow_shared_ptr.h\"\n#include <map>\n\nnamespace dg {\n\n// Representation of memory state with copy-on-write support\ntemplate <typename Key, typename Object>\nclass MemoryState {\n  public:\n    using Map = std::map<Key, cow_shared_ptr<Object>>;\n\n    const Object *get(Key k) const {\n        auto it = _memory.find(k);\n        if (it == _memory.end())\n            return nullptr;\n        return it->second.get();\n    };\n\n    Object *getWritable(Key k) { return _memory[k].getWritable(); };\n\n    void put(Key k, Object *o) { _memory[k].reset(o); }\n\n    // take the memory state rhs and copy\n    // entries for which this state does not have entry\n    bool copyMissing(const MemoryState &rhs) {\n        bool changed = false;\n        for (const auto &rit : rhs._memory) {\n            auto it = _memory.find(rit.first);\n            if (it == _memory.end()) {\n                _memory.emplace_hint(it, rit);\n                changed = true;\n            }\n        }\n\n        return changed;\n    }\n\n    bool merge(const MemoryState &rhs) {\n        bool changed = false;\n        for (const auto &rit : rhs._memory) {\n            auto it = _memory.find(rit.first);\n            if (it == _memory.end()) {\n                _memory.emplace_hint(it, rit);\n                changed = true;\n            } else {\n                // no update necessary\n                if (it->second == rit.second)\n                    continue;\n                auto our = it->second.getWritable();\n                changed |= our->merge(*rit.second.get());\n            }\n        }\n\n        return changed;\n    }\n\n  private:\n    Map _memory;\n\n  public:\n    auto begin() -> decltype(_memory.begin()) { return _memory.begin(); }\n    auto end() -> decltype(_memory.end()) { return _memory.end(); }\n    auto begin() const -> decltype(_memory.begin()) { return _memory.begin(); }\n    auto end() const -> decltype(_memory.end()) { return _memory.end(); }\n\n    // FIXME: add proper iterator\n};\n\n// copy-on-write container around MemoryState\ntemplate <typename Key, typename Object>\nclass COWMemoryState {\n    cow_shared_ptr<MemoryState<Key, Object>> state;\n\n    const Object *get(Key k) const { return state->get(k); };\n\n    Object *getWritable(Key k) { return state.getWritable()->getWritable(k); };\n\n    void put(Key k, Object *o) { state.getWritable()->put(k, o); }\n\n    // take the memory state rhs and copy\n    // entries for which this state does not have entry\n    bool copyMissing(const MemoryState &rhs) {\n        return state.getWritable()->copyMissing(rhs);\n    }\n\n    bool copyMissing(const COWMemoryState &rhs) {\n        return state.getWritable()->copyMissing(rhs.state);\n    }\n\n    bool merge(const MemoryState &rhs) {\n        return state.getWritable()->merge(rhs);\n    }\n\n    bool merge(const COWMemoryState &rhs) {\n        return state.getWritable()->merge(rhs.state);\n    }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/Node.h",
    "content": "#ifndef NODE_H_\n#define NODE_H_\n\n#include \"ADT/DGContainer.h\"\n#include \"DGParameters.h\"\n#include \"legacy/Analysis.h\"\n\nnamespace dg {\n\ntemplate <typename NodeT>\nclass DependenceGraph;\n\n/// ------------------------------------------------------------------\n//  -- Node\n//     one node in DependenceGraph. The type of dependence graph is\n//     fully determined by the type of node. Dependence graph is just\n//     a container for nodes - everything interesting is here.\n//     Concrete implementation will inherit from an instance of this\n//     template.\n/// ------------------------------------------------------------------\ntemplate <typename DependenceGraphT, typename KeyT, typename NodeT>\nclass Node {\n  public:\n    using EdgesT = EdgesContainer<NodeT>;\n    using ControlEdgesT = EdgesT;\n    using DataEdgesT = EdgesT;\n    using UseEdgesT = EdgesT;\n    using InterferenceEdges = EdgesT;\n\n    // to be able to reference the KeyT and DG\n    using KeyType = KeyT;\n    using DependenceGraphType = DependenceGraphT;\n\n    using control_iterator = typename ControlEdgesT::iterator;\n    using const_control_iterator = typename ControlEdgesT::const_iterator;\n    using data_iterator = typename DataEdgesT::iterator;\n    using const_data_iterator = typename DataEdgesT::const_iterator;\n    using use_iterator = typename DataEdgesT::iterator;\n    using const_use_iterator = typename DataEdgesT::const_iterator;\n    using interference_iterator = typename InterferenceEdges::iterator;\n    using const_interference_iterator =\n            typename InterferenceEdges::const_iterator;\n\n    Node(const KeyT &k) : key(k) {}\n\n    DependenceGraphT *setDG(DependenceGraphT *dg) {\n        DependenceGraphT *old = this->dg;\n        this->dg = dg;\n\n        return old;\n    }\n\n    DependenceGraphT *getDG() const { return dg; }\n\n    // add control dependence edge 'this'-->'n',\n    // thus making 'n' control dependend on this node\n    bool addControlDependence(NodeT *n) {\n        return _addBidirectionalEdge(static_cast<NodeT *>(this), n,\n                                     controlDepEdges, n->revControlDepEdges);\n    }\n\n    // add data dependence edge 'this'-->'n',\n    // thus making 'n' data dependend on this node\n    bool addDataDependence(NodeT *n) {\n        return _addBidirectionalEdge(static_cast<NodeT *>(this), n,\n                                     dataDepEdges, n->revDataDepEdges);\n    }\n\n    // this node uses (e.g. like an operand) the node 'n'\n    bool addUseDependence(NodeT *n) {\n        return _addBidirectionalEdge(static_cast<NodeT *>(this), n, useEdges,\n                                     n->userEdges);\n    }\n\n    bool addInterferenceDependence(NodeT *n) {\n        return _addBidirectionalEdge(static_cast<NodeT *>(this), n,\n                                     interferenceDepEdges,\n                                     n->revInterferenceDepEdges);\n    }\n\n    // remove edge 'this'-->'n' from control dependencies\n    bool removeControlDependence(NodeT *n) {\n        return _removeBidirectionalEdge(static_cast<NodeT *>(this), n,\n                                        controlDepEdges, n->revControlDepEdges);\n    }\n\n    // remove edge 'this'-->'n' from data dependencies\n    bool removeDataDependence(NodeT *n) {\n        return _removeBidirectionalEdge(static_cast<NodeT *>(this), n,\n                                        dataDepEdges, n->revDataDepEdges);\n    }\n\n    bool removeUseDependence(NodeT *n) {\n        return _removeBidirectionalEdge(static_cast<NodeT *>(this), n, useEdges,\n                                        n->userEdges);\n    }\n\n    bool removeInterferenceDependence(NodeT *n) {\n        return _removeBidirectionalEdge(static_cast<NodeT *>(this), n,\n                                        interferenceDepEdges,\n                                        n->revInterferenceDepEdges);\n    }\n\n    // remove all control dependencies going from/to this node\n    void removeOutcomingCDs() {\n        while (!controlDepEdges.empty())\n            removeControlDependence(*controlDepEdges.begin());\n    }\n\n    void removeIncomingCDs() {\n        while (!revControlDepEdges.empty()) {\n            NodeT *cd = *revControlDepEdges.begin();\n            // this will remove the reverse control dependence from\n            // this node\n            cd->removeControlDependence(static_cast<NodeT *>(this));\n        }\n    }\n\n    void removeCDs() {\n        removeOutcomingCDs();\n        removeIncomingCDs();\n    }\n\n    void removeOutcomingDDs() {\n        while (!dataDepEdges.empty())\n            removeDataDependence(*dataDepEdges.begin());\n    }\n\n    void removeIncomingDDs() {\n        while (!revDataDepEdges.empty()) {\n            NodeT *cd = *revDataDepEdges.begin();\n            // this will remove the reverse control dependence from\n            // this node\n            cd->removeDataDependence(static_cast<NodeT *>(this));\n        }\n    }\n\n    // remove all data dependencies going from/to this node\n    void removeDDs() {\n        removeOutcomingDDs();\n        removeIncomingDDs();\n    }\n\n    void removeOutcomingUses() {\n        while (!useEdges.empty())\n            removeUseDependence(*useEdges.begin());\n    }\n\n    void removeIncomingUses() {\n        while (!userEdges.empty()) {\n            NodeT *cd = *userEdges.begin();\n            // this will remove the reverse control dependence from\n            // this node\n            cd->removeUseDependence(static_cast<NodeT *>(this));\n        }\n    }\n\n    // remove all direct (top-level) data dependencies going from/to this node\n    void removeUses() {\n        removeOutcomingUses();\n        removeIncomingUses();\n    }\n\n    // remove all edges from/to this node\n    void isolate() {\n        // remove CD and DD and uses from this node\n        removeDDs();\n        removeUses();\n        removeCDs();\n\n#ifdef ENABLE_CFG\n        // if this is head or tail of BB,\n        // we must take it into account\n        if (basicBlock) {\n            // XXX removing the node from BB is in linear time,\n            // could we do it better?\n            basicBlock->removeNode(static_cast<NodeT *>(this));\n\n            // if this was the only node in BB, remove the BB\n            if (basicBlock->empty())\n                basicBlock->remove();\n\n            // if this is a callSite it is no longer part of BBlock,\n            // so we must remove it from callSites\n            if (hasSubgraphs()) {\n#ifndef NDEBUG\n                bool ret =\n#endif\n                        basicBlock->removeCallSite(static_cast<NodeT *>(this));\n                assert(ret && \"the call site was not in BB's callSites\");\n            }\n\n            basicBlock = nullptr;\n        }\n#endif\n    }\n\n    // control dependency edges iterators\n    control_iterator control_begin() { return controlDepEdges.begin(); }\n    const_control_iterator control_begin() const {\n        return controlDepEdges.begin();\n    }\n    control_iterator control_end() { return controlDepEdges.end(); }\n    const_control_iterator control_end() const { return controlDepEdges.end(); }\n\n    // reverse control dependency edges iterators\n    control_iterator rev_control_begin() { return revControlDepEdges.begin(); }\n    const_control_iterator rev_control_begin() const {\n        return revControlDepEdges.begin();\n    }\n    control_iterator rev_control_end() { return revControlDepEdges.end(); }\n    const_control_iterator rev_control_end() const {\n        return revControlDepEdges.end();\n    }\n\n    // interference dependency edges iteraotrs\n    const_interference_iterator interference_begin() const {\n        return interferenceDepEdges.begin();\n    }\n    interference_iterator interference_begin() {\n        return interferenceDepEdges.begin();\n    }\n    const_interference_iterator interference_end() const {\n        return interferenceDepEdges.end();\n    }\n    interference_iterator interference_end() {\n        return interferenceDepEdges.end();\n    }\n\n    // reverse interference dependency edges iterators\n    const_interference_iterator rev_interference_begin() const {\n        return revInterferenceDepEdges.begin();\n    }\n    interference_iterator rev_interference_begin() {\n        return revInterferenceDepEdges.begin();\n    }\n    const_interference_iterator rev_interference_end() const {\n        return revInterferenceDepEdges.end();\n    }\n    interference_iterator rev_interference_end() {\n        return revInterferenceDepEdges.end();\n    }\n\n    /// NOTE: we have two kinds of data dependencies.\n    // The first one is when a value is used as an argument\n    // in another instruction, that is direct (or top-level) dependency.\n    // The other case is when an instruction reads a value from memory\n    // which has been written by another instruction. This is\n    // \"indirect\" dependency.\n    // The user can choose whether to use both or just one of\n    // these dependencies.\n\n    // data dependency edges iterators (indirect dependency)\n    data_iterator data_begin() { return dataDepEdges.begin(); }\n    const_data_iterator data_begin() const { return dataDepEdges.begin(); }\n    data_iterator data_end() { return dataDepEdges.end(); }\n    const_data_iterator data_end() const { return dataDepEdges.end(); }\n\n    // reverse data dependency edges iterators (indirect dependency)\n    data_iterator rev_data_begin() { return revDataDepEdges.begin(); }\n    const_data_iterator rev_data_begin() const {\n        return revDataDepEdges.begin();\n    }\n    data_iterator rev_data_end() { return revDataDepEdges.end(); }\n    const_data_iterator rev_data_end() const { return revDataDepEdges.end(); }\n\n    // use dependency edges iterators (indirect data dependency\n    // -- uses of this node e.g. in operands)\n    use_iterator use_begin() { return useEdges.begin(); }\n    const_use_iterator use_begin() const { return useEdges.begin(); }\n    use_iterator use_end() { return useEdges.end(); }\n    const_use_iterator use_end() const { return useEdges.end(); }\n\n    // user dependency edges iterators (indirect data dependency)\n    use_iterator user_begin() { return userEdges.begin(); }\n    const_use_iterator user_begin() const { return userEdges.begin(); }\n    use_iterator user_end() { return userEdges.end(); }\n    const_use_iterator user_end() const { return userEdges.end(); }\n\n    size_t getControlDependenciesNum() const { return controlDepEdges.size(); }\n    size_t getRevControlDependenciesNum() const {\n        return revControlDepEdges.size();\n    }\n    size_t getDataDependenciesNum() const { return dataDepEdges.size(); }\n    size_t getRevDataDependenciesNum() const { return revDataDepEdges.size(); }\n    size_t getUseDependenciesNum() const { return useEdges.size(); }\n    size_t getUserDependenciesNum() const { return userEdges.size(); }\n\n#ifdef ENABLE_CFG\n    BBlock<NodeT> *getBBlock() { return basicBlock; }\n    const BBlock<NodeT> *getBBlock() const { return basicBlock; }\n\n    BBlock<NodeT> *setBasicBlock(BBlock<NodeT> *nbb) {\n        BBlock<NodeT> *old = basicBlock;\n        basicBlock = nbb;\n        return old;\n    }\n\n    unsigned int getDFSOrder() const { return analysisAuxData.dfsorder; }\n\n#endif /* ENABLE_CFG */\n\n    bool addSubgraph(DependenceGraphT *sub) {\n        bool ret = subgraphs.insert(sub).second;\n\n        if (ret) {\n            // increase references of this graph\n            // if we added it\n            sub->ref();\n            sub->addCaller(static_cast<NodeT *>(this));\n        }\n\n        return ret;\n    }\n\n    DGParameters<NodeT> *setParameters(DGParameters<NodeT> *params) {\n        DGParameters<NodeT> *old = parameters;\n\n        parameters = params;\n        return old;\n    }\n\n    const std::set<DependenceGraphT *> &getSubgraphs() const {\n        return subgraphs;\n    }\n\n    bool hasSubgraphs() const { return !subgraphs.empty(); }\n\n    size_t subgraphsNum() const { return subgraphs.size(); }\n\n    DGParameters<NodeT> *getParameters() const { return parameters; }\n\n    KeyT getKey() const { return key; }\n\n    uint32_t getSlice() const { return slice_id; }\n    uint32_t setSlice(uint32_t sid) {\n        uint32_t old = slice_id;\n        slice_id = sid;\n        return old;\n    }\n\n  protected:\n    // key uniquely identifying this node in a graph\n    KeyT key{};\n\n    // each node has a reference to the DependenceGraph\n    DependenceGraphT *dg{nullptr};\n\n  private:\n    // add an edge 'ths' --> 'n' to containers of 'ths' and 'n'\n    static bool _addBidirectionalEdge(NodeT *ths, NodeT *n, EdgesT &ths_cont,\n                                      EdgesT &n_cont) {\n#ifndef NDEBUG\n        bool ret1 =\n#endif\n                n_cont.insert(ths);\n        bool ret2 = ths_cont.insert(n);\n\n        assert(ret1 == ret2 &&\n               \"Already had one of the edges, but not the other\");\n\n        return ret2;\n    }\n\n    // remove edge 'this'-->'n' from control dependencies\n    static bool _removeBidirectionalEdge(NodeT *ths, NodeT *n, EdgesT &ths_cont,\n                                         EdgesT &n_cont) {\n        bool ret1 = n_cont.erase(ths);\n#ifndef NDEBUG\n        bool ret2 =\n#endif\n                ths_cont.erase(n);\n\n        // must have both or none\n        assert(ret1 == ret2 && \"An edge without rev. or vice versa\");\n\n        return ret1;\n    }\n\n    ControlEdgesT controlDepEdges;\n    DataEdgesT dataDepEdges;\n    UseEdgesT useEdges;\n    InterferenceEdges interferenceDepEdges;\n\n    // Nodes that have control/dep edge to this node\n    ControlEdgesT revControlDepEdges;\n    DataEdgesT revDataDepEdges;\n    UseEdgesT userEdges;\n    InterferenceEdges revInterferenceDepEdges;\n\n    // a node can have more subgraphs (i. e. function pointers)\n    std::set<DependenceGraphT *> subgraphs;\n\n    // actual parameters if this is a callsite\n    DGParameters<NodeT> *parameters{nullptr};\n\n    // id of the slice this nodes is in. If it is 0, it is in no slice\n    uint32_t slice_id{0};\n\n#ifdef ENABLE_CFG\n    // some analyses need classical CFG edges\n    // and it is better to have even basic blocks\n    BBlock<NodeT> *basicBlock{nullptr};\n#endif /* ENABLE_CFG */\n\n    // auxiliary data for different analyses\n    legacy::AnalysesAuxiliaryData analysisAuxData;\n    friend class legacy::Analysis<NodeT>;\n};\n\n} // namespace dg\n\n#endif // _NODE_H_\n"
  },
  {
    "path": "include/dg/NodesWalk.h",
    "content": "#ifndef DG_NODES_WALK_H_\n#define DG_NODES_WALK_H_\n\n#include <initializer_list>\n#include <set>\n\nnamespace dg {\n\n// universal but not very efficient visits tracker\ntemplate <typename Node>\nstruct SetVisitTracker {\n    std::set<Node *> _visited{};\n\n    void visit(Node *n) { _visited.insert(n); }\n    bool visited(Node *n) const { return _visited.count(n); }\n};\n\n// universal but not very efficient nodes info\ntemplate <typename Node>\nstruct SuccessorsEdgeChooser {\n    class range {\n        Node *_node;\n\n      public:\n        range(Node *n) : _node(n) {}\n\n        auto begin() -> decltype(_node->successors().begin()) {\n            return _node->successors().begin();\n        }\n\n        auto end() -> decltype(_node->successors().end()) {\n            return _node->successors().end();\n        }\n\n        auto begin() const -> decltype(_node->successors().begin()) {\n            return _node->successors().begin();\n        }\n\n        auto end() const -> decltype(_node->successors().end()) {\n            return _node->successors().end();\n        }\n    };\n\n    range operator()(Node *n) const { return range(n); }\n};\n\nnamespace sfinae {\n// std::void_t is from C++17...\ntemplate <typename... Ts>\nstruct make_void {\n    using type = void;\n};\ntemplate <typename... Ts>\nusing void_t = typename make_void<Ts...>::type;\n} // namespace sfinae\n\n// SFINAE check\ntemplate <typename T, typename = void>\nstruct has_foreach : std::false_type {};\ntemplate <typename T>\nstruct has_foreach<T, sfinae::void_t<decltype(&T::foreach)>> : std::true_type {\n};\n\ntemplate <typename Node, typename Queue,\n          typename VisitTracker = SetVisitTracker<Node>,\n          typename EdgeChooser = SuccessorsEdgeChooser<Node>>\nclass NodesWalk {\n    EdgeChooser _chooser{};\n    VisitTracker _visits{};\n    Queue _queue{};\n\n    void _enqueue(Node *n) {\n        _queue.push(n);\n        _visits.visit(n);\n    }\n\n    // edge chooser uses operator()\n    template <typename Func,\n              typename std::enable_if<!has_foreach<EdgeChooser>::value,\n                                      Func>::type * = nullptr>\n    void _run(Func F) {\n        while (!_queue.empty()) {\n            Node *current = _queue.pop();\n\n            F(current);\n\n            for (Node *succ : _chooser(current)) {\n                if (!_visits.visited(succ)) {\n                    _enqueue(succ);\n                }\n            }\n        }\n    }\n\n    // edge chooser yields nodes using foreach()\n    template <typename Func,\n              typename std::enable_if<has_foreach<EdgeChooser>::value,\n                                      Func>::type * = nullptr>\n    void _run(Func F) {\n        while (!_queue.empty()) {\n            Node *current = _queue.pop();\n\n            F(current);\n\n            _chooser.foreach (current, [&](Node *n) {\n                if (!_visits.visited(n)) {\n                    _enqueue(n);\n                }\n            });\n        }\n    }\n\n  public:\n    NodesWalk() = default;\n\n    NodesWalk(EdgeChooser &&chooser) : _chooser(std::move(chooser)) {}\n    NodesWalk(VisitTracker &&tracker) : _visits(std::move(tracker)) {}\n    NodesWalk(VisitTracker &&tracker, EdgeChooser &&chooser)\n            : _chooser(std::move(chooser)), _visits(std::move(tracker)) {}\n\n    template <typename Func>\n    void run(Node *start, Func F) {\n        _enqueue(start);\n        _run(F);\n    }\n\n    template <typename Func, typename Container>\n    void run(const Container &start, Func F) {\n        for (Node *n : start)\n            _enqueue(n);\n\n        _run(F);\n    }\n\n    template <typename Func>\n    void run(const std::initializer_list<Node *> &start, Func F) {\n        for (Node *n : start)\n            _enqueue(n);\n\n        _run(F);\n    }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/Offset.h",
    "content": "#ifndef DG_OFFSET_H_\n#define DG_OFFSET_H_\n\n#include <cstdint>\n\n#ifndef NDEBUG\n#include <iostream>\n#endif // not NDEBUG\n\nnamespace dg {\n\n// just a wrapper around uint64_t to\n// handle Offset::UNKNOWN somehow easily\n// maybe later we'll make it a range\nstruct Offset {\n    using type = uint64_t;\n\n    // the value used for the unknown offset\n    static const type UNKNOWN;\n\n    static Offset getUnknown() { return Offset(Offset::UNKNOWN); }\n\n    static Offset getZero() { return Offset(0); }\n\n    // cast to type\n    // operator type() { return offset; }\n\n    Offset(type o = UNKNOWN) : offset(o) {}\n    Offset(const Offset &) = default;\n\n    Offset operator+(const Offset o) const {\n        if (offset == UNKNOWN || o.offset == UNKNOWN ||\n            offset >= UNKNOWN - o.offset) {\n            return UNKNOWN;\n        }\n\n        return Offset(offset + o.offset);\n    }\n\n    Offset &operator+=(const Offset o) {\n        if (offset == UNKNOWN || o.offset == UNKNOWN ||\n            offset >= UNKNOWN - o.offset) {\n            offset = UNKNOWN;\n        } else {\n            offset += o.offset;\n        }\n\n        return *this;\n    }\n\n    Offset &operator=(const Offset o) {\n        offset = o.offset;\n        return *this;\n    }\n\n    Offset operator-(const Offset &o) const {\n        if (offset == UNKNOWN || o.offset == UNKNOWN || offset < o.offset) {\n            return Offset(UNKNOWN);\n        }\n\n        return Offset(offset - o.offset);\n    }\n\n    Offset &operator-(const Offset &o) {\n        if (offset == UNKNOWN || o.offset == UNKNOWN || offset < o.offset) {\n            offset = UNKNOWN;\n        } else {\n            offset -= o.offset;\n        }\n        return *this;\n    }\n\n    Offset &operator~() {\n        if (offset != UNKNOWN) {\n            offset = ~offset;\n        }\n        return *this;\n    }\n\n    Offset operator~() const {\n        if (offset != UNKNOWN) {\n            return Offset(~offset);\n        }\n        return Offset::UNKNOWN;\n    }\n\n    // strict comparision (no 'maybe' comparions\n    // that arises due to UNKNOWN)\n    bool operator<(const Offset &o) const { return offset < o.offset; }\n\n    bool operator>(const Offset &o) const { return offset > o.offset; }\n\n    bool operator<=(const Offset &o) const { return offset <= o.offset; }\n\n    bool operator>=(const Offset &o) const { return offset >= o.offset; }\n\n    bool operator==(const Offset &o) const { return offset == o.offset; }\n\n    bool operator!=(const Offset &o) const { return offset != o.offset; }\n\n    bool inRange(type from, type to) const {\n        return (offset >= from && offset <= to);\n    }\n\n    bool isUnknown() const { return offset == UNKNOWN; }\n    bool isZero() const { return offset == 0; }\n\n    type operator*() const { return offset; }\n    const type *operator->() const { return &offset; }\n\n#ifndef NDEBUG\n    friend std::ostream &operator<<(std::ostream &os, const Offset &o) {\n        if (o.isUnknown())\n            os << \"?\";\n        else\n            os << o.offset;\n        return os;\n    }\n\n    void dump() const { std::cout << *this << \"\\n\"; }\n#endif // not NDEBUG\n\n    type offset;\n};\n\n} // namespace dg\n\n#include <functional>\n\nnamespace std {\ntemplate <>\nstruct hash<dg::Offset> {\n    size_t operator()(const dg::Offset &o) const { return *o; }\n};\n} // namespace std\n\n#endif\n"
  },
  {
    "path": "include/dg/PointerAnalysis/MemoryObject.h",
    "content": "#ifndef DG_MEMORY_OBJECT_H_\n#define DG_MEMORY_OBJECT_H_\n\n#include <cassert>\n#include <map>\n#include <set>\n#include <unordered_map>\n\n#ifndef NDEBUG\n#include \"dg/PointerAnalysis/PSNode.h\"\n#include <iostream>\n#endif // not NDEBUG\n\n#include \"PointsToSet.h\"\n\nnamespace dg {\nnamespace pta {\n\nstruct MemoryObject {\n    using PointsToMapT = std::map<Offset, PointsToSetT>;\n\n    MemoryObject(/*uint64_t s = 0, bool isheap = false, */ PSNode *n = nullptr)\n            : node(n) /*, is_heap(isheap), size(s)*/ {}\n\n    // where was this memory allocated? for debugging\n    PSNode *node;\n    // possible pointers stored in this memory object\n    PointsToMapT pointsTo;\n\n    PointsToSetT &getPointsTo(const Offset off) { return pointsTo[off]; }\n\n    PointsToMapT::iterator find(const Offset off) { return pointsTo.find(off); }\n\n    PointsToMapT::const_iterator find(const Offset off) const {\n        return pointsTo.find(off);\n    }\n\n    PointsToMapT::iterator begin() { return pointsTo.begin(); }\n    PointsToMapT::iterator end() { return pointsTo.end(); }\n    PointsToMapT::const_iterator begin() const { return pointsTo.begin(); }\n    PointsToMapT::const_iterator end() const { return pointsTo.end(); }\n\n    bool merge(const MemoryObject &rhs) {\n        bool changed = false;\n        for (const auto &rit : rhs.pointsTo) {\n            if (rit.second.empty())\n                continue;\n            changed |= pointsTo[rit.first].add(rit.second);\n        }\n\n        return changed;\n    }\n\n    bool addPointsTo(const Offset &off, const Pointer &ptr) {\n        assert(ptr.target != nullptr &&\n               \"Cannot have NULL target, use unknown instead\");\n\n        return pointsTo[off].add(ptr);\n    }\n\n    bool addPointsTo(const Offset &off, const PointsToSetT &pointers) {\n        if (pointers.empty())\n            return false;\n        return pointsTo[off].add(pointers);\n    }\n\n    bool addPointsTo(const Offset &off,\n                     std::initializer_list<Pointer> pointers) {\n        if (pointers.size() == 0)\n            return false;\n        return pointsTo[off].add(pointers);\n    }\n\n#ifndef NDEBUG\n    void dump() const {\n        std::cout << \"MO [\" << this << \"] for \";\n        node->dump();\n    }\n\n    void dumpv() const {\n        dump();\n        for (const auto &it : pointsTo) {\n            std::cout << \"[\";\n            it.first.dump();\n            std::cout << \"]\";\n            for (const auto &ptr : it.second) {\n                std::cout << \"  -> \";\n                ptr.dump();\n                std::cout << \"\\n\";\n            }\n        }\n        std::cout << \"\\n\";\n    }\n\n    void print() const {\n        dump();\n        std::cout << \"\\n\";\n    }\n#endif // not NDEBUG\n};\n\n} // namespace pta\n} // namespace dg\n\n#endif // DG_MEMORY_OBJECT_H_\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PSNode.h",
    "content": "#ifndef DG_PS_NODE_H_\n#define DG_PS_NODE_H_\n\n#include <cassert>\n#include <cstdarg>\n#include <iostream>\n#include <string>\n#include <utility>\n\n#ifndef NDEBUG\n#include <iostream>\n#endif // not NDEBUG\n\n#include \"dg/PointerAnalysis/Pointer.h\"\n#include \"dg/PointerAnalysis/PointsToSet.h\"\n#include \"dg/SubgraphNode.h\"\n\nnamespace dg {\nnamespace pta {\n\nenum class PSNodeType {\n    // these are nodes that just represent memory allocation sites\n    ALLOC = 1,\n    LOAD,\n    STORE,\n    GEP,\n    PHI,\n    CAST,\n    // support for calls via function pointers.\n    // The FUNCTION node is the same as ALLOC\n    // but having it as separate type has the nice\n    // advantage of type checking\n    FUNCTION,\n    // support for interprocedural analysis,\n    // operands are null terminated. It is a noop,\n    // just for the user's convenience\n    CALL,\n    // call via function pointer\n    CALL_FUNCPTR,\n    // return from the subprocedure (in caller),\n    // synonym to PHI\n    CALL_RETURN,\n    // this is the entry node of a subprocedure\n    // and serves just as no op for our convenience,\n    // can be optimized away later\n    ENTRY,\n    // this is the exit node of a subprocedure\n    // that returns a value - works as phi node\n    RETURN,\n    // nodes which should represent creating\n    // and joining of threads\n    FORK,\n    JOIN,\n    // node that invalidates allocated memory\n    // after returning from a function\n    INVALIDATE_LOCALS,\n    // node that invalidates memory after calling free\n    // on a pointer\n    FREE,\n    // node that invalidates allocated memory\n    // after llvm.lifetime.end call\n    INVALIDATE_OBJECT,\n    // node that has only one points-to relation\n    // that never changes\n    CONSTANT,\n    // no operation node - this nodes can be used as a branch or join\n    // node for convenient PointerGraph generation. For example as an\n    // unified entry to the function or unified return from the function.\n    // These nodes can be optimized away later. No points-to computation\n    // is performed on them\n    NOOP,\n    // copy whole block of memory\n    MEMCPY,\n    // special nodes\n    NULL_ADDR,\n    UNKNOWN_MEM,\n    // tags memory as invalidated\n    INVALIDATED\n};\n\ninline const char *PSNodeTypeToCString(enum PSNodeType type) {\n#define ELEM(t)                                                                \\\n    case t:                                                                    \\\n        do {                                                                   \\\n            return (#t);                                                       \\\n        } while (0);                                                           \\\n        break;\n    switch (type) {\n        ELEM(PSNodeType::ALLOC)\n        ELEM(PSNodeType::LOAD)\n        ELEM(PSNodeType::STORE)\n        ELEM(PSNodeType::GEP)\n        ELEM(PSNodeType::PHI)\n        ELEM(PSNodeType::CAST)\n        ELEM(PSNodeType::FUNCTION)\n        ELEM(PSNodeType::CALL)\n        ELEM(PSNodeType::CALL_FUNCPTR)\n        ELEM(PSNodeType::CALL_RETURN)\n        ELEM(PSNodeType::FORK)\n        ELEM(PSNodeType::JOIN)\n        ELEM(PSNodeType::ENTRY)\n        ELEM(PSNodeType::RETURN)\n        ELEM(PSNodeType::CONSTANT)\n        ELEM(PSNodeType::NOOP)\n        ELEM(PSNodeType::MEMCPY)\n        ELEM(PSNodeType::NULL_ADDR)\n        ELEM(PSNodeType::UNKNOWN_MEM)\n        ELEM(PSNodeType::FREE)\n        ELEM(PSNodeType::INVALIDATE_OBJECT)\n        ELEM(PSNodeType::INVALIDATE_LOCALS)\n        ELEM(PSNodeType::INVALIDATED)\n    default:\n        assert(0 && \"unknown PointerGraph type\");\n        return \"Unknown type\";\n    };\n#undef ELEM\n}\n\nclass PointerGraph;\nclass PointerSubgraph;\n\nclass PSNode : public SubgraphNode<PSNode> {\n  public:\n    using IDType = SubgraphNode<PSNode>::IDType;\n\n  private:\n    PSNodeType type;\n\n    // in some cases some nodes are kind of paired - like formal and actual\n    // parameters or call and return node. Here the analasis can store\n    // such a node - if it needs for generating the PointerGraph\n    // - it is not used anyhow by the base analysis itself\n    // XXX: maybe we cold store this somewhere in a map instead of in every\n    // node (if the map is sparse, it would be much more memory efficient)\n    PSNode *pairedNode = nullptr;\n\n    // in some cases we need to know from which function the node is\n    PointerSubgraph *_parent = nullptr;\n\n    unsigned int dfsid = 0;\n\n  public:\n    ///\n    // Construct a PSNode\n    // \\param t     type of the node\n    // Different types take different arguments:\n    //\n    // ALLOC:        no argument\n    // FUNCTION:     no argument\n    // NOOP:         no argument\n    // ENTRY:        no argument\n    // LOAD:         one argument representing pointer to location from where\n    //               we're loading the value (another pointer in this case)\n    // STORE:        first argument is the value (the pointer to be stored)\n    //               in memory pointed by the second argument\n    // GEP:          get pointer to memory on given offset (get element pointer)\n    //               first argument is pointer to the memory, second is the\n    //               offset (as Offset class instance, unknown offset is\n    //               represented by Offset::UNKNOWN constant)\n    // CAST:         cast pointer from one type to other type (like void * to\n    //               int *). The pointers are just copied, so we can optimize\n    //               away this node later. The argument is just the pointer\n    //               (we don't care about types atm.)\n    // MEMCPY:       Copy whole block of memory. <from> <to> <offset> <len>\n    // FUNCTION:     Object representing the function in memory - so that it\n    //               can be pointed to and used as an argument to the Pointer\n    // CONSTANT:     node that keeps constant points-to information\n    //               the argument is the pointer it points to\n    // PHI:          phi node that gathers pointers from different paths in CFG\n    //               arguments are null-terminated list of the relevant nodes\n    //               from predecessors\n    // CALL:         represents call of subprocedure,\n    //               XXX: get rid of the arguments here?\n    //               arguments are null-terminated list of nodes that can user\n    //               use arbitrarily - they are not used by the analysis itself.\n    //               The arguments can be used e. g. when mapping call arguments\n    //               back to original CFG. Actually, the CALL node is not needed\n    //               in most cases (just 'inline' the subprocedure into the\n    //               PointerGraph when building it)\n    // CALL_FUNCPTR: call via function pointer. The argument is the node that\n    //               bears the pointers.\n    // CALL_RETURN:  site where given call returns. Bears the pointers\n    //               returned from the subprocedure. Works like PHI\n    // RETURN:       represents returning value from a subprocedure,\n    //               works as a PHI node - it gathers pointers returned from\n    //               the subprocedure\n    // INVALIDATE_LOCALS:\n    //               invalidates memory after returning from a function\n    // FREE:         invalidates memory after calling free function on a pointer\n\n    PSNode(IDType id, PSNodeType t) : SubgraphNode<PSNode>(id), type(t) {\n        switch (type) {\n        case PSNodeType::ALLOC:\n        case PSNodeType::FUNCTION:\n            // these always points-to itself\n            // (they points to the node where the memory was allocated)\n            addPointsTo(this, 0);\n            break;\n        default:\n            break;\n        }\n    }\n\n    // Unfortunately, constructors cannot use enums in templates\n    template <typename... Args>\n    PSNode(IDType id, PSNodeType type, Args &&...args) : PSNode(id, type) {\n        addOperand(std::forward<Args>(args)...);\n    }\n\n    virtual ~PSNode() = default;\n\n    PSNodeType getType() const { return type; }\n\n    // an auxiliary method to determine whether a node is a call\n    bool isCall() const {\n        return type == PSNodeType::CALL || type == PSNodeType::CALL_FUNCPTR;\n    }\n\n    void setParent(PointerSubgraph *p) { _parent = p; }\n    PointerSubgraph *getParent() { return _parent; }\n    const PointerSubgraph *getParent() const { return _parent; }\n\n    PSNode *getPairedNode() const { return pairedNode; }\n    void setPairedNode(PSNode *n) { pairedNode = n; }\n\n    bool isNull() const { return type == PSNodeType::NULL_ADDR; }\n    bool isUnknownMemory() const { return type == PSNodeType::UNKNOWN_MEM; }\n    bool isInvalidated() const { return type == PSNodeType::INVALIDATED; }\n\n    // make this public, that's basically the only\n    // reason the PointerGraph node exists, so don't hide it\n    PointsToSetT pointsTo;\n\n    // convenient helper\n    bool addPointsTo(PSNode *n, Offset o) {\n        return pointsTo.add(Pointer(n, o));\n    }\n    bool addPointsTo(const Pointer &ptr) { return pointsTo.add(ptr); }\n    bool addPointsTo(const PointsToSetT &ptrs) { return pointsTo.add(ptrs); }\n    bool addPointsTo(std::initializer_list<Pointer> ptrs) {\n        return pointsTo.add(ptrs);\n    }\n\n    bool doesPointsTo(const Pointer &p) const { return pointsTo.count(p) == 1; }\n\n    bool doesPointsTo(PSNode *n, Offset o = 0) const {\n        return doesPointsTo(Pointer(n, o));\n    }\n\n    ///\n    // Strip all casts from the node as the\n    // casts do not transform the pointer in any way\n    PSNode *stripCasts() {\n        PSNode *node = this;\n        while (node->getType() == PSNodeType::CAST)\n            node = node->getOperand(0);\n\n        return node;\n    }\n\n#ifndef NDEBUG\n    void dump() const override {\n        std::cout << \"<\" << getID() << \"> \" << PSNodeTypeToCString(getType());\n    }\n\n    // verbose dump\n    void dumpv() const override {\n        dump();\n        std::cout << \"(\";\n        int n = 0;\n        for (const auto *op : getOperands()) {\n            if (++n > 1)\n                std::cout << \", \";\n            op->dump();\n        }\n        std::cout << \")\";\n\n        for (const auto &ptr : pointsTo) {\n            std::cout << \"\\n  -> \";\n            ptr.dump();\n        }\n        std::cout << \"\\n\";\n    }\n#endif // not NDEBUG\n\n    // FIXME: maybe get rid of these friendships?\n    friend class PointerAnalysis;\n    friend class PointerGraph;\n\n    friend void getNodes(std::set<PSNode *> &cont, PSNode *n, PSNode *exit,\n                         unsigned int dfsnum);\n};\n\n// check type of node\ntemplate <PSNodeType T>\nbool isa(const PSNode *n) {\n    return n->getType() == T;\n}\n\ntemplate <typename T>\nstruct PSNodeGetter {\n    static T *get(PSNode *n) { return static_cast<T *>(n); }\n    static const T *get(const PSNode *n) { return static_cast<const T *>(n); }\n};\n\ntemplate <typename T>\nT *_cast(PSNode *n) {\n    assert(T::get(n) && \"Invalid cast\");\n    return T::get(n);\n}\n\nclass PSNodeAlloc : public PSNode {\n    // was memory zeroed at initialization or right after allocating?\n    bool zeroInitialized = false;\n    // is memory allocated on heap?\n    bool is_heap = false;\n    // is it a global value?\n    bool is_global = false;\n    // is it a temporary value? (its address cannot be taken)\n    bool is_temporary = false;\n\n  public:\n    PSNodeAlloc(IDType id, bool isTemp = false)\n            : PSNode(id, PSNodeType::ALLOC), is_temporary(isTemp) {}\n\n    template <typename T>\n    static auto get(T *n) -> decltype(PSNodeGetter<PSNodeAlloc>::get(n)) {\n        return isa<PSNodeType::ALLOC>(n) ? PSNodeGetter<PSNodeAlloc>::get(n)\n                                         : nullptr;\n    }\n\n    static PSNodeAlloc *cast(PSNode *n) { return _cast<PSNodeAlloc>(n); }\n\n    void setZeroInitialized() { zeroInitialized = true; }\n    bool isZeroInitialized() const { return zeroInitialized; }\n\n    void setIsHeap() { is_heap = true; }\n    bool isHeap() const { return is_heap; }\n\n    void setIsGlobal() { is_global = true; }\n    bool isGlobal() const { return is_global; }\n\n    void setIsTemporary() { is_temporary = true; }\n    bool isTemporary() const { return is_temporary; }\n};\n\n#if 0\nclass PSNodeTemporaryAlloc : public PSNodeAlloc {\n    PSNodeTemporaryAlloc(IDType id)\n    : PSNodeAlloc(id, PSNodeType::ALLOC, /* isTemp */ true) {}\n\n    static PSNodeTemporaryAlloc *get(PSNode *n) {\n        if (auto alloc = PSNodeAlloc::get(n)) {\n            return alloc->isTemporary() ?\n                    static_cast<PSNodeTemporaryAlloc *>(n) : nullptr;\n        }\n\n        return nullptr;\n    }\n};\n#endif\n\nclass PSNodeConstant : public PSNode {\n    Offset offset;\n\n  public:\n    PSNodeConstant(IDType id, PSNode *op, Offset offset)\n            : PSNode(id, PSNodeType::CONSTANT, op), offset(offset) {\n        addPointsTo(op, offset);\n    }\n\n    static PSNodeConstant *get(PSNode *n) {\n        return isa<PSNodeType::CONSTANT>(n) ? static_cast<PSNodeConstant *>(n)\n                                            : nullptr;\n    }\n\n    static PSNodeConstant *cast(PSNode *n) { return _cast<PSNodeConstant>(n); }\n\n    Pointer getPointer() const { return {getOperand(0), offset}; }\n    Offset getOffset() const { return offset; }\n    PSNode *getTarget() { return getOperand(0); }\n    const PSNode *getTarget() const { return getOperand(0); }\n};\n\nclass PSNodeMemcpy : public PSNode {\n    Offset len;\n\n  public:\n    PSNodeMemcpy(IDType id, PSNode *src, PSNode *dest, Offset len)\n            : PSNode(id, PSNodeType::MEMCPY, src, dest), len(len) {}\n\n    static PSNodeMemcpy *get(PSNode *n) {\n        return isa<PSNodeType::MEMCPY>(n) ? static_cast<PSNodeMemcpy *>(n)\n                                          : nullptr;\n    }\n\n    static PSNodeMemcpy *cast(PSNode *n) { return _cast<PSNodeMemcpy>(n); }\n\n    PSNode *getSource() const { return getOperand(0); }\n    PSNode *getDestination() const { return getOperand(1); }\n    Offset getLength() const { return len; }\n};\n\nclass PSNodeGep : public PSNode {\n    Offset offset;\n\n  public:\n    PSNodeGep(IDType id, PSNode *src, Offset o)\n            : PSNode(id, PSNodeType::GEP, src), offset(o) {}\n\n    static PSNodeGep *get(PSNode *n) {\n        return isa<PSNodeType::GEP>(n) ? static_cast<PSNodeGep *>(n) : nullptr;\n    }\n\n    // get() with a check\n    static PSNodeGep *cast(PSNode *n) { return _cast<PSNodeGep>(n); }\n\n    PSNode *getSource() const { return getOperand(0); }\n\n    void setOffset(uint64_t o) { offset = o; }\n    Offset getOffset() const { return offset; }\n};\n\nclass PSNodeEntry : public PSNode {\n    std::string functionName;\n    std::vector<PSNode *> callers;\n\n  public:\n    PSNodeEntry(IDType id, std::string name = \"not-known\")\n            : PSNode(id, PSNodeType::ENTRY), functionName(std::move(name)) {}\n\n    static PSNodeEntry *get(PSNode *n) {\n        return isa<PSNodeType::ENTRY>(n) ? static_cast<PSNodeEntry *>(n)\n                                         : nullptr;\n    }\n    static PSNodeEntry *cast(PSNode *n) { return _cast<PSNodeEntry>(n); }\n\n    void setFunctionName(const std::string &name) { functionName = name; }\n    const std::string &getFunctionName() const { return functionName; }\n\n    const std::vector<PSNode *> &getCallers() const { return callers; }\n\n    bool addCaller(PSNode *n) {\n        // we suppose there are just few callees,\n        // so this should be faster than std::set\n        for (auto *p : callers) {\n            if (p == n)\n                return false;\n        }\n\n        callers.push_back(n);\n        return true;\n    }\n};\n\nclass PSNodeCall : public PSNode {\n    // what this call calls?\n    std::vector<PointerSubgraph *> callees;\n    // where it returns?\n    PSNode *callReturn{nullptr};\n\n  public:\n    PSNodeCall(IDType id) : PSNode(id, PSNodeType::CALL) {}\n\n    PSNodeCall(IDType id, PSNode *op)\n            : PSNode(id, PSNodeType::CALL_FUNCPTR, op) {}\n\n    static PSNodeCall *get(PSNode *n) {\n        return (isa<PSNodeType::CALL>(n) || isa<PSNodeType::CALL_FUNCPTR>(n))\n                       ? static_cast<PSNodeCall *>(n)\n                       : nullptr;\n    }\n    static PSNodeCall *cast(PSNode *n) { return _cast<PSNodeCall>(n); }\n\n    void setCallReturn(PSNode *callRet) { callReturn = callRet; }\n    PSNode *getCallReturn() { return callReturn; }\n    const PSNode *getCallReturn() const { return callReturn; }\n\n    const std::vector<PointerSubgraph *> &getCallees() const { return callees; }\n\n    bool addCallee(PointerSubgraph *ps) {\n        // we suppose there are just few callees,\n        // so this should be faster than std::set\n        for (PointerSubgraph *p : callees) {\n            if (p == ps)\n                return false;\n        }\n\n        callees.push_back(ps);\n        return true;\n    }\n\n#ifndef NDEBUG\n    // verbose dump\n    void dumpv() const override {\n        PSNode::dumpv();\n        if (callReturn)\n            std::cout << \"returns to \" << callReturn->getID();\n        else\n            std::cout << \"does not return \";\n\n        std::cout << \" calls: [\";\n        int n = 0;\n        for (const auto *op : callees) {\n            if (++n > 1)\n                std::cout << \", \";\n            std::cout << op;\n        }\n        std::cout << \"]\";\n        std::cout << \"\\n\";\n    }\n#endif // not NDEBUG\n};\n\nclass PSNodeCallRet : public PSNode {\n    // return nodes that go to this call-return node\n    std::vector<PSNode *> returns;\n    PSNode *call;\n\n  public:\n    template <typename... Args>\n    PSNodeCallRet(IDType id, Args &&...args)\n            : PSNode(id, PSNodeType::CALL_RETURN, std::forward<Args>(args)...) {\n    }\n\n    static PSNodeCallRet *get(PSNode *n) {\n        return isa<PSNodeType::CALL_RETURN>(n) ? static_cast<PSNodeCallRet *>(n)\n                                               : nullptr;\n    }\n\n    static PSNodeCallRet *cast(PSNode *n) { return _cast<PSNodeCallRet>(n); }\n\n    void setCall(PSNode *c) { call = c; }\n    PSNode *getCall() { return call; }\n    const PSNode *getCall() const { return call; }\n\n    const std::vector<PSNode *> &getReturns() const { return returns; }\n\n    bool addReturn(PSNode *p) {\n        // we suppose there are just few callees,\n        // so this should be faster than std::set\n        for (auto *r : returns) {\n            if (p == r)\n                return false;\n        }\n\n        returns.push_back(p);\n        return true;\n    }\n\n#ifndef NDEBUG\n    // verbose dump\n    void dumpv() const override {\n        PSNode::dumpv();\n        std::cout << \"Return-site of call \" << call->getID() << \" rets: [\";\n        int n = 0;\n        for (const auto *op : returns) {\n            if (++n > 1)\n                std::cout << \", \";\n            op->dump();\n        }\n        std::cout << \"]\";\n        std::cout << \"\\n\";\n    }\n#endif // not NDEBUG\n};\n\nclass PSNodeRet : public PSNode {\n    // this node returns control to...\n    std::vector<PSNode *> returns;\n\n  public:\n    template <typename... Args>\n    PSNodeRet(IDType id, Args &&...args)\n            : PSNode(id, PSNodeType::RETURN, std::forward<Args>(args)...) {}\n\n    static PSNodeRet *get(PSNode *n) {\n        return isa<PSNodeType::RETURN>(n) ? static_cast<PSNodeRet *>(n)\n                                          : nullptr;\n    }\n\n    const std::vector<PSNode *> &getReturnSites() const { return returns; }\n\n    bool addReturnSite(PSNode *r) {\n        // we suppose there are just few callees,\n        // so this should be faster than std::set\n        for (PSNode *p : returns) {\n            if (p == r)\n                return false;\n        }\n\n        returns.push_back(r);\n        return true;\n    }\n\n#ifndef NDEBUG\n    // verbose dump\n    void dumpv() const override {\n        PSNode::dumpv();\n        std::cout << \"Returns from: [\";\n        int n = 0;\n        for (const auto *op : returns) {\n            if (++n > 1)\n                std::cout << \", \";\n            op->dump();\n        }\n        std::cout << \"]\";\n        std::cout << \"\\n\";\n    }\n#endif // not NDEBUG\n};\n\nclass PSNodeFork;\nclass PSNodeJoin;\n\nclass PSNodeFork : public PSNode {\n    PSNode *callInstruction = nullptr;\n    std::set<PSNodeJoin *> joins;\n    std::set<PSNode *> functions_;\n\n  public:\n    PSNodeFork(IDType id, PSNode *from) : PSNode(id, PSNodeType::FORK, from) {}\n\n    static PSNodeFork *get(PSNode *n) {\n        return isa<PSNodeType::FORK>(n) ? static_cast<PSNodeFork *>(n)\n                                        : nullptr;\n    }\n    static PSNodeFork *cast(PSNode *n) { return _cast<PSNodeFork>(n); }\n\n    std::set<PSNodeJoin *> getJoins() const { return joins; }\n\n    bool addFunction(PSNode *function) {\n        return functions_.insert(function).second;\n    }\n\n    std::set<PSNode *> functions() const { return functions_; }\n\n    void setCallInst(PSNode *callInst) { callInstruction = callInst; }\n\n    PSNode *callInst() const { return callInstruction; }\n\n    friend class PSNodeJoin;\n};\n\nclass PSNodeJoin : public PSNode {\n    PSNode *callInstruction = nullptr;\n    std::set<PSNodeFork *> forks_;\n    std::set<PSNode *> functions_;\n\n  public:\n    PSNodeJoin(IDType id) : PSNode(id, PSNodeType::JOIN) {}\n\n    static PSNodeJoin *get(PSNode *n) {\n        return isa<PSNodeType::JOIN>(n) ? static_cast<PSNodeJoin *>(n)\n                                        : nullptr;\n    }\n    static PSNodeJoin *cast(PSNode *n) { return _cast<PSNodeJoin>(n); }\n\n    void setCallInst(PSNode *callInst) { callInstruction = callInst; }\n\n    PSNode *callInst() const { return callInstruction; }\n\n    bool addFunction(PSNode *function) {\n        return functions_.insert(function).second;\n    }\n\n    bool addFork(PSNodeFork *fork) {\n        forks_.insert(fork);\n        return fork->joins.insert(this).second;\n    }\n\n    std::set<PSNodeFork *> forks() { return forks_; }\n\n    std::set<PSNode *> functions() const { return functions_; }\n\n    friend class PSNodeFork;\n};\n\ntemplate <PSNodeType Type, typename = void>\nstruct GetNodeType {\n    using type = PSNode;\n};\n\ntemplate <>\nstruct GetNodeType<PSNodeType::ALLOC> {\n    using type = PSNodeAlloc;\n};\n\ntemplate <>\nstruct GetNodeType<PSNodeType::CONSTANT> {\n    using type = PSNodeConstant;\n};\n\ntemplate <>\nstruct GetNodeType<PSNodeType::GEP> {\n    using type = PSNodeGep;\n};\n\ntemplate <>\nstruct GetNodeType<PSNodeType::MEMCPY> {\n    using type = PSNodeMemcpy;\n};\n\ntemplate <>\nstruct GetNodeType<PSNodeType::ENTRY> {\n    using type = PSNodeEntry;\n};\n\ntemplate <PSNodeType Type>\nstruct GetNodeType<\n        Type, typename std::enable_if<Type == PSNodeType::CALL ||\n                                      Type == PSNodeType::CALL_FUNCPTR>::type> {\n    using type = PSNodeCall;\n};\n\ntemplate <>\nstruct GetNodeType<PSNodeType::FORK> {\n    using type = PSNodeFork;\n};\n\ntemplate <>\nstruct GetNodeType<PSNodeType::JOIN> {\n    using type = PSNodeJoin;\n};\n\ntemplate <>\nstruct GetNodeType<PSNodeType::RETURN> {\n    using type = PSNodeRet;\n};\n\ntemplate <>\nstruct GetNodeType<PSNodeType::CALL_RETURN> {\n    using type = PSNodeCallRet;\n};\n\n} // namespace pta\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/PointerAnalysis/Pointer.h",
    "content": "#ifndef DG_POINTER_H_\n#define DG_POINTER_H_\n\n#include \"dg/Offset.h\"\n#include <cassert>\n#include <cstddef>\n\nnamespace dg {\nnamespace pta {\n\n// declare PSNode\nclass PSNode;\n\nextern PSNode *NULLPTR;\nextern PSNode *UNKNOWN_MEMORY;\nextern PSNode *INVALIDATED;\n\nstruct Pointer {\n    Pointer() = default;\n\n    Pointer(PSNode *n, Offset off) : target(n), offset(off) {\n        assert(n && \"Cannot have a pointer with nullptr as target\");\n    }\n\n    // PSNode that allocated the memory this pointer points-to\n    PSNode *target{nullptr};\n    // offset into the memory it points to\n    Offset offset;\n\n    bool operator<(const Pointer &oth) const {\n        return target == oth.target ? offset < oth.offset : target < oth.target;\n    }\n\n    bool operator==(const Pointer &oth) const {\n        return target == oth.target && offset == oth.offset;\n    }\n\n    bool isNull() const { return target == NULLPTR; }\n    bool isUnknown() const { return target == UNKNOWN_MEMORY; }\n    bool isValid() const { return !isNull() && !isUnknown(); }\n    bool isInvalidated() const { return target == INVALIDATED; }\n\n    size_t hash() const;\n\n#ifndef NDEBUG\n    void dump() const;\n    void print() const;\n#endif // not NDEBUG\n};\n\nextern const Pointer UnknownPointer;\nextern const Pointer NullPointer;\n\n} // namespace pta\n} // namespace dg\n\nnamespace std {\ntemplate <>\nstruct hash<dg::pta::Pointer> {\n    size_t operator()(const dg::pta::Pointer &p) const { return p.hash(); }\n};\n} // namespace std\n\n#endif\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointerAnalysis.h",
    "content": "#ifndef DG_POINTER_ANALYSIS_H_\n#define DG_POINTER_ANALYSIS_H_\n\n#include <cassert>\n#include <utility>\n#include <vector>\n\n#include \"dg/ADT/Queue.h\"\n#include \"dg/PointerAnalysis/MemoryObject.h\"\n#include \"dg/PointerAnalysis/Pointer.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisOptions.h\"\n#include \"dg/PointerAnalysis/PointerGraph.h\"\n\nnamespace dg {\nnamespace pta {\n\nclass PointerAnalysis {\n    static void initPointerAnalysis() {}\n\n  protected:\n    // a set of changed nodes that are going to be\n    // processed by the analysis\n    std::vector<PSNode *> to_process;\n    std::vector<PSNode *> changed;\n\n    // the pointer state subgraph\n    PointerGraph *PG{nullptr};\n\n    const PointerAnalysisOptions options{};\n\n  public:\n    PointerAnalysis(PointerGraph *ps, PointerAnalysisOptions opts)\n            : PG(ps), options(std::move(opts)) {\n        initPointerAnalysis();\n    }\n\n    // default options\n    PointerAnalysis(PointerGraph *ps) : PointerAnalysis(ps, {}) {}\n\n    virtual ~PointerAnalysis() = default;\n\n    // takes a PSNode 'where' and 'what' and reference to a vector\n    // and fills into the vector the objects that are relevant\n    // for the PSNode 'what' (valid memory states for of this PSNode)\n    // on location 'where' in PointerGraph\n    virtual void getMemoryObjects(PSNode *where, const Pointer &pointer,\n                                  std::vector<MemoryObject *> &objects) = 0;\n\n    /*\n    virtual bool addEdge(MemoryObject *from, MemoryObject *to,\n                         Offset off1 = 0, Offset off2 = 0)\n    {\n        return false;\n    }\n    */\n\n    /* hooks for analysis - optional. The analysis may do everything\n     * in getMemoryObjects, but spliting it into before-get-after sequence\n     * is more readable */\n    virtual bool beforeProcessed(PSNode * /*unused*/) { return false; }\n\n    virtual bool afterProcessed(PSNode * /*unused*/) { return false; }\n\n    PointerGraph *getPG() { return PG; }\n    const PointerGraph *getPG() const { return PG; }\n\n    virtual void enqueue(PSNode *n) { changed.push_back(n); }\n\n    virtual void preprocess() {}\n\n    void initialize_queue() {\n        assert(to_process.empty());\n\n        PSNode *root = PG->getEntry()->getRoot();\n        assert(root && \"Do not have root of PG\");\n        // rely on C++11 move semantics\n        to_process = PG->getNodes(root);\n    }\n\n    void queue_globals() {\n        assert(to_process.empty());\n        for (auto *g : PG->getGlobals()) {\n            to_process.push_back(g);\n        }\n    }\n\n    bool iteration() {\n        assert(changed.empty());\n\n        for (PSNode *cur : to_process) {\n            bool enq = false;\n            enq |= beforeProcessed(cur);\n            enq |= processNode(cur);\n            enq |= afterProcessed(cur);\n\n            if (enq)\n                enqueue(cur);\n        }\n\n        return !changed.empty();\n    }\n\n    void queue_changed() {\n        unsigned last_processed_num = to_process.size();\n        to_process.clear();\n\n        if (!changed.empty()) {\n            // DONT std::move - it prevents compiler from copy ellision\n            to_process = PG->getNodes(changed /* starting set */,\n                                      true /* interprocedural */,\n                                      last_processed_num /* expected num */);\n\n            // since changed was not empty,\n            // the to_process must not be empty too\n            assert(!to_process.empty());\n            assert(to_process.size() >= changed.size());\n            changed.clear();\n        }\n    }\n\n    bool run();\n\n    // generic error\n    // @msg - message for the user\n    // XXX: maybe create some enum that will represent the error\n    virtual bool error(PSNode * /*at*/, const char * /*msg*/) {\n        // let this on the user - in flow-insensitive analysis this is\n        // no error, but in flow sensitive it is ...\n        return false;\n    }\n\n    // handle specific situation (error) in the analysis\n    // @return whether the function changed the some points-to set\n    //  (e. g. added pointer to unknown memory)\n    virtual bool errorEmptyPointsTo(PSNode * /*from*/, PSNode * /*to*/) {\n        // let this on the user - in flow-insensitive analysis this is\n        // no error, but in flow sensitive it is ...\n        return false;\n    }\n\n    // adjust the PointerGraph on function pointer call\n    // @ where is the callsite\n    // @ what is the function that is being called\n    virtual bool functionPointerCall(PSNode * /*where*/, PSNode * /*what*/) {\n        return false;\n    }\n\n    // adjust the PointerGraph on when a new function that can be\n    // spawned by fork is discovered\n    // @ fork is the callsite\n    // @ called is the function that is being called\n    virtual bool handleFork(PSNode * /* fork */, PSNode * /* called */) {\n        return false;\n    }\n\n    // handle join of threads\n    // FIXME: this should be done in the generic pointer analysis,\n    // we do not need to pass this to the LLVM part...\n    virtual bool handleJoin(PSNode * /*unused*/) { return false; }\n\n  private:\n    // check the sanity of results of pointer analysis\n    void sanityCheck();\n\n    bool processNode(PSNode * /*node*/);\n    bool processLoad(PSNode *node);\n    bool processGep(PSNode *node);\n    bool processMemcpy(PSNode *node);\n    bool processMemcpy(std::vector<MemoryObject *> &srcObjects,\n                       std::vector<MemoryObject *> &destObjects,\n                       const Pointer &sptr, const Pointer &dptr, Offset len);\n};\n\n} // namespace pta\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointerAnalysisFI.h",
    "content": "#ifndef DG_ANALYSIS_POINTS_TO_FLOW_INSENSITIVE_H_\n#define DG_ANALYSIS_POINTS_TO_FLOW_INSENSITIVE_H_\n\n#include <cassert>\n#include <memory>\n#include <vector>\n\n#include \"PointerAnalysis.h\"\n\nnamespace dg {\nnamespace pta {\n\n///\n// Flow-insensitive inclusion-based pointer analysis\n//\nclass PointerAnalysisFI : public PointerAnalysis {\n    std::vector<std::unique_ptr<MemoryObject>> memory_objects;\n\n    void preprocessGEPs() {\n        // if a node is in a loop (a scc that has more than one node),\n        // then every GEP that is also stored to the same memory afterwards\n        // in the loop will end up with Offset::UNKNOWN after some\n        // number of iterations (in FI analysis), so we can do that right now\n        // and save iterations\n\n        assert(getPG() && \"Must have PG\");\n        for (const auto &sg : getPG()->getSubgraphs()) {\n            for (const auto &loop : sg->getLoops()) {\n                for (PSNode *n : loop) {\n                    if (PSNodeGep *gep = PSNodeGep::get(n))\n                        gep->setOffset(Offset::UNKNOWN);\n                }\n            }\n        }\n    }\n\n  public:\n    PointerAnalysisFI(PointerGraph *ps) : PointerAnalysisFI(ps, {}) {}\n\n    PointerAnalysisFI(PointerGraph *ps, const PointerAnalysisOptions &opts)\n            : PointerAnalysis(ps, opts) {\n        memory_objects.reserve(\n                std::max(ps->size() / 100, static_cast<size_t>(8)));\n    }\n\n    void preprocess() override {\n        if (options.preprocessGeps)\n            preprocessGEPs();\n    }\n\n    void getMemoryObjects(PSNode *where, const Pointer &pointer,\n                          std::vector<MemoryObject *> &objects) override {\n        // irrelevant in flow-insensitive\n        (void) where;\n        PSNode *n = pointer.target;\n\n        // we want to have memory in allocation sites\n        if (n->getType() == PSNodeType::CAST || n->getType() == PSNodeType::GEP)\n            n = n->getOperand(0);\n        else if (n->getType() == PSNodeType::CONSTANT) {\n            assert(n->pointsTo.size() == 1);\n            n = (*n->pointsTo.begin()).target;\n        }\n\n        if (n->getType() == PSNodeType::FUNCTION)\n            return;\n\n        assert(n->getType() == PSNodeType::ALLOC ||\n               n->getType() == PSNodeType::UNKNOWN_MEM);\n\n        MemoryObject *mo = n->getData<MemoryObject>();\n        if (!mo) {\n            mo = new MemoryObject(n);\n            memory_objects.emplace_back(mo);\n            n->setData<MemoryObject>(mo);\n        }\n\n        objects.push_back(mo);\n    }\n};\n\n} // namespace pta\n} // namespace dg\n\n#endif // DG_ANALYSIS_POINTS_TO_FLOW_INSENSITIVE_H_\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointerAnalysisFS.h",
    "content": "#ifndef DG_ANALYSIS_POINTS_TO_FLOW_SENSITIVE_H_\n#define DG_ANALYSIS_POINTS_TO_FLOW_SENSITIVE_H_\n\n#include <cassert>\n#include <memory>\n\n#include \"MemoryObject.h\"\n#include \"PointerGraph.h\"\n\nnamespace dg {\nnamespace pta {\n\n///\n// Flow-sensitive pointer analysis\n//\nclass PointerAnalysisFS : public PointerAnalysis {\n  public:\n    // using MemoryObjectsSetT = std::set<MemoryObject *>;\n    using MemoryMapT = std::map<PSNode *, std::unique_ptr<MemoryObject>>;\n\n    // this is an easy but not very efficient implementation,\n    // works for testing\n    PointerAnalysisFS(PointerGraph *ps, PointerAnalysisOptions opts)\n            : PointerAnalysis(ps, opts.setPreprocessGeps(false)) {\n        assert(opts.preprocessGeps == false &&\n               \"Preprocessing GEPs does not work correctly for FS analysis\");\n        memoryMaps.reserve(ps->size() / 5);\n        ps->computeLoops();\n    }\n\n    PointerAnalysisFS(PointerGraph *ps) : PointerAnalysisFS(ps, {}) {}\n\n    bool beforeProcessed(PSNode *n) override {\n        MemoryMapT *mm = n->getData<MemoryMapT>();\n        if (mm)\n            return false;\n\n        // on these nodes the memory map can change\n        if (needsMerge(n)) {\n            mm = createMM();\n\n            // if this is the root of the entry procedure,\n            // we must propagate the points-to information\n            // from the globals initialization\n            if (n == PG->getEntry()->getRoot()) {\n                mergeGlobalsState(mm, PG->getGlobals());\n            }\n        } else {\n            // this node can not change the memory map,\n            // so just add a pointer from the predecessor\n            // to this map\n            PSNode *pred = n->getSinglePredecessor();\n            mm = pred->getData<MemoryMapT>();\n            assert(mm && \"No memory map in the predecessor\");\n        }\n\n        assert(mm && \"Did not create the MM\");\n\n        // memory map initialized, set it as data,\n        // so that we won't initialize it again\n        n->setData<MemoryMapT>(mm);\n\n        return true;\n    }\n\n    bool afterProcessed(PSNode *n) override {\n        bool changed = false;\n        PointsToSetT *overwritten = nullptr;\n\n        MemoryMapT *mm = n->getData<MemoryMapT>();\n        // we must have the memory map, we created it\n        // in the beforeProcessed method\n        assert(mm && \"Do not have memory map\");\n\n        // every store that stores to a memory allocated\n        // not in a loop is a strong update\n        // FIXME: memcpy can be strong update too\n        if (n->getType() == PSNodeType::STORE) {\n            if (!pointsToAllocationInLoop(n->getOperand(1)))\n                overwritten = &n->getOperand(1)->pointsTo;\n        }\n\n        // merge information from predecessors if there's\n        // more of them (if there's just one predecessor\n        // and this is not a store, the memory map couldn't\n        // change, so we don't have to do that)\n        if (needsMerge(n)) {\n            for (PSNode *p : n->predecessors()) {\n                if (MemoryMapT *pm = p->getData<MemoryMapT>()) {\n                    // merge pm to mm (but only if pm was already created)\n                    changed |= mergeMaps(mm, pm, overwritten);\n                }\n            }\n\n            // interprocedural stuff - merge information from calls\n            if (auto *CR = PSNodeCallRet::get(n)) {\n                for (auto *p : CR->getReturns()) {\n                    if (MemoryMapT *pm = p->getData<MemoryMapT>()) {\n                        // merge pm to mm (but only if pm was already created)\n                        changed |= mergeMaps(mm, pm, overwritten);\n                    }\n                }\n            }\n            if (auto *E = PSNodeEntry::get(n)) {\n                for (auto *p : E->getCallers()) {\n                    if (MemoryMapT *pm = p->getData<MemoryMapT>()) {\n                        // merge pm to mm (but only if pm was already created)\n                        changed |= mergeMaps(mm, pm, overwritten);\n                    }\n                }\n            }\n        }\n\n        return changed;\n    }\n\n    bool functionPointerCall(PSNode * /*unused*/,\n                             PSNode * /*unused*/) override {\n        PG->computeLoops();\n        return false;\n    }\n\n    void getMemoryObjects(PSNode *where, const Pointer &pointer,\n                          std::vector<MemoryObject *> &objects) override {\n        MemoryMapT *mm = where->getData<MemoryMapT>();\n        assert(mm && \"Node does not have memory map\");\n\n        auto I = mm->find(pointer.target);\n        if (I != mm->end()) {\n            objects.push_back(I->second.get());\n        }\n\n        // if we haven't found any memory object, but this psnode\n        // is a write to memory, create a new one, so that\n        // the write has something to write to\n        if (objects.empty() && canChangeMM(where)) {\n            MemoryObject *mo = new MemoryObject(pointer.target);\n            mm->emplace(pointer.target, std::unique_ptr<MemoryObject>(mo));\n            objects.push_back(mo);\n        }\n    }\n\n  protected:\n    static bool canChangeMM(PSNode *n) {\n        switch (n->getType()) {\n        case PSNodeType::STORE:\n        case PSNodeType::MEMCPY:\n        case PSNodeType::CALL_FUNCPTR:\n            // a call via function pointer needs to\n            // have its own memory map as we dont know\n            // how the graph will look like after the\n            // call yet\n            return true;\n        case PSNodeType::CALL_RETURN:\n            // return from function that was called via function\n            // pointer must have its own memory map from the\n            // same reason why CALL_FUNCPTR nodes need its\n            // own memory map\n            assert(n->getPairedNode());\n            return n->getPairedNode()->getType() == PSNodeType::CALL_FUNCPTR;\n        default:\n            return false;\n        }\n\n        return false;\n    }\n\n    static bool mergeObjects(PSNode *node, MemoryObject *to, MemoryObject *from,\n                             PointsToSetT *overwritten) {\n        bool changed = false;\n\n        for (auto &fromIt : from->pointsTo) {\n            if (overwritten && overwritten->count(Pointer(node, fromIt.first)))\n                continue;\n\n            auto &S = to->pointsTo[fromIt.first];\n            for (const auto &ptr : fromIt.second)\n                changed |= S.add(ptr);\n        }\n\n        return changed;\n    }\n\n    // Merge two Memory maps, return true if any new information was created,\n    // otherwise return false\n    static bool mergeMaps(MemoryMapT *mm, MemoryMapT *from,\n                          PointsToSetT *overwritten) {\n        bool changed = false;\n        for (auto &it : *from) {\n            PSNode *fromTarget = it.first;\n            std::unique_ptr<MemoryObject> &toMo = (*mm)[fromTarget];\n            if (toMo == nullptr)\n                toMo.reset(new MemoryObject(fromTarget));\n\n            changed |= mergeObjects(fromTarget, toMo.get(), it.second.get(),\n                                    overwritten);\n        }\n\n        return changed;\n    }\n\n    MemoryMapT *createMM() {\n        MemoryMapT *mm = new MemoryMapT();\n        memoryMaps.emplace_back(mm);\n        return mm;\n    }\n\n    static bool isOnLoop(const PSNode *n) {\n        // if the scc's size > 1, the node is in loop\n        return n->getParent() ? (n->getParent()->getLoop(n) != nullptr) : false;\n    }\n\n    static bool pointsToAllocationInLoop(PSNode *n) {\n        for (const auto &ptr : n->pointsTo) {\n            // skip invalidated, null and unknown memory\n            if (!ptr.isValid() || ptr.isInvalidated())\n                continue;\n\n            if (isOnLoop(ptr.target))\n                return true;\n        }\n        return false;\n    }\n\n    static inline bool needsMerge(PSNode *n) {\n        return n->predecessorsNum() > 1 ||\n               n->predecessorsNum() == 0 ||               // root node\n               n->getType() == PSNodeType::CALL_RETURN || // call return is join\n               canChangeMM(n);\n    }\n\n    static void mergeGlobalsState(MemoryMapT *mm,\n                                  decltype(PG->getGlobals()) &globals) {\n        for (const auto &glob : globals) {\n            if (MemoryMapT *globmm = glob->getData<MemoryMapT>()) {\n                mergeMaps(mm, globmm, nullptr);\n            }\n        }\n    }\n\n  private:\n    // keep all the maps in order to free the memory\n    std::vector<std::unique_ptr<MemoryMapT>> memoryMaps;\n};\n\n} // namespace pta\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointerAnalysisFSInv.h",
    "content": "#ifndef DG_ANALYSIS_POINTS_TO_WITH_INVALIDATE_H_\n#define DG_ANALYSIS_POINTS_TO_WITH_INVALIDATE_H_\n\n#include \"PointerAnalysisFS.h\"\n#include <cassert>\n\nnamespace dg {\nnamespace pta {\n\nclass PointerAnalysisFSInv : public PointerAnalysisFS {\n    static bool canInvalidateMM(PSNode *n) {\n        return isa<PSNodeType::FREE>(n) ||\n               isa<PSNodeType::INVALIDATE_OBJECT>(n) ||\n               isa<PSNodeType::INVALIDATE_LOCALS>(n);\n    }\n\n    static bool needsMerge(PSNode *n) {\n        return canInvalidateMM(n) || PointerAnalysisFS::needsMerge(n);\n    }\n\n    static MemoryObject *getOrCreateMO(MemoryMapT *mm, PSNode *target) {\n        std::unique_ptr<MemoryObject> &moptr = (*mm)[target];\n        if (!moptr)\n            moptr.reset(new MemoryObject(target));\n\n        assert(mm->find(target) != mm->end());\n        return moptr.get();\n    }\n\n  public:\n    using MemoryMapT = PointerAnalysisFS::MemoryMapT;\n\n    // this is an easy but not very efficient implementation,\n    // works for testing\n    PointerAnalysisFSInv(PointerGraph *ps, PointerAnalysisOptions opts)\n            : PointerAnalysisFS(ps, opts.setInvalidateNodes(true)) {}\n\n    // default options\n    PointerAnalysisFSInv(PointerGraph *ps) : PointerAnalysisFSInv(ps, {}) {}\n\n    // NOTE: we must override this method as it is using our \"needsMerge\"\n    bool beforeProcessed(PSNode *n) override {\n        MemoryMapT *mm = n->getData<MemoryMapT>();\n        if (mm)\n            return false;\n\n        // on these nodes the memory map can change\n        if (needsMerge(n)) { // root node\n            mm = createMM();\n\n            // if this is the root of the entry procedure,\n            // we must propagate the points-to information\n            // from the globals initialization\n            if (n == PG->getEntry()->getRoot()) {\n                mergeGlobalsState(mm, PG->getGlobals());\n            }\n        } else {\n            // this node can not change the memory map,\n            // so just add a pointer from the predecessor\n            // to this map\n            PSNode *pred = n->getSinglePredecessor();\n            mm = pred->getData<MemoryMapT>();\n            assert(mm && \"No memory map in the predecessor\");\n        }\n\n        assert(mm && \"Did not create the MM\");\n\n        // memory map initialized, set it as data,\n        // so that we won't initialize it again\n        n->setData<MemoryMapT>(mm);\n\n        return true;\n    }\n\n    bool afterProcessed(PSNode *n) override {\n        if (n->getType() == PSNodeType::INVALIDATE_LOCALS)\n            return handleInvalidateLocals(n);\n        if (n->getType() == PSNodeType::INVALIDATE_OBJECT)\n            return invalidateMemory(n);\n        if (n->getType() == PSNodeType::FREE)\n            return handleFree(n);\n\n        assert(n->getType() != PSNodeType::FREE &&\n               n->getType() != PSNodeType::INVALIDATE_OBJECT &&\n               n->getType() != PSNodeType::INVALIDATE_LOCALS);\n\n        bool ret = PointerAnalysisFS::afterProcessed(n);\n\n        // check that all pointers in this memory map\n        // are initialized in all predecessors and\n        // set them to invalidated otherwise\n        MemoryMapT *mm = n->getData<MemoryMapT>();\n        assert(mm && \"Do not have memory map\");\n        if (n->predecessorsNum() > 1) {\n            for (PSNode *p : n->predecessors()) {\n                if (MemoryMapT *pm = p->getData<MemoryMapT>()) {\n                    ret |= handleUninitialized(mm, pm);\n                }\n            }\n        }\n        return ret;\n    }\n\n    static bool isLocal(PSNodeAlloc *alloc, PSNode *where) {\n        return !alloc->isHeap() && !alloc->isGlobal() &&\n               alloc->getParent() == where->getParent();\n    }\n\n    static bool containsRemovableLocals(PSNode *where, PointsToSetT &S) {\n        for (const auto &ptr : S) {\n            if (ptr.isNull() || ptr.isUnknown() || ptr.isInvalidated())\n                continue;\n\n            if (PSNodeAlloc *alloc = PSNodeAlloc::get(ptr.target)) {\n                if (isLocal(alloc, where) && knownInstance(alloc))\n                    return true;\n            }\n        }\n\n        return false;\n    }\n\n    // not very efficient\n    static void replaceLocalsWithInv(PSNode *where, PointsToSetT &S1) {\n        PointsToSetT S;\n\n        for (const auto &ptr : S1) {\n            if (ptr.isNull() || ptr.isUnknown() || ptr.isInvalidated())\n                continue;\n\n            if (PSNodeAlloc *alloc = PSNodeAlloc::get(ptr.target)) {\n                // if this is not local pointer or it is,\n                // but we do not know which instance is being destroyed,\n                // then keep the pointer\n                if (!isLocal(alloc, where) || !knownInstance(alloc))\n                    S.add(ptr);\n            }\n        }\n\n        S.add(INVALIDATED, 0);\n        S1.swap(S);\n    }\n\n    static inline bool isInvalidTarget(const PSNode *const target) {\n        return target == INVALIDATED || target == UNKNOWN_MEMORY ||\n               target == NULLPTR;\n    }\n\n    static bool handleInvalidateLocals(PSNode *node) {\n        bool changed = false;\n        for (PSNode *pred : node->predecessors()) {\n            changed |= handleInvalidateLocals(node, pred);\n        }\n        return changed;\n    }\n\n    static bool handleInvalidateLocals(PSNode *node, PSNode *pred) {\n        MemoryMapT *pmm = pred->getData<MemoryMapT>();\n        if (!pmm) {\n            // predecessor was not processed yet\n            return false;\n        }\n\n        MemoryMapT *mm = node->getData<MemoryMapT>();\n        assert(mm && \"Node does not have a memory map\");\n\n        bool changed = false;\n        for (auto &I : *pmm) {\n            if (isInvalidTarget(I.first))\n                continue;\n\n            // get or create a memory object for this target\n\n            MemoryObject *mo = getOrCreateMO(mm, I.first);\n            MemoryObject *pmo = I.second.get();\n\n            for (auto &it : *mo) {\n                // remove pointers to locals from the points-to set\n                if (containsRemovableLocals(node, it.second)) {\n                    replaceLocalsWithInv(node, it.second);\n                    assert(!containsRemovableLocals(node, it.second));\n                    changed = true;\n                }\n            }\n\n            for (auto &it : *pmo) {\n                PointsToSetT &predS = it.second;\n                if (predS.empty())\n                    continue;\n\n                PointsToSetT &S = mo->pointsTo[it.first];\n\n                // merge pointers from the previous states\n                // but do not include the pointers\n                // that _must_ point to destroyed memory\n                for (const auto &ptr : predS) {\n                    PSNodeAlloc *alloc = PSNodeAlloc::get(ptr.target);\n                    if (alloc && isLocal(alloc, node) && knownInstance(alloc)) {\n                        changed |= S.add(INVALIDATED, 0);\n                    } else\n                        changed |= S.add(ptr);\n                }\n\n                assert(!S.empty());\n            }\n        }\n\n        return changed;\n    }\n\n    static void replaceTargetWithInv(PointsToSetT &S1, PSNode *target) {\n        PointsToSetT S;\n        for (const auto &ptr : S1) {\n            if (ptr.target != target)\n                S.add(ptr);\n        }\n\n        S.add(INVALIDATED, 0);\n        S1.swap(S);\n    }\n\n    static bool invalidateMemory(PSNode *node) {\n        bool changed = false;\n        for (PSNode *pred : node->predecessors()) {\n            changed |= invalidateMemory(node, pred);\n        }\n        return changed;\n    }\n\n    static bool handleFree(PSNode *node) {\n        bool changed = false;\n        for (PSNode *pred : node->predecessors()) {\n            changed |= invalidateMemory(node, pred, true /* is free */);\n        }\n        return changed;\n    }\n\n    // return true if we know the instance of the object\n    // (allocations in loop or recursive calls may have\n    // multiple instances)\n    static bool knownInstance(const PSNode *node) { return !isOnLoop(node); }\n\n    static bool invStrongUpdate(const PSNode *operand) {\n        // If we are freeing memory through node that\n        // points to precisely known valid memory that is not allocated\n        // on a loop, we can do strong update.\n        //\n        // TODO: we can do strong update also on must-aliases\n        // of the invalidated pointer. That is, e.g. for\n        // free(p), we may do strong update for q if q is must-alias\n        // of p (no matter the size of p's and q's points-to sets)\n        if (operand->pointsTo.size() != 1)\n            return false;\n\n        const auto &ptr = *(operand->pointsTo.begin());\n        return !ptr.offset.isUnknown() && !isInvalidTarget(ptr.target) &&\n               knownInstance(ptr.target);\n    }\n\n    ///\n    // Check whether we can overwrite the memory object that was used to load\n    // the pointer into free().\n    // Return the PSNode that represents this memory object\n    static PSNode *moFromFreeToOverwrite(PSNode *operand) {\n        // Bail out if the operand has no pointers yet,\n        // otherwise we can add invalidated imprecisely\n        // (the rest of invalidateMemory would not perform strong update)\n        if (operand->pointsTo.empty())\n            return nullptr;\n\n        // invalidate(p) translates to\n        //  1 = load x\n        //  ...\n        //  invalidate(1)\n        // Get objects where x may point to. If this object is only one,\n        // then we know that this object will point to invalid memory\n        // (no what is its state).\n        PSNode *strippedOp = operand->stripCasts();\n        if (strippedOp->getType() == PSNodeType::LOAD) {\n            // get the pointer to the memory that holds the pointers\n            // that are being freed\n            PSNode *loadOp = strippedOp->getOperand(0);\n            if (invStrongUpdate(loadOp)) {\n                return (*(loadOp->pointsTo.begin())).target;\n            }\n        }\n\n        return nullptr;\n    }\n\n    static bool overwriteMOFromFree(MemoryMapT *mm, PSNode *target) {\n        // if we know exactly which memory object\n        // is being used for freeing the memory,\n        // we can set it to invalidated\n        auto *mo = getOrCreateMO(mm, target);\n        if (mo->pointsTo.size() == 1) {\n            auto &S = mo->pointsTo[0];\n            if (S.size() == 1 && (*S.begin()).target == INVALIDATED) {\n                return false; // no update\n            }\n        }\n\n        mo->pointsTo.clear();\n        mo->pointsTo[0].add(INVALIDATED, 0);\n        return true;\n    }\n\n    static bool invalidateMemory(PSNode *node, PSNode *pred,\n                                 bool is_free = false) {\n        MemoryMapT *pmm = pred->getData<MemoryMapT>();\n        if (!pmm) {\n            // predecessor was not processed yet\n            return false;\n        }\n\n        MemoryMapT *mm = node->getData<MemoryMapT>();\n        assert(mm && \"Node does not have memory map\");\n\n        bool changed = false;\n\n        PSNode *operand = node->getOperand(0);\n        PSNode *strong_update = nullptr;\n        // if we call e.g. free(load p), then the contents of\n        // the memory pointed by p will point\n        // to invalidated memory (we can do this when we\n        // know precisely what is the memory).\n        if (is_free) {\n            strong_update = moFromFreeToOverwrite(operand);\n            if (strong_update)\n                changed |= overwriteMOFromFree(mm, strong_update);\n        }\n\n        for (auto &I : *pmm) {\n            assert(I.first && \"nullptr as target\");\n\n            if (isInvalidTarget(I.first))\n                continue;\n\n            // strong update on this variable?\n            if (strong_update == I.first)\n                continue;\n\n            // get or create a memory object for this target\n            MemoryObject *mo = getOrCreateMO(mm, I.first);\n            MemoryObject *pmo = I.second.get();\n\n            // Remove references to invalidated memory from mo\n            // if the invalidated object is just one.\n            // Otherwise, add the invalidated pointer to the points-to sets\n            // (strong vs. weak update) as we do not know which\n            // object is actually being invalidated.\n            for (auto &it : *mo) {\n                if (invStrongUpdate(operand)) { // strong update\n                    const auto &ptr = *(operand->pointsTo.begin());\n                    if (ptr.isUnknown())\n                        changed |= it.second.add(INVALIDATED, 0);\n                    else if (ptr.isNull() || ptr.isInvalidated())\n                        continue;\n                    else if (it.second.pointsToTarget(ptr.target)) {\n                        replaceTargetWithInv(it.second, ptr.target);\n                        assert(!it.second.pointsToTarget(ptr.target));\n                        changed = true;\n                    }\n                } else { // weak update\n                    for (const auto &ptr : operand->pointsTo) {\n                        if (ptr.isNull() || ptr.isInvalidated())\n                            continue;\n\n                        // invalidate on unknown memory yields invalidate for\n                        // each element\n                        if (ptr.isUnknown() ||\n                            it.second.pointsToTarget(ptr.target)) {\n                            changed |= it.second.add(INVALIDATED, 0);\n                        }\n                    }\n                }\n            }\n\n            // merge pointers from pmo to mo, but skip\n            // the pointers that may point to the freed memory\n            for (auto &it : *pmo) {\n                PointsToSetT &predS = it.second;\n                if (predS.empty()) // keep the map clean\n                    continue;\n\n                PointsToSetT &S = mo->pointsTo[it.first];\n\n                // merge pointers from the previous states\n                // but do not include the pointers\n                // that may point to freed memory.\n                // These must be replaced with invalidated.\n                for (const auto &ptr : predS) {\n                    if (ptr.isValid() && // if the ptr is null or unkown,\n                                         // we want to copy it\n                        operand->pointsTo.pointsToTarget(ptr.target)) {\n                        if (!invStrongUpdate(operand)) {\n                            // we still want to copy the original pointer\n                            // if we cannot perform strong update\n                            // on this invalidated memory\n                            changed |= S.add(ptr);\n                        }\n                        changed |= S.add(INVALIDATED, 0);\n                    } else {\n                        // this is a pointer to some memory that was not\n                        // invalidated, so merge it into the points-to set\n                        changed |= S.add(ptr);\n                    }\n                }\n\n                assert(!S.empty());\n            }\n        }\n\n        return changed;\n    }\n\n    bool handleUninitialized(MemoryMapT *mm, MemoryMapT *pm) {\n        bool changed = false;\n        for (auto &it : *mm) {\n            auto pmit = pm->find(it.first);\n            if (pmit == pm->end()) {\n                for (auto &mit : *it.second) {\n                    if (mit.first.isUnknown())\n                        continue; // FIXME: we are optimistic here...\n                    changed |= it.second->addPointsTo(mit.first,\n                                                      Pointer{INVALIDATED, 0});\n                }\n                continue;\n            }\n\n            /* check the initialization of memory objects\n            auto *pmo = pmit->second.get();\n            for (auto &mit : *it.second) {\n                if (pmo->find(mit.first) != pmo->end())\n                    continue;\n                if (mit.first.isUnknown())\n                    continue; // FIXME: we are optimistic here...\n\n                changed |= it.second->addPointsTo(mit.first,\n                                                  Pointer{INVALIDATED, 0});\n            }\n            */\n        }\n\n        return changed;\n    }\n};\n\n} // namespace pta\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointerAnalysisOptions.h",
    "content": "#ifndef DG_POINTER_ANALYSIS_OPTIONS_H_\n#define DG_POINTER_ANALYSIS_OPTIONS_H_\n\n#include \"dg/AnalysisOptions.h\"\n\nnamespace dg {\n\nstruct PointerAnalysisOptions : AnalysisOptions {\n    // Preprocess GEP nodes such that the offset\n    // is directly set to UNKNOWN if we can identify\n    // that it will be the result of the computation\n    // (saves iterations)\n    bool preprocessGeps{true};\n\n    // Should the analysis keep track of invalidate\n    // (e.g. freed) memory? Pointers pointing to such\n    // memory are then represented as pointing to\n    // INVALIDATED object.\n    bool invalidateNodes{false};\n\n    PointerAnalysisOptions &setInvalidateNodes(bool b) {\n        invalidateNodes = b;\n        return *this;\n    }\n    PointerAnalysisOptions &setPreprocessGeps(bool b) {\n        preprocessGeps = b;\n        return *this;\n    }\n\n    // Perform maximally this number of iterations.\n    // If exceeded, the analysis is terminated and points-to sets\n    // of the unprocessed nodes are set to {}.\n    size_t maxIterations{0};\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointerGraph.h",
    "content": "#ifndef DG_POINTER_GRAPH_H_\n#define DG_POINTER_GRAPH_H_\n\n#include \"dg/ADT/Queue.h\"\n#include \"dg/BFS.h\"\n#include \"dg/CallGraph/CallGraph.h\"\n#include \"dg/PointerAnalysis/PSNode.h\"\n#include \"dg/SCC.h\"\n#include \"dg/SubgraphNode.h\"\n#include \"dg/util/debug.h\"\n\n#include <cassert>\n#include <cstdarg>\n#include <functional>\n#include <memory>\n#include <unordered_map>\n#include <vector>\n\nnamespace dg {\nnamespace pta {\n\n// special nodes and pointers to them\n\nclass PointerGraph;\n\n// A single procedure in Pointer Graph\nclass PointerSubgraph {\n    friend class PointerGraph;\n\n    unsigned _id{0};\n\n    PointerSubgraph(unsigned id, PSNode *r1, PSNode *va = nullptr)\n            : _id(id), root(r1), vararg(va) {}\n\n    // non-trivial strongly connected components\n    bool _computed_loops{false};\n    std::vector<std::vector<PSNode *>> _loops;\n    std::unordered_map<const PSNode *, size_t> _node_to_loop;\n\n  public:\n    PointerSubgraph(PointerSubgraph &&) = default;\n    PointerSubgraph() = default;\n    PointerSubgraph(const PointerSubgraph &) = delete;\n\n    unsigned getID() const { return _id; }\n\n    // FIXME: make the attrs private\n\n    // the first node of the subgraph. XXX: rename to entry\n    PSNode *root{nullptr};\n\n    // return nodes of this graph\n    std::set<PSNode *> returnNodes{};\n\n    // this is the node where we gather the variadic-length arguments\n    PSNode *vararg{nullptr};\n\n    PSNode *getRoot() { return root; }\n    const PSNode *getRoot() const { return root; }\n\n    bool computedLoops() const { return _computed_loops; }\n\n    // information about loops in this subgraph\n    const std::vector<PSNode *> *getLoop(const PSNode *nd) const {\n        assert(_computed_loops && \"Call computeLoops() first\");\n\n        auto it = _node_to_loop.find(nd);\n        assert(it == _node_to_loop.end() || it->second < _loops.size());\n        return it == _node_to_loop.end() ? nullptr : &_loops[it->second];\n    }\n\n    const std::vector<std::vector<PSNode *>> &getLoops() const {\n        assert(_computed_loops && \"Call computeLoops() first\");\n        return _loops;\n    }\n\n    const std::vector<std::vector<PSNode *>> &getLoops() {\n        if (!computedLoops())\n            computeLoops();\n        return _loops;\n    }\n\n    // FIXME: remember just that a node is on loop, not the whole loops\n    void computeLoops();\n};\n\n// IDs of special nodes\nenum PointerGraphReservedIDs {\n    ID_UNKNOWN = 1,\n    ID_NULL = 2,\n    ID_INVALIDATED = 3,\n    LAST_RESERVED_ID = 3\n};\n\n///\n// Basic graph for pointer analysis\n// -- contains CFG graphs for all procedures of the program.\nclass PointerGraph {\n    unsigned int dfsnum{0};\n\n    // root of the pointer state subgraph\n    PointerSubgraph *_entry{nullptr};\n\n    using NodesT = std::vector<std::unique_ptr<PSNode>>;\n    using GlobalNodesT = std::vector<PSNode *>;\n    using SubgraphsT = std::vector<std::unique_ptr<PointerSubgraph>>;\n\n    NodesT nodes;\n    SubgraphsT _subgraphs;\n\n    // Take care of assigning ids to new nodes\n    unsigned int last_node_id = PointerGraphReservedIDs::LAST_RESERVED_ID;\n    unsigned int getNewNodeId() { return ++last_node_id; }\n\n    GenericCallGraph<PSNode *> callGraph;\n    GlobalNodesT _globals;\n\n    // check for correct count of variadic arguments\n    template <PSNodeType type, size_t actual_size>\n    constexpr static ssize_t expected_args_size() {\n        // C++14 TODO: replace this atrocity with a switch\n        return type == PSNodeType::NOOP || type == PSNodeType::ENTRY ||\n                               type == PSNodeType::FUNCTION ||\n                               type == PSNodeType::FORK ||\n                               type == PSNodeType::JOIN\n                       ? 0\n               : type == PSNodeType::CAST || type == PSNodeType::LOAD ||\n                               type == PSNodeType::INVALIDATE_OBJECT ||\n                               type == PSNodeType::INVALIDATE_LOCALS ||\n                               type == PSNodeType::FREE\n                       ? 1\n               : type == PSNodeType::STORE || type == PSNodeType::CONSTANT ? 2\n               : type == PSNodeType::CALL || type == PSNodeType::CALL_FUNCPTR ||\n                               type == PSNodeType::CALL_RETURN ||\n                               type == PSNodeType::PHI ||\n                               type == PSNodeType::RETURN\n                       ? actual_size\n                       : -1;\n    }\n\n    // C++17 TODO:\n    //   * replace the two definitions of nodeFactory with one using\n    //     `if constexpr (needs_type)`\n    //   * replace GetNodeType with a chain of `if constexpr` expressions\n    template <PSNodeType Type, typename... Args,\n              typename Node = typename GetNodeType<Type>::type>\n    typename std::enable_if<!std::is_same<Node, PSNode>::value, Node *>::type\n    nodeFactory(Args &&...args) {\n        return new Node(getNewNodeId(), std::forward<Args>(args)...);\n    }\n\n    // we need to check that the number of arguments is correct with general\n    // PSNode\n    template <PSNodeType Type, typename... Args,\n              typename Node = typename GetNodeType<Type>::type>\n    typename std::enable_if<std::is_same<Node, PSNode>::value, Node *>::type\n    nodeFactory(Args &&...args) {\n        static_assert(expected_args_size<Type, sizeof...(args)>() ==\n                              sizeof...(args),\n                      \"Incorrect number of arguments\");\n        return new Node(getNewNodeId(), Type, std::forward<Args>(args)...);\n    }\n\n  public:\n    PointerGraph() {\n        // nodes[0] represents invalid node (the node with id 0)\n        nodes.emplace_back(nullptr);\n        // the first several nodes are special nodes. For now, we just replace\n        // them with nullptr, as those are created statically <-- FIXME!\n        nodes.emplace_back(nullptr);\n        nodes.emplace_back(nullptr);\n        nodes.emplace_back(nullptr);\n        assert(nodes.size() - 1 == PointerGraphReservedIDs::LAST_RESERVED_ID);\n        initStaticNodes();\n    }\n\n    static void initStaticNodes();\n\n    PointerSubgraph *createSubgraph(PSNode *root, PSNode *vararg = nullptr) {\n        // NOTE: id of the subgraph is always index in _subgraphs + 1\n        _subgraphs.emplace_back(new PointerSubgraph(\n                static_cast<unsigned>(_subgraphs.size()) + 1, root, vararg));\n        return _subgraphs.back().get();\n    }\n\n    template <PSNodeType Type, typename... Args>\n    PSNode *create(Args &&...args) {\n        PSNode *n = nodeFactory<Type>(std::forward<Args>(args)...);\n        nodes.emplace_back(n); // C++17 returns a referece\n        assert(n->getID() == nodes.size() - 1);\n        return n;\n    }\n\n    // create a global node. Global nodes will be processed\n    // in the same order in which they are created.\n    // The global nodes are processed only once before the\n    // analysis starts.\n    template <PSNodeType Type, typename... Args>\n    PSNode *createGlobal(Args &&...args) {\n        PSNode *n = create<Type>(std::forward<Args>(args)...);\n        _globals.push_back(n); // C++17 returns a referece\n        assert(n->getID() == nodes.size() - 1);\n        return n;\n    }\n\n    bool registerCall(PSNode *a, PSNode *b) { return callGraph.addCall(a, b); }\n\n    GenericCallGraph<PSNode *> &getCallGraph() { return callGraph; }\n    const GenericCallGraph<PSNode *> &getCallGraph() const { return callGraph; }\n    const SubgraphsT &getSubgraphs() const { return _subgraphs; }\n\n    const NodesT &getNodes() const { return nodes; }\n    const GlobalNodesT &getGlobals() const { return _globals; }\n    size_t size() const { return nodes.size() + _globals.size(); }\n\n    void computeLoops();\n\n    PointerGraph(PointerGraph &&) = default;\n    PointerGraph &operator=(PointerGraph &&) = default;\n    PointerGraph(const PointerGraph &) = delete;\n    PointerGraph operator=(const PointerGraph &) = delete;\n\n    PointerSubgraph *getEntry() const { return _entry; }\n    void setEntry(PointerSubgraph *e);\n\n    void remove(PSNode *nd);\n\n    // get nodes in BFS order and store them into\n    // the container\n    template <typename ContainerOrNode>\n    std::vector<PSNode *> getNodes(const ContainerOrNode &start,\n                                   bool interprocedural = true,\n                                   unsigned expected_num = 0) {\n        ++dfsnum;\n\n        std::vector<PSNode *> cont;\n        if (expected_num != 0)\n            cont.reserve(expected_num);\n\n        struct DfsIdTracker {\n            const unsigned dfsnum;\n            DfsIdTracker(unsigned dnum) : dfsnum(dnum) {}\n\n            void visit(PSNode *n) { n->dfsid = dfsnum; }\n            bool visited(PSNode *n) const { return n->dfsid == dfsnum; }\n        };\n\n        // iterate over successors and call (return) edges\n        struct EdgeChooser {\n            const bool interproc;\n            EdgeChooser(bool inter = true) : interproc(inter) {}\n\n            void foreach (PSNode *cur, std::function<void(PSNode *)> Dispatch) {\n                if (interproc) {\n                    if (PSNodeCall *C = PSNodeCall::get(cur)) {\n                        for (auto *subg : C->getCallees()) {\n                            Dispatch(subg->root);\n                        }\n                        // we do not need to iterate over succesors\n                        // if we dive into the procedure (as we will\n                        // return via call return)\n                        // NOTE: we must iterate over successors if the\n                        // function is undefined\n                        if (!C->getCallees().empty())\n                            return;\n                    } else if (PSNodeRet *R = PSNodeRet::get(cur)) {\n                        for (auto *ret : R->getReturnSites()) {\n                            Dispatch(ret);\n                        }\n                        if (!R->getReturnSites().empty())\n                            return;\n                    }\n                }\n\n                for (auto *s : cur->successors())\n                    Dispatch(s);\n            }\n        };\n\n        DfsIdTracker visitTracker(dfsnum);\n        EdgeChooser chooser(interprocedural);\n        BFS<PSNode, DfsIdTracker, EdgeChooser> bfs(visitTracker, chooser);\n\n        bfs.run(start, [&cont](PSNode *n) { cont.push_back(n); });\n\n        return cont;\n    }\n};\n\n///\n// get nodes reachable from n (including n),\n// stop at node 'exit' (excluding) if not set to null\ninline std::set<PSNode *> getReachableNodes(PSNode *n, PSNode *exit = nullptr,\n                                            bool interproc = true) {\n    ADT::QueueFIFO<PSNode *> fifo;\n    std::set<PSNode *> cont;\n\n    assert(n && \"No starting node given.\");\n    fifo.push(n);\n\n    while (!fifo.empty()) {\n        PSNode *cur = fifo.pop();\n        if (!cont.insert(cur).second)\n            continue; // we already visited this node\n\n        for (PSNode *succ : cur->successors()) {\n            assert(succ != nullptr);\n\n            if (succ == exit)\n                continue;\n\n            fifo.push(succ);\n        }\n\n        if (interproc) {\n            if (PSNodeCall *C = PSNodeCall::get(cur)) {\n                for (auto *subg : C->getCallees()) {\n                    if (subg->root == exit)\n                        continue;\n                    fifo.push(subg->root);\n                }\n            } else if (PSNodeRet *R = PSNodeRet::get(cur)) {\n                for (auto *ret : R->getReturnSites()) {\n                    if (ret == exit)\n                        continue;\n                    fifo.push(ret);\n                }\n            }\n        }\n    }\n\n    return cont;\n}\n\n} // namespace pta\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointerGraphOptimizations.h",
    "content": "#ifndef DG_POINTER_SUBGRAPH_OPTIMIZATIONS_H_\n#define DG_POINTER_SUBGRAPH_OPTIMIZATIONS_H_\n\n#include \"PointsToMapping.h\"\n\nnamespace dg {\nnamespace pta {\n\nclass PSNoopRemover {\n    PointerGraph *G;\n\n  public:\n    PSNoopRemover(PointerGraph *g) : G(g) {}\n    unsigned run();\n};\n\n// try to remove loads/stores that are provably\n// loads and stores of unknown memory\n// (these usually correspond to integers)\nclass PSUnknownsReducer {\n    using MappingT = PointsToMapping<PSNode *>;\n\n    PointerGraph *G;\n    MappingT mapping;\n\n    unsigned removed = 0;\n\n    void processAllocs();\n\n  public:\n    PSUnknownsReducer(PointerGraph *g) : G(g) {}\n\n    MappingT &getMapping() { return mapping; }\n    const MappingT &getMapping() const { return mapping; }\n\n    unsigned run() {\n        processAllocs();\n        return removed;\n    };\n};\n\nclass PSEquivalentNodesMerger {\n  public:\n    using MappingT = PointsToMapping<PSNode *>;\n\n    PSEquivalentNodesMerger(PointerGraph *g) : G(g), merged_nodes_num(0) {\n        mapping.reserve(32);\n    }\n\n    MappingT &getMapping() { return mapping; }\n    const MappingT &getMapping() const { return mapping; }\n\n    unsigned getNumOfMergedNodes() const { return merged_nodes_num; }\n\n    unsigned run() {\n        mergeCasts();\n        return merged_nodes_num;\n    }\n\n  private:\n    // get rid of all casts\n    void mergeCasts();\n\n    // merge node1 and node2 (node2 will be\n    // the representant and node1 will be removed,\n    // mapping will be set to  node1 -> node2)\n    void merge(PSNode *node1, PSNode *node2);\n\n    PointerGraph *G;\n    // map nodes to its equivalent representant\n    MappingT mapping;\n\n    unsigned merged_nodes_num;\n};\n\nclass PointerGraphOptimizer {\n    using MappingT = PointsToMapping<PSNode *>;\n\n    PointerGraph *G;\n    MappingT mapping;\n\n    unsigned removed = 0;\n\n  public:\n    PointerGraphOptimizer(PointerGraph *g) : G(g) {}\n\n    void removeNoops() {\n        PSNoopRemover remover(G);\n        removed += remover.run();\n    }\n\n    void removeUnknowns() {\n        PSUnknownsReducer reducer(G);\n        if (auto r = reducer.run()) {\n            mapping.merge(std::move(reducer.getMapping()));\n            removed += r;\n        }\n    }\n\n    void removeEquivalentNodes() {\n        PSEquivalentNodesMerger merger(G);\n        if (auto r = merger.run()) {\n            mapping.merge(std::move(merger.getMapping()));\n            removed += r;\n        }\n    }\n\n    unsigned run() {\n        removeNoops();\n        removeEquivalentNodes();\n        removeUnknowns();\n        // need to call this once more because\n        // the optimizations may have created\n        // the same operands in a phi nodes,\n        // which breaks the validity of the graph\n        removeEquivalentNodes();\n\n        return removed;\n    }\n\n    unsigned getNumOfRemovedNodes() const { return removed; }\n    MappingT &getMapping() { return mapping; }\n    const MappingT &getMapping() const { return mapping; }\n};\n\n} // namespace pta\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointerGraphValidator.h",
    "content": "#ifndef DG_POINTER_SUBGRAPH_VALIDATOR_H_\n#define DG_POINTER_SUBGRAPH_VALIDATOR_H_\n\n#include \"dg/PointerAnalysis/PointerGraph.h\"\n#include <string>\n\nnamespace dg {\nnamespace pta {\n\n/**\n * Take PointerGraph instance and check whether it is not broken\n * FIXME: make this private to PointerGraph\n */\nclass PointerGraphValidator {\n    /* These methods return true if the graph is invalid */\n    bool checkEdges();\n    bool checkNodes();\n    bool checkOperands();\n\n    // do not check for the connectivity of the graph\n    bool no_connectivity;\n\n  protected:\n    const PointerGraph *PS;\n\n    std::string errors{};\n    std::string warnings{};\n\n    virtual bool reportInvalOperands(const PSNode *n,\n                                     const std::string &user_err = \"\");\n    virtual bool reportInvalEdges(const PSNode *n,\n                                  const std::string &user_err = \"\");\n    virtual bool reportInvalNode(const PSNode *n,\n                                 const std::string &user_err = \"\");\n    virtual bool reportUnreachableNode(const PSNode * /*nd*/);\n\n    virtual bool warn(const PSNode *n, const std::string &warning);\n\n  public:\n    PointerGraphValidator(const PointerGraph *ps, bool no_conn = false)\n            : no_connectivity(no_conn), PS(ps) {}\n    virtual ~PointerGraphValidator() = default;\n\n    bool validate();\n\n    const std::string &getErrors() const { return errors; }\n    const std::string &getWarnings() const { return warnings; }\n};\n\n} // namespace pta\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointsToMapping.h",
    "content": "#ifndef DG_POINTS_TO_MAPPING_H_\n#define DG_POINTS_TO_MAPPING_H_\n\n#include \"PSNode.h\"\n#include <unordered_map>\n\nnamespace dg {\nnamespace pta {\n\n// this is a wrapper around a map that\n// is supposed to keep mapping of program values\n// to pointer analysis nodes that are actually not\n// created (or that are removed later by an analysis).\ntemplate <typename ValT>\nclass PointsToMapping {\n    using MappingT = std::unordered_map<ValT, PSNode *>;\n    using iterator = typename MappingT::iterator;\n    using const_iterator = typename MappingT::const_iterator;\n\n    MappingT mapping;\n\n  public:\n    void reserve(size_t s) { mapping.reserve(s); }\n\n    size_t size() const { return mapping.size(); }\n\n    PSNode *get(ValT val) const {\n        auto it = mapping.find(val);\n        if (it == mapping.end())\n            return nullptr;\n\n        return it->second;\n    }\n\n    void add(ValT val, PSNode *nd) {\n        auto it = mapping.find(val);\n        assert(it == mapping.end());\n        mapping.emplace_hint(it, val, nd);\n    }\n\n    void set(ValT val, PSNode *nd) { mapping[val] = nd; }\n\n    // merge some other points-to mapping to this one\n    // (destroying the other one). If there are\n    // duplicates values, than the ones from 'rhs'\n    // are used\n    void merge(PointsToMapping &&rhs) {\n        // merge values from this map to rhs (making preference for\n        // duplicate rhs values).\n        rhs.mapping.insert(mapping.begin(), mapping.end());\n        rhs.mapping.swap(mapping);\n        rhs.mapping.clear();\n    }\n\n    // compose this mapping with some other mapping:\n    // (PSNode * -> PSNode *) o (ValT -> PSNode *)\n    // leads to (ValT -> PSNode *).\n    void compose(PointsToMapping<PSNode *> &&rhs) {\n        for (auto &it : mapping) {\n            if (PSNode *rhs_node = rhs.get(it.second)) {\n                it.second = rhs_node;\n            }\n        }\n    }\n\n    iterator begin() { return mapping.begin(); }\n    iterator end() { return mapping.end(); }\n    const_iterator begin() const { return mapping.begin(); }\n    const_iterator end() const { return mapping.end(); }\n};\n\n} // namespace pta\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointsToSet.h",
    "content": "#ifndef DG_POINTS_TO_SET_H_\n#define DG_POINTS_TO_SET_H_\n\n#include \"dg/PointerAnalysis/PointsToSets/AlignedPointerIdPointsToSet.h\"\n#include \"dg/PointerAnalysis/PointsToSets/AlignedSmallOffsetsPointsToSet.h\"\n#include \"dg/PointerAnalysis/PointsToSets/OffsetsSetPointsToSet.h\"\n#include \"dg/PointerAnalysis/PointsToSets/PointerIdPointsToSet.h\"\n#include \"dg/PointerAnalysis/PointsToSets/SeparateOffsetsPointsToSet.h\"\n#include \"dg/PointerAnalysis/PointsToSets/SimplePointsToSet.h\"\n#include \"dg/PointerAnalysis/PointsToSets/SmallOffsetsPointsToSet.h\"\n\nnamespace dg {\nnamespace pta {\n\nusing PointsToSetT = PointerIdPointsToSet;\nusing PointsToMapT = std::map<Offset, PointsToSetT>;\n\n} // namespace pta\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointsToSets/AlignedPointerIdPointsToSet.h",
    "content": "#ifndef DG_ALIGNEDBITVECTORPOINTSTOSET_H\n#define DG_ALIGNEDBITVECTORPOINTSTOSET_H\n\n#include \"dg/ADT/Bitvector.h\"\n#include \"dg/PointerAnalysis/Pointer.h\"\n#include \"dg/util/iterators.h\"\n\n#include <cassert>\n#include <map>\n#include <set>\n#include <vector>\n\nnamespace dg {\nnamespace pta {\n\nclass PSNode;\n\nclass AlignedPointerIdPointsToSet {\n    static const unsigned int multiplier = 4;\n\n    ADT::SparseBitvector pointers;\n    std::set<Pointer> overflowSet;\n    static std::map<Pointer, size_t> ids; // pointers are numbered 1, 2, ...\n    static std::vector<Pointer>\n            idVector; // starts from 0 (pointer = idVector[id - 1])\n\n    // if the pointer doesn't have ID, it's assigned one\n    static size_t getPointerID(const Pointer &ptr) {\n        auto it = ids.find(ptr);\n        if (it != ids.end()) {\n            return it->second;\n        }\n        idVector.push_back(ptr);\n        return ids.emplace_hint(it, ptr, ids.size() + 1)->second;\n    }\n\n    bool addWithUnknownOffset(PSNode *node) {\n        removeAny(node);\n        return !pointers.set(getPointerID({node, Offset::UNKNOWN}));\n    }\n\n    static bool isOffsetValid(Offset off) {\n        return off.isUnknown() || *off % multiplier == 0;\n    }\n\n  public:\n    AlignedPointerIdPointsToSet() = default;\n    AlignedPointerIdPointsToSet(std::initializer_list<Pointer> elems) {\n        add(elems);\n    }\n\n    bool add(PSNode *target, Offset off) { return add(Pointer(target, off)); }\n\n    bool add(const Pointer &ptr) {\n        if (has({ptr.target, Offset::UNKNOWN})) {\n            return false;\n        }\n        if (ptr.offset.isUnknown()) {\n            return addWithUnknownOffset(ptr.target);\n        }\n        if (isOffsetValid(ptr.offset)) {\n            return !pointers.set(getPointerID(ptr));\n        }\n        return overflowSet.insert(ptr).second;\n    }\n\n    bool add(const AlignedPointerIdPointsToSet &S) {\n        bool changed = pointers.set(S.pointers);\n        for (const auto &ptr : S.overflowSet) {\n            changed |= overflowSet.insert(ptr).second;\n        }\n        return changed;\n    }\n\n    bool remove(const Pointer &ptr) {\n        if (isOffsetValid(ptr.offset)) {\n            return pointers.unset(getPointerID(ptr));\n        }\n        return overflowSet.erase(ptr) != 0;\n    }\n\n    bool remove(PSNode *target, Offset offset) {\n        return remove(Pointer(target, offset));\n    }\n\n    bool removeAny(PSNode *target) {\n        std::vector<size_t> toRemove;\n        for (const auto &ptrID : pointers) {\n            if (idVector[ptrID - 1].target == target) {\n                toRemove.push_back(ptrID);\n            }\n        }\n\n        for (auto ptrID : toRemove) {\n            pointers.unset(ptrID);\n        }\n\n        bool changed = false;\n        auto it = overflowSet.begin();\n        while (it != overflowSet.end()) {\n            if (it->target == target) {\n                it = overflowSet.erase(it);\n                // Note: the iterator to the next element is now in it\n                changed = true;\n            } else {\n                it++;\n            }\n        }\n        return changed || !toRemove.empty();\n    }\n\n    void clear() {\n        pointers.reset();\n        overflowSet.clear();\n    }\n\n    bool pointsTo(const Pointer &ptr) const {\n        if (isOffsetValid(ptr.offset)) {\n            return pointers.get(getPointerID(ptr));\n        }\n        return overflowSet.find(ptr) != overflowSet.end();\n    }\n\n    bool mayPointTo(const Pointer &ptr) const {\n        return pointsTo(ptr) || pointsTo(Pointer(ptr.target, Offset::UNKNOWN));\n    }\n\n    bool mustPointTo(const Pointer &ptr) const {\n        assert(!ptr.offset.isUnknown() && \"Makes no sense\");\n        return pointsTo(ptr) && isSingleton();\n    }\n\n    bool pointsToTarget(PSNode *target) const {\n        for (const auto &kv : ids) {\n            if (kv.first.target == target && pointers.get(kv.second)) {\n                return true;\n            }\n        }\n        return dg::any_of(overflowSet, [target](const Pointer &ptr) {\n            return ptr.target == target;\n        });\n    }\n\n    bool isSingleton() const {\n        return (pointers.size() == 1 && overflowSet.empty()) ||\n               (pointers.empty() && overflowSet.size() == 1);\n    }\n\n    bool empty() const { return pointers.empty() && overflowSet.empty(); }\n\n    size_t count(const Pointer &ptr) const { return pointsTo(ptr); }\n\n    bool has(const Pointer &ptr) const { return count(ptr) > 0; }\n\n    bool hasUnknown() const { return pointsToTarget(UNKNOWN_MEMORY); }\n\n    bool hasNull() const { return pointsToTarget(NULLPTR); }\n\n    bool hasInvalidated() const { return pointsToTarget(INVALIDATED); }\n\n    size_t size() const { return pointers.size() + overflowSet.size(); }\n\n    void swap(AlignedPointerIdPointsToSet &rhs) {\n        pointers.swap(rhs.pointers);\n        overflowSet.swap(rhs.overflowSet);\n    }\n\n    size_t overflowSetSize() const { return overflowSet.size(); }\n\n    static unsigned int getMultiplier() { return multiplier; }\n\n    class const_iterator {\n        typename ADT::SparseBitvector::const_iterator bitvector_it;\n        typename ADT::SparseBitvector::const_iterator bitvector_end;\n        typename std::set<Pointer>::const_iterator set_it;\n        bool secondContainer;\n\n        const_iterator(const ADT::SparseBitvector &pointers,\n                       const std::set<Pointer> &overflow, bool end = false)\n                : bitvector_it(end ? pointers.end() : pointers.begin()),\n                  bitvector_end(pointers.end()),\n                  set_it(end ? overflow.end() : overflow.begin()),\n                  secondContainer(end) {\n            if (bitvector_it == bitvector_end) {\n                secondContainer = true;\n            }\n        }\n\n      public:\n        const_iterator &operator++() {\n            if (!secondContainer) {\n                bitvector_it++;\n                if (bitvector_it == bitvector_end) {\n                    secondContainer = true;\n                }\n            } else {\n                set_it++;\n            }\n            return *this;\n        }\n\n        const_iterator operator++(int) {\n            auto tmp = *this;\n            operator++();\n            return tmp;\n        }\n\n        Pointer operator*() const {\n            if (!secondContainer) {\n                return {idVector[*bitvector_it - 1]};\n            }\n            return *set_it;\n        }\n\n        bool operator==(const const_iterator &rhs) const {\n            return bitvector_it == rhs.bitvector_it && set_it == rhs.set_it;\n        }\n\n        bool operator!=(const const_iterator &rhs) const {\n            return !operator==(rhs);\n        }\n\n        friend class AlignedPointerIdPointsToSet;\n    };\n\n    const_iterator begin() const { return {pointers, overflowSet}; }\n    const_iterator end() const {\n        return {pointers, overflowSet, true /* end */};\n    }\n\n    friend class const_iterator;\n};\n\n} // namespace pta\n} // namespace dg\n\n#endif // DG_ALIGNEDBITVECTORPOINTSTOSET_H\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointsToSets/AlignedSmallOffsetsPointsToSet.h",
    "content": "#ifndef ALIGNEDOFFSETSPOINTSTOSET_H\n#define ALIGNEDOFFSETSPOINTSTOSET_H\n\n#include \"dg/ADT/Bitvector.h\"\n#include \"dg/PointerAnalysis/Pointer.h\"\n\n#include <cassert>\n#include <map>\n#include <set>\n#include <vector>\n\nnamespace dg {\nnamespace pta {\n\nclass PSNode;\n\nclass AlignedSmallOffsetsPointsToSet {\n    static const size_t MAX_OFFSET = 63;\n    static const unsigned int multiplier =\n            4; // offsets that are divisible by this value are stored in\n               // bitvector up to 62 * multiplier\n\n    ADT::SparseBitvector pointers;\n    std::set<Pointer> oddPointers;\n    static std::map<PSNode *, size_t> ids; // nodes are numbered 1,2, ...\n    static std::vector<PSNode *>\n            idVector; // starts from 0 (node = idVector[id - 1])\n\n    // if the node doesn't have ID, it's assigned one\n    static size_t getNodeID(PSNode *node) {\n        auto it = ids.find(node);\n        if (it != ids.end()) {\n            return it->second;\n        }\n        idVector.push_back(node);\n        return ids.emplace_hint(it, node, ids.size() + 1)->second;\n    }\n\n    static size_t getNodePosition(PSNode *node) {\n        return ((getNodeID(node) - 1) * (MAX_OFFSET + 1));\n    }\n\n    static size_t getPosition(PSNode *node, Offset off) {\n        if (off.isUnknown()) {\n            return getNodePosition(node) + MAX_OFFSET;\n        }\n        return getNodePosition(node) + (*off / multiplier);\n    }\n\n    static bool isOffsetValid(Offset off) {\n        return off.isUnknown() || (*off <= (MAX_OFFSET - 1) * multiplier &&\n                                   *off % multiplier == 0);\n    }\n\n    bool addWithUnknownOffset(PSNode *target) {\n        removeAny(target);\n        return !pointers.set(getPosition(target, Offset::UNKNOWN));\n    }\n\n  public:\n    AlignedSmallOffsetsPointsToSet() = default;\n    AlignedSmallOffsetsPointsToSet(std::initializer_list<Pointer> elems) {\n        add(elems);\n    }\n\n    bool add(PSNode *target, Offset off) {\n        if (has({target, Offset::UNKNOWN})) {\n            return false;\n        }\n        if (off.isUnknown()) {\n            return addWithUnknownOffset(target);\n        }\n        if (isOffsetValid(off)) {\n            return !pointers.set(getPosition(target, off));\n        }\n        return oddPointers.emplace(target, off).second;\n    }\n\n    bool add(const Pointer &ptr) { return add(ptr.target, ptr.offset); }\n\n    bool add(const AlignedSmallOffsetsPointsToSet &S) {\n        bool changed = pointers.set(S.pointers);\n        for (const auto &ptr : S.oddPointers) {\n            changed |= oddPointers.insert(ptr).second;\n        }\n        return changed;\n    }\n\n    bool remove(const Pointer &ptr) {\n        if (isOffsetValid(ptr.offset)) {\n            return pointers.unset(getPosition(ptr.target, ptr.offset));\n        }\n        return oddPointers.erase(ptr) != 0;\n    }\n\n    bool remove(PSNode *target, Offset offset) {\n        return remove(Pointer(target, offset));\n    }\n\n    bool removeAny(PSNode *target) {\n        bool changed = false;\n        size_t position = getNodePosition(target);\n        for (size_t i = position; i < position + (MAX_OFFSET + 1); i++) {\n            changed |= pointers.unset(i);\n        }\n        auto it = oddPointers.begin();\n        while (it != oddPointers.end()) {\n            if (it->target == target) {\n                it = oddPointers.erase(it);\n                changed = true;\n            } else {\n                it++;\n            }\n        }\n        return changed;\n    }\n\n    void clear() {\n        pointers.reset();\n        oddPointers.clear();\n    }\n\n    bool pointsTo(const Pointer &ptr) const {\n        if (isOffsetValid(ptr.offset)) {\n            return pointers.get(getPosition(ptr.target, ptr.offset));\n        }\n        return oddPointers.find(ptr) != oddPointers.end();\n    }\n\n    bool mayPointTo(const Pointer &ptr) const {\n        return pointsTo(ptr) || pointsTo(Pointer(ptr.target, Offset::UNKNOWN));\n    }\n\n    bool mustPointTo(const Pointer &ptr) const {\n        assert(!ptr.offset.isUnknown() && \"Makes no sense\");\n        return pointsTo(ptr) && isSingleton();\n    }\n\n    bool pointsToTarget(PSNode *target) const {\n        size_t position = getNodePosition(target);\n        for (size_t i = position; i < position + (MAX_OFFSET + 1); i++) {\n            if (pointers.get(i))\n                return true;\n        }\n        return dg::any_of(oddPointers, [target](const Pointer &ptr) {\n            return ptr.target == target;\n        });\n    }\n\n    bool isSingleton() const {\n        return (pointers.size() == 1 && oddPointers.empty()) ||\n               (pointers.empty() && oddPointers.size() == 1);\n    }\n\n    bool empty() const { return pointers.empty() && oddPointers.empty(); }\n\n    size_t count(const Pointer &ptr) const { return pointsTo(ptr); }\n\n    bool has(const Pointer &ptr) const { return count(ptr) > 0; }\n\n    bool hasUnknown() const { return pointsToTarget(UNKNOWN_MEMORY); }\n\n    bool hasNull() const { return pointsToTarget(NULLPTR); }\n\n    bool hasInvalidated() const { return pointsToTarget(INVALIDATED); }\n\n    size_t size() const { return pointers.size() + oddPointers.size(); }\n\n    void swap(AlignedSmallOffsetsPointsToSet &rhs) {\n        pointers.swap(rhs.pointers);\n        oddPointers.swap(rhs.oddPointers);\n    }\n\n    size_t overflowSetSize() const { return oddPointers.size(); }\n\n    static unsigned int getMultiplier() { return multiplier; }\n\n    // iterates over the bitvector first, then over the set\n    class const_iterator {\n        typename ADT::SparseBitvector::const_iterator bitvector_it;\n        typename ADT::SparseBitvector::const_iterator bitvector_end;\n        typename std::set<Pointer>::const_iterator set_it;\n        bool secondContainer;\n\n        const_iterator(const ADT::SparseBitvector &pointers,\n                       const std::set<Pointer> &oddPointers, bool end = false)\n                : bitvector_it(end ? pointers.end() : pointers.begin()),\n                  bitvector_end(pointers.end()),\n                  set_it(end ? oddPointers.end() : oddPointers.begin()),\n                  secondContainer(end) {\n            if (bitvector_it == bitvector_end) {\n                secondContainer = true;\n            }\n        }\n\n      public:\n        const_iterator &operator++() {\n            if (!secondContainer) {\n                bitvector_it++;\n                if (bitvector_it == bitvector_end) {\n                    secondContainer = true;\n                }\n            } else {\n                set_it++;\n            }\n            return *this;\n        }\n\n        const_iterator operator++(int) {\n            auto tmp = *this;\n            operator++();\n            return tmp;\n        }\n\n        Pointer operator*() const {\n            if (!secondContainer) {\n                size_t offsetPosition = (*bitvector_it % (MAX_OFFSET + 1));\n                size_t nodeID =\n                        ((*bitvector_it - offsetPosition) / (MAX_OFFSET + 1)) +\n                        1;\n                return offsetPosition == MAX_OFFSET\n                               ? Pointer(idVector[nodeID - 1], Offset::UNKNOWN)\n                               : Pointer(idVector[nodeID - 1],\n                                         offsetPosition * multiplier);\n            }\n            return *set_it;\n        }\n\n        bool operator==(const const_iterator &rhs) const {\n            return bitvector_it == rhs.bitvector_it && set_it == rhs.set_it;\n        }\n\n        bool operator!=(const const_iterator &rhs) const {\n            return !operator==(rhs);\n        }\n\n        friend class AlignedSmallOffsetsPointsToSet;\n    };\n\n    const_iterator begin() const { return {pointers, oddPointers}; }\n    const_iterator end() const {\n        return {pointers, oddPointers, true /* end */};\n    }\n\n    friend class const_iterator;\n};\n\n} // namespace pta\n} // namespace dg\n\n#endif /* ALIGNEDOFFSETSPOINTSTOSET_H */\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointsToSets/LookupTable.h",
    "content": "#ifndef DG_PTSETS_LOOKUPTABLE_H_\n#define DG_PTSETS_LOOKUPTABLE_H_\n\n#include <map>\n#include <vector>\n\n#if defined(HAVE_TSL_HOPSCOTCH) || (__clang__)\n#include \"dg/ADT/HashMap.h\"\n#else\n#include \"dg/ADT/Map.h\"\n#endif\n\n#include \"dg/Offset.h\"\n#include \"dg/PointerAnalysis/Pointer.h\"\n\nnamespace dg {\n\nclass PointerIDLookupTable {\n  public:\n    using IDTy = size_t;\n    using Pointer = pta::Pointer;\n    using PSNode = pta::PSNode;\n#if defined(HAVE_TSL_HOPSCOTCH) || (__clang__)\n    using PtrToIDMap = dg::HashMap<PSNode *, dg::HashMap<dg::Offset, IDTy>>;\n#else\n    // we create the lookup table statically and there is a bug in GCC\n    // that breaks statically created std::unordered_map.\n    // So if we have not Hopscotch map, use std::map instead.\n    using PtrToIDMap = dg::Map<PSNode *, dg::Map<dg::Offset, IDTy>>;\n#endif\n\n    // this will get a new ID for the pointer if not present\n    IDTy getOrCreate(const Pointer &ptr) {\n        auto res = get(ptr);\n        if (res != 0)\n            return res;\n\n        _idToPtr.push_back(ptr);\n        res = _idToPtr.size();\n#ifndef NDEBUG\n        bool r =\n#endif\n                _ptrToID[ptr.target].put(ptr.offset, res);\n\n        assert(r && \"Duplicated ID!\");\n        assert(get(res) == ptr);\n        assert(res == get(ptr));\n        assert(res > 0 && \"ID must always be greater than 0\");\n        return res;\n    }\n\n    IDTy get(const Pointer &ptr) const {\n        auto it = _ptrToID.find(ptr.target);\n        if (it == _ptrToID.end()) {\n            return 0; // invalid ID\n        }\n        auto it2 = it->second.find(ptr.offset);\n        if (it2 == it->second.end())\n            return 0;\n        return it2->second;\n    }\n\n    const Pointer &get(IDTy id) const {\n        assert(id - 1 < _idToPtr.size());\n        return _idToPtr[id - 1];\n    }\n\n  private:\n    // PSNode -> (Offset -> id)\n    // Not space efficient, but we need mainly the time efficiency here...\n    // NOTE: unfortunately, atm, we cannot use the id of the target for hashing\n    // because it would break repeated runs of the analysis\n    // as multiple graphs will contain nodes with the same id\n    // (and resetting the state is really painful, I tried that,\n    // but just didn't succeed).\n    PtrToIDMap _ptrToID;\n    std::vector<Pointer> _idToPtr; // starts from 0 (pointer = idVector[id - 1])\n};\n\n/*\nclass PointerIDLookupTable {\npublic:\n    using IDTy = size_t;\n    using Pointer = pta::Pointer;\n\n    // this will get a new ID for the pointer if not present\n    IDTy getOrCreate(const Pointer& ptr) {\n        auto it = _ptrToID.find(ptr);\n        if (it != _ptrToID.end()) {\n            return it->second;\n        }\n        auto res = _ptrToID.size() + 1;\n        assert(_idToPtr.size() == res - 1);\n\n        _idToPtr.push_back(ptr);\n        _ptrToID.emplace(ptr, _ptrToID.size() + 1);\n\n        assert(get(res) == ptr);\n        assert(res == get(ptr));\n        return res;\n\n       //bool r = _ptrToID.put(ptr, ids.size() + 1);\n       //assert(r && \"Duplicated ID!\");\n       //return ids.size() + 1;\n    }\n\n    IDTy get(const Pointer& ptr) const {\n        auto it = _ptrToID.find(ptr);\n        if (it != _ptrToID.end()) {\n            return it->second;\n        }\n        return 0; // invalid ID\n    }\n\n    const Pointer& get(IDTy id) const {\n        assert(id - 1 < _idToPtr.size());\n        return _idToPtr[id - 1];\n    }\n\nprivate:\n    std::map<Pointer, IDTy> _ptrToID;\n    std::vector<Pointer> _idToPtr; //starts from 0 (pointer = idVector[id - 1])\n};\n*/\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointsToSets/OffsetsSetPointsToSet.h",
    "content": "#ifndef DG_OFFSETS_SET_PTSET_H\n#define DG_OFFSETS_SET_PTSET_H\n\n#include \"dg/ADT/Bitvector.h\"\n#include \"dg/PointerAnalysis/Pointer.h\"\n\n#include <cassert>\n#include <map>\n\nnamespace dg {\nnamespace pta {\n\n// declare PSNode\nclass PSNode;\n\nclass OffsetsSetPointsToSet {\n    // each pointer is a pair (PSNode *, {offsets}),\n    // so we represent them coinciesly this way\n    using ContainerT = std::map<PSNode *, ADT::SparseBitvector>;\n    ContainerT pointers;\n\n    bool addWithUnknownOffset(PSNode *target) {\n        auto it = pointers.find(target);\n        if (it != pointers.end()) {\n            // we already had that offset?\n            if (it->second.get(Offset::UNKNOWN))\n                return false;\n\n            // get rid of other offsets and keep\n            // only the unknown offset\n            it->second.reset();\n            it->second.set(Offset::UNKNOWN);\n            return true;\n        }\n\n        return !pointers[target].set(Offset::UNKNOWN);\n    }\n\n  public:\n    OffsetsSetPointsToSet() = default;\n    OffsetsSetPointsToSet(std::initializer_list<Pointer> elems) { add(elems); }\n\n    bool add(PSNode *target, Offset off) {\n        if (off.isUnknown())\n            return addWithUnknownOffset(target);\n\n        auto it = pointers.find(target);\n        if (it == pointers.end()) {\n            pointers.emplace_hint(it, target, *off);\n            return true;\n        }\n        if (it->second.get(Offset::UNKNOWN))\n            return false;\n        // the set will return the previous value\n        // of the bit, so that means false if we are\n        // setting a new value\n        return !it->second.set(*off);\n    }\n\n    bool add(const Pointer &ptr) { return add(ptr.target, ptr.offset); }\n\n    // union (unite S into this set)\n    bool add(const OffsetsSetPointsToSet &S) {\n        bool changed = false;\n        for (const auto &it : S.pointers) {\n            changed |= pointers[it.first].set(it.second);\n        }\n        return changed;\n    }\n\n    bool add(std::initializer_list<Pointer> elems) {\n        bool changed = false;\n        for (const auto &e : elems) {\n            changed |= add(e);\n        }\n        return changed;\n    }\n\n    bool remove(const Pointer &ptr) { return remove(ptr.target, ptr.offset); }\n\n    ///\n    // Remove pointer to this target with this offset.\n    // This is method really removes the pair\n    // (target, off) even when the off is unknown\n    bool remove(PSNode *target, Offset offset) {\n        auto it = pointers.find(target);\n        if (it == pointers.end()) {\n            return false;\n        }\n\n        bool ret = it->second.unset(*offset);\n        if (ret && it->second.empty()) {\n            pointers.erase(it);\n        }\n        assert((ret || !it->second.empty()) && \"Inconsistence\");\n        return ret;\n    }\n\n    ///\n    // Remove pointers pointing to this target\n    bool removeAny(PSNode *target) {\n        auto it = pointers.find(target);\n        if (it == pointers.end()) {\n            return false;\n        }\n\n        pointers.erase(it);\n        return true;\n    }\n\n    void clear() { pointers.clear(); }\n\n    bool pointsTo(const Pointer &ptr) const {\n        auto it = pointers.find(ptr.target);\n        if (it == pointers.end())\n            return false;\n        return it->second.get(*ptr.offset);\n    }\n\n    // points to the pointer or the the same target\n    // with unknown offset? Note: we do not count\n    // unknown memory here...\n    bool mayPointTo(const Pointer &ptr) const {\n        return pointsTo(ptr) || pointsTo(Pointer(ptr.target, Offset::UNKNOWN));\n    }\n\n    bool mustPointTo(const Pointer &ptr) const {\n        assert(!ptr.offset.isUnknown() && \"Makes no sense\");\n        return pointsTo(ptr) && isSingleton();\n    }\n\n    bool pointsToTarget(PSNode *target) const {\n        return pointers.find(target) != pointers.end();\n    }\n\n    bool isSingleton() const { return pointers.size() == 1; }\n\n    bool empty() const { return pointers.empty(); }\n\n    size_t count(const Pointer &ptr) const {\n        auto it = pointers.find(ptr.target);\n        if (it != pointers.end()) {\n            return it->second.get(*ptr.offset);\n        }\n\n        return 0;\n    }\n\n    bool has(const Pointer &ptr) const { return count(ptr) > 0; }\n\n    bool hasUnknown() const { return pointsToTarget(UNKNOWN_MEMORY); }\n    bool hasNull() const { return pointsToTarget(NULLPTR); }\n    bool hasInvalidated() const { return pointsToTarget(INVALIDATED); }\n\n    size_t size() const {\n        size_t num = 0;\n        for (const auto &it : pointers) {\n            num += it.second.size();\n        }\n\n        return num;\n    }\n\n    void swap(OffsetsSetPointsToSet &rhs) { pointers.swap(rhs.pointers); }\n\n    class const_iterator {\n        typename ContainerT::const_iterator container_it;\n        typename ContainerT::const_iterator container_end;\n        typename ADT::SparseBitvector::const_iterator innerIt;\n\n        const_iterator(const ContainerT &cont, bool end = false)\n                : container_it(end ? cont.end() : cont.begin()),\n                  container_end(cont.end()) {\n            if (container_it != container_end) {\n                innerIt = container_it->second.begin();\n            }\n        }\n\n      public:\n        const_iterator &operator++() {\n            ++innerIt;\n            if (innerIt == container_it->second.end()) {\n                ++container_it;\n                if (container_it != container_end)\n                    innerIt = container_it->second.begin();\n                else\n                    innerIt = ADT::SparseBitvector::const_iterator();\n            }\n            return *this;\n        }\n\n        const_iterator operator++(int) {\n            auto tmp = *this;\n            operator++();\n            return tmp;\n        }\n\n        Pointer operator*() const { return {container_it->first, *innerIt}; }\n\n        bool operator==(const const_iterator &rhs) const {\n            return container_it == rhs.container_it && innerIt == rhs.innerIt;\n        }\n\n        bool operator!=(const const_iterator &rhs) const {\n            return !operator==(rhs);\n        }\n\n        friend class OffsetsSetPointsToSet;\n    };\n\n    const_iterator begin() const { return {pointers}; }\n    const_iterator end() const { return {pointers, true /* end */}; }\n\n    friend class const_iterator;\n};\n\n} // namespace pta\n} // namespace dg\n\n#endif // DG_OFFSETS_SET_PTSET_H\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointsToSets/PointerIdPointsToSet.h",
    "content": "#ifndef DG_SINGLEBITVECTORPOINTSTOSET_H\n#define DG_SINGLEBITVECTORPOINTSTOSET_H\n\n#include <cassert>\n#include <map>\n#include <vector>\n\n#include \"LookupTable.h\"\n#include \"dg/ADT/Bitvector.h\"\n#include \"dg/PointerAnalysis/Pointer.h\"\n\nnamespace dg {\nnamespace pta {\n\nclass PSNode;\n\nclass PointerIdPointsToSet {\n    static PointerIDLookupTable lookupTable;\n\n#if defined(HAVE_TSL_HOPSCOTCH) || (__clang__)\n    using PointersT = ADT::SparseBitvectorHashImpl;\n#else\n    using PointersT = ADT::SparseBitvector;\n#endif\n    PointersT pointers;\n\n    // if the pointer doesn't have ID, it's assigned one\n    static size_t getPointerID(const Pointer &ptr) {\n        return lookupTable.getOrCreate(ptr);\n    }\n\n    static const Pointer &getPointer(size_t id) { return lookupTable.get(id); }\n\n    bool addWithUnknownOffset(PSNode *node) {\n        auto ptrid = getPointerID({node, Offset::UNKNOWN});\n        if (!pointers.get(ptrid)) {\n            removeAny(node);\n            return !pointers.set(ptrid);\n        }\n        return false; // we already had it\n    }\n\n  public:\n    PointerIdPointsToSet() = default;\n    explicit PointerIdPointsToSet(const std::initializer_list<Pointer> &elems) {\n        add(elems);\n    }\n\n    bool add(PSNode *target, Offset off) { return add(Pointer(target, off)); }\n\n    bool add(const Pointer &ptr) {\n        if (has({ptr.target, Offset::UNKNOWN})) {\n            return false;\n        }\n        if (ptr.offset.isUnknown()) {\n            return addWithUnknownOffset(ptr.target);\n        }\n        return !pointers.set(getPointerID(ptr));\n    }\n\n    template <typename ContainerTy>\n    bool add(const ContainerTy &C) {\n        bool changed = false;\n        for (const auto &ptr : C)\n            changed |= add(ptr);\n        return changed;\n    }\n\n    bool add(const PointerIdPointsToSet &S) { return pointers.set(S.pointers); }\n\n    bool remove(const Pointer &ptr) {\n        return pointers.unset(getPointerID(ptr));\n    }\n\n    bool remove(PSNode *target, Offset offset) {\n        return remove(Pointer(target, offset));\n    }\n\n    bool removeAny(PSNode *target) {\n        decltype(pointers) tmp;\n        tmp.reserve(pointers.size());\n        bool removed = false;\n        for (const auto &ptrID : pointers) {\n            if (lookupTable.get(ptrID).target != target) {\n                tmp.set(ptrID);\n            } else {\n                removed = true;\n            }\n        }\n\n        tmp.swap(pointers);\n\n        return removed;\n    }\n\n    void clear() { pointers.reset(); }\n\n    bool pointsTo(const Pointer &ptr) const {\n        return pointers.get(getPointerID(ptr));\n    }\n\n    bool mayPointTo(const Pointer &ptr) const {\n        return pointsTo(ptr) || pointsTo(Pointer(ptr.target, Offset::UNKNOWN));\n    }\n\n    bool mustPointTo(const Pointer &ptr) const {\n        assert(!ptr.offset.isUnknown() && \"Makes no sense\");\n        return pointsTo(ptr) && isSingleton();\n    }\n\n    bool pointsToTarget(PSNode *target) const {\n        for (auto ptrid : pointers) {\n            const auto &ptr = getPointer(ptrid);\n            if (ptr.target == target) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    bool isSingleton() const { return pointers.size() == 1; }\n\n    bool empty() const { return pointers.empty(); }\n\n    size_t count(const Pointer &ptr) const { return pointsTo(ptr); }\n\n    bool has(const Pointer &ptr) const { return count(ptr) > 0; }\n\n    bool hasUnknown() const { return pointsToTarget(UNKNOWN_MEMORY); }\n\n    bool hasNull() const { return pointsToTarget(NULLPTR); }\n\n    bool hasNullWithOffset() const {\n        for (auto ptrid : pointers) {\n            const auto &ptr = getPointer(ptrid);\n            if (ptr.target == NULLPTR && *ptr.offset != 0) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    bool hasInvalidated() const { return pointsToTarget(INVALIDATED); }\n\n    size_t size() const { return pointers.size(); }\n\n    void swap(PointerIdPointsToSet &rhs) { pointers.swap(rhs.pointers); }\n\n    class const_iterator {\n        typename PointersT::const_iterator container_it;\n\n        const_iterator(const PointersT &pointers, bool end = false)\n                : container_it(end ? pointers.end() : pointers.begin()) {}\n\n      public:\n        const_iterator &operator++() {\n            container_it++;\n            return *this;\n        }\n\n        const_iterator operator++(int) {\n            auto tmp = *this;\n            operator++();\n            return tmp;\n        }\n\n        Pointer operator*() const { return {lookupTable.get(*container_it)}; }\n\n        bool operator==(const const_iterator &rhs) const {\n            return container_it == rhs.container_it;\n        }\n\n        bool operator!=(const const_iterator &rhs) const {\n            return !operator==(rhs);\n        }\n\n        friend class PointerIdPointsToSet;\n    };\n\n    const_iterator begin() const { return {pointers}; }\n    const_iterator end() const { return {pointers, true /* end */}; }\n\n    friend class const_iterator;\n};\n\n} // namespace pta\n} // namespace dg\n\n#endif // DG_SINGLEBITVECTORPOINTSTOSET_H\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointsToSets/SeparateOffsetsPointsToSet.h",
    "content": "#ifndef SEPARATEOFFSETSPOINTSTOSET_H\n#define SEPARATEOFFSETSPOINTSTOSET_H\n\n#include \"dg/ADT/Bitvector.h\"\n#include \"dg/PointerAnalysis/Pointer.h\"\n\n#include <cstdlib>\n#include <map>\n#include <vector>\n\nnamespace dg {\nnamespace pta {\n\nclass PSNode;\n\nclass SeparateOffsetsPointsToSet {\n    ADT::SparseBitvector nodes;\n    ADT::SparseBitvector offsets;\n    static std::map<PSNode *, size_t> ids; // nodes are numbered 1, 2, ...\n    static std::vector<PSNode *>\n            idVector; // starts from 0 (node = idVector[id - 1])\n\n    // if the node doesn't have ID, it is assigned one\n    static size_t getNodeID(PSNode *node) {\n        auto it = ids.find(node);\n        if (it != ids.end()) {\n            return it->second;\n        }\n        idVector.push_back(node);\n        return ids.emplace_hint(it, node, ids.size() + 1)->second;\n    }\n\n  public:\n    SeparateOffsetsPointsToSet() = default;\n    SeparateOffsetsPointsToSet(std::initializer_list<Pointer> elems) {\n        add(elems);\n    }\n\n    bool add(PSNode *target, Offset off) {\n        if (offsets.get(Offset::UNKNOWN)) {\n            return !nodes.set(getNodeID(target));\n        }\n        if (off.isUnknown()) {\n            offsets.reset();\n        }\n        bool changed = !nodes.set(getNodeID(target));\n        return !offsets.set(*off) || changed;\n    }\n\n    bool add(const Pointer &ptr) { return add(ptr.target, ptr.offset); }\n\n    bool add(const SeparateOffsetsPointsToSet &S) {\n        bool changed = nodes.set(S.nodes);\n        return offsets.set(S.offsets) || changed;\n    }\n\n    static bool remove(__attribute__((unused)) const Pointer &ptr) { abort(); }\n\n    static bool remove(__attribute__((unused)) PSNode *target,\n                       __attribute__((unused)) Offset offset) {\n        abort();\n    }\n\n    static bool removeAny(__attribute__((unused)) PSNode *target) { abort(); }\n\n    void clear() {\n        nodes.reset();\n        offsets.reset();\n    }\n\n    bool pointsTo(const Pointer &ptr) const {\n        return nodes.get(getNodeID(ptr.target)) && offsets.get(*ptr.offset);\n    }\n\n    bool mayPointTo(const Pointer &ptr) const {\n        return pointsTo(ptr) || pointsTo(Pointer(ptr.target, Offset::UNKNOWN));\n    }\n\n    bool mustPointTo(const Pointer &ptr) const {\n        return (nodes.size() == 1 || offsets.size() == 1) && pointsTo(ptr);\n    }\n\n    bool pointsToTarget(PSNode *target) const {\n        return nodes.get(getNodeID(target));\n    }\n\n    bool isSingleton() const {\n        return nodes.size() == 1 && offsets.size() == 1;\n    }\n\n    bool empty() const { return nodes.empty() && offsets.empty(); }\n\n    size_t count(const Pointer &ptr) const { return pointsTo(ptr); }\n\n    bool has(const Pointer &ptr) const { return count(ptr) > 0; }\n\n    bool hasUnknown() const { return pointsToTarget(UNKNOWN_MEMORY); }\n\n    bool hasNull() const { return pointsToTarget(NULLPTR); }\n\n    bool hasInvalidated() const { return pointsToTarget(INVALIDATED); }\n\n    size_t size() const { return nodes.size() * offsets.size(); }\n\n    void swap(SeparateOffsetsPointsToSet &rhs) {\n        nodes.swap(rhs.nodes);\n        offsets.swap(rhs.offsets);\n    }\n\n    // iterates through all the possible combinations of nodes and their offsets\n    // stored in this points-to set\n    class const_iterator {\n        typename ADT::SparseBitvector::const_iterator nodes_it;\n        typename ADT::SparseBitvector::const_iterator nodes_end;\n        typename ADT::SparseBitvector::const_iterator offsets_it;\n        typename ADT::SparseBitvector::const_iterator offsets_begin;\n        typename ADT::SparseBitvector::const_iterator offsets_end;\n\n        const_iterator(const ADT::SparseBitvector &nodes,\n                       const ADT::SparseBitvector &offsets, bool end = false)\n                : nodes_it(end ? nodes.end() : nodes.begin()),\n                  nodes_end(nodes.end()), offsets_it(offsets.begin()),\n                  offsets_begin(offsets.begin()), offsets_end(offsets.end()) {\n            if (nodes_it == nodes_end) {\n                offsets_it = offsets_end;\n            }\n        }\n\n      public:\n        const_iterator &operator++() {\n            offsets_it++;\n            if (offsets_it == offsets_end) {\n                nodes_it++;\n                if (nodes_it != nodes_end) {\n                    offsets_it = offsets_begin;\n                }\n            }\n            return *this;\n        }\n\n        const_iterator operator++(int) {\n            auto tmp = *this;\n            operator++();\n            return tmp;\n        }\n\n        Pointer operator*() const {\n            return {idVector[*nodes_it - 1], *offsets_it};\n        }\n\n        bool operator==(const const_iterator &rhs) const {\n            return nodes_it == rhs.nodes_it && offsets_it == rhs.offsets_it;\n        }\n\n        bool operator!=(const const_iterator &rhs) const {\n            return !operator==(rhs);\n        }\n\n        friend class SeparateOffsetsPointsToSet;\n    };\n\n    const_iterator begin() const { return {nodes, offsets}; }\n    const_iterator end() const { return {nodes, offsets, true /* end */}; }\n\n    friend class const_iterator;\n};\n\n} // namespace pta\n} // namespace dg\n\n#endif /* SEPARATEOFFSETSPOINTSTOSET_H */\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointsToSets/SimplePointsToSet.h",
    "content": "#ifndef SIMPLEPOINTSTOSET_H\n#define SIMPLEPOINTSTOSET_H\n\n#include \"dg/ADT/Bitvector.h\"\n#include \"dg/PointerAnalysis/Pointer.h\"\n#include \"dg/util/iterators.h\"\n\n#include <cassert>\n#include <set>\n\nnamespace dg {\nnamespace pta {\n\nclass PSNode;\n//\n// We keep the implementation of this points-to set because\n// it is good for comparison and regression testing\nclass SimplePointsToSet {\n    using ContainerT = std::set<Pointer>;\n    ContainerT pointers;\n\n    bool addWithUnknownOffset(PSNode *target) {\n        if (has({target, Offset::UNKNOWN}))\n            return false;\n\n        ContainerT tmp;\n        for (const auto &ptr : pointers) {\n            if (ptr.target != target)\n                tmp.insert(ptr);\n        }\n\n        tmp.swap(pointers);\n        return pointers.insert({target, Offset::UNKNOWN}).second;\n    }\n\n  public:\n    SimplePointsToSet() = default;\n    SimplePointsToSet(std::initializer_list<Pointer> elems) { add(elems); }\n\n    using const_iterator = typename ContainerT::const_iterator;\n\n    bool add(PSNode *target, Offset off) {\n        if (off.isUnknown())\n            return addWithUnknownOffset(target);\n\n        // if we have the same pointer but with unknown offset,\n        // do nothing\n        if (has({target, Offset::UNKNOWN}))\n            return false;\n\n        return pointers.emplace(target, off).second;\n    }\n\n    bool add(const Pointer &ptr) { return add(ptr.target, ptr.offset); }\n\n    // make union of the two sets and store it\n    // into 'this' set (i.e. merge rhs to this set)\n    bool add(const SimplePointsToSet &rhs) {\n        bool changed = false;\n        for (const auto &ptr : rhs.pointers) {\n            changed |= pointers.insert(ptr).second;\n        }\n\n        return changed;\n    }\n\n    bool add(std::initializer_list<Pointer> elems) {\n        bool changed = false;\n        for (const auto &e : elems) {\n            changed |= add(e);\n        }\n        return changed;\n    }\n\n    bool remove(const Pointer &ptr) { return pointers.erase(ptr) != 0; }\n\n    ///\n    // Remove pointer to this target with this offset.\n    // This is method really removes the pair\n    // (target, off), even when the off is unknown\n    bool remove(PSNode *target, Offset offset) {\n        return remove(Pointer(target, offset));\n    }\n\n    ///\n    // Remove pointers pointing to this target\n    bool removeAny(PSNode *target) {\n        if (pointsToTarget(target)) {\n            SimplePointsToSet tmp;\n            for (const auto &ptr : pointers) {\n                if (ptr.target == target) {\n                    continue;\n                }\n                tmp.add(ptr);\n            }\n            assert(tmp.size() < size());\n            swap(tmp);\n            return true;\n        }\n        return false;\n    }\n\n    void clear() { pointers.clear(); }\n\n    bool pointsTo(const Pointer &ptr) const { return pointers.count(ptr) > 0; }\n\n    // points to the pointer or the the same target\n    // with unknown offset? Note: we do not count\n    // unknown memory here...\n    bool mayPointTo(const Pointer &ptr) const {\n        return pointsTo(ptr) || pointsTo(Pointer(ptr.target, Offset::UNKNOWN));\n    }\n\n    bool mustPointTo(const Pointer &ptr) const {\n        assert(!ptr.offset.isUnknown() && \"Makes no sense\");\n        return pointsTo(ptr) && isSingleton();\n    }\n\n    bool pointsToTarget(PSNode *target) const {\n        return dg::any_of(pointers, [target](const Pointer &ptr) {\n            return ptr.target == target;\n        });\n    }\n\n    bool isSingleton() const { return pointers.size() == 1; }\n\n    size_t count(const Pointer &ptr) { return pointers.count(ptr); }\n    size_t size() const { return pointers.size(); }\n    bool empty() const { return pointers.empty(); }\n    bool has(const Pointer &ptr) { return count(ptr) > 0; }\n    bool hasUnknown() const { return pointsToTarget(UNKNOWN_MEMORY); }\n    bool hasNull() const { return pointsToTarget(NULLPTR); }\n    bool hasInvalidated() const { return pointsToTarget(INVALIDATED); }\n\n    void swap(SimplePointsToSet &rhs) { pointers.swap(rhs.pointers); }\n\n    const_iterator begin() const { return pointers.begin(); }\n    const_iterator end() const { return pointers.end(); }\n};\n\n} // namespace pta\n} // namespace dg\n\n#endif /* SIMPLEPOINTSTOSET_H */\n"
  },
  {
    "path": "include/dg/PointerAnalysis/PointsToSets/SmallOffsetsPointsToSet.h",
    "content": "#ifndef DG_SMALLOFFSETSPOINTSTOSET_H\n#define DG_SMALLOFFSETSPOINTSTOSET_H\n\n#include <cassert>\n#include <map>\n#include <set>\n#include <vector>\n\n#include \"dg/ADT/Bitvector.h\"\n#include \"dg/PointerAnalysis/Pointer.h\"\n#include \"dg/util/iterators.h\"\n\nnamespace dg {\nnamespace pta {\n\nclass PSNode;\n\nclass SmallOffsetsPointsToSet {\n    static const size_t MAX_OFFSET = 63;\n    ADT::SparseBitvector pointers;\n    std::set<Pointer> largePointers;\n    static std::map<PSNode *, size_t> ids; // nodes are numbered 1,2, ...\n    static std::vector<PSNode *>\n            idVector; // starts from 0 (node = idVector[id - 1])\n\n    // if the node doesn't have ID, it's assigned one\n    static size_t getNodeID(PSNode *node) {\n        auto it = ids.find(node);\n        if (it != ids.end()) {\n            return it->second;\n        }\n        idVector.push_back(node);\n        return ids.emplace_hint(it, node, ids.size() + 1)->second;\n    }\n\n    static size_t getNodePosition(PSNode *node) {\n        return ((getNodeID(node) - 1) * (MAX_OFFSET + 1));\n    }\n\n    static size_t getPosition(PSNode *node, Offset off) {\n        if (off.isUnknown()) {\n            return getNodePosition(node) + MAX_OFFSET;\n        }\n        return getNodePosition(node) + *off;\n    }\n\n    static bool isOffsetValid(Offset off) {\n        return off.isUnknown() || *off <= (MAX_OFFSET - 1);\n    }\n\n    bool addWithUnknownOffset(PSNode *target) {\n        removeAny(target);\n        return !pointers.set(getPosition(target, Offset::UNKNOWN));\n    }\n\n  public:\n    SmallOffsetsPointsToSet() = default;\n    SmallOffsetsPointsToSet(std::initializer_list<Pointer> elems) {\n        add(elems);\n    }\n\n    bool add(PSNode *target, Offset off) {\n        if (has({target, Offset::UNKNOWN})) {\n            return false;\n        }\n        if (off.isUnknown()) {\n            return addWithUnknownOffset(target);\n        }\n        if (isOffsetValid(off)) {\n            return !pointers.set(getPosition(target, off));\n        }\n        return largePointers.emplace(target, off).second;\n    }\n\n    bool add(const Pointer &ptr) { return add(ptr.target, ptr.offset); }\n\n    bool add(const SmallOffsetsPointsToSet &S) {\n        bool changed = pointers.set(S.pointers);\n        for (const auto &ptr : S.largePointers) {\n            changed |= largePointers.insert(ptr).second;\n        }\n        return changed;\n    }\n\n    bool remove(const Pointer &ptr) {\n        if (isOffsetValid(ptr.offset)) {\n            return pointers.unset(getPosition(ptr.target, ptr.offset));\n        }\n        return largePointers.erase(ptr) != 0;\n    }\n\n    bool remove(PSNode *target, Offset offset) {\n        return remove(Pointer(target, offset));\n    }\n\n    bool removeAny(PSNode *target) {\n        bool changed = false;\n        size_t position = getNodePosition(target);\n        for (size_t i = position; i < position + (MAX_OFFSET + 1); i++) {\n            changed |= pointers.unset(i);\n        }\n        auto it = largePointers.begin();\n        while (it != largePointers.end()) {\n            if (it->target == target) {\n                it = largePointers.erase(it);\n                changed = true;\n            } else {\n                it++;\n            }\n        }\n        return changed;\n    }\n\n    void clear() {\n        pointers.reset();\n        largePointers.clear();\n    }\n\n    bool pointsTo(const Pointer &ptr) const {\n        if (isOffsetValid(ptr.offset)) {\n            return pointers.get(getPosition(ptr.target, ptr.offset));\n        }\n        return largePointers.find(ptr) != largePointers.end();\n    }\n\n    bool mayPointTo(const Pointer &ptr) const {\n        return pointsTo(ptr) || pointsTo(Pointer(ptr.target, Offset::UNKNOWN));\n    }\n\n    bool mustPointTo(const Pointer &ptr) const {\n        assert(!ptr.offset.isUnknown() && \"Makes no sense\");\n        return pointsTo(ptr) && isSingleton();\n    }\n\n    bool pointsToTarget(PSNode *target) const {\n        size_t position = getNodePosition(target);\n        for (size_t i = position; i < position + MAX_OFFSET + 1; i++) {\n            if (pointers.get(i))\n                return true;\n        }\n        return dg::any_of(largePointers, [target](const Pointer &ptr) {\n            return ptr.target == target;\n        });\n    }\n\n    bool isSingleton() const {\n        return (pointers.size() == 1 && largePointers.empty()) ||\n               (pointers.empty() && largePointers.size() == 1);\n    }\n\n    bool empty() const { return pointers.empty() && largePointers.empty(); }\n\n    size_t count(const Pointer &ptr) const { return pointsTo(ptr); }\n\n    bool has(const Pointer &ptr) const { return count(ptr) > 0; }\n\n    bool hasUnknown() const { return pointsToTarget(UNKNOWN_MEMORY); }\n\n    bool hasNull() const { return pointsToTarget(NULLPTR); }\n\n    bool hasInvalidated() const { return pointsToTarget(INVALIDATED); }\n\n    size_t size() const { return pointers.size() + largePointers.size(); }\n\n    void swap(SmallOffsetsPointsToSet &rhs) {\n        pointers.swap(rhs.pointers);\n        largePointers.swap(rhs.largePointers);\n    }\n\n    size_t overflowSetSize() const { return largePointers.size(); }\n\n    // iterates over the bitvector first, then over the set\n    class const_iterator {\n        typename ADT::SparseBitvector::const_iterator bitvector_it;\n        typename ADT::SparseBitvector::const_iterator bitvector_end;\n        typename std::set<Pointer>::const_iterator set_it;\n        bool secondContainer;\n\n        const_iterator(const ADT::SparseBitvector &pointers,\n                       const std::set<Pointer> &largePointers, bool end = false)\n                : bitvector_it(end ? pointers.end() : pointers.begin()),\n                  bitvector_end(pointers.end()),\n                  set_it(end ? largePointers.end() : largePointers.begin()),\n                  secondContainer(end) {\n            if (bitvector_it == bitvector_end) {\n                secondContainer = true;\n            }\n        }\n\n      public:\n        const_iterator &operator++() {\n            if (!secondContainer) {\n                bitvector_it++;\n                if (bitvector_it == bitvector_end) {\n                    secondContainer = true;\n                }\n            } else {\n                set_it++;\n            }\n            return *this;\n        }\n\n        const_iterator operator++(int) {\n            auto tmp = *this;\n            operator++();\n            return tmp;\n        }\n\n        Pointer operator*() const {\n            if (!secondContainer) {\n                size_t offsetID = *bitvector_it % (MAX_OFFSET + 1);\n                size_t nodeID =\n                        ((*bitvector_it - offsetID) / (MAX_OFFSET + 1)) + 1;\n                return offsetID == MAX_OFFSET\n                               ? Pointer(idVector[nodeID - 1], Offset::UNKNOWN)\n                               : Pointer(idVector[nodeID - 1], offsetID);\n            }\n            return *set_it;\n        }\n\n        bool operator==(const const_iterator &rhs) const {\n            return bitvector_it == rhs.bitvector_it && set_it == rhs.set_it;\n        }\n\n        bool operator!=(const const_iterator &rhs) const {\n            return !operator==(rhs);\n        }\n\n        friend class SmallOffsetsPointsToSet;\n    };\n\n    const_iterator begin() const { return {pointers, largePointers}; }\n    const_iterator end() const {\n        return {pointers, largePointers, true /* end */};\n    }\n\n    friend class const_iterator;\n};\n} // namespace pta\n} // namespace dg\n\n#endif // DG_SMALLOFFSETSPOINTSTOSET_H\n"
  },
  {
    "path": "include/dg/ReadWriteGraph/DefSite.h",
    "content": "#ifndef DG_DEF_SITE_H_\n#define DG_DEF_SITE_H_\n\n#include <cassert>\n#include <list>\n#include <map>\n#include <set>\n\n#include \"dg/ADT/IntervalsList.h\"\n#include \"dg/Offset.h\"\n\nnamespace dg {\nnamespace dda {\n\nclass RWNode;\n\n/// Take two intervals (a, a_len) and (b, b_len) where 'a' ('b', resp.) is the\n// start of the interval and 'a_len' ('b_len', resp.) is the length of the\n// interval and check whether their are disjunctive.\n// The length can be Offset::UNKNOWN for unknown length.\n// The start ('a' and 'b') must be concrete numbers.\n// \\return true iff intervals are disjunctive\n//         false iff intervals are not disjunctive\ninline bool intervalsDisjunctive(uint64_t a, uint64_t a_len, uint64_t b,\n                                 uint64_t b_len) {\n    assert(a != Offset::UNKNOWN && \"Start of an interval is unknown\");\n    assert(b != Offset::UNKNOWN && \"Start of an interval is unknown\");\n    assert(a_len > 0 && \"Interval of lenght 0 given\");\n    assert(b_len > 0 && \"Interval of lenght 0 given\");\n\n    if (a_len == Offset::UNKNOWN) {\n        if (b_len == Offset::UNKNOWN) {\n            return false;\n        } // b_len is concrete and a_len is unknown\n        // use less or equal, because we are starting\n        // from 0 and the bytes are distinct (e.g. 4th byte\n        // is on offset 3)\n        return (a <= b) ? false : b_len <= a - b;\n    }\n    if (b_len == Offset::UNKNOWN) {\n        return (a <= b) ? a_len <= b - a : false;\n    }\n\n    // the lenghts and starts are both concrete\n    return ((a <= b) ? (a_len <= b - a) : (b_len <= a - b));\n}\n\n///\n// Take two intervals (a1, a2) and (b1, b2)\n// (over non-negative whole numbers) and check\n//  whether they overlap (not sharply, i.e.\n//  if a2 == b1, then itervals already overlap)\ninline bool intervalsOverlap(uint64_t a1, uint64_t a2, uint64_t b1,\n                             uint64_t b2) {\n    return !intervalsDisjunctive(a1, a2, b1, b2);\n}\n\ntemplate <typename NodeT>\nstruct GenericDefSite {\n    using NodeTy = NodeT;\n\n    GenericDefSite(NodeT *t, const Offset &o = Offset::UNKNOWN,\n                   const Offset &l = Offset::UNKNOWN)\n            : target(t), offset(o), len(l) {\n        assert((o.isUnknown() || l.isUnknown() || *o + *l > 0) &&\n               \"Invalid offset and length given\");\n    }\n\n    bool operator<(const GenericDefSite &oth) const {\n        return target == oth.target\n                       ? (offset == oth.offset ? len < oth.len\n                                               : offset < oth.offset)\n                       : target < oth.target;\n    }\n\n    bool operator==(const GenericDefSite &oth) const {\n        return target == oth.target && offset == oth.offset && len == oth.len;\n    }\n\n    Offset end() const {\n        // if the offset is unknown, stretch the interval over all possible\n        // bytes\n        if (offset.isUnknown()) {\n            return Offset::UNKNOWN;\n        }\n        return offset + (len - 1);\n    }\n\n    std::pair<Offset, Offset> getInterval() const {\n        // if the offset is unknown, stretch the interval over all possible\n        // bytes\n        if (offset.isUnknown()) {\n            return {0, Offset::UNKNOWN};\n        }\n        return {offset, offset + (len - 1)};\n    }\n\n    // what memory this node defines\n    NodeT *target;\n    // on what offset\n    Offset offset;\n    // how many bytes\n    Offset len;\n};\n\n// for compatibility until we need to change it\nusing DefSite = GenericDefSite<RWNode>;\n\nextern RWNode *UNKNOWN_MEMORY;\n\n// FIXME: change this std::set to std::map (target->offsets)\nclass DefSiteSet : public std::set<DefSite> {\n  public:\n    DefSiteSet intersect(const DefSiteSet &rhs) const {\n        std::map<DefSite::NodeTy *, IntervalsList> lhssites;\n        std::map<DefSite::NodeTy *, IntervalsList> rhssites;\n\n        for (const auto &ds : *this) {\n            lhssites[ds.target].add(ds.getInterval());\n        }\n        for (const auto &ds : rhs) {\n            rhssites[ds.target].add(ds.getInterval());\n        }\n\n        DefSiteSet retval;\n\n        for (auto &lit : lhssites) {\n            auto rit = rhssites.find(lit.first);\n            if (rit != rhssites.end()) {\n                for (const auto &I : lit.second.intersectWith(rit->second)) {\n                    retval.emplace(lit.first, I.start, I.length());\n                }\n            }\n        }\n\n        return retval;\n    }\n\n    template <typename Container>\n    void add(const Container &C) {\n        for (auto &e : C) {\n            insert(e);\n        }\n    }\n};\n\n// FIXME: get rid of this using\nusing DefSiteSetT = DefSiteSet;\n\n// wrapper around std::set<> with few\n// improvements that will be handy in our set-up\n/*\nclass RWNodesSet {\n    using ContainerTy = std::set<RWNode *>;\n\n    ContainerTy nodes;\n    bool is_unknown;\n\npublic:\n    RWNodesSet() : is_unknown(false) {}\n\n    // the set contains unknown mem. location\n    void makeUnknown() {\n        nodes.clear();\n        nodes.insert(UNKNOWN_MEMORY);\n        is_unknown = true;\n    }\n\n    bool insert(RWNode *n) {\n        if (is_unknown)\n            return false;\n\n        if (n == UNKNOWN_MEMORY) {\n            makeUnknown();\n            return true;\n        } else\n            return nodes.insert(n).second;\n    }\n\n    size_t count(RWNode *n) const { return nodes.count(n); }\n    size_t size() const { return nodes.size(); }\n\n    bool isUnknown() const { return is_unknown; }\n\n    void clear() {\n        nodes.clear();\n        is_unknown = false;\n    }\n\n    ContainerTy::iterator begin() { return nodes.begin(); }\n    ContainerTy::iterator end() { return nodes.end(); }\n    ContainerTy::const_iterator begin() const { return nodes.begin(); }\n    ContainerTy::const_iterator end() const { return nodes.end(); }\n\n    ContainerTy& getNodes() {\n        return nodes;\n    };\n\n};\n*/\n\n} // namespace dda\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/ReadWriteGraph/RWBBlock.h",
    "content": "#ifndef DG_RWBBLOCK_H_\n#define DG_RWBBLOCK_H_\n\n#include <memory>\n\n#include \"dg/BBlockBase.h\"\n#include \"dg/ReadWriteGraph/RWNode.h\"\n\nnamespace dg {\nnamespace dda {\n\nclass RWBBlock;\nclass RWNode;\n\nclass RWBBlock : public BBlockBase<RWBBlock, RWNode> {\n    RWSubgraph *subgraph{nullptr};\n\n  public:\n    using NodeT = RWNode;\n\n    RWBBlock() = default;\n    RWBBlock(RWSubgraph *s) : subgraph(s) {}\n\n    RWSubgraph *getSubgraph() { return subgraph; }\n    const RWSubgraph *getSubgraph() const { return subgraph; }\n\n    /*\n    auto begin() -> decltype(_nodes.begin()) { return _nodes.begin(); }\n    auto begin() const -> decltype(_nodes.begin()) { return _nodes.begin(); }\n    auto end() -> decltype(_nodes.end()) { return _nodes.end(); }\n    auto end() const -> decltype(_nodes.end()) { return _nodes.end(); }\n    */\n\n    // Split the block before and after the given node.\n    // Return newly created basic blocks (there are at most two of them).\n    std::pair<std::unique_ptr<RWBBlock>, std::unique_ptr<RWBBlock>>\n    splitAround(NodeT *node) {\n        assert(node->getBBlock() == this && \"Spliting a block on invalid node\");\n\n        RWBBlock *withnode = nullptr;\n        RWBBlock *after = nullptr;\n\n        if (getNodes().size() == 1) {\n            assert(*getNodes().begin() == node);\n            return {nullptr, nullptr};\n        }\n\n#ifndef NDEBUG\n        auto old_size = getNodes().size();\n        assert(old_size > 1);\n#endif\n        unsigned num = 0;\n        auto it = getNodes().begin(), et = getNodes().end();\n        for (; it != et; ++it) {\n            if (*it == node) {\n                break;\n            }\n            ++num;\n        }\n\n        assert(it != et && \"Did not find the node\");\n        assert(*it == node);\n\n        ++it;\n        if (it != et) {\n            after = new RWBBlock(subgraph);\n            for (; it != et; ++it) {\n                after->append(*it);\n            }\n        }\n\n        // truncate nodes in this block\n        if (num > 0) {\n            withnode = new RWBBlock(subgraph);\n            withnode->append(node);\n\n            getNodes().resize(num);\n        } else {\n            assert(*getNodes().begin() == node);\n            assert(after && \"Should have a suffix\");\n            getNodes().resize(1);\n        }\n\n        assert(!withnode || withnode->size() == 1);\n        assert(((getNodes().size() + (withnode ? withnode->size() : 0) +\n                 (after ? after->size() : 0)) == old_size) &&\n               \"Bug in splitting nodes\");\n\n        // reconnect edges\n        RWBBlock *bbwithsuccessors = after;\n        if (!bbwithsuccessors) // no suffix\n            bbwithsuccessors = withnode;\n\n        assert(bbwithsuccessors);\n        for (auto *s : this->_successors) {\n            for (auto &p : s->_predecessors) {\n                if (p == this) {\n                    p = bbwithsuccessors;\n                }\n            }\n        }\n        // swap this and after successors\n        bbwithsuccessors->_successors.swap(this->_successors);\n\n        if (withnode) {\n            this->addSuccessor(withnode);\n            if (after) {\n                withnode->addSuccessor(after);\n            }\n        } else {\n            assert(after && \"Should have a suffix\");\n            this->addSuccessor(after);\n        }\n\n        return {std::unique_ptr<RWBBlock>(withnode),\n                std::unique_ptr<RWBBlock>(after)};\n    }\n\n    bool isReturnBBlock() const {\n        if (const auto *last = getLast()) {\n            return last->isRet();\n        }\n        return false;\n    }\n\n#ifndef NDEBUG\n    void dump() const;\n#endif\n};\n\n} // namespace dda\n} // namespace dg\n\n#endif // DG_RWBBLOCK_H_\n"
  },
  {
    "path": "include/dg/ReadWriteGraph/RWNode.h",
    "content": "#ifndef DG_RW_NODE_H_\n#define DG_RW_NODE_H_\n\n#include <vector>\n\n#include \"DefSite.h\"\n#include \"dg/Offset.h\"\n#include \"dg/SubgraphNode.h\"\n#include \"dg/util/iterators.h\"\n\n#include \"dg/DataDependence/DataDependenceAnalysisOptions.h\"\n\nnamespace dg {\nnamespace dda {\n\nclass RWNode;\nclass RWSubgraph;\nclass ReachingDefinitionsAnalysis;\n\n// here the types are for type-checking (optional - user can do it\n// when building the graph) and for later optimizations\nenum class RWNodeType {\n    // invalid type of node\n    NONE,\n    // these are nodes that just represent memory allocation sites\n    // we need to have them even in reaching definitions analysis,\n    // so that we can use them as targets in DefSites\n    ALLOC,\n    DYN_ALLOC,\n    GLOBAL,\n    // nodes that write the memory\n    STORE,\n    // nodes that use the memory\n    LOAD,\n    // merging information from several locations\n    PHI,\n    ////  PHIs used to pass information between procedures\n    // PHIs on the side of procedure (formal arguments)\n    INARG,\n    OUTARG,\n    // PHIs on the side of call (actual arguments)\n    CALLIN,\n    CALLOUT,\n    // artificial use (load)\n    MU,\n    // return from the subprocedure\n    RETURN,\n    // call node\n    CALL,\n    FORK,\n    JOIN,\n    // node that may define/use memory but does\n    // not fall into any of these categories\n    // (e.g., it represents an undefined call for which we have a model)\n    GENERIC,\n    // dummy nodes\n    NOOP\n};\n\nclass RWBBlock;\n\nclass RWNode : public SubgraphNode<RWNode> {\n    RWNodeType type;\n    bool has_address_taken{false};\n    RWBBlock *bblock = nullptr;\n\n    class DefUses {\n        using T = std::vector<RWNode *>;\n        T defuse;\n        // to differentiate between empty() because nothing\n        // has been added yet and empty() because there are no\n        // definitions\n        bool _init{false};\n\n      public:\n        bool add(RWNode *d) {\n            _init = true;\n            for (auto *x : defuse) {\n                if (x == d) {\n                    return false;\n                }\n            }\n            defuse.push_back(d);\n            return true;\n        }\n\n        template <typename Cont>\n        bool add(const Cont &C) {\n            _init = true;\n            bool changed = false;\n            for (RWNode *n : C)\n                changed |= add(n);\n            return changed;\n        }\n\n        bool initialized() const { return _init; }\n\n        operator std::vector<RWNode *>() { return defuse; }\n\n        T::iterator begin() { return defuse.begin(); }\n        T::iterator end() { return defuse.end(); }\n        T::const_iterator begin() const { return defuse.begin(); }\n        T::const_iterator end() const { return defuse.end(); }\n    };\n\n  public:\n    ///\n    /// Gathers information about the node\n    /// - what memory it accesses and whether it writes it or reads it.\n    ///\n    mutable struct Annotations {\n        // weak update\n        DefSiteSetT defs;\n        // strong update\n        DefSiteSetT overwrites;\n        // this is set of variables used in this node\n        DefSiteSetT uses;\n\n        DefSiteSetT &getDefines() { return defs; }\n        DefSiteSetT &getOverwrites() { return overwrites; }\n        DefSiteSetT &getUses() { return uses; }\n        const DefSiteSetT &getDefines() const { return defs; }\n        const DefSiteSetT &getOverwrites() const { return overwrites; }\n        const DefSiteSetT &getUses() const { return uses; }\n    } annotations;\n\n    // for invalid nodes like UNKNOWN_MEMLOC\n    RWNode(RWNodeType t = RWNodeType::NONE)\n            : SubgraphNode<RWNode>(0), type(t) {}\n\n    RWNode(unsigned id, RWNodeType t = RWNodeType::NONE)\n            : SubgraphNode<RWNode>(id), type(t) {}\n\n    RWNodeType getType() const { return type; }\n\n    // FIXME: create a child class (RWNodeAddressTaken??)\n    // and move this bool there, it is not relevant for all nodes\n    // (from this node then can inherit alloca, etc.)\n    bool hasAddressTaken() const { return has_address_taken; }\n    void setAddressTaken() { has_address_taken = true; }\n\n    virtual ~RWNode() = default;\n\n#ifndef NDEBUG\n    void dump() const override;\n#endif\n\n    // places where this node is defined\n    // (so this node has non-empty uses)\n    // FIXME: add a getter\n    DefUses defuse;\n\n    bool addDefUse(RWNode *n) { return defuse.add(n); }\n\n    template <typename C>\n    bool addDefUse(const C &c) {\n        return defuse.add(c);\n    }\n\n    virtual Annotations &getAnnotations() { return annotations; }\n    virtual const Annotations &getAnnotations() const { return annotations; }\n\n    DefSiteSetT &getDefines() { return getAnnotations().getDefines(); }\n    DefSiteSetT &getOverwrites() { return getAnnotations().getOverwrites(); }\n    DefSiteSetT &getUses() { return getAnnotations().getUses(); }\n    const DefSiteSetT &getDefines() const {\n        return getAnnotations().getDefines();\n    }\n    const DefSiteSetT &getOverwrites() const {\n        return getAnnotations().getOverwrites();\n    }\n    const DefSiteSetT &getUses() const { return getAnnotations().getUses(); }\n\n    bool defines(const RWNode *target,\n                 const Offset &off = Offset::UNKNOWN) const {\n        // FIXME: this is not efficient implementation,\n        // use the ordering on the nodes\n        if (off.isUnknown()) {\n            for (const DefSite &ds : getDefines())\n                if (ds.target == target)\n                    return true;\n            for (const DefSite &ds : getOverwrites())\n                if (ds.target == target)\n                    return true;\n        } else {\n            for (const DefSite &ds : getDefines())\n                if (ds.target == target &&\n                    off.inRange(*ds.offset, *ds.offset + *ds.len))\n                    return true;\n\n            for (const DefSite &ds : getOverwrites())\n                if (ds.target == target &&\n                    off.inRange(*ds.offset, *ds.offset + *ds.len))\n                    return true;\n        }\n\n        return false;\n    }\n\n    bool usesUnknown() const {\n        return dg::any_of(getUses(), [](const DefSite &ds) {\n            return ds.target->isUnknown();\n        });\n    }\n\n    bool usesOnlyGlobals() const {\n        return !dg::any_of(getUses(), [](const DefSite &ds) {\n            return !ds.target->isGlobal();\n        });\n    }\n\n    // add uses to annotations of 'this' object\n    // (call objects can have several annotations as they are\n    //  composed of several nodes)\n    void addUse(const DefSite &ds) { annotations.getUses().insert(ds); }\n\n    void addUse(RWNode *target, const Offset &off = Offset::UNKNOWN,\n                const Offset &len = Offset::UNKNOWN) {\n        addUse(DefSite(target, off, len));\n    }\n\n    template <typename T>\n    void addUses(T &&u) {\n        for (auto &ds : u) {\n            annotations.getUses().insert(ds);\n        }\n    }\n\n    // add definitions to annotations of 'this' object\n    // (call objects can have several annotations as they are\n    //  composed of several nodes)\n    void addDef(const DefSite &ds, bool strong_update = false) {\n        if (strong_update)\n            annotations.getOverwrites().insert(ds);\n        else\n            annotations.getDefines().insert(ds);\n    }\n\n    ///\n    // register that the node defines the memory 'target'\n    // at offset 'off' of length 'len', i.e. it writes\n    // to memory 'target' to bytes [off, off + len].\n    void addDef(RWNode *target, const Offset &off = Offset::UNKNOWN,\n                const Offset &len = Offset::UNKNOWN,\n                bool strong_update = false) {\n        addDef(DefSite(target, off, len), strong_update);\n    }\n\n    template <typename T>\n    void addDefs(T &&defs) {\n        for (auto &ds : defs) {\n            addDef(ds);\n        }\n    }\n\n    void addOverwrites(RWNode *target, const Offset &off = Offset::UNKNOWN,\n                       const Offset &len = Offset::UNKNOWN) {\n        addOverwrites(DefSite(target, off, len));\n    }\n\n    void addOverwrites(const DefSite &ds) {\n        annotations.getOverwrites().insert(ds);\n    }\n\n    bool isUnknown() const { return this == UNKNOWN_MEMORY; }\n    bool isUse() const { return !getUses().empty(); }\n    bool isDef() const {\n        return !getDefines().empty() || !getOverwrites().empty();\n    }\n\n    bool isInOut() const {\n        return getType() == RWNodeType::INARG ||\n               getType() == RWNodeType::OUTARG ||\n               getType() == RWNodeType::CALLIN ||\n               getType() == RWNodeType::CALLOUT;\n    }\n    bool isPhi() const { return getType() == RWNodeType::PHI || isInOut(); }\n    bool isGlobal() const { return getType() == RWNodeType::GLOBAL; }\n    bool isCall() const { return getType() == RWNodeType::CALL; }\n    bool isAlloc() const { return getType() == RWNodeType::ALLOC; }\n    bool isAllocation() const { return isAlloc() || isDynAlloc(); }\n    bool isRet() const { return getType() == RWNodeType::RETURN; }\n    bool isDynAlloc() const;\n\n    bool canEscape() const {\n        return isDynAlloc() || isGlobal() || hasAddressTaken();\n    }\n\n    const RWBBlock *getBBlock() const { return bblock; }\n    RWBBlock *getBBlock() { return bblock; }\n    void setBBlock(RWBBlock *bb) { bblock = bb; }\n\n    friend class ReadWriteGraph;\n};\n\n// we may either call a properly defined function\n// or a function that is undefined and we\n// have just a model for it.\nclass RWCalledValue {\n    RWSubgraph *subgraph{nullptr};\n    RWNode *calledValue{nullptr};\n\n  public:\n    RWCalledValue(RWSubgraph *s) : subgraph(s) {}\n    RWCalledValue(RWNode *c) : calledValue(c) {}\n\n    bool callsUndefined() const { return calledValue != nullptr; }\n\n    RWSubgraph *getSubgraph() { return subgraph; }\n    RWNode *getCalledValue() { return calledValue; }\n    const RWSubgraph *getSubgraph() const { return subgraph; }\n    const RWNode *getCalledValue() const { return calledValue; }\n};\n\nclass RWNodeCall : public RWNode {\n    // what this call calls?\n    using CalleesT = std::vector<RWCalledValue>;\n    // PHI nodes representing defined/used memory\n    // by the call\n    using InputsT = std::vector<RWNode *>;\n    using OutputsT = std::vector<RWNode *>;\n    RWNode *unknownInput{nullptr};\n\n    CalleesT callees;\n    InputsT inputs;\n    OutputsT outputs;\n\n    mutable bool _annotations_summarized{false};\n\n    // compute the overall effect of all undefined calls\n    // in this call and store them into the annotations\n    // of this node\n    void _summarizeAnnotation() const {\n        if (callees.size() > 1) {\n            std::vector<const RWNode *> undefined;\n            for (const auto &cv : callees) {\n                if (const auto *uc = cv.getCalledValue()) {\n                    undefined.push_back(uc);\n                }\n            }\n\n            if (undefined.size() == 1) {\n                annotations = undefined[0]->annotations;\n            } else if (undefined.size() > 1) {\n                auto kills = undefined[0]->annotations.overwrites.intersect(\n                        undefined[1]->annotations.overwrites);\n                for (size_t i = 2; i < undefined.size(); ++i) {\n                    kills = kills.intersect(\n                            undefined[i]->annotations.overwrites);\n                }\n\n                annotations.overwrites = kills;\n                for (const auto *u : undefined) {\n                    annotations.defs.add(u->annotations.defs);\n                    annotations.uses.add(u->annotations.uses);\n                }\n            }\n        }\n        _annotations_summarized = true;\n    }\n\n  public:\n    RWNodeCall(unsigned id) : RWNode(id, RWNodeType::CALL) {}\n\n    static RWNodeCall *get(RWNode *n) {\n        return n->isCall() ? static_cast<RWNodeCall *>(n) : nullptr;\n    }\n\n    static const RWNodeCall *get(const RWNode *n) {\n        return n->isCall() ? static_cast<const RWNodeCall *>(n) : nullptr;\n    }\n\n    RWNode *getUnknownPhi() { return unknownInput; }\n\n    RWCalledValue *getSingleCallee() {\n        if (callees.size() != 1)\n            return nullptr;\n        return &callees[0];\n    }\n\n    const RWCalledValue *getSingleCallee() const {\n        if (callees.size() != 1)\n            return nullptr;\n        return &callees[0];\n    }\n\n    RWNode *getSingleUndefined() {\n        auto *cv = getSingleCallee();\n        return cv ? cv->getCalledValue() : nullptr;\n    }\n\n    const RWNode *getSingleUndefined() const {\n        const auto *cv = getSingleCallee();\n        return cv ? cv->getCalledValue() : nullptr;\n    }\n\n    bool callsOneUndefined() const { return getSingleUndefined() != nullptr; }\n\n    bool callsDefined() const {\n        return dg::any_of(callees, [](const RWCalledValue &c) {\n            return c.getSubgraph() != nullptr;\n        });\n    }\n\n    bool callsUndefined() const {\n        return dg::any_of(callees, [](const RWCalledValue &c) {\n            return c.getCalledValue() != nullptr;\n        });\n    }\n\n    const CalleesT &getCallees() const { return callees; }\n    CalleesT &getCallees() { return callees; }\n\n    void addCallee(const RWCalledValue &cv) { callees.push_back(cv); }\n    void addCallee(RWNode *n) { callees.emplace_back(n); }\n    void addCallee(RWSubgraph *s);\n\n    Annotations &getAnnotations() override {\n        if (auto *uc = getSingleUndefined())\n            return uc->annotations;\n        if (!_annotations_summarized)\n            _summarizeAnnotation();\n        return annotations;\n    }\n    const Annotations &getAnnotations() const override {\n        if (const auto *uc = getSingleUndefined())\n            return uc->annotations;\n        if (!_annotations_summarized)\n            _summarizeAnnotation();\n        return annotations;\n    }\n\n    void addOutput(RWNode *n) {\n        assert(n->isPhi());\n        outputs.push_back(n);\n    }\n    const OutputsT &getOutputs() const { return outputs; }\n\n    void addInput(RWNode *n) {\n        assert(n->isPhi());\n        inputs.push_back(n);\n    }\n\n    void addUnknownInput(RWNode *n) {\n        assert(unknownInput == nullptr);\n        assert(n->isPhi());\n        inputs.push_back(n);\n        unknownInput = n;\n    }\n    const InputsT &getInputs() const { return inputs; }\n\n#ifndef NDEBUG\n    void dump() const override;\n#endif\n};\n\n} // namespace dda\n} // namespace dg\n\n#endif //  DG_RW_NODE_H_\n"
  },
  {
    "path": "include/dg/ReadWriteGraph/RWSubgraph.h",
    "content": "#ifndef DG_READ_WRITE_SUBRAPH_H_\n#define DG_READ_WRITE_SUBRAPH_H_\n\n#include <memory>\n#include <vector>\n\n#include \"RWBBlock.h\"\n#include \"dg/util/iterators.h\"\n\nnamespace dg {\nnamespace dda {\n\nclass ReadWriteGraph;\nclass RWNode;\n\nclass RWSubgraph {\n    // FIXME: get rid of this\n    // unsigned int dfsnum{1};\n\n    using BBlocksVecT = std::vector<std::unique_ptr<RWBBlock>>;\n\n    // iterator over the bblocks that returns the bblock,\n    // not the unique_ptr to the bblock\n    struct block_iterator : public BBlocksVecT::iterator {\n        using ContainedType = std::remove_reference<decltype(*(\n                std::declval<BBlocksVecT::iterator>()->get()))>::type;\n\n        block_iterator(const BBlocksVecT::iterator &it)\n                : BBlocksVecT::iterator(it) {}\n        block_iterator(const block_iterator &) = default;\n        block_iterator() = default;\n\n        ContainedType *operator*() {\n            return (BBlocksVecT::iterator::operator*()).get();\n        };\n        ContainedType *operator->() {\n            return ((BBlocksVecT::iterator::operator*()).get());\n        };\n    };\n\n    BBlocksVecT _bblocks;\n\n    struct blocks_range {\n        BBlocksVecT &blocks;\n        blocks_range(BBlocksVecT &b) : blocks(b) {}\n\n        block_iterator begin() { return block_iterator(blocks.begin()); }\n        block_iterator end() { return block_iterator(blocks.end()); }\n    };\n\n    // Build blocks for the nodes. If 'dce' is set to true,\n    // the dead code is eliminated after building the blocks.\n    void buildBBlocks(bool dce = false);\n\n    friend class ReadWriteGraph;\n\n    std::vector<RWNode *> _callers;\n\n    // for debugging\n    std::string name;\n\n  public:\n    RWSubgraph() = default;\n    RWSubgraph(RWSubgraph &&) = default;\n    RWSubgraph &operator=(RWSubgraph &&) = default;\n\n    RWNode *getRoot() { return _bblocks.front()->getFirst(); }\n    const RWNode *getRoot() const { return _bblocks.front()->getFirst(); }\n\n    void setName(const std::string &nm) { name = nm; }\n    const std::string &getName() const { return name; }\n\n    RWBBlock &createBBlock() {\n        _bblocks.emplace_back(new RWBBlock(this));\n        return *_bblocks.back().get();\n    }\n\n    bool hasCaller(RWNode *c) const {\n        return dg::any_of(_callers, [c](RWNode *tmp) { return tmp == c; });\n    }\n\n    void splitBBlocksOnCalls();\n    void addCaller(RWNode *c) {\n        assert(c->getType() == RWNodeType::CALL);\n        if (hasCaller(c)) {\n            return;\n        }\n        _callers.push_back(c);\n    }\n\n    std::vector<RWNode *> &getCallers() { return _callers; }\n    const std::vector<RWNode *> &getCallers() const { return _callers; }\n\n    const BBlocksVecT &getBBlocks() const { return _bblocks; }\n\n    block_iterator bblocks_begin() { return {_bblocks.begin()}; }\n    block_iterator bblocks_end() { return {_bblocks.end()}; }\n    blocks_range bblocks() { return {_bblocks}; }\n\n    auto size() const -> decltype(_bblocks.size()) { return _bblocks.size(); }\n};\n\n} // namespace dda\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/ReadWriteGraph/ReadWriteGraph.h",
    "content": "#ifndef DG_READ_WRITE_GRAPH_H_\n#define DG_READ_WRITE_GRAPH_H_\n\n#include <memory>\n#include <vector>\n\n#include \"dg/BFS.h\"\n#include \"dg/ReadWriteGraph/RWBBlock.h\"\n#include \"dg/ReadWriteGraph/RWNode.h\"\n#include \"dg/ReadWriteGraph/RWSubgraph.h\"\n\n#include \"dg/util/debug.h\"\n\nnamespace dg {\nnamespace dda {\n\nclass ReadWriteGraph {\n    size_t lastNodeID{0};\n    using NodesT = std::vector<std::unique_ptr<RWNode>>;\n    using SubgraphsT = std::vector<std::unique_ptr<RWSubgraph>>;\n\n    NodesT _nodes;\n    SubgraphsT _subgraphs;\n    RWSubgraph *_entry{nullptr};\n\n    // iterator over the bsubgraphs that returns the bsubgraph,\n    // not the unique_ptr to the bsubgraph\n    struct subgraph_iterator : public SubgraphsT::iterator {\n        using ContainedType = std::remove_reference<decltype(*(\n                std::declval<SubgraphsT::iterator>()->get()))>::type;\n\n        subgraph_iterator(const SubgraphsT::iterator &it)\n                : SubgraphsT::iterator(it) {}\n\n        ContainedType *operator*() {\n            return (SubgraphsT::iterator::operator*()).get();\n        };\n        ContainedType *operator->() {\n            return ((SubgraphsT::iterator::operator*()).get());\n        };\n    };\n\n    struct subgraphs_range {\n        SubgraphsT &subgraphs;\n        subgraphs_range(SubgraphsT &b) : subgraphs(b) {}\n\n        subgraph_iterator begin() { return {subgraphs.begin()}; }\n        subgraph_iterator end() { return {subgraphs.end()}; }\n    };\n\n  public:\n    ReadWriteGraph() = default;\n    ReadWriteGraph(ReadWriteGraph &&) = default;\n    ReadWriteGraph &operator=(ReadWriteGraph &&) = default;\n\n    RWSubgraph *getEntry() { return _entry; }\n    const RWSubgraph *getEntry() const { return _entry; }\n    void setEntry(RWSubgraph *e) { _entry = e; }\n\n    void removeUselessNodes();\n\n    void optimize() { removeUselessNodes(); }\n\n    RWNode *getNode(unsigned id) {\n        assert(id - 1 < _nodes.size());\n        auto *n = _nodes[id - 1].get();\n        assert(n->getID() == id);\n        return n;\n    }\n\n    const RWNode *getNode(unsigned id) const {\n        assert(id - 1 < _nodes.size());\n        auto *n = _nodes[id - 1].get();\n        assert(n->getID() == id);\n        return n;\n    }\n\n    RWNode &create(RWNodeType t) {\n        if (t == RWNodeType::CALL) {\n            _nodes.emplace_back(new RWNodeCall(++lastNodeID));\n        } else {\n            _nodes.emplace_back(new RWNode(++lastNodeID, t));\n        }\n        return *_nodes.back().get();\n    }\n\n    RWSubgraph &createSubgraph() {\n        _subgraphs.emplace_back(new RWSubgraph());\n        return *_subgraphs.back().get();\n    }\n\n    // Build blocks for the nodes. If 'dce' is set to true,\n    // the dead code is eliminated after building the blocks.\n    /*\n    void buildBBlocks(bool dce = false) {\n        for (auto& s : _subgraphs) {\n            s->buildBBlocks(dce);\n        }\n    }\n    */\n\n    void splitBBlocksOnCalls() {\n        for (auto &s : _subgraphs) {\n            s->splitBBlocksOnCalls();\n        }\n    }\n\n    subgraph_iterator subgraphs_begin() { return {_subgraphs.begin()}; }\n    subgraph_iterator subgraphs_end() { return {_subgraphs.end()}; }\n\n    subgraphs_range subgraphs() { return {_subgraphs}; }\n\n    auto size() const -> decltype(_subgraphs.size()) {\n        return _subgraphs.size();\n    }\n};\n\n} // namespace dda\n} // namespace dg\n\n#endif // DG_READ_WRITE_GRAPH_H_\n"
  },
  {
    "path": "include/dg/SCC.h",
    "content": "#ifndef DG_SCC_H_\n#define DG_SCC_H_\n\n#include <set>\n#include <vector>\n\n#include \"dg/ADT/Queue.h\"\n#include \"dg/ADT/STLHashMap.h\"\n\nnamespace dg {\n\n// implementation of tarjan's algorithm for\n// computing strongly connected components\n// for a directed graph that has a starting vertex\n// from which are all other vertices reachable\ntemplate <typename NodeT>\nclass SCC {\n  public:\n    using SCC_component_t = std::vector<NodeT *>;\n    using SCC_t = std::vector<SCC_component_t>;\n\n    SCC<NodeT>() = default;\n\n    // returns a vector of vectors - every inner vector\n    // contains the nodes contained in one SCC\n    SCC_t &compute(NodeT *start) {\n        _compute(start);\n        assert(stack.empty());\n\n        return scc;\n    }\n\n    const SCC_t &getSCC() const { return scc; }\n\n    SCC_component_t &operator[](unsigned idx) {\n        assert(idx < scc.size());\n        return scc[idx];\n    }\n\n  private:\n    struct NodeInfo {\n        unsigned dfs_id{0};\n        unsigned lowpt{0};\n        bool on_stack{false};\n    };\n\n    ADT::QueueLIFO<NodeT *> stack;\n    CachingHashMap<NodeT *, NodeInfo> _info;\n    unsigned index{0};\n\n    // container for the strongly connected components.\n    SCC_t scc;\n\n    void _compute(NodeT *n) {\n        auto &info = _info[n];\n        // here we using the fact that we are a friend class\n        // of SubgraphNode. If we would need to make this\n        // algorithm more generinc, we add setters/getters.\n        info.dfs_id = info.lowpt = ++index;\n        info.on_stack = true;\n        stack.push(n);\n\n        for (auto *succ : n->successors()) {\n            auto &succ_info = _info[succ];\n            if (succ_info.dfs_id == 0) {\n                assert(!succ_info.on_stack);\n                _compute(succ);\n                info.lowpt = std::min(info.lowpt, succ_info.lowpt);\n            } else if (succ_info.on_stack) {\n                info.lowpt = std::min(info.lowpt, succ_info.dfs_id);\n            }\n        }\n\n        if (info.lowpt == info.dfs_id) {\n            SCC_component_t component;\n            size_t component_num = scc.size();\n\n            NodeT *w;\n            while (_info[stack.top()].dfs_id >= info.dfs_id) {\n                w = stack.pop();\n                auto &winfo = _info[w];\n                assert(winfo.on_stack == true);\n                winfo.on_stack = false;\n                component.push_back(w);\n                // the numbers scc_id give\n                // a reverse topological order\n                w->setSCCId(component_num);\n\n                if (stack.empty())\n                    break;\n            }\n\n            scc.push_back(std::move(component));\n        }\n    }\n};\n\ntemplate <typename NodeT>\nclass SCCCondensation {\n    using SCC_t = typename SCC<NodeT>::SCC_t;\n    using SCC_component_t = typename SCC<NodeT>::SCC_component_t;\n\n    struct Node {\n        const SCC_component_t &component;\n        std::set<unsigned> _successors;\n\n        Node(SCC_component_t &comp) : component(comp) {}\n\n        void addSuccessor(unsigned idx) { _successors.insert(idx); }\n        const SCC_component_t &operator*() const { return component; }\n        // XXX: create iterators instead\n        const std::set<unsigned> &successors() const { return _successors; }\n    };\n\n    std::vector<Node> nodes;\n\n  public:\n    Node &operator[](unsigned idx) {\n        assert(idx < nodes.size());\n        return nodes[idx];\n    }\n\n    void compute(SCC_t &scc) {\n        // we know the size before-hand\n        nodes.reserve(scc.size());\n\n        // create the nodes in our condensation graph\n        for (auto &comp : scc)\n            nodes.push_back(Node(comp));\n\n        assert(nodes.size() == scc.size());\n\n        int idx = 0;\n        for (auto &comp : scc) {\n            for (NodeT *node : comp) {\n                // we can get from this component\n                // to the component of succ\n                for (NodeT *succ : node->successors()) {\n                    unsigned succ_idx = succ->getSCCId();\n                    if (static_cast<int>(succ_idx) != idx)\n                        nodes[idx].addSuccessor(succ_idx);\n                }\n            }\n\n            ++idx;\n        }\n    }\n\n    SCCCondensation<NodeT>() = default;\n    SCCCondensation<NodeT>(SCC<NodeT> &S) { compute(S.getSCC()); }\n\n    SCCCondensation<NodeT>(SCC_t &s) { compute(s); }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/Slicing.h",
    "content": "#ifndef DG_SLICING_H_\n#define DG_SLICING_H_\n\n#include <set>\n\n#include \"dg/ADT/Queue.h\"\n#include \"dg/DependenceGraph.h\"\n#include \"dg/legacy/Analysis.h\"\n#include \"dg/legacy/BFS.h\"\n#include \"dg/legacy/NodesWalk.h\"\n\n#ifdef ENABLE_CFG\n#include \"dg/BBlock.h\"\n#endif\n\nnamespace dg {\n\n// this class will go through the nodes\n// and will mark the ones that should be in the slice\ntemplate <typename NodeT>\nclass WalkAndMark\n        : public legacy::NodesWalk<NodeT, dg::ADT::QueueFIFO<NodeT *>> {\n    using Queue = dg::ADT::QueueFIFO<NodeT *>;\n\n  public:\n    ///\n    // forward_slc makes searching the dependencies\n    // in forward direction instead of backward\n    WalkAndMark(bool forward_slc = false)\n            : legacy::NodesWalk<NodeT, Queue>(\n                      forward_slc\n                              ? (legacy::NODES_WALK_DD | // legacy::NODES_WALK_CD\n                                                         // NOTE: we handle CD\n                                                         // separately\n                                 legacy::NODES_WALK_USE | legacy::NODES_WALK_ID)\n                              : (legacy::NODES_WALK_REV_CD |\n                                 legacy::NODES_WALK_REV_DD |\n                                 legacy::NODES_WALK_USER |\n                                 legacy::NODES_WALK_ID |\n                                 legacy::NODES_WALK_REV_ID)),\n              forward_slice(forward_slc) {}\n\n    void mark(const std::set<NodeT *> &start, uint32_t slice_id) {\n        WalkData data(slice_id, this, forward_slice ? &markedBlocks : nullptr);\n        this->walk(start, markSlice, &data);\n    }\n\n    void mark(NodeT *start, uint32_t slice_id) {\n        WalkData data(slice_id, this, forward_slice ? &markedBlocks : nullptr);\n        this->walk(start, markSlice, &data);\n    }\n\n    bool isForward() const { return forward_slice; }\n    // returns marked blocks, but only for forward slicing atm\n    const std::set<BBlock<NodeT> *> &getMarkedBlocks() { return markedBlocks; }\n\n  private:\n    bool forward_slice{false};\n    std::set<BBlock<NodeT> *> markedBlocks;\n\n    struct WalkData {\n        WalkData(uint32_t si, WalkAndMark *wm,\n                 std::set<BBlock<NodeT> *> *mb = nullptr)\n                : slice_id(si), analysis(wm)\n#ifdef ENABLE_CFG\n                  ,\n                  markedBlocks(mb)\n#endif\n        {\n        }\n\n        uint32_t slice_id;\n        WalkAndMark *analysis;\n#ifdef ENABLE_CFG\n        std::set<BBlock<NodeT> *> *markedBlocks;\n#endif\n    };\n\n    static void markSlice(NodeT *n, WalkData *data) {\n        uint32_t slice_id = data->slice_id;\n        n->setSlice(slice_id);\n\n#ifdef ENABLE_CFG\n        // when we marked a node, we need to mark even\n        // the basic block - if there are basic blocks\n        if (BBlock<NodeT> *B = n->getBBlock()) {\n            B->setSlice(slice_id);\n            if (data->markedBlocks) {\n                data->markedBlocks->insert(B);\n            }\n\n            // if this node has CDs, enque them\n            if (data->analysis->isForward()) {\n                for (auto it = n->control_begin(), et = n->control_end();\n                     it != et; ++it) {\n                    data->analysis->enqueue(*it);\n                }\n\n                // if this node is a jump instruction,\n                // add also nodes that control depend on this jump\n                if (n == B->getLastNode()) {\n                    for (BBlock<NodeT> *CD : B->controlDependence()) {\n                        for (auto *cdnd : CD->getNodes()) {\n                            data->analysis->enqueue(cdnd);\n                        }\n                    }\n                }\n            }\n        }\n#endif\n\n        // the same with dependence graph, if we keep a node from\n        // a dependence graph, we need to keep the dependence graph\n        if (DependenceGraph<NodeT> *dg = n->getDG()) {\n            dg->setSlice(slice_id);\n            if (!data->analysis->isForward()) {\n                // and keep also all call-sites of this func (they are\n                // control dependent on the entry node)\n                // This is correct but not so precise - fix it later.\n                // Now I need the correctness...\n                NodeT *entry = dg->getEntry();\n                assert(entry && \"No entry node in dg\");\n                data->analysis->enqueue(entry);\n            }\n        }\n    }\n};\n\nstruct SlicerStatistics {\n    SlicerStatistics() = default;\n\n    // total number of nodes that were checked for removing\n    uint64_t nodesTotal{0};\n    // total number of nodes actually removed (including the\n    // ones removed in blocks)\n    uint64_t nodesRemoved{0};\n    // number of whole blocks removed\n    uint32_t blocksRemoved{0};\n};\n\ntemplate <typename NodeT>\nclass Slicer : legacy::Analysis<NodeT> {\n    uint32_t options;\n    uint32_t slice_id{0};\n\n    std::set<DependenceGraph<NodeT> *> sliced_graphs;\n\n    // slice nodes from the graph; do it recursively for call-nodes\n    void sliceNodes(DependenceGraph<NodeT> *dg, uint32_t slice_id) {\n        for (auto &it : *dg) {\n            NodeT *n = it.second;\n\n            if (n->getSlice() != slice_id) {\n                if (removeNode(n)) // do backend's specific logic\n                    dg->deleteNode(n);\n\n                continue;\n            }\n\n            // slice subgraphs if this node is\n            // a call-site that is in the slice\n            for (DependenceGraph<NodeT> *sub : n->getSubgraphs()) {\n                // slice the subgraph if we haven't sliced it yet\n                if (sliced_graphs.insert(sub).second)\n                    sliceNodes(sub, slice_id);\n            }\n        }\n\n        // slice the global nodes\n        const auto &global_nodes = dg->getGlobalNodes();\n        if (!global_nodes)\n            return;\n\n        for (auto &it : *global_nodes.get()) {\n            NodeT *n = it.second;\n\n            if (n->getSlice() != slice_id) {\n                if (removeNode(n)) // do backend's specific logic\n                    dg->deleteGlobalNode(n);\n                continue;\n            }\n        }\n    }\n\n  protected:\n    // how many nodes and blocks were removed or kept\n    SlicerStatistics statistics;\n\n  public:\n    Slicer<NodeT>(uint32_t opt = 0) : options(opt) {}\n\n    SlicerStatistics &getStatistics() { return statistics; }\n    const SlicerStatistics &getStatistics() const { return statistics; }\n\n    ///\n    // Mark nodes dependent on 'start' with 'sl_id'.\n    // If 'forward_slice' is true, mark the nodes depending on 'start' instead.\n    uint32_t mark(NodeT *start, uint32_t sl_id = 0,\n                  bool forward_slice = false) {\n        if (sl_id == 0)\n            sl_id = ++slice_id;\n\n        WalkAndMark<NodeT> wm(forward_slice);\n        wm.mark(start, sl_id);\n\n        ///\n        // If we are performing forward slicing,\n        // we must do the slice executable as we now just\n        // marked the nodes that are data dependent on the\n        // slicing criterion. We do that by using these\n        // nodes as slicing criteria in normal backward slicing.\n        if (forward_slice) {\n            std::set<NodeT *> inslice;\n            for (auto *BB : wm.getMarkedBlocks()) {\n#if ENABLE_CFG\n                for (auto *nd : BB->getNodes()) {\n                    if (nd->getSlice() == sl_id) {\n                        inslice.insert(nd);\n                    }\n                }\n#endif\n            }\n\n            // do backward slicing to make the slice executable\n            if (!inslice.empty()) {\n                WalkAndMark<NodeT> wm2;\n                wm2.mark(inslice, sl_id);\n            }\n        }\n\n        return sl_id;\n    }\n\n    // slice the graph and its subgraphs. mark needs to be called\n    // before this routine (otherwise everything is sliced)\n    uint32_t slice(DependenceGraph<NodeT> *dg, uint32_t sl_id = 0) {\n#ifdef ENABLE_CFG\n        // first slice away bblocks that should go away\n        sliceBBlocks(dg, sl_id);\n#endif // ENABLE_CFG\n\n        // now slice the nodes from the remaining graphs\n        sliceNodes(dg, sl_id);\n\n        return sl_id;\n    }\n\n    // remove node from the graph\n    // This virtual method allows to taky an action\n    // when node is being removed from the graph. It can also\n    // disallow removing this node by returning false\n    virtual bool removeNode(NodeT * /*unused*/) { return true; }\n\n#ifdef ENABLE_CFG\n    virtual bool removeBlock(BBlock<NodeT> * /*unused*/) { return true; }\n\n    struct RemoveBlockData {\n        uint32_t sl_id;\n        std::set<BBlock<NodeT> *> &blocks;\n    };\n\n    static void getBlocksToRemove(BBlock<NodeT> *BB, RemoveBlockData &data) {\n        if (BB->getSlice() == data.sl_id)\n            return;\n\n        data.blocks.insert(BB);\n    }\n\n    void sliceBBlocks(BBlock<NodeT> *start, uint32_t sl_id) {\n        // we must queue the blocks ourselves before we potentially remove them\n        legacy::BBlockBFS<NodeT> bfs(legacy::BFS_BB_CFG);\n        std::set<BBlock<NodeT> *> blocks;\n\n        RemoveBlockData data = {sl_id, blocks};\n        bfs.run(start, getBlocksToRemove, data);\n\n        for (BBlock<NodeT> *blk : blocks) {\n            // update statistics\n            statistics.nodesRemoved += blk->size();\n            statistics.nodesTotal += blk->size();\n            ++statistics.blocksRemoved;\n\n            // call specific handlers (overriden by child class)\n            removeBlock(blk);\n\n            // remove block from the graph\n            blk->remove();\n        }\n    }\n\n    // remove BBlocks that contain no node that should be in\n    // sliced graph\n    void sliceBBlocks(DependenceGraph<NodeT> *graph, uint32_t sl_id) {\n        auto &CB = graph->getBlocks();\n#ifndef NDEBUG\n        uint32_t blocksNum = CB.size();\n#endif\n        // gather the blocks\n        // FIXME: we don't need two loops, just go carefully\n        // through the constructed blocks (keep temporary always-valid iterator)\n        std::set<BBlock<NodeT> *> blocks;\n        for (auto &it : CB) {\n            if (it.second->getSlice() != sl_id)\n                blocks.insert(it.second);\n        }\n\n        for (BBlock<NodeT> *blk : blocks) {\n            // update statistics\n            statistics.nodesRemoved += blk->size();\n            statistics.nodesTotal += blk->size();\n            ++statistics.blocksRemoved;\n\n            // call specific handlers (overriden by child class)\n            if (removeBlock(blk)) {\n                // remove block from the graph\n                blk->remove();\n            }\n        }\n\n        assert(CB.size() + blocks.size() == blocksNum &&\n               \"Inconsistency in sliced blocks\");\n    }\n\n#endif\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/SubgraphBase.h",
    "content": "#ifndef DG_SUBGRAPHBASE_H_\n#define DG_SUBGRAPHBASE_H_\n\nnamespace dg {\n\ntemplate <typename SubgraphT, typename BBlockT>\nclass SubgraphBase {\n    using BBlocksVecT = std::vector<std::unique_ptr<BBlockT>>;\n\n    // iterator over the bblocks that returns the bblock,\n    // not the unique_ptr to the bblock\n    struct block_iterator : public BBlocksVecT::iterator {\n        using ContainedType = typename std::remove_reference<decltype(*(\n                std::declval<BBlocksVecT::iterator>()->get()))>::type;\n\n        block_iterator(const typename BBlocksVecT::iterator &it)\n                : BBlocksVecT::iterator(it) {}\n        block_iterator(const block_iterator &) = default;\n        block_iterator() = default;\n\n        ContainedType *operator*() {\n            return (BBlocksVecT::iterator::operator*()).get();\n        };\n        ContainedType *operator->() {\n            return ((BBlocksVecT::iterator::operator*()).get());\n        };\n    };\n\n    BBlocksVecT _bblocks;\n\n    struct blocks_range {\n        BBlocksVecT &blocks;\n        blocks_range(BBlocksVecT &b) : blocks(b) {}\n\n        block_iterator begin() { return block_iterator(blocks.begin()); }\n        block_iterator end() { return block_iterator(blocks.end()); }\n    };\n\n    // std::vector<typename BBlockT::NodeType *> _callers;\n\n    // for debugging\n    std::string name;\n\n  public:\n    SubgraphBase() = default;\n    SubgraphBase(SubgraphBase &&) = default;\n    SubgraphBase &operator=(SubgraphBase &&) = default;\n\n    void setName(const std::string &nm) { name = nm; }\n    const std::string &getName() const { return name; }\n\n    BBlockT &createBBlock() {\n        _bblocks.emplace_back(new BBlockT(static_cast<SubgraphT *>(this)));\n        return *_bblocks.back().get();\n    }\n\n    /*\n    void addCaller(RWNode *c) {\n        assert(c->getType() == RWNodeType::CALL);\n        for (auto *tmp : _callers) {\n            if (tmp == c)\n                return;\n        }\n        _callers.push_back(c);\n    }\n\n    std::vector<RWNode *>& getCallers() { return _callers; }\n    const std::vector<RWNode *>& getCallers() const { return _callers; }\n    */\n\n    const BBlocksVecT &getBBlocks() const { return _bblocks; }\n\n    block_iterator bblocks_begin() { return block_iterator(_bblocks.begin()); }\n    block_iterator bblocks_end() { return block_iterator(_bblocks.end()); }\n\n    blocks_range bblocks() { return blocks_range(_bblocks); }\n\n    auto size() const -> decltype(_bblocks.size()) { return _bblocks.size(); }\n};\n\n} // namespace dg\n\n#endif // SUBGRAPHBASE_H\n"
  },
  {
    "path": "include/dg/SubgraphNode.h",
    "content": "#ifndef SUBGRAPH_NODE_H_\n#define SUBGRAPH_NODE_H_\n\n// This file defines a basis for nodes from\n// PointerGraph and reaching definitions subgraph.\n\n#ifndef NDEBUG\n#include <iostream>\n#endif // not NDEBUG\n\n#include <algorithm>\n#include <cassert>\n#include <set>\n#include <vector>\n\n#include <dg/util/iterators.h>\n\nnamespace dg {\n\nnamespace pta {\nclass PSNode;\n}\nnamespace dda {\nclass RWNode;\n}\n\ntemplate <typename NodeT>\nclass SubgraphNode {\n  public:\n    using IDType = unsigned;\n    using NodesVec = std::vector<NodeT *>;\n\n  private:\n    // id of the node. Every node from a graph has a unique ID;\n    IDType id = 0;\n\n    // data that can an analysis store in node\n    // for its own needs\n    void *data{nullptr};\n\n    // data that can user store in the node\n    // NOTE: I considered if this way is better than\n    // creating subclass of PSNode and have whatever we\n    // need in the subclass. Since AFAIK we need just this one pointer\n    // at this moment, I decided to do it this way since it\n    // is more simple than dynamic_cast... Once we need more\n    // than one pointer, we can change this design.\n    void *user_data{nullptr};\n\n    // id of scc component\n    unsigned int scc_id{0};\n\n  protected:\n    // XXX: make those private!\n    NodesVec _successors;\n    NodesVec _predecessors;\n    // XXX: maybe we could use SmallPtrVector or something like that\n    NodesVec operands;\n    // nodes that use this node\n    NodesVec users;\n\n    // size of the memory\n    size_t size{0};\n\n  public:\n    SubgraphNode(IDType id) : id(id) {}\n#ifndef NDEBUG\n    // in debug mode, we have virtual dump methods\n    // and then we want virtual dtor. Otherwise,\n    // we never use polymorphism for childern classes,\n    // so we do not need the virtual dtor.\n    virtual ~SubgraphNode() = default;\n#endif\n\n    IDType getID() const { return id; }\n\n    void setSize(size_t s) { size = s; }\n    size_t getSize() const { return size; }\n    void setSCCId(unsigned id) { scc_id = id; }\n    unsigned getSCCId() const { return scc_id; }\n\n    // getters & setters for analysis's data in the node\n    template <typename T>\n    T *getData() {\n        return static_cast<T *>(data);\n    }\n    template <typename T>\n    const T *getData() const {\n        return static_cast<T *>(data);\n    }\n\n    template <typename T>\n    void *setData(T *newdata) {\n        void *old = data;\n        data = static_cast<void *>(newdata);\n        return old;\n    }\n\n    // getters & setters for user's data in the node\n    template <typename T>\n    T *getUserData() {\n        return static_cast<T *>(user_data);\n    }\n    template <typename T>\n    const T *getUserData() const {\n        return static_cast<T *>(user_data);\n    }\n\n    template <typename T>\n    void *setUserData(T *newdata) {\n        void *old = user_data;\n        user_data = static_cast<void *>(newdata);\n        return old;\n    }\n\n    NodeT *getOperand(size_t idx) const {\n        assert(idx < operands.size() && \"Operand index out of range\");\n\n        return operands[idx];\n    }\n\n    void setOperand(size_t idx, NodeT *nd) {\n        assert(idx < operands.size() && \"Operand index out of range\");\n\n        operands[idx] = nd;\n    }\n\n    size_t getOperandsNum() const { return operands.size(); }\n\n    void removeAllOperands() {\n        for (auto *o : operands) {\n            o->removeUser(static_cast<NodeT *>(this));\n        }\n        operands.clear();\n    }\n\n    template <typename NodePtr, typename... Args>\n    size_t addOperand(NodePtr node, Args &&...args) {\n        addOperand(node);\n        return addOperand(std::forward<Args>(args)...);\n    }\n\n    template <typename NodePtr,\n              typename Node_plain = typename std::remove_pointer<NodePtr>::type>\n    size_t addOperand(NodePtr n) {\n        static_assert(std::is_pointer<NodePtr>::value &&\n                              std::is_base_of<NodeT, Node_plain>::value,\n                      \"Argument is not a pointer or is not derived from this \"\n                      \"class.\");\n        assert(n && \"Passed nullptr as the operand\");\n        operands.push_back(n);\n        n->addUser(static_cast<NodeT *>(this));\n        assert(!n->users.empty());\n\n        return operands.size();\n    }\n\n    bool hasOperand(NodeT *n) const {\n        return dg::any_of(operands, [n](NodeT *x) { return x == n; });\n    }\n\n    void addSuccessor(NodeT *succ) {\n        assert(succ && \"Passed nullptr as the successor\");\n        _successors.push_back(succ);\n        succ->_predecessors.push_back(static_cast<NodeT *>(this));\n    }\n\n    // return const only, so that we cannot change them\n    // other way then addSuccessor()\n    const NodesVec &successors() const { return _successors; }\n    const NodesVec &predecessors() const { return _predecessors; }\n    const NodesVec &getOperands() const { return operands; }\n    const NodesVec &getUsers() const { return users; }\n\n    void replaceSingleSuccessor(NodeT *succ) {\n        assert(succ && \"Passed nullptr as the successor\");\n        removeSingleSuccessor();\n        addSuccessor(succ);\n    }\n\n    void removeSingleSuccessor() {\n        assert(_successors.size() == 1);\n\n        // we need to remove this node from\n        // successor's predecessors\n        _removeThisFromSuccessorsPredecessors(_successors[0]);\n\n        // remove the successor\n        _successors.clear();\n    }\n\n    // get the successor when we know there's only one of them\n    NodeT *getSingleSuccessor() const {\n        assert(_successors.size() == 1);\n        return _successors.front();\n    }\n\n    // get the successor when there's only one of them,\n    // otherwise get null\n    NodeT *getSingleSuccessorOrNull() const {\n        if (_successors.size() == 1)\n            return _successors.front();\n\n        return nullptr;\n    }\n\n    // get the predecessor when we know there's only one of them\n    NodeT *getSinglePredecessor() const {\n        assert(_predecessors.size() == 1);\n        return _predecessors.front();\n    }\n\n    // get the predecessor when there's only one of them,\n    // or get null\n    NodeT *getSinglePredecessorOrNull() const {\n        if (_predecessors.size() == 1)\n            return _predecessors.front();\n\n        return nullptr;\n    }\n\n    // insert this node in PointerGraph after n\n    // this node must not be in any PointerGraph\n    void insertAfter(NodeT *n) {\n        assert(n && \"Passed nullptr as the node\");\n        assert(predecessorsNum() == 0);\n        assert(successorsNum() == 0);\n\n        // take over successors\n        _successors.swap(n->_successors);\n\n        // make this node the successor of n\n        n->addSuccessor(static_cast<NodeT *>(this));\n\n        // replace the reference to n in successors\n        for (NodeT *succ : _successors) {\n            for (unsigned i = 0; i < succ->predecessorsNum(); ++i) {\n                if (succ->_predecessors[i] == n)\n                    succ->_predecessors[i] = static_cast<NodeT *>(this);\n            }\n        }\n    }\n\n    // insert this node in PointerGraph before n\n    // this node must not be in any PointerGraph\n    void insertBefore(NodeT *n) {\n        assert(n && \"Passed nullptr as the node\");\n        assert(predecessorsNum() == 0);\n        assert(successorsNum() == 0);\n\n        // take over predecessors\n        _predecessors.swap(n->_predecessors);\n\n        // 'n' is a successors of this node\n        addSuccessor(n);\n\n        // replace the reference to n in predecessors\n        for (NodeT *pred : _predecessors) {\n            for (unsigned i = 0; i < pred->successorsNum(); ++i) {\n                if (pred->_successors[i] == n)\n                    pred->_successors[i] = static_cast<NodeT *>(this);\n            }\n        }\n    }\n\n    // insert a sequence before this node in PointerGraph\n    void insertSequenceBefore(std::pair<NodeT *, NodeT *> &seq) {\n        assert(seq.first && seq.second && \"Passed nullptr in the sequence\");\n        // the sequence must not be inserted in any PointerGraph\n        assert(seq.first->predecessorsNum() == 0);\n        assert(seq.second->successorsNum() == 0);\n\n        // first node of the sequence takes over predecessors\n        // this also clears 'this->predecessors' since seq.first\n        // has no predecessors\n        _predecessors.swap(seq.first->_predecessors);\n\n        // replace the reference to 'this' in predecessors\n        for (NodeT *pred : seq.first->_predecessors) {\n            for (unsigned i = 0; i < pred->successorsNum(); ++i) {\n                if (pred->_successors[i] == this)\n                    pred->_successors[i] = seq.first;\n            }\n        }\n\n        // this node is successors of the last node in sequence\n        seq.second->addSuccessor(this);\n    }\n\n    void isolate() {\n        // Remove this node from successors of the predecessors\n        for (NodeT *pred : _predecessors) {\n            std::vector<NodeT *> new_succs;\n            new_succs.reserve(pred->_successors.size());\n\n            for (NodeT *n : pred->_successors) {\n                if (n != this)\n                    new_succs.push_back(n);\n            }\n\n            new_succs.swap(pred->_successors);\n        }\n\n        // remove this nodes from successors' predecessors\n        for (NodeT *succ : _successors) {\n            std::vector<NodeT *> new_preds;\n            new_preds.reserve(succ->_predecessors.size());\n\n            for (NodeT *n : succ->_predecessors) {\n                if (n != this)\n                    new_preds.push_back(n);\n            }\n\n            new_preds.swap(succ->_predecessors);\n        }\n\n        // Take every predecessor and connect it to every successor.\n        for (NodeT *pred : _predecessors) {\n            for (NodeT *succ : _successors) {\n                assert(succ != this && \"Self-loop\");\n                pred->addSuccessor(succ);\n            }\n        }\n\n        _successors.clear();\n        _predecessors.clear();\n    }\n\n    void replaceAllUsesWith(NodeT *nd, bool removeDupl = true) {\n        assert(nd != this && \"Replacing uses of 'this' with 'this'\");\n\n        // Replace 'this' in every user with 'nd'.\n        for (NodeT *user : users) {\n            for (int i = 0, e = user->getOperandsNum(); i < e; ++i) {\n                if (user->getOperand(i) == this) {\n                    user->setOperand(i, nd);\n                    // register that 'nd' is now used in 'user'\n                    nd->addUser(user);\n                }\n            }\n\n            if (removeDupl)\n                user->removeDuplicitOperands();\n        }\n\n        users.clear();\n    }\n\n    size_t predecessorsNum() const { return _predecessors.size(); }\n\n    size_t successorsNum() const { return _successors.size(); }\n\n#ifndef NDEBUG\n    virtual void dump() const { std::cout << \"SubgraphNode <\" << getID(); }\n\n    virtual void print() const {\n        dump();\n        std::cout << \"\\n\";\n    }\n\n    virtual void dumpv() const { print(); }\n#endif\n\n  private:\n    void _removeThisFromSuccessorsPredecessors(NodeT *succ) {\n        std::vector<NodeT *> tmp;\n        tmp.reserve(succ->predecessorsNum());\n        for (NodeT *p : succ->_predecessors) {\n            if (p != this)\n                tmp.push_back(p);\n        }\n\n        succ->_predecessors.swap(tmp);\n    }\n\n    bool removeDuplicitOperands() {\n        std::set<NodeT *> ops;\n        bool duplicated = false;\n        for (auto *op : getOperands()) {\n            if (!ops.insert(op).second)\n                duplicated = true;\n        }\n\n        if (duplicated) {\n            operands.clear();\n            operands.reserve(ops.size());\n            // just push the new operads,\n            // the users should not change in this case\n            // (as we just remove the duplicated ones)\n            for (auto *op : ops)\n                operands.push_back(op);\n        }\n\n        return duplicated;\n    }\n\n    void addUser(NodeT *nd) {\n        // do not add duplicate users\n        for (auto *u : users)\n            if (u == nd)\n                return;\n\n        users.push_back(nd);\n    }\n\n    void removeUser(NodeT *node) {\n        using std::find;\n        NodesVec &u = users;\n\n        auto nodeToRemove = find(u.begin(), u.end(), node);\n        if (nodeToRemove != u.end()) {\n            u.erase(nodeToRemove);\n        }\n    }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/SystemDependenceGraph/DGArgumentPair.h",
    "content": "#ifndef DG_DG_ARG_PAIR_H_\n#define DG_DG_ARG_PAIR_H_\n\n#include \"DGNode.h\"\n#include <cassert>\n\nnamespace dg {\nnamespace sdg {\n\nclass DGParameters;\n\n///\n// Input-output pair of arguments that is associated to some (formal or\n// actual) DGParameters object.\nclass DGArgumentPair : public DGElement {\n    friend class DGParameters;\n\n    DGParameters &_parameters;\n\n    DGNodeArgument _input;\n    DGNodeArgument _output;\n\n    DGArgumentPair(DGParameters &p);\n\n  public:\n    static DGArgumentPair *get(DGElement *n) {\n        return isa<DGElementType::ARG_PAIR>(n)\n                       ? static_cast<DGArgumentPair *>(n)\n                       : nullptr;\n    }\n\n    DGNodeArgument &getInputArgument() { return _input; }\n    const DGNodeArgument &getInputArgument() const { return _input; }\n\n    DGNodeArgument &getOutputArgument() { return _output; }\n    const DGNodeArgument &getOutputArgument() const { return _output; }\n\n    DGParameters &getParameters() { return _parameters; }\n    const DGParameters &getParameters() const { return _parameters; }\n};\n\n} // namespace sdg\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/SystemDependenceGraph/DGBBlock.h",
    "content": "#ifndef DG_DGBBLOCK_H_\n#define DG_DGBBLOCK_H_\n\n#include <cassert>\n#include <vector>\n\n#include \"DGNode.h\"\n#include \"DepDGElement.h\"\n\nnamespace dg {\nnamespace sdg {\n\nclass DependenceGraph;\n\n///\n// A basic block of a dependence graph.\n// Basic blocks are useful even in dependence graph in order\n// to cluster nodes with the same control dependence.\nclass DGBBlock : public DepDGElement {\n    friend class DependenceGraph;\n    using NodesTy = std::vector<DGNode *>;\n\n    NodesTy _nodes;\n    DGBBlock(DependenceGraph &g) : DepDGElement(g, DGElementType::BBLOCK) {}\n\n  public:\n    static DGBBlock *get(DGElement *elem) {\n        return elem->getType() == DGElementType::BBLOCK\n                       ? static_cast<DGBBlock *>(elem)\n                       : nullptr;\n    }\n\n    NodesTy &getNodes() { return _nodes; }\n    const NodesTy &getNodes() const { return _nodes; }\n\n    void append(DGNode *n) {\n        assert(n && \"nullptr passed as node\");\n        assert(n->getBBlock() == nullptr && \"BBlock already set\");\n        _nodes.push_back(n);\n        n->setBBlock(this);\n    }\n\n    DGNode *front() { return _nodes.front(); }\n    DGNode *back() { return _nodes.back(); }\n    const DGNode *front() const { return _nodes.front(); }\n    const DGNode *back() const { return _nodes.back(); }\n};\n\n} // namespace sdg\n} // namespace dg\n\n#endif // DG_DGBBLOCK_H_\n"
  },
  {
    "path": "include/dg/SystemDependenceGraph/DGElement.h",
    "content": "#ifndef DG_DG_ELEMENT_H_\n#define DG_DG_ELEMENT_H_\n\n#include <cassert>\n\n#ifndef NDEBUG\n// FIXME: move this to .cpp file\n#include <iostream>\n#endif // not NDEBUG\n\nnamespace dg {\nnamespace sdg {\n\nenum class DGElementType {\n    // Invalid node\n    INVALID = 0,\n    /// special elements\n    // Pair of arguments (input & output)\n    ARG_PAIR = 1,\n    BBLOCK,\n    // nodes\n    // NOTE: here can follow only childs of DGNode class\n    NODE = 3,\n    ND_INSTRUCTION,\n    ND_ARGUMENT,\n    ND_CALL,\n    ND_ARTIFICIAL\n};\n\ninline const char *DGElemTypeToCString(enum DGElementType type) {\n#define ELEM(t)                                                                \\\n    case t:                                                                    \\\n        do {                                                                   \\\n            return (#t);                                                       \\\n        } while (0);                                                           \\\n        break;\n    switch (type) {\n        ELEM(DGElementType::INVALID)\n        ELEM(DGElementType::ARG_PAIR)\n        ELEM(DGElementType::BBLOCK)\n        ELEM(DGElementType::NODE)\n        ELEM(DGElementType::ND_INSTRUCTION)\n        ELEM(DGElementType::ND_ARGUMENT)\n        ELEM(DGElementType::ND_CALL)\n        ELEM(DGElementType::ND_ARTIFICIAL)\n    default:\n        assert(false && \"unknown node type\");\n        return \"Unknown type\";\n    };\n#undef ELEM\n}\n\nclass DependenceGraph;\n\nclass DGElement {\n    unsigned _id{0};\n    DGElementType _type;\n    DependenceGraph &_dg;\n\n  protected:\n    friend class DependenceGraph;\n    // Only for the use in ctor. This method gets the ID of this node\n    // from the DependenceGraph (increasing the graph's id counter).\n    static unsigned getNewID(DependenceGraph &g);\n\n  public:\n    virtual ~DGElement() = default;\n\n    DGElement(DependenceGraph &dg, DGElementType t);\n\n    DGElementType getType() const { return _type; }\n    unsigned getID() const { return _id; }\n\n    const DependenceGraph &getDG() const { return _dg; }\n    DependenceGraph &getDG() { return _dg; }\n\n#ifndef NDEBUG\n    virtual void dump() const { std::cout << DGElemTypeToCString(getType()); }\n\n    // verbose dump\n    void dumpv() const {\n        dump();\n        std::cout << \"\\n\";\n    }\n#endif // not NDEBUG\n};\n\n} // namespace sdg\n\n// check type of node\ntemplate <sdg::DGElementType T>\nbool isa(sdg::DGElement *n) {\n    return n->getType() == T;\n}\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/SystemDependenceGraph/DGNode.h",
    "content": "#ifndef DG_DG_NODE_H_\n#define DG_DG_NODE_H_\n\n#include <cassert>\n\n#include \"DepDGElement.h\"\n#include \"dg/ADT/DGContainer.h\"\n\nnamespace dg {\nnamespace sdg {\n\nclass DGBBlock;\n\nclass DGNode : public DepDGElement {\n    DGBBlock *_bblock{nullptr};\n\n  protected:\n    DGNode(DependenceGraph &g, DGElementType t);\n\n  public:\n    ///\n    // Assign a BBlock to the node. Having BBlocks in SDG is optional,\n    // but usually useful (we can merge control dependencies of nodes).\n    void setBBlock(DGBBlock *g) { _bblock = g; }\n    const DGBBlock *getBBlock() const { return _bblock; }\n    DGBBlock *getBBlock() { return _bblock; }\n\n    static DGNode *get(DGElement *n) {\n        switch (n->getType()) {\n        case DGElementType::ND_INSTRUCTION:\n        case DGElementType::ND_CALL:\n        case DGElementType::ND_ARGUMENT:\n        case DGElementType::ND_ARTIFICIAL:\n            return static_cast<DGNode *>(n);\n        default:\n            return nullptr;\n        }\n    }\n\n#ifndef NDEBUG\n    void dump() const override {\n        std::cout << \"<\" << getID() << \"> \";\n        DGElement::dump();\n    }\n#endif // not NDEBUG\n};\n\n/// ----------------------------------------------------------------------\n// Instruction\n/// ----------------------------------------------------------------------\nclass DGNodeInstruction : public DGNode {\n  public:\n    DGNodeInstruction(DependenceGraph &g)\n            : DGNode(g, DGElementType::ND_INSTRUCTION) {}\n\n    static DGNodeInstruction *get(DGElement *n) {\n        return isa<DGElementType::ND_INSTRUCTION>(n)\n                       ? static_cast<DGNodeInstruction *>(n)\n                       : nullptr;\n    }\n};\n\n/// ----------------------------------------------------------------------\n// Argument\n/// ----------------------------------------------------------------------\nclass DGNodeArgument : public DGNode {\n    // parameter in edges\n    EdgesContainer<DepDGElement> _in_edges;\n    EdgesContainer<DepDGElement> _rev_in_edges;\n    // parameter out edges\n    EdgesContainer<DepDGElement> _out_edges;\n    EdgesContainer<DepDGElement> _rev_out_edges;\n\n    using edge_iterator = DepDGElement::edge_iterator;\n    using const_edge_iterator = DepDGElement::const_edge_iterator;\n    using edges_range = DepDGElement::edges_range;\n    using const_edges_range = DepDGElement::const_edges_range;\n\n  public:\n    DGNodeArgument(DependenceGraph &g)\n            : DGNode(g, DGElementType::ND_ARGUMENT) {}\n\n    static DGNodeArgument *get(DGElement *n) {\n        return isa<DGElementType::ND_ARGUMENT>(n)\n                       ? static_cast<DGNodeArgument *>(n)\n                       : nullptr;\n    }\n\n    edge_iterator parameter_in_begin() { return _in_edges.begin(); }\n    edge_iterator parameter_in_end() { return _in_edges.end(); }\n    edge_iterator parameter_rev_in_begin() { return _rev_in_edges.begin(); }\n    edge_iterator parameter_rev_in_end() { return _rev_in_edges.end(); }\n    const_edge_iterator parameter_in_begin() const { return _in_edges.begin(); }\n    const_edge_iterator parameter_in_end() const { return _in_edges.end(); }\n    const_edge_iterator parameter_rev_in_begin() const {\n        return _rev_in_edges.begin();\n    }\n    const_edge_iterator parameter_rev_in_end() const {\n        return _rev_in_edges.end();\n    }\n\n    edges_range parameter_in() { return {_in_edges}; }\n    const_edges_range parameter_in() const { return {_in_edges}; }\n    edges_range parameter_rev_in() { return {_rev_in_edges}; }\n    const_edges_range parameter_rev_in() const { return {_rev_in_edges}; }\n\n    edge_iterator parameter_out_begin() { return _out_edges.begin(); }\n    edge_iterator parameter_out_end() { return _out_edges.end(); }\n    edge_iterator parameter_rev_out_begin() { return _rev_out_edges.begin(); }\n    edge_iterator parameter_rev_out_end() { return _rev_out_edges.end(); }\n    const_edge_iterator parameter_out_begin() const {\n        return _out_edges.begin();\n    }\n    const_edge_iterator parameter_out_end() const { return _out_edges.end(); }\n    const_edge_iterator parameter_rev_out_begin() const {\n        return _rev_out_edges.begin();\n    }\n    const_edge_iterator parameter_rev_out_end() const {\n        return _rev_out_edges.end();\n    }\n\n    edges_range parameter_out() { return {_out_edges}; }\n    const_edges_range parameter_out() const { return {_out_edges}; }\n    edges_range parameter_rev_out() { return {_rev_out_edges}; }\n    const_edges_range parameter_rev_out() const { return {_rev_out_edges}; }\n};\n\n/// ----------------------------------------------------------------------\n// Artificial node (e.g., vararg node, noreturn node,\n// unified return node, etc.)\n/// ----------------------------------------------------------------------\nclass DGNodeArtificial : public DGNode {\n  public:\n    DGNodeArtificial(DependenceGraph &g)\n            : DGNode(g, DGElementType::ND_ARTIFICIAL) {}\n};\n\n} // namespace sdg\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/SystemDependenceGraph/DGNodeCall.h",
    "content": "#ifndef DG_DG_NODE_CALL_H_\n#define DG_DG_NODE_CALL_H_\n\n#include \"DGNode.h\"\n#include \"DGParameters.h\"\n#include <cassert>\n#include <set>\n\nnamespace dg {\nnamespace sdg {\n\n/// ----------------------------------------------------------------------\n// Call\n/// ----------------------------------------------------------------------\nclass DGNodeCall : public DGNode {\n    // FIXME: change to vector set or smallptr set (small vector set?)\n    using CalleesTy = std::set<DependenceGraph *>;\n\n    CalleesTy _callees;\n    DGParameters _parameters;\n\n  public:\n    DGNodeCall(DependenceGraph &g)\n            : DGNode(g, DGElementType::ND_CALL), _parameters(g) {}\n\n    static DGNodeCall *get(DGElement *n) {\n        return isa<DGElementType::ND_CALL>(n) ? static_cast<DGNodeCall *>(n)\n                                              : nullptr;\n    }\n\n    const CalleesTy &getCallees() const { return _callees; }\n    bool addCallee(DependenceGraph &g);\n\n    DGParameters &getParameters() { return _parameters; }\n    const DGParameters &getParameters() const { return _parameters; }\n};\n\n} // namespace sdg\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/SystemDependenceGraph/DGParameters.h",
    "content": "#ifndef DG_SDG_PARAMETERS_H_\n#define DG_SDG_PARAMETERS_H_\n\n#include <cassert>\n#include <memory>\n#include <vector>\n\n#include \"DGArgumentPair.h\"\n#include \"DGBBlock.h\"\n\nnamespace dg {\nnamespace sdg {\n\nclass DependenceGraph;\n\nclass DGParameters {\n    DependenceGraph &_dg;\n    // node representing that the function may not return\n    // (it terminates the program or loops forever)\n    // NOTE: it is owned by the _dg after creation\n    DGNodeArtificial *_noreturn{nullptr};\n    // output argument representing the return from the function\n    DGNodeArtificial *_return{nullptr};\n\n    using ParametersContainerTy = std::vector<std::unique_ptr<DGArgumentPair>>;\n    ParametersContainerTy _params;\n\n    // wrapper around graphs iterator that unwraps the unique_ptr\n    struct params_iterator : public decltype(_params.begin()) {\n        using OrigItType = decltype(_params.begin());\n\n        params_iterator() = default;\n        params_iterator(const params_iterator &I) = default;\n        params_iterator(const OrigItType &I) : OrigItType(I) {}\n\n        DGArgumentPair &operator*() { return *OrigItType::operator*(); }\n        DGArgumentPair *operator->() { return OrigItType::operator*().get(); }\n    };\n\n    class params_range {\n        friend class DependenceGraph;\n\n        ParametersContainerTy &_C;\n\n        params_range(ParametersContainerTy &C) : _C(C) {}\n\n      public:\n        params_iterator begin() { return params_iterator(_C.begin()); }\n        params_iterator end() { return params_iterator(_C.end()); }\n    };\n\n  public:\n    DGParameters(DependenceGraph &dg) : _dg(dg) {}\n\n    DependenceGraph &getDG() { return _dg; }\n    const DependenceGraph &getDG() const { return _dg; }\n\n    DGArgumentPair &createParameter() {\n        auto *nd = new DGArgumentPair(*this);\n        _params.emplace_back(nd);\n        return *nd;\n    }\n\n    DGArgumentPair &getParameter(unsigned idx) {\n        assert(idx < _params.size());\n        return *_params[idx].get();\n    }\n\n    const DGArgumentPair &getParameter(unsigned idx) const {\n        assert(idx < _params.size());\n        return *_params[idx].get();\n    }\n\n    size_t parametersNum() const { return _params.size(); }\n\n    params_iterator begin() { return params_iterator(_params.begin()); }\n    params_iterator end() { return params_iterator(_params.end()); }\n\n    DGNode &createReturn();\n    DGNode *getReturn() { return _return; }\n    const DGNode *getReturn() const { return _return; }\n\n    DGNode &createNoReturn();\n    DGNode *getNoReturn() { return _noreturn; }\n    const DGNode *getNoReturn() const { return _noreturn; }\n};\n\nclass DGFormalParameters : public DGParameters {\n    friend class DependenceGraph;\n    // parameters are associated to this dependence graph\n    std::unique_ptr<DGNodeArtificial> _vararg;\n\n    DGFormalParameters(DependenceGraph &dg) : DGParameters(dg) {}\n\n  public:\n    DGNodeArtificial &createVarArg();\n};\n\nclass DGNodeCall;\n\nclass DGActualParameters : public DGParameters {\n    friend class DGNodeCall;\n    // these parameters are associated to this call\n    DGNodeCall &_call;\n\n    DGActualParameters(DGNodeCall &call);\n\n  public:\n    DGNodeCall &getCall() { return _call; }\n    const DGNodeCall &getCall() const { return _call; }\n};\n\n} // namespace sdg\n} // namespace dg\n\n#endif // DG_SDG_PARAMETERS_H_\n"
  },
  {
    "path": "include/dg/SystemDependenceGraph/DepDGElement.h",
    "content": "#ifndef DG_DEPENDENCIES_ELEM_H_\n#define DG_DEPENDENCIES_ELEM_H_\n\n#include \"DGElement.h\"\n#include \"dg/ADT/DGContainer.h\"\n\nnamespace dg {\nnamespace sdg {\n\nclass DependenceGraph;\nclass DGNodeArgument;\n\n///\n// An element of the graph that can have dependencies\n//\n// FIXME: split to data and control classes,\n// so that e.g., basic blocks do not bear the memory dependencies.\n// It is a waste of memory.\nclass DepDGElement : public DGElement {\n    // nodes that use this node as operand\n    EdgesContainer<DepDGElement> _use_deps;\n    // nodes that write to memory that this node reads\n    EdgesContainer<DepDGElement> _memory_deps;\n    // control dependencies\n    EdgesContainer<DepDGElement> _control_deps;\n\n    // reverse containers\n    EdgesContainer<DepDGElement> _rev_use_deps;\n    EdgesContainer<DepDGElement> _rev_memory_deps;\n    EdgesContainer<DepDGElement> _rev_control_deps;\n\n  protected:\n    using edge_iterator = EdgesContainer<DepDGElement>::iterator;\n    using const_edge_iterator = EdgesContainer<DepDGElement>::const_iterator;\n\n    class edges_range {\n        friend class DepDGElement;\n        friend class DGNodeArgument;\n        EdgesContainer<DepDGElement> &_C;\n\n        edges_range(EdgesContainer<DepDGElement> &C) : _C(C) {}\n\n      public:\n        edge_iterator begin() { return _C.begin(); }\n        edge_iterator end() { return _C.end(); }\n    };\n\n    class const_edges_range {\n        friend class DepDGElement;\n        friend class DGNodeArgument;\n        const EdgesContainer<DepDGElement> &_C;\n\n        const_edges_range(const EdgesContainer<DepDGElement> &C) : _C(C) {}\n\n      public:\n        const_edge_iterator begin() const { return _C.begin(); }\n        const_edge_iterator end() const { return _C.end(); }\n    };\n\n    // FIXME: add data deps iterator = use + memory\n    //\n\n    DepDGElement(DependenceGraph &g, DGElementType type) : DGElement(g, type) {}\n\n  public:\n    static DepDGElement *get(DGElement *elem) {\n        if (elem->getType() == DGElementType::BBLOCK ||\n            elem->getType() >= DGElementType::NODE)\n            return static_cast<DepDGElement *>(elem);\n        return nullptr;\n    }\n\n    /// add user of this node (edge 'this'->'nd')\n    void addUser(DepDGElement &nd) {\n        _use_deps.insert(&nd);\n        nd._rev_use_deps.insert(this);\n    }\n\n    /// this node uses nd (the edge 'nd'->'this')\n    void addUses(DepDGElement &nd) { nd.addUser(*this); }\n\n    // this node reads values from 'nd' (the edge 'nd' -> 'this')\n    void addMemoryDep(DepDGElement &nd) {\n        _memory_deps.insert(&nd);\n        nd._rev_memory_deps.insert(this);\n    }\n\n    // this node is control dependent on 'nd' (the edge 'nd' -> 'this')\n    void addControlDep(DepDGElement &nd) {\n        _control_deps.insert(&nd);\n        nd._rev_control_deps.insert(this);\n    }\n\n    // this node controls 'nd' (the edge 'this' -> 'nd')\n    void addControls(DepDGElement &nd) { nd.addControlDep(*this); }\n\n    // use dependencies\n    edge_iterator uses_begin() { return _use_deps.begin(); }\n    edge_iterator uses_end() { return _use_deps.end(); }\n    edge_iterator users_begin() { return _rev_use_deps.begin(); }\n    edge_iterator users_end() { return _rev_use_deps.end(); }\n    const_edge_iterator uses_begin() const { return _use_deps.begin(); }\n    const_edge_iterator uses_end() const { return _use_deps.end(); }\n    const_edge_iterator users_begin() const { return _rev_use_deps.begin(); }\n    const_edge_iterator users_end() const { return _rev_use_deps.end(); }\n\n    edges_range uses() { return {_use_deps}; }\n    const_edges_range uses() const { return {_use_deps}; }\n    edges_range users() { return {_rev_use_deps}; }\n    const_edges_range users() const { return {_rev_use_deps}; }\n\n    // memory dependencies\n    edge_iterator memdep_begin() { return _memory_deps.begin(); }\n    edge_iterator memdep_end() { return _memory_deps.end(); }\n    edge_iterator rev_memdep_begin() { return _rev_memory_deps.begin(); }\n    edge_iterator rev_memdep_end() { return _rev_memory_deps.end(); }\n    const_edge_iterator memdep_begin() const { return _memory_deps.begin(); }\n    const_edge_iterator memdep_end() const { return _memory_deps.end(); }\n    const_edge_iterator rev_memdep_begin() const {\n        return _rev_memory_deps.begin();\n    }\n    const_edge_iterator rev_memdep_end() const {\n        return _rev_memory_deps.end();\n    }\n\n    edges_range memdep() { return {_memory_deps}; }\n    const_edges_range memdep() const { return {_memory_deps}; }\n    edges_range rev_memdep() { return {_rev_memory_deps}; }\n    const_edges_range rev_memdep() const { return {_rev_memory_deps}; }\n\n    // FIXME: add datadep iterator = memdep + uses\n\n    // control dependencies\n    edge_iterator control_dep_begin() { return _control_deps.begin(); }\n    edge_iterator control_dep_end() { return _control_deps.end(); }\n    edge_iterator controls_begin() { return _rev_control_deps.begin(); }\n    edge_iterator controls_dep_end() { return _rev_control_deps.end(); }\n    const_edge_iterator control_dep_begin() const {\n        return _control_deps.begin();\n    }\n    const_edge_iterator control_dep_end() const { return _control_deps.end(); }\n    const_edge_iterator controls_begin() const {\n        return _rev_control_deps.begin();\n    }\n    const_edge_iterator controls_end() const { return _rev_control_deps.end(); }\n\n    edges_range control_deps() { return {_control_deps}; }\n    const_edges_range control_deps() const { return {_control_deps}; }\n    edges_range controls() { return {_rev_control_deps}; }\n    const_edges_range controls() const { return {_rev_control_deps}; }\n};\n\n} // namespace sdg\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/SystemDependenceGraph/DependenceGraph.h",
    "content": "#ifndef DG_DEPENDENCE_GRAPH_H_\n#define DG_DEPENDENCE_GRAPH_H_\n\n#include <cassert>\n#include <string>\n#include <vector>\n\n#include \"DGBBlock.h\"\n#include \"DGNode.h\"\n#include \"DGNodeCall.h\"\n#include \"DGParameters.h\"\n\nnamespace dg {\nnamespace sdg {\n\nclass SystemDependenceGraph;\nclass DGElement;\n\n///\n// Dependence graph for one procedure in an system dependence graph\n// (in papers refered to as Program Dependence Graph)\nclass DependenceGraph {\n    friend class SystemDependenceGraph;\n    friend unsigned DGElement::getNewID(DependenceGraph &g);\n\n    unsigned _id{0};\n    unsigned _lastNodeID{0};\n\n    // SDG to which this dependence graph belongs\n    SystemDependenceGraph &_sdg;\n    // parameters associated to this graph\n    DGFormalParameters _parameters;\n\n    using NodesContainerTy = std::vector<std::unique_ptr<DGNode>>;\n    using BBlocksContainerTy = std::vector<std::unique_ptr<DGBBlock>>;\n    using CallersContainerTy = std::set<DGNodeCall *>;\n\n    NodesContainerTy _nodes;\n    BBlocksContainerTy _bblocks;\n    // call nodes that call this function\n    CallersContainerTy _callers;\n\n    // only SystemDependenceGraph can create new DependenceGraph's\n    DependenceGraph(unsigned id, SystemDependenceGraph &g)\n            : _id(id), _sdg(g), _parameters(*this) {\n        assert(id > 0);\n    }\n\n    std::string _name;\n\n    // wrapper around block iterator that unwraps the unique_ptr\n    struct bblocks_iterator : public decltype(_bblocks.begin()) {\n        using OrigItType = decltype(_bblocks.begin());\n\n        bblocks_iterator() = default;\n        bblocks_iterator(const bblocks_iterator &I) = default;\n        bblocks_iterator(const OrigItType &I) : OrigItType(I) {}\n\n        DGBBlock *operator*() { return OrigItType::operator*().get(); }\n        // DependenceGraph* operator->() { return OrigItType::operator*().get();\n        // }\n    };\n\n    class bblocks_range {\n        friend class DependenceGraph;\n\n        BBlocksContainerTy &_C;\n\n        bblocks_range(BBlocksContainerTy &C) : _C(C) {}\n\n      public:\n        bblocks_iterator begin() { return bblocks_iterator(_C.begin()); }\n        bblocks_iterator end() { return bblocks_iterator(_C.end()); }\n    };\n\n    // wrapper around nodes iterator that unwraps the unique_ptr\n    struct nodes_iterator : public decltype(_nodes.begin()) {\n        using OrigItType = decltype(_nodes.begin());\n\n        nodes_iterator() = default;\n        nodes_iterator(const nodes_iterator &I) = default;\n        nodes_iterator(const OrigItType &I) : OrigItType(I) {}\n\n        DGNode *operator*() { return OrigItType::operator*().get(); }\n        // DependenceGraph* operator->() { return OrigItType::operator*().get();\n        // }\n    };\n\n    class nodes_range {\n        friend class DependenceGraph;\n\n        NodesContainerTy &_C;\n\n        nodes_range(NodesContainerTy &C) : _C(C) {}\n\n      public:\n        nodes_iterator begin() { return nodes_iterator(_C.begin()); }\n        nodes_iterator end() { return nodes_iterator(_C.end()); }\n    };\n\n    unsigned getNextNodeID() {\n        // we could use _nodes.size(), but this is more error-prone\n        // as this function could not increate _nodes.size()\n        return ++_lastNodeID;\n    }\n\n  public:\n    unsigned getID() const { return _id; }\n    SystemDependenceGraph &getSDG() { return _sdg; }\n    const SystemDependenceGraph &getSDG() const { return _sdg; }\n\n    void setName(const std::string &nm) { _name = nm; }\n    const std::string &getName() const { return _name; }\n\n    // FIXME: rename to blocks() and nodes()\n    bblocks_range getBBlocks() { return {_bblocks}; }\n    nodes_range getNodes() { return {_nodes}; }\n\n    // we do not have any total order on nodes or blocks in SDG,\n    // but sometimes we need to get \"some\" node/block, so add\n    // a getter for the first element in containers\n    DGBBlock *getEntryBBlock() {\n        return _bblocks.empty() ? nullptr : _bblocks.begin()->get();\n    }\n\n    const DGBBlock *getEntryBBlock() const {\n        return _bblocks.empty() ? nullptr : _bblocks.begin()->get();\n    }\n\n    DGNode *getFirstNode() {\n        return _nodes.empty() ? nullptr : _nodes.begin()->get();\n    }\n\n    const DGNode *getFirstNode() const {\n        return _nodes.empty() ? nullptr : _nodes.begin()->get();\n    }\n\n    DGNodeInstruction &createInstruction() {\n        auto *nd = new DGNodeInstruction(*this);\n        _nodes.emplace_back(nd);\n        return *nd;\n    }\n\n    DGNodeCall &createCall() {\n        auto *nd = new DGNodeCall(*this);\n        _nodes.emplace_back(nd);\n        return *nd;\n    }\n\n    DGNodeArtificial &createArtificial() {\n        auto *nd = new DGNodeArtificial(*this);\n        _nodes.emplace_back(nd);\n        return *nd;\n    }\n\n    DGBBlock &createBBlock() {\n        _bblocks.emplace_back(new DGBBlock(*this));\n        return *_bblocks.back().get();\n    }\n\n    void addCaller(DGNodeCall *n) { _callers.insert(n); }\n\n    const CallersContainerTy &getCallers() const { return _callers; }\n\n    DGFormalParameters &getParameters() { return _parameters; }\n    const DGFormalParameters &getParameters() const { return _parameters; }\n};\n\n} // namespace sdg\n} // namespace dg\n\n#endif // DG_DEPENDENCE_GRAPH_H_\n"
  },
  {
    "path": "include/dg/SystemDependenceGraph/SystemDependenceGraph.h",
    "content": "#ifndef DG_SYSTEM_DEPENDENCE_GRAPH_H_\n#define DG_SYSTEM_DEPENDENCE_GRAPH_H_\n\n#include <memory>\n#include <set>\n#include <vector>\n\n#include \"dg/SystemDependenceGraph/DependenceGraph.h\"\n\nnamespace dg {\n// Use the namespace sdg for now to avoid name collisions.\n// When this class is finished and working, we'll remove\n// the old dependence graph class and this namespace.\nnamespace sdg {\n\nclass DGNode;\n\nclass SystemDependenceGraph {\n    std::set<DGNode *> _globals;\n    std::vector<std::unique_ptr<DependenceGraph>> _graphs;\n    DependenceGraph *_entry{nullptr};\n\n    // wrapper around graphs iterator that unwraps the unique_ptr\n    struct graphs_iterator : public decltype(_graphs.begin()) {\n        using OrigItType = decltype(_graphs.begin());\n\n        graphs_iterator() = default;\n        graphs_iterator(const graphs_iterator &I) = default;\n        graphs_iterator(const OrigItType &I) : OrigItType(I) {}\n\n        DependenceGraph *operator*() { return OrigItType::operator*().get(); }\n        // DependenceGraph* operator->() { return OrigItType::operator*().get();\n        // }\n    };\n\n  public:\n    DependenceGraph *getEntry() { return _entry; }\n    const DependenceGraph *getEntry() const { return _entry; }\n    void setEntry(DependenceGraph *g) { _entry = g; }\n\n    DependenceGraph &createGraph() {\n        _graphs.emplace_back(new DependenceGraph(_graphs.size() + 1, *this));\n        return *_graphs.back().get();\n    }\n\n    DependenceGraph &createGraph(const std::string &name) {\n        auto &g = createGraph();\n        g.setName(name);\n        return g;\n    }\n\n    size_t size() const { return _graphs.size(); }\n\n    graphs_iterator begin() { return graphs_iterator(_graphs.begin()); }\n    graphs_iterator end() { return graphs_iterator(_graphs.end()); }\n};\n\n} // namespace sdg\n} // namespace dg\n\n#endif // _DG_DEPENDENCE_GRAPH_H_\n"
  },
  {
    "path": "include/dg/ValueRelations/Bucket.h",
    "content": "#ifndef DG_LLVM_VALUE_RELATIONS_BUCKET_H_\n#define DG_LLVM_VALUE_RELATIONS_BUCKET_H_\n\n#ifndef NDEBUG\n#include <iostream>\n#endif\n\n#include <algorithm>\n#include <cassert>\n#include <functional>\n#include <set>\n#include <type_traits>\n#include <vector>\n\n#include \"Relations.h\"\n\nnamespace dg {\nnamespace vr {\n\n// implementation of set using vector to save memory (at the time of writing,\n// saved about a quarter of total), with no time overhead in this case\ntemplate <typename T>\nclass VectorSet {\n    std::vector<T> vec;\n\n  public:\n    using const_iterator = typename std::vector<T>::const_iterator;\n    using iterator = typename std::vector<T>::iterator;\n    using const_reverse_iterator =\n            typename std::vector<T>::const_reverse_iterator;\n\n    VectorSet() = default;\n\n    template <typename S>\n    VectorSet(std::initializer_list<S> lst) : vec(std::move(lst)) {}\n\n    template <typename S>\n    iterator find(const S &val) {\n        return std::find(vec.begin(), vec.end(), val);\n    }\n    template <typename S>\n    const_iterator find(const S &val) const {\n        return std::find(vec.begin(), vec.end(), val);\n    }\n\n    template <typename S>\n    bool contains(const S &val) const {\n        return find(val) != vec.end();\n    }\n\n    template <typename... S>\n    void emplace(S &&...vals) {\n        T val(std::forward<S>(vals)...);\n        if (!contains(val))\n            vec.emplace_back(std::move(val));\n    }\n\n    template <typename... S>\n    void sure_emplace(S &&...vals) {\n        vec.emplace_back(std::forward<S>(vals)...);\n    }\n\n    template <typename It, typename X = typename It::iterator_category>\n    iterator erase(const It &it) {\n        return vec.erase(it);\n    }\n\n    template <typename S,\n              typename X = decltype(std::declval<S &>() == std::declval<T &>())>\n    bool erase(const S &val) {\n        auto it = find(val);\n        if (it == vec.end())\n            return false;\n        vec.erase(it);\n        return true;\n    }\n\n    void clear() { vec.clear(); }\n    size_t size() const { return vec.size(); }\n    bool empty() const { return vec.empty(); }\n\n    iterator begin() { return vec.begin(); }\n    iterator end() { return vec.end(); }\n    const_iterator begin() const { return vec.begin(); }\n    const_iterator end() const { return vec.end(); }\n\n    iterator rbegin() { return vec.rbegin(); }\n    iterator rend() { return vec.rend(); }\n    const_reverse_iterator rbegin() const { return vec.rbegin(); }\n    const_reverse_iterator rend() const { return vec.rend(); }\n\n    T any() const {\n        assert(!empty());\n        return vec[0];\n    }\n};\n\nstruct Bucket {\n    using ConstBucketSet = VectorSet<std::reference_wrapper<const Bucket>>;\n    using BucketSet = VectorSet<std::reference_wrapper<Bucket>>;\n    const size_t id;\n\n    class RelationEdge {\n        std::reference_wrapper<const Bucket> _from;\n        Relations::Type _rel;\n        std::reference_wrapper<const Bucket> _to;\n\n        friend bool operator==(const RelationEdge &lt, const RelationEdge &rt) {\n            return lt.from() == rt.from() && lt.rel() == rt.rel() &&\n                   lt.to() == rt.to();\n        }\n\n        friend bool operator!=(const RelationEdge &lt, const RelationEdge &rt) {\n            return !(lt == rt);\n        }\n\n        // purely for placement in set\n        friend bool operator<(const RelationEdge &lt, const RelationEdge &rt) {\n            if (lt.from() != rt.from())\n                return lt.from() < rt.from();\n            if (lt.rel() != rt.rel())\n                return lt.rel() < rt.rel();\n            return lt.to() < rt.to();\n        }\n\n      public:\n        RelationEdge(const Bucket &f, Relations::Type r, const Bucket &t)\n                : _from(f), _rel(r), _to(t) {}\n\n        const Bucket &from() const { return _from; }\n        Relations::Type rel() const { return _rel; }\n        const Bucket &to() const { return _to; }\n\n        RelationEdge inverted() const {\n            return {_to, Relations::inverted(_rel), _from};\n        }\n\n#ifndef NDEBUG\n        friend std::ostream &operator<<(std::ostream &out,\n                                        const RelationEdge &edge) {\n            out << edge.from().id << \" \" << edge.rel() << \" \" << edge.to().id;\n            return out;\n        }\n#endif\n    };\n\n    class DirectRelIterator {\n        using SetIterator = typename BucketSet::const_iterator;\n        using RelationIterator = decltype(Relations::all)::const_iterator;\n        friend class EdgeIterator;\n\n        RelationIterator relationIt;\n        SetIterator bucketIt;\n\n        RelationEdge current;\n\n        const BucketSet &relationSet() const {\n            return current.from().relatedBuckets[*relationIt];\n        }\n\n        void updateCurrent() {\n            current = RelationEdge(current.from(), *relationIt, *bucketIt);\n        }\n\n      public:\n        // for end iterator\n        DirectRelIterator(const Bucket &b, RelationIterator r)\n                : relationIt(r), current(b, Relations::EQ, b) {}\n        // for begin iterator\n        DirectRelIterator(const Bucket &b)\n                : relationIt(Relations::all.begin()),\n                  bucketIt(b.relatedBuckets[*relationIt].begin()),\n                  current(b, *relationIt, *bucketIt) {\n            nextViableEdge();\n        }\n\n        bool nextViableEdge() {\n            while (bucketIt == relationSet().end()) {\n                ++relationIt;\n                if (relationIt == Relations::all.end())\n                    return false;\n                bucketIt = relationSet().begin();\n            }\n            updateCurrent();\n            return true;\n        }\n\n        DirectRelIterator &inc() {\n            ++bucketIt;\n            return *this;\n        }\n        DirectRelIterator &operator++() {\n            ++bucketIt;\n            nextViableEdge();\n            return *this;\n        }\n        DirectRelIterator operator++(int) {\n            auto copy = *this;\n            ++*this;\n            return copy;\n        }\n\n        friend bool operator==(const DirectRelIterator &lt,\n                               const DirectRelIterator &rt) {\n            return lt.current.from() == rt.current.from() &&\n                   lt.relationIt ==\n                           rt.relationIt; // && lt.bucketIt == rt.bucketIt;\n        }\n        friend bool operator!=(const DirectRelIterator &lt,\n                               const DirectRelIterator &rt) {\n            return !(lt == rt);\n        }\n\n        const RelationEdge &operator*() const { return current; }\n        const RelationEdge *operator->() const { return &current; }\n\n#ifndef NDEBUG\n        friend std::ostream &operator<<(std::ostream &out,\n                                        const DirectRelIterator &it) {\n            out << *it;\n            return out;\n        }\n#endif\n    };\n\n  private:\n    // R -> { a } such that (this, a) \\in R (e.g. LE -> { a } such that this LE\n    // a)\n    std::array<BucketSet, Relations::total> relatedBuckets;\n\n    // purely for storing in a set\n    friend bool operator<(const Bucket &lt, const Bucket &rt) {\n        return lt.id < rt.id;\n    }\n\n    template <typename T>\n    friend class RelationsGraph;\n\n    Bucket(size_t i) : id(i) { relatedBuckets[Relations::EQ].emplace(*this); }\n\n    void merge(const Bucket &other) {\n        if (*this == other)\n            return;\n        for (Relations::Type type : Relations::all) {\n            if (type == Relations::EQ)\n                continue;\n            for (Bucket &related : other.relatedBuckets[type]) {\n                if (related != *this)\n                    setRelated(*this, type, related);\n            }\n        }\n    }\n\n    void disconnect() {\n        for (Relations::Type type : Relations::all) {\n            if (type == Relations::EQ) {\n                assert(relatedBuckets[type].size() == 1);\n                relatedBuckets[type].clear();\n            }\n            for (auto it = relatedBuckets[type].begin();\n                 it != relatedBuckets[type].end();\n                 /*incremented by erase*/) {\n                if (*this != *it)\n                    it->get().relatedBuckets[Relations::inverted(type)].erase(\n                            *this);\n                it = relatedBuckets[type].erase(it);\n            }\n        }\n        assert(!hasAnyRelation());\n    }\n\n    friend void setRelated(Bucket &lt, Relations::Type type, Bucket &rt) {\n        assert(lt != rt || !comparative.has(type));\n        lt.relatedBuckets[type].emplace(rt);\n        rt.relatedBuckets[Relations::inverted(type)].emplace(lt);\n    }\n\n    friend bool unsetRelated(Bucket &lt, Relations::Type type, Bucket &rt) {\n        assert(type != Relations::EQ);\n        if (lt == rt) {\n            return lt.relatedBuckets[type].erase(rt);\n        }\n        auto &ltRelated = lt.relatedBuckets[type];\n        auto &rtRelated = rt.relatedBuckets[Relations::inverted(type)];\n\n        auto found = ltRelated.find(rt);\n        if (found == ltRelated.end()) {\n            assert(!rtRelated.contains(lt));\n            return false;\n        }\n\n        ltRelated.erase(found);\n        rtRelated.erase(lt);\n        return true;\n    }\n\n    bool unset(Relations::Type rel) {\n        bool changed = false;\n        BucketSet related = relatedBuckets[rel];\n        for (Bucket &other : related) {\n            changed |= unsetRelated(*this, rel, other);\n        }\n        return changed;\n    }\n\n    bool unset(const Relations &rels) {\n        bool changed = false;\n        for (Relations::Type rel : Relations::all) {\n            if (rels.has(rel))\n                changed |= unset(rel);\n        }\n        return changed;\n    }\n\n  public:\n    Bucket(const Bucket &) = delete;\n\n    const Bucket &getRelated(Relations::Type type) const {\n        assert(!relatedBuckets[type].empty());\n        return *relatedBuckets[type].begin();\n    }\n\n    bool hasRelation(Relations::Type type) const {\n        return !relatedBuckets[type].empty();\n    }\n\n    bool hasAnyRelation(Relations rels) const {\n        for (Relations::Type rel : Relations::all) {\n            if (rels.has(rel) && hasRelation(rel))\n                return true;\n        }\n        return false;\n    }\n\n    bool hasAnyRelation() const {\n        return hasAnyRelation(\n                Relations(allRelations).set(Relations::EQ, false));\n    }\n\n    friend bool operator==(const Bucket &lt, const Bucket &rt) {\n        return lt.id == rt.id;\n    }\n\n    friend bool operator!=(const Bucket &lt, const Bucket &rt) {\n        return !(lt == rt);\n    }\n\n    /********************** begin iterator stuff *********************/\n\n    struct EdgeIterator {\n        Relations allowedEdges;\n        bool undirectedOnly = false;\n        bool relationsFocused = false;\n        using Visited = std::set<RelationEdge>;\n\n      private:\n        std::vector<DirectRelIterator> stack;\n        std::reference_wrapper<Visited> visited;\n\n        bool shouldFollowThrough() const {\n            if (stack.size() < 2)\n                return true;\n            Relations::Type prev = (*std::next(stack.rbegin()))->rel();\n            return Relations::transitiveOver(prev, stack.back()->rel());\n        }\n\n        bool isViable() {\n            return visited.get().find(*stack.back()) == visited.get().end() &&\n                   allowedEdges.has(stack.back()->rel()) &&\n                   (!relationsFocused || shouldFollowThrough());\n        }\n\n        bool nextViableTopEdge() {\n            while (stack.back().nextViableEdge()) {\n                if (isViable()) {\n                    visited.get().emplace(*stack.back());\n                    if (undirectedOnly)\n                        visited.get().emplace(stack.back()->inverted());\n                    return true;\n                }\n                stack.back().inc();\n            }\n            return false;\n        }\n\n        void nextViableEdge() {\n            while (!stack.empty() && !nextViableTopEdge()) {\n                stack.pop_back();\n            }\n        }\n\n      public:\n        // for end iterator\n        EdgeIterator(Visited &v) : visited(v) {}\n        // for begin iterator\n        EdgeIterator(const Bucket &start, Visited &v, const Relations &a,\n                     bool u, bool r)\n                : allowedEdges(a), undirectedOnly(u), relationsFocused(r),\n                  visited(v) {\n            assert(start.relatedBuckets.begin() != start.relatedBuckets.end() &&\n                   \"at least one relation\");\n\n            stack.emplace_back(start);\n            nextViableEdge();\n        }\n\n        friend bool operator==(const EdgeIterator &lt, const EdgeIterator &rt) {\n            return lt.stack == rt.stack;\n        }\n        friend bool operator!=(const EdgeIterator &lt, const EdgeIterator &rt) {\n            return !(lt == rt);\n        }\n\n        EdgeIterator &operator++() {\n            DirectRelIterator current = stack.back();\n            stack.pop_back();\n\n            const Bucket &to = current->to();\n\n            // plan return to next successor of \"from\" bucket\n            current.inc(); // dont use ++, because incoming relation is needed\n                           // on the stack\n            stack.emplace_back(current);\n\n            // plan visit to first successor of \"to\" bucket if unexplored so far\n            stack.emplace_back(to);\n            nextViableEdge();\n\n            return *this;\n        }\n\n        EdgeIterator &skipSuccessors() {\n            stack.back().inc();\n            nextViableEdge();\n            return *this;\n        }\n\n        void setVisited(Visited &v) { visited = v; }\n\n        EdgeIterator operator++(int) {\n            auto copy = *this;\n            ++*this;\n            return copy;\n        }\n\n        const RelationEdge &operator*() const { return *stack.back(); }\n        const RelationEdge *operator->() const { return &(*stack.back()); }\n    };\n\n    using iterator = EdgeIterator;\n\n    iterator begin(iterator::Visited &visited, const Relations &relations,\n                   bool undirectedOnly, bool relationsFocused) const {\n        return iterator(*this, visited, relations, undirectedOnly,\n                        relationsFocused);\n    }\n\n    iterator begin(iterator::Visited &visited) const {\n        return begin(visited, allRelations, true, true);\n    }\n\n    static iterator end(iterator::Visited &visited) {\n        return iterator(visited);\n    }\n\n    DirectRelIterator begin() const { return {*this}; }\n\n    DirectRelIterator end() const { return {*this, Relations::all.end()}; }\n\n    /*********************** end iterator stuff **********************/\n\n#ifndef NDEBUG\n    friend std::ostream &operator<<(std::ostream &out, const Bucket &bucket) {\n        out << bucket.id << \" | \";\n        for (Relations::Type type : Relations::all) {\n            if (bucket.hasRelation(type)) {\n                out << type << \" - \";\n                for (Bucket &related : bucket.relatedBuckets[type])\n                    out << related.id\n                        << (related == *bucket.relatedBuckets[type].rbegin()\n                                    ? \"\"\n                                    : \", \");\n                out << \"; \";\n            }\n        }\n        return out;\n    }\n#endif\n};\n\n} // namespace vr\n} // namespace dg\n\n#endif // DG_LLVM_VALUE_RELATIONS_BUCKET_H_\n"
  },
  {
    "path": "include/dg/ValueRelations/Relations.h",
    "content": "#ifndef DG_LLVM_VALUE_RELATIONS_RELATIONS_H_\n#define DG_LLVM_VALUE_RELATIONS_RELATIONS_H_\n\n#ifndef NDEBUG\n#include <iostream>\n#endif\n\n#include <array>\n#include <bitset>\n\nnamespace dg {\nnamespace vr {\n\nstruct Relations {\n    // ************** type stuff **************\n    enum Type { EQ, NE, SLE, SLT, ULE, ULT, SGE, SGT, UGE, UGT, PT, PF };\n    static const size_t total = 12;\n    static const std::array<Type, total> all;\n\n    static Type inverted(Type type);\n    static Type negated(Type type);\n    static bool transitiveOver(Type fst, Type snd);\n    static Relations conflicting(Type type);\n    static bool isStrict(Type type);\n    static bool isNonStrict(Type type);\n    static Type getStrict(Type type);\n    static Type getNonStrict(Type type);\n    static Relations getAugmented(Relations rels);\n    static bool isSigned(Type type);\n\n    // ************** bitset stuff **************\n    Relations() = default;\n    explicit Relations(unsigned long long val) : bits(val) {}\n\n    bool has(Type type) const { return bits[type]; }\n    Relations &set(Type t, bool v = true) {\n        bits.set(t, v);\n        return *this;\n    }\n\n    Type get() const;\n\n    Relations &eq() { return set(EQ); }\n    Relations &ne() { return set(NE); }\n    Relations &sle() { return set(SLE); }\n    Relations &slt() { return set(SLT); }\n    Relations &ule() { return set(ULE); }\n    Relations &ult() { return set(ULT); }\n    Relations &sge() { return set(SGE); }\n    Relations &sgt() { return set(SGT); }\n    Relations &uge() { return set(UGE); }\n    Relations &ugt() { return set(UGT); }\n    Relations &pt() { return set(PT); }\n    Relations &pf() { return set(PF); }\n\n    Relations &addImplied();\n    Relations &invert();\n    bool any() const { return bits.any(); }\n    bool conflictsWith(Type type) const { return anyCommon(conflicting(type)); }\n    bool anyCommon(const Relations &other) const {\n        return (bits & other.bits).any();\n    }\n    /* if A lt B and B rt C, return relations between A and C */\n    friend Relations compose(const Relations &lt, const Relations &rt);\n\n    friend bool operator==(const Relations &lt, const Relations &rt) {\n        return lt.bits == rt.bits;\n    }\n    friend bool operator!=(const Relations &lt, const Relations &rt) {\n        return !(lt == rt);\n    }\n\n    Relations &operator&=(const Relations &other) {\n        bits &= other.bits;\n        return *this;\n    }\n    Relations &operator|=(const Relations &other) {\n        bits |= other.bits;\n        return *this;\n    }\n    friend Relations operator&(const Relations &lt, const Relations &rt) {\n        return Relations((lt.bits & rt.bits).to_ulong());\n    }\n    friend Relations operator|(const Relations &lt, const Relations &rt) {\n        return Relations((lt.bits | rt.bits).to_ulong());\n    }\n\n#ifndef NDEBUG\n    friend std::ostream &operator<<(std::ostream &out, const Relations &rels);\n#endif\n\n  private:\n    std::bitset<total> bits;\n};\n\nconst Relations allRelations(~0);\nconst Relations comparative(1 << Relations::EQ | 1 << Relations::NE |\n                            1 << Relations::SLT | 1 << Relations::SLE |\n                            1 << Relations::ULT | 1 << Relations::ULE |\n                            1 << Relations::SGT | 1 << Relations::SGE |\n                            1 << Relations::UGT | 1 << Relations::UGE);\nconst Relations restricted(1 << Relations::EQ | 1 << Relations::NE |\n                           1 << Relations::SLT | 1 << Relations::SLE |\n                           1 << Relations::ULT | 1 << Relations::ULE |\n                           1 << Relations::PT);\nconst Relations strict(1 << Relations::SLT | 1 << Relations::ULT |\n                       1 << Relations::SGT | 1 << Relations::UGT);\nconst Relations nonStrict(1 << Relations::SLE | 1 << Relations::ULE |\n                          1 << Relations::SGE | 1 << Relations::UGE);\n\n#ifndef NDEBUG\nstd::ostream &operator<<(std::ostream &out, Relations::Type r);\n#endif\n\n} // namespace vr\n} // namespace dg\n\n#endif // DG_LLVM_VALUE_RELATIONS_RELATIONS_H_\n"
  },
  {
    "path": "include/dg/ValueRelations/RelationsGraph.h",
    "content": "#ifndef DG_LLVM_VALUE_RELATIONS_RELATIONS_GRAPH_H_\n#define DG_LLVM_VALUE_RELATIONS_RELATIONS_GRAPH_H_\n\n#ifndef NDEBUG\n#include <iostream>\n#endif\n\n#include <algorithm>\n#include <cassert>\n#include <functional>\n#include <map>\n#include <memory>\n#include <set>\n#include <stack>\n\n#include \"Bucket.h\"\n\nnamespace dg {\nnamespace vr {\n\ntemplate <typename T>\nclass RelationsGraph {\n  public:\n    using RelationsMap =\n            std::map<std::reference_wrapper<const Bucket>, Relations>;\n\n    const Bucket *getBorderB(size_t id) const {\n        assert(id != std::string::npos);\n        for (const auto &pair : borderBuckets)\n            if (pair.first == id)\n                return &pair.second.get();\n        return nullptr;\n    }\n\n    size_t getBorderId(const Bucket &h) const {\n        for (const auto &pair : borderBuckets)\n            if (pair.second == h)\n                return pair.first;\n        return std::string::npos;\n    }\n\n  private:\n    using UniqueBucketSet = std::set<std::unique_ptr<Bucket>>;\n\n    class EdgeIterator {\n        using BucketIterator = UniqueBucketSet::iterator;\n        Bucket::iterator::Visited visited;\n\n        BucketIterator bucketIt;\n        BucketIterator endIt;\n        Bucket::iterator edgeIt;\n\n        void nextViableEdge() {\n            while (edgeIt == (*bucketIt)->end(visited)) {\n                ++bucketIt;\n                if (bucketIt == endIt)\n                    return;\n                edgeIt = (*bucketIt)->begin(visited, edgeIt.allowedEdges,\n                                            edgeIt.undirectedOnly,\n                                            edgeIt.relationsFocused);\n            }\n        }\n\n      public:\n        using value_type = Bucket::RelationEdge;\n        using difference_type = int64_t;\n        using iterator_category = std::output_iterator_tag;\n        using reference = value_type &;\n        using pointer = value_type *;\n\n        EdgeIterator(BucketIterator end)\n                : bucketIt(end), endIt(end), edgeIt(visited) {}\n        EdgeIterator(BucketIterator start, BucketIterator end,\n                     const Relations &a, bool u, bool r)\n                : bucketIt(start), endIt(end),\n                  edgeIt((*bucketIt)->begin(visited, a, u, r)) {\n            assert(bucketIt != endIt && \"at least one bucket\");\n            nextViableEdge();\n        }\n\n        EdgeIterator(const EdgeIterator &other)\n                : visited(other.visited), bucketIt(other.bucketIt),\n                  endIt(other.endIt), edgeIt(other.edgeIt) {\n            edgeIt.setVisited(visited);\n        }\n\n        EdgeIterator(EdgeIterator &&other)\n                : visited(std::move(other.visited)),\n                  bucketIt(std::move(other.bucketIt)),\n                  endIt(std::move(other.endIt)),\n                  edgeIt(std::move(other.edgeIt)) {\n            edgeIt.setVisited(visited);\n        }\n\n        EdgeIterator &operator=(EdgeIterator other) {\n            swap(*this, other);\n            return *this;\n        }\n\n        friend void swap(EdgeIterator &lt, EdgeIterator &rt) {\n            using std::swap;\n\n            swap(lt.visited, rt.visited);\n            swap(lt.bucketIt, rt.bucketIt);\n            swap(lt.endIt, rt.endIt);\n            swap(lt.edgeIt, rt.edgeIt);\n        }\n\n        friend bool operator==(const EdgeIterator &lt, const EdgeIterator &rt) {\n            return lt.bucketIt == rt.bucketIt && lt.edgeIt == rt.edgeIt;\n        }\n\n        friend bool operator!=(const EdgeIterator &lt, const EdgeIterator &rt) {\n            return !(lt == rt);\n        }\n\n        EdgeIterator &operator++() {\n            ++edgeIt;\n            nextViableEdge();\n            return *this;\n        }\n\n        EdgeIterator operator++(int) {\n            auto copy = *this;\n            ++*this;\n            return copy;\n        }\n\n        void skipSuccessors() {\n            edgeIt.skipSuccessors();\n            nextViableEdge();\n        }\n\n        const Bucket::RelationEdge &operator*() const { return *edgeIt; }\n        const Bucket::RelationEdge *operator->() const { return &(*edgeIt); }\n    };\n\n    //*********************** end iterator stuff **********************\n\n    T &reported;\n    UniqueBucketSet buckets;\n    size_t lastId = 0;\n\n    std::vector<std::pair<size_t, std::reference_wrapper<const Bucket>>>\n            borderBuckets;\n\n    bool setEqual(Bucket &to, Bucket &from) {\n        assert(to != from);\n        if (getBorderId(from) != std::string::npos) {\n            assert(getBorderId(to) ==\n                   std::string::npos); // cannot merge two border buckets\n            for (auto &pair : borderBuckets) {\n                if (from == pair.second)\n                    pair.second = to;\n            }\n        }\n        reported.areMerged(to, from);\n        to.merge(from);\n        erase(from);\n        return true;\n    }\n\n    UniqueBucketSet::iterator getItFor(const Bucket &bucket) const {\n        for (auto it = buckets.begin(); it != buckets.end(); ++it) {\n            if (**it == bucket)\n                return it;\n        }\n        assert(0 && \"unreachable\");\n        abort();\n    }\n\n    static RelationsMap &filterResult(const Relations &relations,\n                                      RelationsMap &result) {\n        for (auto it = result.begin(); it != result.end();) {\n            if (!it->second.anyCommon(relations))\n                it = result.erase(it);\n            else\n                ++it;\n        }\n        return result;\n    }\n\n    static bool processEdge(const Bucket::RelationEdge &edge,\n                            Relations::Type strictRel, Relations &updated,\n                            bool toFirstStrict,\n                            const Bucket::iterator::Visited &firstStrictEdges) {\n        if (!Relations::transitiveOver(strictRel,\n                                       edge.rel())) // edge not relevant\n            return true;\n        if (!toFirstStrict) { // finding all strictly related\n            updated.set(strictRel);\n            return false;\n        }\n        // else unsetting all that are not really first strict\n\n        bool targetOfFSE = updated.has(strictRel); // FSE = first strict edge\n\n        if (!targetOfFSE) {\n            updated.set(Relations::getNonStrict(strictRel), false);\n            return false;\n        }\n\n        // else possible false strict\n        bool thisIsFSE = firstStrictEdges.find(edge) != firstStrictEdges.end();\n\n        if (thisIsFSE) { // strict relation set by false first strict\n            updated.set(strictRel, false);\n            updated.set(Relations::getNonStrict(strictRel), false);\n        }\n        return true; // skip because search will happen from target sooner or\n                     // later\n    }\n\n    RelationsMap getAugmentedRelated(const Bucket &start,\n                                     const Relations &relations,\n                                     bool toFirstStrict) const {\n        RelationsMap result;\n\n        Bucket::iterator::Visited firstStrictEdges;\n        for (auto it = begin_related(start, relations);\n             it != end_related(start);\n             /*incremented in body */) {\n            result[it->to()].set(it->rel());\n\n            if (Relations::isStrict(it->rel())) {\n                firstStrictEdges.emplace(*it);\n                it.skipSuccessors();\n            } else\n                ++it;\n        }\n\n        Bucket::iterator::Visited nestedVisited;\n        for (Bucket::RelationEdge edge : firstStrictEdges) {\n            const Bucket &nestedStart = edge.to();\n            Relations::Type strictRel = edge.rel();\n\n            bool shouldSkip = false;\n            for (auto it = nestedStart.begin(nestedVisited, relations, true,\n                                             true);\n                 it != nestedStart.end(nestedVisited);\n                 shouldSkip ? it.skipSuccessors() : ++it) {\n                shouldSkip = processEdge(*it, strictRel, result[it->to()],\n                                         toFirstStrict, firstStrictEdges);\n                if (shouldSkip)\n                    nestedVisited.erase(*it);\n            }\n        }\n        return result;\n    }\n\n    Relations fromMaybeBetween(const Bucket &lt, const Bucket &rt,\n                               Relations *maybeBetween) const {\n        return maybeBetween ? *maybeBetween : relationsBetween(lt, rt);\n    }\n\n    Bucket::BucketSet getIntersectingNonstrict(const Bucket &lt,\n                                               const Bucket &rt,\n                                               Relations::Type type) {\n        assert(type == Relations::SGE || type == Relations::UGE);\n        assert(areRelated(lt, type, rt));\n        RelationsMap ltGE = getRelated(lt, Relations().set(type));\n        RelationsMap rtLE =\n                getRelated(rt, Relations().set(Relations::inverted(type)));\n\n        RelationsMap result;\n        std::set_intersection(ltGE.begin(), ltGE.end(), rtLE.begin(),\n                              rtLE.end(), std::inserter(result, result.begin()),\n                              [](RelationsMap::value_type &ltPair,\n                                 RelationsMap::value_type &rtPair) {\n                                  return ltPair.first < rtPair.first;\n                              });\n\n        Bucket::BucketSet other;\n        for (auto &pair : result) {\n            Bucket &b = const_cast<Bucket &>(pair.first.get());\n            assert(!other.contains(b));\n            other.sure_emplace(b);\n        }\n\n        return other;\n    }\n\n  public:\n    RelationsGraph(T &r) : reported(r) {}\n    RelationsGraph(const RelationsGraph &) = delete;\n\n    using iterator = EdgeIterator;\n\n    Relations relationsBetween(const Bucket &lt, const Bucket &rt) const {\n        RelationsMap result = getRelated(lt, allRelations);\n        return result[rt];\n    }\n\n    iterator begin_related(const Bucket &start,\n                           const Relations &relations) const {\n        auto startIt = getItFor(start);\n        auto endIt = std::next(startIt);\n        return iterator(startIt, endIt, relations, true, true);\n    }\n\n    iterator begin_related(const Bucket &start) const {\n        return begin_related(start, allRelations);\n    }\n\n    iterator end_related(const Bucket &start) const {\n        auto endIt = ++getItFor(start);\n        return iterator(endIt);\n    }\n\n    iterator begin() const {\n        return begin(Relations().eq().ne().sle().slt().ule().ult().pt());\n    }\n\n    iterator begin(const Relations &relations,\n                   bool undirectedOnly = true) const {\n        if (!buckets.empty())\n            return iterator(buckets.begin(), buckets.end(), relations,\n                            undirectedOnly, false);\n        return end();\n    }\n\n    iterator end() const { return iterator(buckets.end()); }\n\n    RelationsMap getRelated(const Bucket &start, const Relations &relations,\n                            bool toFirstStrict = false) const {\n        Relations augmented = Relations::getAugmented(relations);\n\n        RelationsMap result =\n                getAugmentedRelated(start, augmented, toFirstStrict);\n\n        for (auto &pair : result) {\n            pair.second.addImplied();\n        }\n\n        return filterResult(relations, result);\n    }\n\n    bool areRelated(const Bucket &lt, Relations::Type type, const Bucket &rt,\n                    Relations *maybeBetween = nullptr) const {\n        Relations between = fromMaybeBetween(lt, rt, maybeBetween);\n        return between.has(type);\n    }\n\n    bool haveConflictingRelation(const Bucket &lt, Relations::Type type,\n                                 const Bucket &rt,\n                                 Relations *maybeBetween = nullptr) const {\n        switch (type) {\n        case Relations::EQ:\n        case Relations::NE:\n        case Relations::SLT:\n        case Relations::SLE:\n        case Relations::ULT:\n        case Relations::ULE:\n        case Relations::SGT:\n        case Relations::SGE:\n        case Relations::UGT:\n        case Relations::UGE: {\n            Relations between = fromMaybeBetween(lt, rt, maybeBetween);\n            return between.conflictsWith(type);\n        }\n        case Relations::PT:\n            return lt.hasRelation(type) &&\n                   haveConflictingRelation(lt.getRelated(type), Relations::EQ,\n                                           rt);\n        case Relations::PF:\n            return haveConflictingRelation(rt, Relations::inverted(type), lt);\n        }\n        assert(0 && \"unreachable\");\n        abort();\n    }\n\n    bool addRelation(const Bucket &lt, Relations::Type type, const Bucket &rt,\n                     Relations *maybeBetween = nullptr) {\n        Bucket &mLt = const_cast<Bucket &>(lt);\n        Bucket &mRt = const_cast<Bucket &>(rt);\n\n        Relations between = fromMaybeBetween(lt, rt, maybeBetween);\n        if (areRelated(lt, type, rt, &between))\n            return false;\n        assert(!haveConflictingRelation(lt, type, rt, &between));\n\n        switch (type) {\n        case Relations::EQ:\n            if (lt.hasRelation(Relations::PT) &&\n                rt.hasRelation(Relations::PT)) {\n                addRelation(lt.getRelated(Relations::PT), Relations::EQ,\n                            rt.getRelated(Relations::PT));\n            }\n            return setEqual(mLt, mRt);\n\n        case Relations::NE:\n            for (Relations::Type rel : {Relations::SLT, Relations::ULT,\n                                        Relations::SGT, Relations::UGT}) {\n                if (areRelated(lt, rel, rt))\n                    return false;\n                if (areRelated(lt, Relations::getNonStrict(rel), rt,\n                               &between)) {\n                    unsetRelated(mLt, Relations::getNonStrict(rel), mRt);\n                    return addRelation(lt, rel, rt, &between);\n                }\n            }\n            break; // jump after switch\n\n        case Relations::SLT:\n        case Relations::ULT:\n            if (areRelated(lt, Relations::getNonStrict(type), rt, &between))\n                unsetRelated(mLt, Relations::getNonStrict(type), mRt);\n            if (areRelated(lt, Relations::NE, rt, &between))\n                unsetRelated(mLt, Relations::NE, mRt);\n            break; // jump after switch\n\n        case Relations::SLE:\n        case Relations::ULE:\n            if (areRelated(lt, Relations::NE, rt, &between)) {\n                unsetRelated(mLt, Relations::NE, mRt);\n                return addRelation(lt, Relations::getStrict(type), rt,\n                                   &between);\n            }\n            if (areRelated(lt, Relations::inverted(type), rt, &between)) {\n                Bucket::BucketSet intersect = getIntersectingNonstrict(\n                        lt, rt, Relations::inverted(type));\n                assert(intersect.size() >= 2);\n                Bucket &first = *intersect.begin();\n                for (auto it = std::next(intersect.begin());\n                     it != intersect.end(); ++it)\n                    setEqual(first, *it);\n                return true;\n            }\n            break; // jump after switch\n\n        case Relations::PT:\n            if (lt.hasRelation(type))\n                return addRelation(lt.getRelated(type), Relations::EQ, rt);\n            break; // jump after switch\n\n        case Relations::SGT:\n        case Relations::SGE:\n        case Relations::UGT:\n        case Relations::UGE:\n        case Relations::PF: {\n            between.invert();\n            return addRelation(rt, Relations::inverted(type), lt, &between);\n        }\n        }\n        setRelated(mLt, type, mRt);\n        return true;\n    }\n\n    const Bucket &getNewBucket() {\n        auto pair = buckets.emplace(new Bucket(++lastId));\n        return **pair.first;\n    }\n\n    const UniqueBucketSet &getBuckets() const { return buckets; }\n\n    bool unset(const Relations &rels) {\n        bool changed = false;\n        for (const auto &bucketPtr : buckets) {\n            changed |= bucketPtr->unset(rels);\n        }\n        return changed;\n    }\n\n    bool unset(const Bucket &bucket, const Relations &rels) {\n        return const_cast<Bucket &>(bucket).unset(rels);\n    }\n\n    void erase(const Bucket &bucket) {\n        Bucket &nBucket = const_cast<Bucket &>(bucket);\n        nBucket.disconnect();\n\n        auto it = getItFor(nBucket);\n        buckets.erase(it);\n    }\n\n    bool empty() const { return buckets.empty(); }\n\n    size_t size() const { return buckets.size(); }\n\n    const Bucket &getBorderBucket(size_t id) {\n        const Bucket &bucket = getNewBucket();\n        assert(getBorderB(id) == nullptr);\n        borderBuckets.emplace_back(id, bucket);\n        return bucket;\n    }\n\n    void makeBorderBucket(const Bucket &b, size_t id) {\n        size_t currentId = getBorderId(b);\n        if (currentId == id)\n            return;\n\n        assert(getBorderB(id) == nullptr);\n        assert(getBorderId(b) == std::string::npos);\n        borderBuckets.emplace_back(id, b);\n    }\n\n#ifndef NDEBUG\n    void dumpBorderBuckets(std::ostream &out = std::cerr) const {\n        out << \"[ \";\n        for (auto &pair : borderBuckets)\n            out << \"(id \" << pair.first << \", b \" << pair.second.get().id\n                << \"), \";\n        out << \"]\\n\";\n    }\n\n    friend std::ostream &operator<<(std::ostream &out,\n                                    const RelationsGraph &graph) {\n        for (const auto &item : graph.buckets)\n            out << \"    \" << *item << \"\\n\";\n        return out;\n    }\n#endif\n};\n\n} // namespace vr\n} // namespace dg\n\n#endif // DG_LLVM_VALUE_RELATIONS_RELATIONS_GRAPH_H_\n"
  },
  {
    "path": "include/dg/legacy/Analysis.h",
    "content": "#ifndef DG_LEGACY_ANALYSIS_H_\n#define DG_LEGACY_ANALYSIS_H_\n\nnamespace dg {\nnamespace legacy {\n\n// data for analyses, stored in nodes\nstruct AnalysesAuxiliaryData {\n    AnalysesAuxiliaryData() = default;\n\n    // last id of walk (DFS/BFS) that ran on this node\n    // ~~> marker if it has been processed\n    unsigned int lastwalkid{0};\n\n    // DFS order number of the node\n    unsigned int dfsorder{0};\n    // BFS order number of the node\n    unsigned int bfsorder{0};\n};\n\n// gather statistics about a run\nstruct AnalysisStatistics {\n    AnalysisStatistics() = default;\n\n    uint64_t processedBlocks{0};\n    uint64_t processedNodes{0};\n\n    uint64_t getProcessedBlocks() const { return processedBlocks; }\n    uint64_t getProcessedNodes() const { return processedNodes; }\n};\n\n/// --------------------------------------------------------\n//  - Analyses using nodes\n/// --------------------------------------------------------\ntemplate <typename NodeT>\nclass Analysis {\n  public:\n    AnalysesAuxiliaryData &getAnalysisData(NodeT *n) {\n        return n->analysisAuxData;\n    }\n\n    const AnalysisStatistics &getStatistics() const { return statistics; }\n\n  protected:\n    AnalysisStatistics statistics;\n};\n\n} // namespace legacy\n} // namespace dg\n\nnamespace dg {\n\n// forward declaration of BBlock\ntemplate <typename NodeT>\nclass BBlock;\n\nnamespace legacy {\n\n/// --------------------------------------------------------\n//  - BBlocks analysis\n/// --------------------------------------------------------\ntemplate <typename NodeT>\nclass BBlockAnalysis : public Analysis<BBlock<NodeT>> {\n  public:\n    using BBlockPtrT = BBlock<NodeT> *;\n\n    AnalysesAuxiliaryData &getAnalysisData(BBlockPtrT BB) {\n        return BB->analysisAuxData;\n    }\n};\n\n} // namespace legacy\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/legacy/BFS.h",
    "content": "#ifndef DG_LEGACY_BFS_H_\n#define DG_LEGACY_BFS_H_\n\n#include \"dg/ADT/Queue.h\"\n#include \"dg/legacy/NodesWalk.h\"\n\nnamespace dg {\nnamespace legacy {\n\nenum BFSFlags {\n    BFS_INTERPROCEDURAL = 1 << 0,\n    BFS_PARAMS = 1 << 1,\n    BFS_CFG = 1 << 2,\n    BFS_REV_CFG = 1 << 3,\n    BFS_CD = 1 << 4,\n    BFS_DD = 1 << 5,\n    BFS_REV_CD = 1 << 6,\n    BFS_REV_DD = 1 << 7,\n    BFS_USE = 1 << 8,\n    BFS_USER = 1 << 9,\n\n    BFS_BB_CFG = 1 << 10,\n    BFS_BB_REV_CFG = 1 << 11,\n    BFS_BB_POSTDOM = 1 << 12,\n    BFS_BB_POSTDOM_FRONTIERS = 1 << 13,\n\n    BFS_BB_NO_CALLSITES = 1 << 14,\n    BFS_BB_DOM = 1 << 15,\n};\n\n#ifdef ENABLE_CFG\n\nstatic inline uint32_t convertBFSBBFlags(uint32_t flags) {\n    uint32_t ret = 0; // for BBs we always have CFG\n\n    if (flags & BFS_INTERPROCEDURAL)\n        ret |= BBLOCK_WALK_INTERPROCEDURAL;\n    if (flags & BFS_BB_CFG)\n        ret |= BBLOCK_WALK_CFG;\n    if (flags & BFS_PARAMS)\n        ret |= BBLOCK_WALK_PARAMS;\n    if (flags & BFS_BB_POSTDOM)\n        ret |= BBLOCK_WALK_POSTDOM;\n    if (flags & BFS_BB_DOM)\n        ret |= BBLOCK_WALK_DOM;\n    if (flags & BFS_BB_NO_CALLSITES)\n        ret |= BBLOCK_NO_CALLSITES;\n\n    return ret;\n}\n\ntemplate <typename NodeT>\nclass BBlockBFS : public BBlockWalk<NodeT, ADT::QueueFIFO<BBlock<NodeT> *>> {\n  public:\n    using BBlockPtrT = BBlock<NodeT> *;\n\n    BBlockBFS<NodeT>(uint32_t fl = 0)\n            : BBlockWalk<NodeT, ADT::QueueFIFO<BBlock<NodeT> *>>(\n                      convertBFSBBFlags(fl)),\n              flags(fl) {}\n\n    template <typename FuncT, typename DataT>\n    void run(BBlockPtrT entry, FuncT func, DataT data) {\n        this->walk(entry, func, data);\n    }\n\n    template <typename FuncT, typename DataT>\n    void operator()(BBlockPtrT entry, FuncT func, DataT data) {\n        run(entry, func, data);\n    }\n\n    uint32_t getFlags() const { return flags; }\n\n  protected:\n    /* virtual */\n    void prepare(BBlockPtrT BB) {\n        // set bfs order number\n        AnalysesAuxiliaryData &aad = this->getAnalysisData(BB);\n        aad.bfsorder = ++bfsorder;\n    }\n\n  private:\n    unsigned int bfsorder{0};\n    uint32_t flags;\n};\n#endif // ENABLE_CFG\n\n} // namespace legacy\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/legacy/DFS.h",
    "content": "#ifndef DG_LEGACY_DFS_H_\n#define DG_LEGACY_DFS_H_\n\n#include \"dg/ADT/Queue.h\"\n#include \"dg/legacy/NodesWalk.h\"\n\nnamespace dg {\nnamespace legacy {\n\nenum DFSFlags {\n    DFS_INTERPROCEDURAL = 1 << 0,\n    DFS_PARAMS = 1 << 1,\n    DFS_CD = 1 << 2,\n    DFS_DD = 1 << 3,\n    DFS_REV_CD = 1 << 4,\n    DFS_REV_DD = 1 << 5,\n    DFS_USE = 1 << 6,\n    DFS_USER = 1 << 7,\n    // go through CFG edges between\n    // basic blocks (enqueue first\n    // nodes of BB successors for _every_ node)\n    DFS_BB_CFG = 1 << 8,\n    DFS_BB_REV_CFG = 1 << 9,\n    DFS_BB_POSTDOM = 1 << 10,\n    DFS_BB_POSTDOM_FRONTIERS = 1 << 11,\n\n    DFS_BB_NO_CALLSITES = 1 << 12,\n};\n\nstatic inline uint32_t convertFlags(uint32_t opts) {\n    uint32_t ret = 0;\n\n    if (opts & DFS_INTERPROCEDURAL)\n        ret |= NODES_WALK_INTERPROCEDURAL;\n    if (opts & DFS_CD)\n        ret |= NODES_WALK_CD;\n    if (opts & DFS_DD)\n        ret |= NODES_WALK_DD;\n    if (opts & DFS_REV_CD)\n        ret |= NODES_WALK_REV_CD;\n    if (opts & DFS_REV_DD)\n        ret |= NODES_WALK_REV_DD;\n    if (opts & DFS_USE)\n        ret |= NODES_WALK_USE;\n    if (opts & DFS_USER)\n        ret |= NODES_WALK_USER;\n    if (opts & DFS_BB_CFG)\n        ret |= NODES_WALK_BB_CFG;\n    if (opts & DFS_BB_REV_CFG)\n        ret |= NODES_WALK_BB_REV_CFG;\n    if (opts & DFS_BB_POSTDOM)\n        ret |= NODES_WALK_BB_POSTDOM;\n    if (opts & DFS_BB_POSTDOM_FRONTIERS)\n        ret |= NODES_WALK_BB_POSTDOM_FRONTIERS;\n\n    assert(!(opts & DFS_PARAMS) && \"Not implemented yet\");\n    assert(!(opts & DFS_INTERPROCEDURAL) && \"Not implemented yet\");\n    assert(!(opts & DFS_BB_NO_CALLSITES) && \"Not implemented yet\");\n    assert(!(opts & DFS_BB_POSTDOM) && \"Not implemented yet\");\n\n    return ret;\n}\n\ntemplate <typename NodeT>\nclass DFS : public NodesWalk<NodeT, ADT::QueueLIFO<NodeT *>> {\n  public:\n    DFS<NodeT>(uint32_t opts)\n            : NodesWalk<NodeT, ADT::QueueLIFO<NodeT *>>(convertFlags(opts)),\n              dfsorder(0), flags(opts) {}\n\n    template <typename FuncT, typename DataT>\n    void run(NodeT *entry, FuncT func, DataT data) {\n        this->walk(entry, func, data);\n    }\n\n    template <typename FuncT, typename DataT>\n    void operator()(NodeT *entry, FuncT func, DataT data) {\n        run(entry, func, data);\n    }\n\n  protected:\n    /* virtual */\n    void prepare(NodeT *BB) {\n        // set dfs order number\n        AnalysesAuxiliaryData &aad = this->getAnalysisData(BB);\n        aad.dfsorder = ++dfsorder;\n    }\n\n  private:\n    unsigned int dfsorder;\n    uint32_t flags;\n};\n\n#ifdef ENABLE_CFG\n\nstatic uint32_t inline convertBBFlags(uint32_t flags) {\n    uint32_t ret = 0; // for BBs we always have CFG\n\n    if (flags & DFS_INTERPROCEDURAL)\n        ret |= BBLOCK_WALK_INTERPROCEDURAL;\n    if (flags & DFS_PARAMS)\n        ret |= BBLOCK_WALK_PARAMS;\n    if (flags & DFS_BB_NO_CALLSITES)\n        ret |= BBLOCK_NO_CALLSITES;\n    if (flags & DFS_BB_CFG)\n        ret |= BBLOCK_WALK_CFG;\n\n    return ret;\n}\n\ntemplate <typename NodeT>\nclass BBlockDFS : public BBlockWalk<NodeT, ADT::QueueLIFO<BBlock<NodeT> *>> {\n  public:\n    using BBlockPtrT = BBlock<NodeT> *;\n\n    BBlockDFS<NodeT>(uint32_t fl = DFS_BB_CFG)\n            : BBlockWalk<NodeT, ADT::QueueLIFO<BBlock<NodeT> *>>(\n                      convertBBFlags(fl)),\n              flags(fl) {}\n\n    template <typename FuncT, typename DataT>\n    void run(BBlockPtrT entry, FuncT func, DataT data) {\n        this->walk(entry, func, data);\n    }\n\n    template <typename FuncT, typename DataT>\n    void operator()(BBlockPtrT entry, FuncT func, DataT data) {\n        run(entry, func, data);\n    }\n\n    uint32_t getFlags() const { return flags; }\n\n  protected:\n    /* virtual */\n    void prepare(BBlockPtrT BB) override {\n        // set dfs order number\n        AnalysesAuxiliaryData &aad = this->getAnalysisData(BB);\n        aad.dfsorder = ++dfsorder;\n    }\n\n  private:\n    unsigned int dfsorder{0};\n    uint32_t flags;\n};\n#endif // ENABLE_CFG\n\n} // namespace legacy\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/legacy/DataFlowAnalysis.h",
    "content": "#ifndef DG_DATA_FLOW_ANALYSIS_H_\n#define DG_DATA_FLOW_ANALYSIS_H_\n\n#include <set>\n#include <utility>\n\n#include \"dg/legacy/Analysis.h\"\n#include \"dg/legacy/DFS.h\"\n\nnamespace dg {\nnamespace legacy {\n\nstruct DataFlowStatistics : public AnalysisStatistics {\n    DataFlowStatistics() = default;\n\n    uint64_t bblocksNum{0};\n    uint64_t iterationsNum{0};\n\n    uint64_t getBBlocksNum() const { return bblocksNum; }\n    uint64_t getIterationsNum() const { return iterationsNum; }\n};\n\nenum DataFlowAnalysisFlags {\n    DATAFLOW_INTERPROCEDURAL = 1 << 0,\n    DATAFLOW_BB_NO_CALLSITES = 1 << 1,\n};\n\n// ordering of nodes with respect to DFS order\n// works for both nodes and blocks\ntemplate <typename T>\nstruct DFSOrderLess {\n    bool operator()(T a, T b) const {\n        return a->getDFSOrder() < b->getDFSOrder();\n    }\n};\n\ntemplate <typename NodeT>\nclass BBlockDataFlowAnalysis : public Analysis<NodeT> {\n  public:\n    BBlockDataFlowAnalysis<NodeT>(BBlock<NodeT> *entryBB, uint32_t fl = 0)\n            : entryBB(entryBB), flags(fl), changed(false) {}\n\n    virtual bool runOnBlock(BBlock<NodeT> *BB) = 0;\n\n    void run() {\n        uint32_t flg = DFS_BB_CFG;\n\n        assert(entryBB && \"entry basic block is nullptr\");\n\n        /* translate flags */\n        if (flags & DATAFLOW_INTERPROCEDURAL)\n            flg |= DFS_INTERPROCEDURAL;\n        if (flags & DATAFLOW_BB_NO_CALLSITES)\n            flg |= DFS_BB_NO_CALLSITES;\n\n        BBlockDFS<NodeT> DFS(flg);\n        DFSDataT data(blocks, changed, this);\n\n        // we will get all the nodes using DFS\n        DFS.run(entryBB, dfs_proc_bb, data);\n\n        // update statistics\n        statistics.bblocksNum = blocks.size();\n        statistics.iterationsNum = 1;\n        // first run goes over each BB once\n        statistics.processedBlocks = statistics.bblocksNum;\n\n        // Iterate over the nodes in dfs reverse order, it is\n        // usually good for reaching fixpoint. Later we can\n        // add options what ordering to use.\n        // Since we used while loop, if nothing changed after the\n        // first iteration (the DFS), the loop will never run\n        while (changed) {\n            changed = false;\n            for (auto I = blocks.rbegin(), E = blocks.rend(); I != E; ++I) {\n                changed |= runOnBlock(*I);\n                ++statistics.processedBlocks;\n            }\n\n            ++statistics.iterationsNum;\n        }\n    }\n\n    uint32_t getFlags() const { return flags; }\n\n    const DataFlowStatistics &getStatistics() const { return statistics; }\n\n    bool addBB(BBlock<NodeT> *BB) {\n        changed |= runOnBlock(BB);\n        bool ret = blocks.insert(BB).second;\n        if (ret)\n            ++statistics.bblocksNum;\n\n        changed |= ret;\n        return ret;\n    }\n\n  private:\n    // define set of blocks to be ordered in dfs order\n    // FIXME if we use dfs order, then addBB does not work,\n    // because the BB's newly added does have dfsorder unset\n    // and the BlocksSet thinks it already contains it, so\n    // it is not added\n    using BlocksSetT = std::set<BBlock<\n            NodeT> * /*,\nDFSOrderLess<BBlock<NodeT> *>*/>;\n    struct DFSDataT {\n        DFSDataT(BlocksSetT &b, bool &c, BBlockDataFlowAnalysis<NodeT> *r)\n                : blocks(b), changed(c), ref(r) {}\n\n        BlocksSetT &blocks;\n        bool &changed;\n        BBlockDataFlowAnalysis<NodeT> *ref;\n    };\n\n    static void dfs_proc_bb(BBlock<NodeT> *BB, DFSDataT &data) {\n        data.changed |= data.ref->runOnBlock(BB);\n        data.blocks.insert(BB);\n    }\n\n    BBlock<NodeT> *entryBB;\n    BlocksSetT blocks;\n    uint32_t flags;\n    bool changed;\n    DataFlowStatistics statistics;\n};\n\ntemplate <typename NodeT>\nclass DataFlowAnalysis : public BBlockDataFlowAnalysis<NodeT> {\n  public:\n    DataFlowAnalysis<NodeT>(BBlock<NodeT> *entryBB, uint32_t fl = 0)\n            : BBlockDataFlowAnalysis<NodeT>(entryBB, fl){};\n\n    /* virtual */\n    bool runOnBlock(BBlock<NodeT> *B) override {\n        bool changed = false;\n        NodeT *prev = nullptr;\n\n        for (NodeT *n : B->getNodes()) {\n            changed |= runOnNode(n, prev);\n            prev = n;\n        }\n\n        return changed;\n    }\n\n    virtual bool runOnNode(NodeT *n, NodeT *prev) = 0;\n};\n\n} // namespace legacy\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/legacy/NodesWalk.h",
    "content": "#ifndef DG_LEGACY_NODES_WALK_H_\n#define DG_LEGACY_NODES_WALK_H_\n\n#include \"dg/DGParameters.h\"\n#include \"dg/legacy/Analysis.h\"\n\nnamespace dg {\nnamespace legacy {\n\nenum NodesWalkFlags {\n    // do not walk any edges, user will\n    // use enqueue method to decide which nodes\n    // will be processed\n    NODES_WALK_NONE_EDGES = 0,\n    NODES_WALK_INTERPROCEDURAL = 1 << 0,\n    NODES_WALK_CD = 1 << 1,\n    NODES_WALK_DD = 1 << 2,\n    NODES_WALK_REV_CD = 1 << 3,\n    NODES_WALK_REV_DD = 1 << 4,\n    NODES_WALK_USE = 1 << 5,\n    NODES_WALK_USER = 1 << 6,\n    // interference dependencies\n    NODES_WALK_ID = 1 << 7,\n    NODES_WALK_REV_ID = 1 << 8,\n    // Add to queue all first nodes of\n    // node's BB successors\n    NODES_WALK_BB_CFG = 1 << 9,\n    // Add to queue all last nodes of\n    // node's BB predecessors\n    NODES_WALK_BB_REV_CFG = 1 << 10,\n    NODES_WALK_BB_POSTDOM = 1 << 11,\n    NODES_WALK_BB_POSTDOM_FRONTIERS = 1 << 12,\n};\n\n// this is a base class for nodes walk, it contains\n// counter. If we would add counter (even static) into\n// NodesWalk itself, we'd have counter for every\n// NodeT+QueueT instantiation, which we don't want to,\n// because then BFS and DFS would collide\ntemplate <typename NodeT>\nclass NodesWalkBase : public Analysis<NodeT> {\n  protected:\n    // this counter will increase each time we run\n    // NodesWalk, so it can be used as an indicator\n    // that we queued a node in a particular run or not\n    static unsigned int walk_run_counter;\n};\n\n// counter definition\ntemplate <typename NodeT>\nunsigned int NodesWalkBase<NodeT>::walk_run_counter = 0;\n\ntemplate <typename NodeT, typename QueueT>\nclass NodesWalk : public NodesWalkBase<NodeT> {\n  public:\n    NodesWalk<NodeT, QueueT>(uint32_t opts = 0) : options(opts) {}\n\n    template <typename FuncT, typename DataT>\n    void walk(NodeT *entry, FuncT func, DataT data) {\n        walk<FuncT, DataT>(std::set<NodeT *>{entry}, func, data);\n    }\n\n    template <typename FuncT, typename DataT>\n    void walk(const std::set<NodeT *> &entry, FuncT func, DataT data) {\n        run_id = ++NodesWalk<NodeT, QueueT>::walk_run_counter;\n\n        assert(!entry.empty() && \"Need entry node for traversing nodes\");\n        for (auto *ent : entry)\n            enqueue(ent);\n\n        while (!queue.empty()) {\n            NodeT *n = queue.pop();\n\n            prepare(n);\n            func(n, data);\n\n            // do not try to process edges if we know\n            // we should not\n            if (options == 0)\n                continue;\n\n            // add unprocessed vertices\n            if (options & NODES_WALK_CD) {\n                processEdges(n->control_begin(), n->control_end());\n#ifdef ENABLE_CFG\n                // we can have control dependencies in BBlocks\n                processBBlockCDs(n);\n#endif // ENABLE_CFG\n            }\n\n            if (options & NODES_WALK_REV_CD) {\n                processEdges(n->rev_control_begin(), n->rev_control_end());\n\n#ifdef ENABLE_CFG\n                // we can have control dependencies in BBlocks\n                processBBlockRevCDs(n);\n#endif // ENABLE_CFG\n            }\n\n            if (options & NODES_WALK_DD)\n                processEdges(n->data_begin(), n->data_end());\n\n            if (options & NODES_WALK_REV_DD)\n                processEdges(n->rev_data_begin(), n->rev_data_end());\n\n            if (options & NODES_WALK_USE)\n                processEdges(n->use_begin(), n->use_end());\n\n            if (options & NODES_WALK_USER)\n                processEdges(n->user_begin(), n->user_end());\n\n            if (options & NODES_WALK_ID)\n                processEdges(n->interference_begin(), n->interference_end());\n\n            if (options & NODES_WALK_REV_ID)\n                processEdges(n->rev_interference_begin(),\n                             n->rev_interference_end());\n\n#ifdef ENABLE_CFG\n            if (options & NODES_WALK_BB_CFG)\n                processBBlockCFG(n);\n\n            if (options & NODES_WALK_BB_REV_CFG)\n                processBBlockRevCFG(n);\n#endif // ENABLE_CFG\n\n            if (options & NODES_WALK_BB_POSTDOM_FRONTIERS)\n                processBBlockPostDomFrontieres(n);\n\n            // FIXME interprocedural\n        }\n    }\n\n    // push a node into queue\n    // This method is public so that analysis can\n    // push some extra nodes into queue as they want.\n    // They can also say that they don't want to process\n    // any edges and take care of pushing the right nodes\n    // on their own\n    void enqueue(NodeT *n) {\n        AnalysesAuxiliaryData &aad = this->getAnalysisData(n);\n\n        if (aad.lastwalkid == run_id)\n            return;\n\n        // mark node as visited\n        aad.lastwalkid = run_id;\n        queue.push(n);\n    }\n\n  protected:\n    // function that will be called for all the nodes,\n    // but is defined by the analysis framework, not\n    // by the analysis itself. For example it may\n    // assign DFS order numbers\n    virtual void prepare(NodeT *n) { (void) n; }\n\n  private:\n    template <typename IT>\n    void processEdges(IT begin, IT end) {\n        for (IT I = begin; I != end; ++I) {\n            enqueue(*I);\n        }\n    }\n\n#ifdef ENABLE_CFG\n    // we can have control dependencies in BBlocks\n    void processBBlockRevCDs(NodeT *n) {\n        // push terminator nodes of all blocks that are\n        // control dependent\n        BBlock<NodeT> *BB = n->getBBlock();\n        if (!BB)\n            return;\n\n        for (BBlock<NodeT> *CD : BB->revControlDependence())\n            enqueue(CD->getLastNode());\n    }\n\n    void processBBlockCDs(NodeT *n) {\n        BBlock<NodeT> *BB = n->getBBlock();\n        if (!BB)\n            return;\n\n        for (BBlock<NodeT> *CD : BB->controlDependence())\n            enqueue(CD->getFirstNode());\n    }\n\n    void processBBlockCFG(NodeT *n) {\n        BBlock<NodeT> *BB = n->getBBlock();\n        if (!BB)\n            return;\n\n        for (auto &E : BB->successors())\n            enqueue(E.target->getFirstNode());\n    }\n\n    void processBBlockRevCFG(NodeT *n) {\n        BBlock<NodeT> *BB = n->getBBlock();\n        if (!BB)\n            return;\n\n        for (BBlock<NodeT> *S : BB->predecessors())\n            enqueue(S->getLastNode());\n    }\n\n    void processBBlockPostDomFrontieres(NodeT *n) {\n        BBlock<NodeT> *BB = n->getBBlock();\n        if (!BB)\n            return;\n\n        for (BBlock<NodeT> *S : BB->getPostDomFrontiers())\n            enqueue(S->getLastNode());\n    }\n#endif // ENABLE_CFG\n\n    QueueT queue;\n    // id of particular nodes walk\n    unsigned int run_id;\n    uint32_t options;\n};\n\nenum BBlockWalkFlags {\n    // recurse into procedures\n    BBLOCK_WALK_INTERPROCEDURAL = 1 << 0,\n    // walk even through params\n    BBLOCK_WALK_PARAMS = 1 << 1,\n    // walk post-dominator tree edges\n    BBLOCK_WALK_POSTDOM = 1 << 2,\n    // walk normal CFG edges\n    BBLOCK_WALK_CFG = 1 << 3,\n    // need to go through the nodes once\n    // because bblocks does not keep information\n    // about call-sites\n    BBLOCK_NO_CALLSITES = 1 << 4,\n    // walk dominator tree edges\n    BBLOCK_WALK_DOM = 1 << 5,\n};\n\n// this is a base class for bblock walk, it contains\n// counter. If we would add counter (even static) into\n// NodesWalk itself, we'd have counter for every\n// NodeT+QueueT instantiation, which we don't want to,\n// because then BFS and DFS would collide\ntemplate <typename NodeT>\nclass BBlockWalkBase : public BBlockAnalysis<NodeT> {\n  protected:\n    // this counter will increase each time we run\n    // NodesWalk, so it can be used as an indicator\n    // that we queued a node in a particular run or not\n    static unsigned int walk_run_counter;\n};\n\n// counter definition\ntemplate <typename NodeT>\nunsigned int BBlockWalkBase<NodeT>::walk_run_counter = 0;\n\n#ifdef ENABLE_CFG\ntemplate <typename NodeT, typename QueueT>\nclass BBlockWalk : public BBlockWalkBase<NodeT> {\n  public:\n    using BBlockPtrT = dg::BBlock<NodeT> *;\n\n    BBlockWalk<NodeT, QueueT>(uint32_t fl = BBLOCK_WALK_CFG) : flags(fl) {}\n\n    template <typename FuncT, typename DataT>\n    void walk(BBlockPtrT entry, FuncT func, DataT data) {\n        queue.push(entry);\n\n        // set up the value of new walk and set it to entry node\n        runid = ++BBlockWalk<NodeT, QueueT>::walk_run_counter;\n        AnalysesAuxiliaryData &aad = this->getAnalysisData(entry);\n        aad.lastwalkid = runid;\n\n        while (!queue.empty()) {\n            BBlockPtrT BB = queue.pop();\n\n            prepare(BB);\n            func(BB, data);\n\n            // update statistics\n            ++this->statistics.processedBlocks;\n\n            // should and can we go into subgraph?\n            if ((flags & BBLOCK_WALK_INTERPROCEDURAL)) {\n                if ((flags & BBLOCK_NO_CALLSITES) &&\n                    BB->getCallSitesNum() == 0) {\n                    // get callsites if bblocks does not keep them\n                    for (NodeT *n : BB->getNodes()) {\n                        if (n->hasSubgraphs())\n                            BB->addCallsite(n);\n                    }\n                }\n\n                if (BB->getCallSitesNum() != 0)\n                    queueSubgraphsBBs(BB);\n            }\n\n            // queue post-dominated blocks if we should\n            if (flags & BBLOCK_WALK_POSTDOM)\n                for (BBlockPtrT S : BB->getPostDominators())\n                    enqueue(S);\n\n            // queue dominated blocks\n            if (flags & BBLOCK_WALK_DOM)\n                for (BBlockPtrT S : BB->getDominators())\n                    enqueue(S);\n\n            // queue sucessors of this BB\n            if (flags & BBLOCK_WALK_CFG)\n                for (auto &E : BB->successors())\n                    enqueue(E.target);\n        }\n    }\n\n    uint32_t getFlags() const { return flags; }\n\n    void enqueue(BBlockPtrT BB) {\n        AnalysesAuxiliaryData &sad = this->getAnalysisData(BB);\n        if (sad.lastwalkid != runid) {\n            sad.lastwalkid = runid;\n            queue.push(BB);\n        }\n    }\n\n  protected:\n    virtual void prepare(BBlockPtrT BB) { (void) BB; }\n\n  private:\n    void queueSubgraphsBBs(BBlockPtrT BB) {\n        DGParameters<NodeT> *params;\n\n        // iterate over call-site nodes\n        for (NodeT *cs : BB->getCallSites()) {\n            // go through parameters if desired\n            if ((flags & BBLOCK_WALK_PARAMS)) {\n                params = cs->getParameters();\n                if (params) {\n                    enqueue(params->getBBIn());\n                    enqueue(params->getBBOut());\n                }\n            }\n\n            // iterate over subgraphs in call-site node\n            // and put into queue entry blocks\n            for (auto subdg : cs->getSubgraphs()) {\n                // go into formal parameters if wanted\n                if ((flags & BBLOCK_WALK_PARAMS)) {\n                    NodeT *entry = subdg->getEntry();\n                    assert(entry && \"No entry node in sub dg\");\n\n                    params = entry->getParameters();\n                    if (params) {\n                        enqueue(params->getBBIn());\n                        enqueue(params->getBBOut());\n                    }\n                }\n\n                // queue entry BBlock\n                BBlockPtrT entryBB = subdg->getEntryBB();\n                assert(entryBB && \"No entry block in sub dg\");\n                enqueue(entryBB);\n            }\n        }\n    }\n\n    QueueT queue;\n    uint32_t flags;\n    unsigned int runid;\n};\n\n#endif\n\n} // namespace legacy\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/llvm/CallGraph/CallGraph.h",
    "content": "#ifndef DG_LLVM_CALLGRAPH_H_\n#define DG_LLVM_CALLGRAPH_H_\n\n#include <memory>\n#include <vector>\n\n#include <llvm/IR/Function.h>\n#include <llvm/IR/InstIterator.h>\n#include <llvm/IR/Module.h>\n\n#include \"dg/ADT/HashMap.h\"\n#include \"dg/ADT/Queue.h\"\n#include \"dg/ADT/SetQueue.h\"\n#include \"dg/CallGraph/CallGraph.h\"\n#include \"dg/PointerAnalysis/PSNode.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n\nnamespace dg {\nnamespace pta {\nclass PSNode;\n}\n\nnamespace llvmdg {\n\nclass CallGraphImpl {\n  public:\n    using FuncVec = std::vector<const llvm::Function *>;\n\n    virtual ~CallGraphImpl() = default;\n\n    // XXX: return iterators...\n\n    ///\n    /// \\brief functions\n    /// \\return Functions that are in the callgraph. Note that there may be\n    /// functions missing if the callgraph is being build lazily\n    /// (you may force building CG by build() method).\n    ///\n    virtual FuncVec functions() const = 0;\n    virtual FuncVec callers(const llvm::Function *) = 0;\n    virtual FuncVec callees(const llvm::Function *) = 0;\n    virtual bool calls(const llvm::Function *, const llvm::Function *) = 0;\n\n    // trigger building the CG (can be used to force building when CG is\n    // constructed on demand)\n    virtual void build() {}\n};\n\n///\n/// Callgraph that re-uses the Call graph built during pointer analysis from DG\n///\nclass DGCallGraphImpl : public CallGraphImpl {\n    const GenericCallGraph<PSNode *> &_cg;\n    std::map<const llvm::Function *, PSNode *> _mapping;\n\n    static const llvm::Function *getFunFromNode(PSNode *n) {\n        auto *f = n->getUserData<llvm::Function>();\n        assert(f && \"Invalid data in a node\");\n        return f;\n    }\n\n  public:\n    DGCallGraphImpl(const dg::GenericCallGraph<PSNode *> &cg) : _cg(cg) {\n        for (const auto &it : _cg) {\n            _mapping[getFunFromNode(it.first)] = it.first;\n        }\n    }\n\n    FuncVec functions() const override {\n        FuncVec ret;\n        for (const auto &it : _mapping) {\n            ret.push_back(it.first);\n        }\n        return ret;\n    }\n\n    FuncVec callers(const llvm::Function *F) override {\n        FuncVec ret;\n        auto it = _mapping.find(F);\n        if (it == _mapping.end())\n            return ret;\n        const auto *fnd = _cg.get(it->second);\n        for (auto *nd : fnd->getCallers()) {\n            ret.push_back(getFunFromNode(nd->getValue()));\n        }\n        return ret;\n    }\n\n    FuncVec callees(const llvm::Function *F) override {\n        FuncVec ret;\n        auto it = _mapping.find(F);\n        if (it == _mapping.end())\n            return ret;\n        const auto *fnd = _cg.get(it->second);\n        for (auto *nd : fnd->getCalls()) {\n            ret.push_back(getFunFromNode(nd->getValue()));\n        }\n        return ret;\n    }\n\n    bool calls(const llvm::Function *F, const llvm::Function *what) override {\n        auto it = _mapping.find(F);\n        if (it == _mapping.end())\n            return false;\n        auto it2 = _mapping.find(what);\n        if (it2 == _mapping.end())\n            return false;\n        const auto *fn1 = _cg.get(it->second);\n        const auto *fn2 = _cg.get(it2->second);\n        if (fn1 && fn2) {\n            return fn1->calls(fn2);\n        }\n        return false;\n    };\n};\n\n// FIXME: copied from llvm-utils.h\nnamespace {\ninline bool isPointerOrIntegerTy(const llvm::Type *Ty) {\n    return Ty->isPointerTy() || Ty->isIntegerTy();\n}\n\n// can the given function be called by the given call inst?\nenum class CallCompatibility {\n    STRICT,       // require full compatibility\n    LOOSE,        // ignore some incompatible patterns that usually work\n                  // in practice, e.g., calling a function of 2 arguments\n                  // with 3 arguments.\n    MATCHING_ARGS // check only that matching arguments are compatible,\n                  // ignore the number of arguments, etc.\n};\n\ninline bool\ncallIsCompatible(const llvm::Function *F, const llvm::CallInst *CI,\n                 CallCompatibility policy = CallCompatibility::LOOSE) {\n    using namespace llvm;\n\n#if LLVM_VERSION_MAJOR >= 8\n    auto max_idx = CI->arg_size();\n#else\n    auto max_idx = CI->getNumArgOperands();\n#endif\n\n    if (policy != CallCompatibility::MATCHING_ARGS) {\n        if (F->isVarArg()) {\n            if (F->arg_size() > max_idx) {\n                return false;\n            }\n        } else if (F->arg_size() != max_idx) {\n            if (policy == CallCompatibility::STRICT ||\n                F->arg_size() > max_idx) {\n                // too few arguments\n                return false;\n            }\n        }\n\n        if (!F->getReturnType()->canLosslesslyBitCastTo(CI->getType())) {\n            // it showed up that the loosless bitcast is too strict\n            // alternative since we can use the constexpr castings\n            if (!(isPointerOrIntegerTy(F->getReturnType()) &&\n                  isPointerOrIntegerTy(CI->getType()))) {\n                return false;\n            }\n        }\n    }\n\n    size_t idx = 0;\n    for (auto A = F->arg_begin(), E = F->arg_end(); idx < max_idx && A != E;\n         ++A, ++idx) {\n        Type *CTy = CI->getArgOperand(idx)->getType();\n        Type *ATy = A->getType();\n\n        if (!(isPointerOrIntegerTy(CTy) && isPointerOrIntegerTy(ATy)))\n            if (!CTy->canLosslesslyBitCastTo(ATy)) {\n                return false;\n            }\n    }\n\n    return true;\n}\n} // anonymous namespace\n\n///\n/// Callgraph that is built based on the results of pointer analysis.\n/// This class has been superseeded by LazyLLVMCallGraph.\n///\nclass LLVMPTACallGraphImpl : public CallGraphImpl {\n    GenericCallGraph<const llvm::Function *> _cg{};\n    const llvm::Module *_module;\n    LLVMPointerAnalysis *_pta;\n\n    void\n    processBBlock(const llvm::Function *parent, const llvm::BasicBlock &B,\n                  ADT::SetQueue<QueueFIFO<const llvm::Function *>> &queue) {\n        for (const auto &I : B) {\n            if (const auto *C = llvm::dyn_cast<llvm::CallInst>(&I)) {\n#if LLVM_VERSION_MAJOR >= 8\n                auto pts = _pta->getLLVMPointsTo(C->getCalledOperand());\n#else\n                auto pts = _pta->getLLVMPointsTo(C->getCalledValue());\n#endif\n                for (const auto &ptr : pts) {\n                    auto *F = llvm::dyn_cast<llvm::Function>(ptr.value);\n                    if (!F || !callIsCompatible(F, C))\n                        continue;\n\n                    _cg.addCall(parent, F);\n                    queue.push(F);\n                }\n            }\n        }\n    }\n\n    void _build() {\n        auto *entry = _module->getFunction(_pta->getOptions().entryFunction);\n        assert(entry && \"Entry function not found\");\n        _cg.createNode(entry);\n\n        ADT::SetQueue<QueueFIFO<const llvm::Function *>> queue;\n        queue.push(entry);\n\n        while (!queue.empty()) {\n            const auto *cur = queue.pop();\n            for (const auto &B : *cur) {\n                processBBlock(cur, B, queue);\n            }\n        }\n    }\n\n  public:\n    LLVMPTACallGraphImpl(const llvm::Module *m, LLVMPointerAnalysis *pta)\n            : _module(m), _pta(pta) {\n        _build();\n    }\n\n    FuncVec functions() const override {\n        FuncVec ret;\n        for (const auto &it : _cg) {\n            ret.push_back(it.first);\n        }\n        return ret;\n    }\n\n    FuncVec callers(const llvm::Function *F) override {\n        FuncVec ret;\n        const auto *fnd = _cg.get(F);\n        for (auto *nd : fnd->getCallers()) {\n            ret.push_back(nd->getValue());\n        }\n        return ret;\n    }\n\n    FuncVec callees(const llvm::Function *F) override {\n        FuncVec ret;\n        const auto *fnd = _cg.get(F);\n        for (auto *nd : fnd->getCalls()) {\n            ret.push_back(nd->getValue());\n        }\n        return ret;\n    }\n\n    bool calls(const llvm::Function *F, const llvm::Function *what) override {\n        const auto *fn1 = _cg.get(F);\n        const auto *fn2 = _cg.get(what);\n        if (fn1 && fn2) {\n            return fn1->calls(fn2);\n        }\n        return false;\n    };\n};\n\ninline bool funHasAddressTaken(const llvm::Function *fun) {\n    using namespace llvm;\n    for (auto &use : fun->uses()) {\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n        Value *user = *use;\n#else\n        Value *user = use.getUser();\n#endif\n        // FIXME: we can detect more cases as false\n        if (auto *C = dyn_cast<CallInst>(user)) {\n            if (fun == C->getCalledFunction()) {\n                continue;\n            }\n        }\n        return true;\n    }\n    return false;\n}\n\n///\n/// \\brief The LazyLLVMCallGraph class\n///\n/// A callgraph that is being build lazily based on user queries.\n/// It can use pointer analysis, but it is sound even without it\n/// (by overapproximating).\nclass LazyLLVMCallGraph : public CallGraphImpl {\n    GenericCallGraph<const llvm::Function *> _cg{};\n    const llvm::Module *_module;\n    LLVMPointerAnalysis *_pta;\n\n    using FuncVec = CallGraphImpl::FuncVec;\n    // resolved function pointers\n    dg::HashMap<const llvm::CallInst *, FuncVec> _funptrs;\n    std::vector<const llvm::Function *> _address_taken;\n    bool _address_taken_initialized{false};\n    // resolved callers of address-taken functions\n    dg::HashMap<const llvm::Function *, std::vector<const llvm::CallInst *>>\n            _callsOf;\n\n    inline const llvm::Value *_getCalledValue(const llvm::CallInst *C) const {\n#if LLVM_VERSION_MAJOR >= 8\n        return C->getCalledOperand()->stripPointerCasts();\n#else\n        return C->getCalledValue()->stripPointerCasts();\n#endif\n    }\n\n    void _initializeAddressTaken() {\n        assert(!_address_taken_initialized);\n        _address_taken_initialized = true;\n\n        for (auto &F : *_module) {\n            if (F.isDeclaration())\n                continue;\n            if (funHasAddressTaken(&F)) {\n                _address_taken.push_back(&F);\n            }\n        }\n    }\n\n    FuncVec _getAddressTakenFuns(const llvm::CallInst *C) {\n        // FIXME: check that C calls initialized values\n        // (in many non-executable pieces of code, the call may call\n        // an uninitialized function pointer. Return no function\n        // in such cases instead of all address taken functions.\n        if (!_address_taken_initialized)\n            _initializeAddressTaken();\n        assert(_address_taken_initialized);\n\n        FuncVec ret;\n        // filter out compatible functions\n        for (auto *fun : _address_taken) {\n            if (callIsCompatible(fun, C)) {\n                ret.push_back(fun);\n            }\n        }\n        return ret;\n    }\n\n    // we pass also the call inst to be able to filter out incompatible\n    // functions\n    FuncVec _getCalledFunctions(const llvm::CallInst *C,\n                                const llvm::Value *val) {\n        if (_pta) {\n            FuncVec ret;\n            auto pts = _pta->getLLVMPointsTo(val);\n            for (const auto &ptr : pts) {\n                if (auto *fun = llvm::dyn_cast<llvm::Function>(ptr.value)) {\n                    if (callIsCompatible(fun, C)) {\n                        ret.push_back(fun);\n                    }\n                }\n            }\n            return ret;\n        } else {\n            return _getAddressTakenFuns(C);\n        }\n    }\n\n    FuncVec _getCalledFunctions(const llvm::CallInst *C) {\n        auto *callval = _getCalledValue(C);\n        assert(!llvm::isa<llvm::Function>(callval) &&\n               \"This method should be called on funptr\");\n        auto *thisf = C->getParent()->getParent();\n        auto ret = _getCalledFunctions(C, callval);\n        for (auto *f : ret)\n            _cg.addCall(thisf, f);\n        return ret;\n    }\n\n    bool hasFn(const llvm::Function *fun) const {\n        return _cg.get(fun) != nullptr;\n    }\n\n    void _populateCalledFunctions(const llvm::Function *fun) {\n        for (auto &B : *fun) {\n            for (auto &I : B) {\n                if (auto *C = llvm::dyn_cast<llvm::CallInst>(&I)) {\n                    getCalledFunctions(C);\n                }\n            }\n        }\n    }\n\n    void\n    processBBlock(const llvm::Function *parent, const llvm::BasicBlock &B,\n                  ADT::SetQueue<QueueFIFO<const llvm::Function *>> &queue) {\n        assert(_pta && \"This method can be used only with PTA\");\n        for (auto &I : B) {\n            if (auto *C = llvm::dyn_cast<llvm::CallInst>(&I)) {\n                auto pts = _pta->getLLVMPointsTo(_getCalledValue(C));\n                for (const auto &ptr : pts) {\n                    if (auto *F = llvm::dyn_cast<llvm::Function>(ptr.value)) {\n                        if (callIsCompatible(F, C)) {\n                            _cg.addCall(parent, F);\n                            queue.push(F);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // FIXME: if we have _pta, use the callgraph from _pta if available\n    const std::vector<const llvm::CallInst *> &\n    getCallsOfAddressTaken(const llvm::Function *F) {\n        assert(funHasAddressTaken(F));\n\n        // if we already computed this, return the cached result\n        auto it = _callsOf.find(F);\n        if (it != _callsOf.end())\n            return it->second;\n\n        // FIXME: could we do this more efficient?\n        // We could gather funptr calls and iterate only over those\n        // + get regular calls from the uses of F...\n        std::vector<const llvm::CallInst *> ret;\n        for (auto &mfun : *_module) {\n            for (auto &B : mfun) {\n                for (auto &I : B) {\n                    auto *C = llvm::dyn_cast<llvm::CallInst>(&I);\n                    if (!C)\n                        continue;\n\n                    for (auto *calledf : getCalledFunctions(C)) {\n                        if (calledf == F) {\n                            _cg.addCall(&mfun, F);\n                            ret.push_back(C);\n                        }\n                    }\n                }\n            }\n        }\n\n        // FIXME: double access...\n        _callsOf[F] = ret;\n        return _callsOf[F];\n    }\n\n  public:\n    LazyLLVMCallGraph(const llvm::Module *m, LLVMPointerAnalysis *pta = nullptr)\n            : _module(m), _pta(pta) {}\n\n    // TODO: add this method to general interface?\n    const FuncVec &getCalledFunctions(const llvm::CallInst *C) {\n        auto *val = _getCalledValue(C);\n        if (auto *fun = llvm::dyn_cast<llvm::Function>(val)) {\n            static FuncVec retval;\n            retval.clear();\n            retval.push_back(fun);\n            _cg.addCall(C->getParent()->getParent(), fun);\n            return retval;\n        }\n\n        auto it = _funptrs.find(C);\n        if (it != _funptrs.end()) {\n            return it->second;\n        }\n\n        // FIXME: do not do multiple lookups\n        _funptrs[C] = _getCalledFunctions(C);\n        return _funptrs[C];\n    }\n\n    std::vector<const llvm::CallInst *> getCallsOf(const llvm::Function *F) {\n        if (funHasAddressTaken(F)) {\n            return getCallsOfAddressTaken(F);\n        }\n\n        // has not address taken, so all users are calls\n        std::vector<const llvm::CallInst *> ret;\n        for (auto &use : F->uses()) {\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n            auto *user = *use;\n#else\n            auto *user = use.getUser();\n#endif\n            auto *C = llvm::cast<llvm::CallInst>(user);\n            _cg.addCall(C->getParent()->getParent(), F);\n            ret.push_back(C);\n        }\n        return ret;\n    }\n\n    FuncVec functions() const override {\n        FuncVec ret;\n        for (auto &it : _cg) {\n            ret.push_back(it.first);\n        }\n        return ret;\n    }\n\n    FuncVec callers(const llvm::Function *F) override {\n        FuncVec ret;\n        // make sure we have the callers\n        // (this will find also caller functions)\n        getCallsOf(F);\n\n        auto fnd = _cg.get(F);\n        assert(fnd);\n        for (auto *nd : fnd->getCallers()) {\n            ret.push_back(nd->getValue());\n        }\n        return ret;\n    }\n\n    FuncVec callees(const llvm::Function *F) override {\n        FuncVec ret;\n        if (!hasFn(F)) {\n            _populateCalledFunctions(F);\n        }\n        auto fnd = _cg.get(F);\n        for (auto *nd : fnd->getCalls()) {\n            ret.push_back(nd->getValue());\n        }\n        return ret;\n    }\n\n    bool calls(const llvm::Function *F, const llvm::Function *what) override {\n        if (!hasFn(F)) {\n            _populateCalledFunctions(F);\n        }\n        auto fn1 = _cg.get(F);\n        auto fn2 = _cg.get(what);\n        if (fn1 && fn2) {\n            return fn1->calls(fn2);\n        }\n        return false;\n    };\n\n    // trigger build\n    void build() override {\n        if (_pta) { // build only reachable functions\n            auto *entry =\n                    _module->getFunction(_pta->getOptions().entryFunction);\n            assert(entry && \"Entry function not found\");\n            _cg.createNode(entry);\n\n            ADT::SetQueue<QueueFIFO<const llvm::Function *>> queue;\n            queue.push(entry);\n\n            while (!queue.empty()) {\n                auto *cur = queue.pop();\n                for (auto &B : *cur) {\n                    processBBlock(cur, B, queue);\n                }\n            }\n        } else {\n            for (auto &F : *_module) {\n                if (F.isDeclaration())\n                    continue;\n                _populateCalledFunctions(&F);\n            }\n        }\n    }\n};\n\nclass CallGraph {\n    std::unique_ptr<CallGraphImpl> _impl;\n\n  public:\n    using FuncVec = CallGraphImpl::FuncVec;\n\n    CallGraph(GenericCallGraph<PSNode *> &cg)\n            : _impl(new DGCallGraphImpl(cg)) {}\n    CallGraph(const llvm::Module *m, LLVMPointerAnalysis *pta, bool lazy = true)\n            : _impl(lazy ? static_cast<CallGraphImpl *>(\n                                   new LazyLLVMCallGraph(m, pta))\n                         : static_cast<CallGraphImpl *>(\n                                   new LLVMPTACallGraphImpl(m, pta))) {}\n    CallGraph(const llvm::Module *m) : _impl(new LazyLLVMCallGraph(m)) {}\n\n    ///\n    /// Get all functions in this call graph\n    ///\n    FuncVec functions() const { return _impl->functions(); }\n    ///\n    /// Get callers of a function\n    ///\n    FuncVec callers(const llvm::Function *F) { return _impl->callers(F); };\n    ///\n    /// Get functions called from the given function\n    ///\n    FuncVec callees(const llvm::Function *F) { return _impl->callees(F); };\n    ///\n    /// Return true if function 'F' calls 'what'\n    ///\n    bool calls(const llvm::Function *F, const llvm::Function *what) {\n        return _impl->calls(F, what);\n    };\n\n    void build() { _impl->build(); }\n};\n\n} // namespace llvmdg\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/llvm/ControlDependence/ControlDependence.h",
    "content": "#ifndef LLVM_DG_CDA_H_\n#define LLVM_DG_CDA_H_\n\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#include <utility>\n\n#include \"dg/llvm/ControlDependence/LLVMControlDependenceAnalysisImpl.h\"\n#include \"dg/llvm/ControlDependence/LLVMControlDependenceAnalysisOptions.h\"\n\nnamespace dg {\n// namespace cda {\n\nclass LLVMPointerAnalysis;\n\nnamespace llvmdg {\nclass CallGraph;\n}\n\nclass LLVMControlDependenceAnalysis {\n  public:\n    using ValVec = std::vector<llvm::Value *>;\n\n  private:\n    const llvm::Module *_module;\n    const LLVMControlDependenceAnalysisOptions _options;\n    std::unique_ptr<LLVMControlDependenceAnalysisImpl> _impl{nullptr};\n    std::unique_ptr<LLVMControlDependenceAnalysisImpl> _interprocImpl{nullptr};\n\n    void initializeImpl(LLVMPointerAnalysis *pta = nullptr,\n                        llvmdg::CallGraph *cg = nullptr);\n\n    template <typename ValT>\n    ValVec _getDependencies(ValT v) {\n        assert(_impl);\n        auto ret = _impl->getDependencies(v);\n\n        if (getOptions().interproceduralCD()) {\n            assert(_interprocImpl);\n            auto interproc = _interprocImpl->getDependencies(v);\n            ret.insert(ret.end(), interproc.begin(), interproc.end());\n        }\n        return ret;\n    }\n\n    template <typename ValT>\n    ValVec _getDependent(ValT v) {\n        assert(_impl);\n        auto ret = _impl->getDependent(v);\n\n        if (getOptions().interproceduralCD()) {\n            assert(_interprocImpl);\n            auto interproc = _interprocImpl->getDependent(v);\n            ret.insert(ret.end(), interproc.begin(), interproc.end());\n        }\n        return ret;\n    }\n\n  public:\n    LLVMControlDependenceAnalysis(const llvm::Module *module,\n                                  LLVMControlDependenceAnalysisOptions opts,\n                                  LLVMPointerAnalysis *pta = nullptr)\n            : _module(module), _options(std::move(opts)) {\n        initializeImpl(pta);\n    }\n\n    // public API\n    const llvm::Module *getModule() const { return _module; }\n    const LLVMControlDependenceAnalysisOptions &getOptions() const {\n        return _options;\n    }\n\n    LLVMControlDependenceAnalysisImpl *getImpl() { return _impl.get(); }\n    const LLVMControlDependenceAnalysisImpl *getImpl() const {\n        return _impl.get();\n    }\n\n    // Compute control dependencies for all functions.\n    // If the analysis works on demand, calling this method\n    // will trigger the computation for the given function\n    // or the whole module if the function is nullptr.\n    // (so you don't want to call that if you want\n    //  on demand)\n    void compute(const llvm::Function *F = nullptr) {\n        _impl->compute(F);\n        if (getOptions().interproceduralCD())\n            _interprocImpl->compute(F);\n    }\n\n    ValVec getDependencies(const llvm::Instruction *v) {\n        return _getDependencies(v);\n    }\n    ValVec getDependent(const llvm::Instruction *v) { return _getDependent(v); }\n\n    ValVec getDependencies(const llvm::BasicBlock *b) {\n        return _getDependencies(b);\n    }\n    ValVec getDependent(const llvm::BasicBlock *b) { return _getDependent(b); }\n\n    ValVec getNoReturns(const llvm::Function *F) {\n        if (_interprocImpl)\n            return _interprocImpl->getNoReturns(F);\n        return {};\n    }\n\n    // A getter for results of closure-based algorithms.\n    // The method may abort if used with non-closure-based analysis.\n    ValVec getClosure(const llvm::Function *F,\n                      const std::set<llvm::Value *> &vals) {\n        return _impl->getClosure(F, vals);\n    }\n    /// XXX TBD\n    //// A getter for iterative building of results of closure-based algorithms.\n    // void startClosure(const llvm::Function *F, const std::set<llvm::Value *>&\n    // startSet) {\n    //    return _impl->startClosure(F, startSet);\n    //}\n    //// A getter for iterative building of results of closure-based algorithms.\n    // void closeSet(const std::set<llvm::Value *>& nodesset) {\n    //    return _impl->closeSet(nodesset);\n    //}\n\n    // FIXME: add also API that return just iterators\n};\n\n//} // namespace cda\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/llvm/ControlDependence/LLVMControlDependenceAnalysisImpl.h",
    "content": "#ifndef LLVM_DG_CDA_IMPL_H_\n#define LLVM_DG_CDA_IMPL_H_\n\n#include <set>\n#include <utility>\n\n#include \"dg/llvm/ControlDependence/LLVMControlDependenceAnalysisOptions.h\"\n\nnamespace llvm {\nclass Module;\nclass Value;\nclass Function;\n}; // namespace llvm\n\nnamespace dg {\n\nclass CDGraph;\n\nclass LLVMControlDependenceAnalysisImpl {\n    const llvm::Module *_module;\n    const LLVMControlDependenceAnalysisOptions _options;\n\n  public:\n    LLVMControlDependenceAnalysisImpl(const llvm::Module *module,\n                                      LLVMControlDependenceAnalysisOptions opts)\n            : _module(module), _options(std::move(opts)) {}\n\n    virtual ~LLVMControlDependenceAnalysisImpl() = default;\n\n    using ValVec = std::vector<llvm::Value *>;\n\n    // public API\n    const llvm::Module *getModule() const { return _module; }\n    const LLVMControlDependenceAnalysisOptions &getOptions() const {\n        return _options;\n    }\n\n    virtual CDGraph *getGraph(const llvm::Function * /*unused*/) {\n        return nullptr;\n    }\n    virtual const CDGraph *getGraph(const llvm::Function * /*unused*/) const {\n        return nullptr;\n    }\n\n    // Compute control dependencies for all functions.\n    // If the analysis works on demand, calling this method\n    // will trigger the computation for the given function\n    // or the whole module if the function is nullptr.\n    // (so you don't want to call that if you want\n    //  on demand)\n    virtual void compute(const llvm::Function *F = nullptr) = 0;\n\n    /// Getters of dependencies for a value\n    virtual ValVec getDependencies(const llvm::Instruction *) = 0;\n    virtual ValVec getDependent(const llvm::Instruction *) = 0;\n\n    /// Getters of dependencies for a basic block\n    virtual ValVec getDependencies(const llvm::BasicBlock *) = 0;\n    virtual ValVec getDependent(const llvm::BasicBlock *) = 0;\n\n    /// Getter for noreturn nodes in function (for interprocedural analysis)\n    virtual ValVec getNoReturns(const llvm::Function * /*unused*/) {\n        assert(false && \"Unsupported\");\n        abort();\n    }\n\n    virtual ValVec getClosure(const llvm::Function * /*unused*/,\n                              const std::set<llvm::Value *> & /*unused*/) {\n        assert(false && \"Unsupported\");\n        abort();\n    }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/llvm/ControlDependence/LLVMControlDependenceAnalysisOptions.h",
    "content": "#ifndef DG_LLVM_CDA_OPTIONS_H_\n#define DG_LLVM_CDA_OPTIONS_H_\n\n#include \"dg/ControlDependence/ControlDependenceAnalysisOptions.h\"\n#include \"dg/llvm/LLVMAnalysisOptions.h\"\n\nnamespace dg {\n\nstruct LLVMControlDependenceAnalysisOptions : public LLVMAnalysisOptions,\n                                              ControlDependenceAnalysisOptions {\n    bool _nodePerInstruction{false};\n    bool _icfg{false};\n\n    void setNodePerInstruction(bool b) { _nodePerInstruction = b; }\n    bool nodePerInstruction() const { return _nodePerInstruction; }\n    bool ICFG() const { return _icfg; }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/llvm/DataDependence/DataDependence.h",
    "content": "#ifndef LLVM_DG_DD_H_\n#define LLVM_DG_DD_H_\n\n#include <memory>\n#include <type_traits>\n#include <unordered_map>\n#include <utility>\n\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#include \"dg/DataDependence/DataDependence.h\"\n\n#include \"dg/llvm/DataDependence/LLVMDataDependenceAnalysisOptions.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n\nnamespace dg {\nnamespace dda {\n\nclass LLVMReadWriteGraphBuilder;\n\nclass LLVMDataDependenceAnalysis {\n    const llvm::Module *m;\n    dg::LLVMPointerAnalysis *pta;\n    const LLVMDataDependenceAnalysisOptions _options;\n    LLVMReadWriteGraphBuilder *builder{nullptr};\n    std::unique_ptr<DataDependenceAnalysis> DDA{nullptr};\n\n    LLVMReadWriteGraphBuilder *createBuilder();\n    DataDependenceAnalysis *createDDA();\n\n  public:\n    LLVMDataDependenceAnalysis(const llvm::Module *m,\n                               dg::LLVMPointerAnalysis *pta,\n                               LLVMDataDependenceAnalysisOptions opts = {})\n            : m(m), pta(pta), _options(std::move(opts)),\n              builder(createBuilder()) {}\n\n    ~LLVMDataDependenceAnalysis();\n\n    void buildGraph() {\n        assert(builder);\n        assert(pta);\n\n        DDA.reset(createDDA());\n    }\n\n    void run() {\n        if (!DDA) {\n            buildGraph();\n        }\n\n        assert(DDA);\n        DDA->run();\n    }\n\n    const LLVMDataDependenceAnalysisOptions &getOptions() const {\n        return _options;\n    }\n\n    ReadWriteGraph *getGraph() { return DDA->getGraph(); }\n    RWNode *getNode(const llvm::Value *val);\n    const RWNode *getNode(const llvm::Value *val) const;\n    const llvm::Value *getValue(const RWNode *node) const;\n\n    bool isUse(const llvm::Value *val) const {\n        const auto *nd = getNode(val);\n        return nd && nd->isUse();\n    }\n\n    bool isDef(const llvm::Value *val) const {\n        const auto *nd = getNode(val);\n        return nd && nd->isDef();\n    }\n\n    std::vector<RWNode *> getDefinitions(RWNode *where, RWNode *mem,\n                                         const Offset &off, const Offset &len) {\n        return DDA->getDefinitions(where, mem, off, len);\n    }\n\n    std::vector<RWNode *> getDefinitions(RWNode *use) {\n        return DDA->getDefinitions(use);\n    }\n\n    std::vector<RWNode *> getDefinitions(llvm::Instruction *where,\n                                         llvm::Value *mem, const Offset &off,\n                                         const Offset &len) {\n        auto *whereN = getNode(where);\n        assert(whereN);\n        auto *memN = getNode(mem);\n        assert(memN);\n        return DDA->getDefinitions(whereN, memN, off, len);\n    }\n\n    std::vector<RWNode *> getDefinitions(llvm::Value *use) {\n        auto *node = getNode(use);\n        assert(node);\n        return getDefinitions(node);\n    }\n\n    // return instructions that define the given value\n    // (the value must read from memory, e.g. LoadInst)\n    std::vector<llvm::Value *> getLLVMDefinitions(llvm::Value *use);\n    std::vector<llvm::Value *> getLLVMDefinitions(llvm::Instruction *where,\n                                                  llvm::Value *mem,\n                                                  const Offset &off,\n                                                  const Offset &len);\n\n    DataDependenceAnalysis *getDDA() { return DDA.get(); }\n    const DataDependenceAnalysis *getDDA() const { return DDA.get(); }\n};\n\n} // namespace dda\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/llvm/DataDependence/LLVMDataDependenceAnalysisOptions.h",
    "content": "#ifndef DG_LLVM_DATA_DEPENDENCE_ANALYSIS_OPTIONS_H_\n#define DG_LLVM_DATA_DEPENDENCE_ANALYSIS_OPTIONS_H_\n\n#include \"dg/DataDependence/DataDependenceAnalysisOptions.h\"\n#include \"dg/llvm/LLVMAnalysisOptions.h\"\n\nnamespace dg {\n\nstruct LLVMDataDependenceAnalysisOptions : public LLVMAnalysisOptions,\n                                           DataDependenceAnalysisOptions {\n    bool threads{false};\n\n    LLVMDataDependenceAnalysisOptions() {\n        // setup models for standard functions\n\n        ///\n        // Memory block functions\n        ///\n        // memcpy defines mem. pointed to by operand 0 from the offset 0\n        // to the offset given by the operand 2\n        functionModelAddDef(\"memcpy\", {0, Offset(0), 2});\n        functionModelAddUse(\"memcpy\", {1, Offset(0), 2});\n        functionModelAddDef(\"__memcpy_chk\", {0, Offset(0), 2});\n        functionModelAddUse(\"__memcpy_chk\", {1, Offset(0), 2});\n        functionModelAddDef(\"llvm.memcpy.p0i8.p0i8.i64\", {0, Offset(0), 2});\n        functionModelAddUse(\"llvm.memcpy.p0i8.p0i8.i64\", {1, Offset(0), 2});\n        functionModelAddDef(\"llvm.memcpy.p0i8.p0i8.i32\", {0, Offset(0), 2});\n        functionModelAddUse(\"llvm.memcpy.p0i8.p0i8.i32\", {1, Offset(0), 2});\n\n        functionModelAddDef(\"memmove\", {0, Offset(0), 2});\n        functionModelAddUse(\"memmove\", {1, Offset(0), 2});\n\n        functionModelAddDef(\"memset\", {0, Offset(0), 2});\n\n        functionModelAddUse(\"memcmp\", {0, Offset(0), 2});\n        functionModelAddUse(\"memcmp\", {1, Offset(0), 2});\n\n        ///\n        // String handling functions\n        ///\n        functionModelAddUse(\"strlen\", {0, Offset(0), Offset::getUnknown()});\n        functionModelAddUse(\"strchr\", {0, Offset(0), Offset::getUnknown()});\n        functionModelAddUse(\"strrchr\", {0, Offset(0), Offset::getUnknown()});\n\n        functionModelAddDef(\"strcpy\", {0, Offset(0), Offset::getUnknown()});\n        functionModelAddUse(\"strcpy\", {1, Offset(0), Offset::getUnknown()});\n        functionModelAddDef(\"strncpy\", {0, Offset(0), 2});\n        functionModelAddUse(\"strncpy\", {1, Offset(0), 2});\n    };\n};\n\n} // namespace dg\n\n#endif // DG_LLVM_DATA_DEPENDENCE_ANALYSIS_OPTIONS_H_\n"
  },
  {
    "path": "include/dg/llvm/Dominators/Dominators.h",
    "content": "#ifndef _DG_DOMINATORS_H_\n#define _DG_DOMINATORS_H_\n\n#include <llvm/IR/Dominators.h>\n#include <llvm/IR/Function.h>\n\n#include \"BBlock.h\"\n#include \"analysis/DominanceFrontiers.h\"\n\nnamespace dg {\nnamespace analysis {\n\n/**\n * Calculates dominators using LLVM framework\n * Template parameters:\n *  NodeT\n *  CalculateDF = should dominance frontiers be calculated, too?\n */\ntemplate <typename NodeT, bool CalculateDF = true>\nclass Dominators {\n  private:\n    using BlockT = BBlock<dg::analysis::rd::RWNode>;\n    using CFMapT =\n            std::unordered_map<const llvm::Function *,\n                               std::map<const llvm::BasicBlock *, BlockT *>>;\n    using BMapT =\n            std::unordered_map<const llvm::Value *, std::unique_ptr<BlockT>>;\n\n  public:\n    void calculate(CFMapT &functions_blocks, const BMapT &all_blocks) {\n        using namespace llvm;\n\n        for (auto &pair : functions_blocks) {\n            Function &f = *const_cast<Function *>(pair.first);\n\n            DominatorTree dt;\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 9))\n            // compute dominator tree for this function\n            dt.runOnFunction(f);\n#else\n            dt.recalculate(f);\n#endif\n            auto it = all_blocks.find(dt.getRoot());\n            assert(it != all_blocks.end() && \"root block must exist\");\n            BlockT *root = it->second.get();\n            auto &blocks = pair.second;\n            for (auto &block : blocks) {\n                BasicBlock *llvm_block = const_cast<BasicBlock *>(block.first);\n                BlockT *basic_block = block.second;\n\n                DomTreeNode *N = dt.getNode(llvm_block);\n                if (!N)\n                    continue;\n\n                DomTreeNode *idom = N->getIDom();\n                BasicBlock *idomBB = idom ? idom->getBlock() : nullptr;\n\n                for (const auto &dom : N->getChildren()) {\n                    const BasicBlock *dom_llvm_block = dom->getBlock();\n                    const auto it = all_blocks.find(\n                            static_cast<const llvm::Value *>(dom_llvm_block));\n                    assert(it != all_blocks.end() &&\n                           \"Do not have constructed domBB\");\n                    const BlockT *dom_block = it->second.get();\n                    if (dom_block != root)\n                        basic_block->addDominator(\n                                const_cast<BlockT *>(dom_block));\n                }\n\n                if (idomBB) {\n                    auto it = all_blocks.find(idomBB);\n                    assert(it != all_blocks.end() &&\n                           \"Do not have constructed BB\");\n                    BlockT *db = it->second.get();\n                    basic_block->setIDom(db);\n                } else {\n                    if (basic_block != root)\n                        basic_block->setIDom(root);\n                }\n            }\n\n            if (CalculateDF) {\n                analysis::DominanceFrontiers<NodeT> dfrontiers;\n                if (root)\n                    dfrontiers.compute(root);\n            }\n        }\n    }\n};\n\n} // namespace analysis\n} // namespace dg\n\n#endif /* _DG_DOMINATORS_H_ */\n"
  },
  {
    "path": "include/dg/llvm/LLVMAnalysisOptions.h",
    "content": "#ifndef DG_LLVM_ANALYSIS_OPTIONS_H_\n#define DG_LLVM_ANALYSIS_OPTIONS_H_\n\n#include \"dg/AnalysisOptions.h\"\n#include <string>\n\nnamespace dg {\n\nstruct LLVMAnalysisOptions {\n    // Number of bytes in objects to track precisely\n    std::string entryFunction{\"main\"};\n\n    LLVMAnalysisOptions &setEntryFunction(const std::string &e) {\n        entryFunction = e;\n        return *this;\n    }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/llvm/LLVMDG2Dot.h",
    "content": "#ifndef DG_LLVMDG2DOT_H_\n#define DG_LLVMDG2DOT_H_\n\n#include <iostream>\n#include <ostream>\n#include <sstream>\n#include <string>\n\n#include \"dg/DG2Dot.h\"\n#include \"dg/llvm/LLVMDependenceGraph.h\"\n#include \"dg/llvm/LLVMNode.h\"\n\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR <= 4))\n#include \"llvm/DebugInfo.h\" //DIScope\n#else\n#include \"llvm/IR/DebugInfo.h\" //DIScope\n#endif\n\nusing namespace dg;\nnamespace dg {\nnamespace debug {\n\n/*\nstatic std::ostream& operator<<(std::ostream& os, const analysis::Offset& off)\n{\n    if (off.offset == Offset::UNKNOWN)\n        os << \"UNKNOWN\";\n    else\n        os << off.offset;\n\n    return os;\n}\n*/\n\nnamespace {\ninline std::ostream &printLLVMVal(std::ostream &os, const llvm::Value *val) {\n    if (!val) {\n        os << \"(null)\";\n        return os;\n    }\n\n    std::ostringstream ostr;\n    llvm::raw_os_ostream ro(ostr);\n\n    if (llvm::isa<llvm::Function>(val)) {\n        ro << \"FUNC \" << val->getName();\n    } else if (const auto *B = llvm::dyn_cast<llvm::BasicBlock>(val)) {\n        ro << B->getParent()->getName() << \"::\\n\";\n        ro << \"label \" << val->getName();\n    } else if (const auto *I = llvm::dyn_cast<llvm::Instruction>(val)) {\n        const auto *const B = I->getParent();\n        if (B) {\n            ro << B->getParent()->getName() << \"::\\n\";\n        } else {\n            ro << \"<null>::\\n\";\n        }\n        ro << *val;\n    } else {\n        ro << *val;\n    }\n\n    ro.flush();\n\n    // break the string if it is too long\n    std::string str = ostr.str();\n    if (str.length() > 100) {\n        str.resize(40);\n    }\n\n    // escape the \"\n    size_t pos = 0;\n    while ((pos = str.find('\"', pos)) != std::string::npos) {\n        str.replace(pos, 1, \"\\\\\\\"\");\n        // we replaced one char with two, so we must shift after the new \"\n        pos += 2;\n    }\n\n    os << str;\n\n    return os;\n}\n} // anonymous namespace\n\nclass LLVMDG2Dot : public debug::DG2Dot<LLVMNode> {\n  public:\n    // FIXME: make dg const\n    LLVMDG2Dot(LLVMDependenceGraph *dg,\n               uint32_t opts = debug::PRINT_CFG | debug::PRINT_DD |\n                               debug::PRINT_CD,\n               const char *file = nullptr)\n            : debug::DG2Dot<LLVMNode>(dg, opts, file) {}\n\n    /* virtual */\n    std::ostream &printKey(std::ostream &os, llvm::Value *val) override {\n        return printLLVMVal(os, val);\n    }\n\n    /* virtual */\n    bool checkNode(std::ostream &os, LLVMNode *node) override {\n        bool err = false;\n        const llvm::Value *val = node->getKey();\n\n        if (!val) {\n            os << \"\\\\nERR: no value in node\";\n            return true;\n        }\n\n        if (!node->getBBlock() && !llvm::isa<llvm::Function>(val) &&\n            !llvm::isa<llvm::GlobalVariable>(val)) {\n            err = true;\n            os << \"\\\\nERR: no BB\";\n        }\n\n        // Print Location in source file. Print it only for LLVM 3.6 and higher.\n        // The versions before 3.6 had different API, so this is quite\n        // a workaround, not a real fix. If anybody needs this functionality\n        // on those versions, fix this :)\n        if (const llvm::Instruction *I =\n                    llvm::dyn_cast<llvm::Instruction>(val)) {\n            const llvm::DebugLoc &Loc = I->getDebugLoc();\n#if ((LLVM_VERSION_MAJOR > 3) ||                                               \\\n     ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR > 6)))\n            if (Loc) {\n                os << \"\\\" labelURL=\\\"\";\n                llvm::raw_os_ostream ross(os);\n                Loc.print(ross);\n#else\n            if (Loc.getLine() > 0) {\n                os << \"\\\" labelURL=\\\"\";\n                llvm::raw_os_ostream ross(os);\n                // Loc.print(I->getParent()->getContext(), ross);\n                const llvm::DebugLoc *tmpLoc = &Loc;\n                int nclosingBrack = 0;\n                while (tmpLoc) {\n                    llvm::DIScope Scope(\n                            tmpLoc->getScope(I->getParent()->getContext()));\n                    ross << Scope.getFilename();\n                    ross << ':' << tmpLoc->getLine();\n                    if (tmpLoc->getCol() != 0)\n                        ross << ':' << tmpLoc->getCol();\n\n                    llvm::MDNode *inlineMN =\n                            tmpLoc->getInlinedAt(I->getParent()->getContext());\n                    if (inlineMN) {\n                        llvm::DebugLoc InlinedAtDL =\n                                llvm::DebugLoc::getFromDILocation(inlineMN);\n                        if (!InlinedAtDL.isUnknown()) {\n                            ross << \" @[ \";\n                            tmpLoc = &InlinedAtDL;\n                            nclosingBrack++;\n                        } else {\n                            tmpLoc = nullptr;\n                        }\n                    } else {\n                        tmpLoc = nullptr;\n                    }\n                }\n                while (nclosingBrack > 0) {\n                    ross << \" ]\";\n                    nclosingBrack--;\n                }\n#endif\n                ross.flush();\n            }\n        }\n\n        return err;\n    }\n\n    bool dump(const char *new_file = nullptr,\n              const char *dump_func_only = nullptr) override {\n        // make sure we have the file opened\n        if (!ensureFile(new_file))\n            return false;\n\n        const std::map<llvm::Value *, LLVMDependenceGraph *> &CF =\n                getConstructedFunctions();\n\n        start();\n\n        for (const auto &F : CF) {\n            if (dump_func_only && !F.first->getName().equals(dump_func_only))\n                continue;\n\n            dumpSubgraph(F.second, F.first->getName().data());\n        }\n\n        end();\n\n        return true;\n    }\n\n  private:\n    void dumpSubgraph(LLVMDependenceGraph *graph, const char *name) {\n        dumpSubgraphStart(graph, name);\n\n        for (auto &B : graph->getBlocks()) {\n            dumpBBlock(B.second);\n        }\n\n        for (auto &B : graph->getBlocks()) {\n            dumpBBlockEdges(B.second);\n        }\n\n        dumpSubgraphEnd(graph);\n    }\n};\n\nclass LLVMDGDumpBlocks : public debug::DG2Dot<LLVMNode> {\n  public:\n    LLVMDGDumpBlocks(LLVMDependenceGraph *dg,\n                     uint32_t opts = debug::PRINT_CFG | debug::PRINT_DD |\n                                     debug::PRINT_CD,\n                     const char *file = nullptr)\n            : debug::DG2Dot<LLVMNode>(dg, opts, file) {}\n\n    /* virtual\n    std::ostream& printKey(std::ostream& os, llvm::Value *val)\n    {\n        return printLLVMVal(os, val);\n    }\n    */\n\n    /* virtual */\n    bool checkNode(std::ostream & /*os*/, LLVMNode * /*node*/) override {\n        return false; // no error\n    }\n\n    bool dump(const char *new_file = nullptr,\n              const char *dump_func_only = nullptr) override {\n        // make sure we have the file opened\n        if (!ensureFile(new_file))\n            return false;\n\n        const std::map<llvm::Value *, LLVMDependenceGraph *> &CF =\n                getConstructedFunctions();\n\n        start();\n\n        for (const auto &F : CF) {\n            // XXX: this is inefficient, we can get the dump_func_only function\n            // from the module (F.getParent()->getModule()->getFunction(...)\n            if (dump_func_only && !F.first->getName().equals(dump_func_only))\n                continue;\n\n            dumpSubgraph(F.second, F.first->getName().data());\n        }\n\n        end();\n\n        return true;\n    }\n\n  private:\n    void dumpSubgraph(LLVMDependenceGraph *graph, const char *name) {\n        dumpSubgraphStart(graph, name);\n\n        for (auto &B : graph->getBlocks()) {\n            dumpBlock(B.second);\n        }\n\n        for (auto &B : graph->getBlocks()) {\n            dumpBlockEdges(B.second);\n        }\n\n        dumpSubgraphEnd(graph, false);\n    }\n\n    void dumpBlock(LLVMBBlock *blk) {\n        out << \"NODE\" << blk << \" [label=\\\"\";\n\n        std::ostringstream ostr;\n        llvm::raw_os_ostream ro(ostr);\n\n        ro << *blk->getKey();\n        ro.flush();\n        std::string str = ostr.str();\n\n        unsigned int i = 0;\n        unsigned int len = 0;\n        while (str[i] != 0) {\n            if (len >= 40) {\n                str[i] = '\\n';\n                len = 0;\n            } else\n                ++len;\n\n            if (str[i] == '\\n')\n                len = 0;\n\n            ++i;\n        }\n\n        unsigned int slice_id = blk->getSlice();\n        if (slice_id != 0)\n            out << \"\\\\nslice: \" << slice_id << \"\\\\n\";\n        out << str << \"\\\"\";\n\n        if (slice_id != 0)\n            out << \"style=filled fillcolor=greenyellow\";\n\n        out << \"]\\n\";\n    }\n\n    void dumpBlockEdges(LLVMBBlock *blk) {\n        for (const LLVMBBlock::BBlockEdge &edge : blk->successors()) {\n            out << \"NODE\" << blk << \" -> NODE\" << edge.target\n                << \" [penwidth=2 label=\\\"\" << static_cast<int>(edge.label)\n                << \"\\\"] \\n\";\n        }\n\n        for (const LLVMBBlock *pdf : blk->controlDependence()) {\n            out << \"NODE\" << blk << \" -> NODE\" << pdf\n                << \" [color=blue constraint=false]\\n\";\n        }\n    }\n};\n} /* namespace debug */\n} /* namespace dg */\n\n#endif\n"
  },
  {
    "path": "include/dg/llvm/LLVMDGAssemblyAnnotationWriter.h",
    "content": "#ifndef LLVM_DG_ASSEMBLY_ANNOTATION_WRITER_H_\n#define LLVM_DG_ASSEMBLY_ANNOTATION_WRITER_H_\n\n#include <llvm/Support/FormattedStream.h>\n\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n#include <llvm/Analysis/Verifier.h>\n#include <llvm/Assembly/AssemblyAnnotationWriter.h>\n#else // >= 3.5\n#include <llvm/IR/AssemblyAnnotationWriter.h>\n#include <llvm/IR/Verifier.h>\n#endif\n\n#include \"dg/llvm/DataDependence/DataDependence.h\"\n#include \"dg/llvm/LLVMDependenceGraph.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n\nnamespace dg {\nnamespace debug {\n\nclass LLVMDGAssemblyAnnotationWriter : public llvm::AssemblyAnnotationWriter {\n    using LLVMDataDependenceAnalysis = dg::dda::LLVMDataDependenceAnalysis;\n\n  public:\n    enum AnnotationOptsT {\n        // data dependencies\n        ANNOTATE_DD = 1 << 0,\n        // forward data dependencies\n        ANNOTATE_FORWARD_DD = 1 << 1,\n        // control dependencies\n        ANNOTATE_CD = 1 << 2,\n        // points-to information\n        ANNOTATE_PTR = 1 << 3,\n        // reaching definitions\n        ANNOTATE_DEF = 1 << 4,\n        // post-dominators\n        ANNOTATE_POSTDOM = 1 << 5,\n        // comment out nodes that will be sliced\n        ANNOTATE_SLICE = 1 << 6,\n        // annotate memory accesses (like ANNOTATE_PTR,\n        // but with byte intervals)\n        ANNOTATE_MEMORYACC = 1 << 7,\n    };\n\n  private:\n    AnnotationOptsT opts;\n    LLVMPointerAnalysis *PTA;\n    LLVMDataDependenceAnalysis *DDA;\n    const std::set<LLVMNode *> *criteria;\n    std::string module_comment{};\n\n    static void printValue(const llvm::Value *val,\n                           llvm::formatted_raw_ostream &os, bool nl = false) {\n        if (val->hasName())\n            os << val->getName().data();\n        else\n            os << *val;\n\n        if (nl)\n            os << \"\\n\";\n    }\n\n    static void printPointer(const LLVMPointer &ptr,\n                             llvm::formatted_raw_ostream &os,\n                             const char *prefix = \"PTR: \", bool nl = true) {\n        os << \"  ; \";\n        if (prefix)\n            os << prefix;\n\n        printValue(ptr.value, os);\n\n        os << \" + \";\n        if (ptr.offset.isUnknown())\n            os << \"?\";\n        else\n            os << *ptr.offset;\n\n        if (nl)\n            os << \"\\n\";\n    }\n\n    static void printDefSite(const dda::DefSite &ds,\n                             llvm::formatted_raw_ostream &os,\n                             const char *prefix = nullptr, bool nl = false) {\n        os << \"  ; \";\n        if (prefix)\n            os << prefix;\n\n        if (ds.target) {\n            const llvm::Value *val = ds.target->getUserData<llvm::Value>();\n            if (ds.target->isUnknown())\n                os << \"unknown\";\n            else\n                printValue(val, os);\n\n            if (ds.offset.isUnknown())\n                os << \" bytes |?\";\n            else\n                os << \" bytes |\" << *ds.offset;\n\n            if (ds.len.isUnknown())\n                os << \" - ?|\";\n            else\n                os << \" - \" << *ds.offset + *ds.len - 1 << \"|\";\n        } else\n            os << \"target is null!\";\n\n        if (nl)\n            os << \"\\n\";\n    }\n\n    static void printMemRegion(const LLVMMemoryRegion &R,\n                               llvm::formatted_raw_ostream &os,\n                               const char *prefix = nullptr, bool nl = false) {\n        os << \"  ; \";\n        if (prefix)\n            os << prefix;\n\n        assert(R.pointer.value);\n        printValue(R.pointer.value, os);\n\n        if (R.pointer.offset.isUnknown())\n            os << \" bytes [?\";\n        else\n            os << \" bytes [\" << *R.pointer.offset;\n\n        if (R.len.isUnknown())\n            os << \" - ?]\";\n        else\n            os << \" - \" << *R.pointer.offset + *R.len - 1 << \"]\";\n\n        if (nl)\n            os << \"\\n\";\n    }\n\n    void emitNodeAnnotations(LLVMNode *node, llvm::formatted_raw_ostream &os) {\n        using namespace llvm;\n\n        if (opts & ANNOTATE_DEF) {\n            assert(DDA && \"No data dependence analysis\");\n            if (DDA->isUse(node->getValue())) {\n                os << \"  ; DEF: \";\n                const auto &defs = DDA->getLLVMDefinitions(node->getValue());\n                if (defs.empty()) {\n                    os << \"none (or global)\\n\";\n                } else {\n                    for (auto *def : defs) {\n                        if (def->hasName())\n                            os << def->getName();\n                        else\n                            os << *def;\n\n                        os << \"(\" << def << \")\\n\";\n                    }\n                }\n            }\n        }\n\n        if (opts & ANNOTATE_DD) {\n            for (auto I = node->rev_data_begin(), E = node->rev_data_end();\n                 I != E; ++I) {\n                const llvm::Value *d = (*I)->getKey();\n                os << \"  ; DD: \";\n\n                if (d->hasName())\n                    os << d->getName();\n                else\n                    os << *d;\n\n                os << \"(\" << d << \")\\n\";\n            }\n        }\n\n        if (opts & ANNOTATE_FORWARD_DD) {\n            for (auto I = node->data_begin(), E = node->data_end(); I != E;\n                 ++I) {\n                const llvm::Value *d = (*I)->getKey();\n                os << \"  ; fDD: \" << *d << \"(\" << d << \")\\n\";\n            }\n        }\n\n        if (opts & ANNOTATE_CD) {\n            for (auto I = node->rev_control_begin(),\n                      E = node->rev_control_end();\n                 I != E; ++I) {\n                const llvm::Value *d = (*I)->getKey();\n                os << \"  ; rCD: \";\n\n                if (d->hasName())\n                    os << d->getName() << \"\\n\";\n                else\n                    os << *d << \"\\n\";\n            }\n        }\n\n        if (opts & ANNOTATE_PTR) {\n            if (PTA) {\n                llvm::Type *Ty = node->getKey()->getType();\n                if (Ty->isPointerTy() || Ty->isIntegerTy()) {\n                    const auto &ps = PTA->getLLVMPointsTo(node->getKey());\n                    if (!ps.empty()) {\n                        for (const auto &llvmptr : ps) {\n                            printPointer(llvmptr, os);\n                        }\n                        if (ps.hasNull()) {\n                            os << \"  ; null\\n\";\n                        }\n                        if (ps.hasNullWithOffset()) {\n                            os << \"  ; null + ?\\n\";\n                        }\n                        if (ps.hasUnknown()) {\n                            os << \"  ; unknown\\n\";\n                        }\n                        if (ps.hasInvalidated()) {\n                            os << \"  ; invalidated\\n\";\n                        }\n                    }\n                }\n            }\n        }\n\n        if (PTA && (opts & ANNOTATE_MEMORYACC)) {\n            if (auto *I = dyn_cast<Instruction>(node->getValue())) {\n                if (I->mayReadOrWriteMemory()) {\n                    auto regions = PTA->getAccessedMemory(I);\n                    if (regions.first) {\n                        os << \"  ; unknown region\\n\";\n                    }\n                    for (const auto &mem : regions.second) {\n                        printMemRegion(mem, os, nullptr, true);\n                    }\n                }\n            }\n        }\n\n        if (opts & ANNOTATE_SLICE) {\n            if (criteria && criteria->count(node) > 0)\n                os << \"  ; SLICING CRITERION\\n\";\n            if (node->getSlice() == 0)\n                os << \"  ; x \";\n        }\n    }\n\n  public:\n    LLVMDGAssemblyAnnotationWriter(\n            AnnotationOptsT o = ANNOTATE_SLICE,\n            LLVMPointerAnalysis *pta = nullptr,\n            LLVMDataDependenceAnalysis *dda = nullptr,\n            const std::set<LLVMNode *> *criteria = nullptr)\n            : opts(o), PTA(pta), DDA(dda), criteria(criteria) {\n        assert(!(opts & ANNOTATE_PTR) || PTA);\n        assert(!(opts & ANNOTATE_DEF) || DDA);\n    }\n\n    void emitModuleComment(const std::string &comment) {\n        module_comment = comment;\n    }\n\n    void emitModuleComment(std::string &&comment) {\n        module_comment = std::move(comment);\n    }\n\n    void emitFunctionAnnot(const llvm::Function * /*unused*/,\n                           llvm::formatted_raw_ostream &os) override {\n        // dump the slicer's setting to the file\n        // for easier comprehension\n        static bool didit = false;\n        if (!didit) {\n            didit = true;\n            os << module_comment;\n        }\n    }\n\n    void emitInstructionAnnot(const llvm::Instruction *I,\n                              llvm::formatted_raw_ostream &os) override {\n        if (opts == 0)\n            return;\n\n        LLVMNode *node = nullptr;\n        for (const auto &it : getConstructedFunctions()) {\n            LLVMDependenceGraph *sub = it.second;\n            node = sub->getNode(const_cast<llvm::Instruction *>(I));\n            if (node)\n                break;\n        }\n\n        if (!node) {\n            if (opts & ANNOTATE_SLICE)\n                os << \"  ; x \";\n            return;\n        }\n\n        emitNodeAnnotations(node, os);\n    }\n\n    void emitBasicBlockStartAnnot(const llvm::BasicBlock *B,\n                                  llvm::formatted_raw_ostream &os) override {\n        if (opts == 0)\n            return;\n\n        for (const auto &it : getConstructedFunctions()) {\n            LLVMDependenceGraph *sub = it.second;\n            auto &cb = sub->getBlocks();\n            auto I = cb.find(const_cast<llvm::BasicBlock *>(B));\n            if (I != cb.end()) {\n                LLVMBBlock *BB = I->second;\n                if (opts & (ANNOTATE_POSTDOM | ANNOTATE_CD))\n                    os << \"  ; BB: \" << BB << \"\\n\";\n\n                if (opts & ANNOTATE_POSTDOM) {\n                    for (LLVMBBlock *p : BB->getPostDomFrontiers())\n                        os << \"  ; PDF: \" << p << \"\\n\";\n\n                    LLVMBBlock *P = BB->getIPostDom();\n                    if (P && P->getKey())\n                        os << \"  ; iPD: \" << P << \"\\n\";\n                }\n\n                if (opts & ANNOTATE_CD) {\n                    for (LLVMBBlock *p : BB->controlDependence())\n                        os << \"  ; CD: \" << p << \"\\n\";\n                }\n            }\n        }\n    }\n};\n\n} // namespace debug\n} // namespace dg\n\n// allow combinations of annotation options\ninline dg::debug::LLVMDGAssemblyAnnotationWriter::AnnotationOptsT\noperator|(dg::debug::LLVMDGAssemblyAnnotationWriter::AnnotationOptsT a,\n          dg::debug::LLVMDGAssemblyAnnotationWriter::AnnotationOptsT b) {\n    using AnT = dg::debug::LLVMDGAssemblyAnnotationWriter::AnnotationOptsT;\n    using T = std::underlying_type<AnT>::type;\n    return static_cast<AnT>(static_cast<T>(a) | static_cast<T>(b));\n}\n\ninline dg::debug::LLVMDGAssemblyAnnotationWriter::AnnotationOptsT\noperator|=(dg::debug::LLVMDGAssemblyAnnotationWriter::AnnotationOptsT &a,\n           dg::debug::LLVMDGAssemblyAnnotationWriter::AnnotationOptsT b) {\n    using AnT = dg::debug::LLVMDGAssemblyAnnotationWriter::AnnotationOptsT;\n    using T = std::underlying_type<AnT>::type;\n    a = static_cast<AnT>(static_cast<T>(a) | static_cast<T>(b));\n    return a;\n}\n\n#endif // LLVM_DG_ANNOTATION_WRITER_H_\n"
  },
  {
    "path": "include/dg/llvm/LLVMDependenceGraph.h",
    "content": "#ifndef LLVM_DEPENDENCE_GRAPH_H_\n#define LLVM_DEPENDENCE_GRAPH_H_\n\n#include <map>\n#include <unordered_map>\n\n#include \"dg/llvm/ControlDependence/LLVMControlDependenceAnalysisOptions.h\"\n#include \"dg/llvm/ThreadRegions/ControlFlowGraph.h\"\n\n// forward declaration of llvm classes\nnamespace llvm {\nclass Module;\nclass Value;\nclass Function;\n} // namespace llvm\n\n#include \"dg/DependenceGraph.h\"\n#include \"dg/llvm/LLVMNode.h\"\n\nnamespace dg {\n\nclass LLVMPointerAnalysis;\n\n// namespace llvmdg {\n// class LLVMControlDependenceAnalysis;\n//}\n\n// FIXME: why PTA is only in the namespace dg\n// and this is that nested? Make it consistent...\n\nnamespace dda {\nclass LLVMDataDependenceAnalysis;\n}\n\nusing dda::LLVMDataDependenceAnalysis;\n// using llvmdg::LLVMControlDependenceAnalysis;\n\nusing LLVMBBlock = dg::BBlock<LLVMNode>;\n\n/// ------------------------------------------------------------------\n//  -- LLVMDependenceGraph\n/// ------------------------------------------------------------------\nclass LLVMDependenceGraph : public DependenceGraph<LLVMNode> {\n    // our artificial unified exit block\n    std::unique_ptr<LLVMBBlock> unifiedExitBB{};\n    llvm::Function *entryFunction{nullptr};\n\n  public:\n    LLVMDependenceGraph(bool threads = false) : threads(threads) {}\n\n    // free all allocated memory and unref subgraphs\n    ~LLVMDependenceGraph() override;\n\n    // build a nodes and CFG edges from module.\n    // This method will build also all subgraphs. If entry is nullptr,\n    // then this methods looks for function named 'main'.\n    // NOTE: this methods does not compute the dependence edges.\n    // For that functionality check the LLVMDependenceGraphBuilder.\n    bool build(llvm::Module *m, llvm::Function *entry = nullptr);\n    bool build(llvm::Module *m, LLVMPointerAnalysis *pts = nullptr,\n               LLVMDataDependenceAnalysis *rda = nullptr,\n               llvm::Function *entry = nullptr);\n\n    // build DependenceGraph for a function. This will automatically\n    // build subgraphs of called functions\n    bool build(llvm::Function *func);\n\n    LLVMDGParameters *getOrCreateParameters();\n    LLVMNode *getOrCreateNoReturn();\n    LLVMNode *getOrCreateNoReturn(LLVMNode *call);\n    LLVMNode *getNoReturn() {\n        auto *params = getParameters();\n        return params ? params->getNoReturn() : nullptr;\n    }\n\n    bool addFormalParameter(llvm::Value *val);\n    bool addFormalGlobal(llvm::Value *val);\n\n    llvm::Module *getModule() const { return module; }\n\n    // if we want to slice according some call-site(s),\n    // we can gather the relevant call-sites while building\n    // graph and do not need to recursively find in the graph\n    // later. This can handle only direct-calls though. If the\n    // function is called via pointer, it won't be covered by this\n    // function\n    void gatherCallsites(const char *name, std::set<LLVMNode *> *callSites) {\n        gather_callsites = name;\n        gatheredCallsites = callSites;\n    }\n\n    // go through the graph and find all (possible) call-sites\n    // for a function\n    // FIXME: can implement via getCallNodes\n    bool getCallSites(const char *name, std::set<LLVMNode *> *callsites);\n    // this method takes NULL-terminated array of names\n    static bool getCallSites(const char *names[],\n                             std::set<LLVMNode *> *callsites);\n    static bool getCallSites(const std::vector<std::string> &names,\n                             std::set<LLVMNode *> *callsites);\n\n    // FIXME we need remove the callsite from here if we slice away\n    // the callsite\n    const std::set<LLVMNode *> &getCallNodes() const { return callNodes; }\n    std::set<LLVMNode *> &getCallNodes() { return callNodes; }\n    bool addCallNode(LLVMNode *c) { return callNodes.insert(c).second; }\n\n    // build subgraph for a call node\n    LLVMDependenceGraph *buildSubgraph(LLVMNode *node);\n    LLVMDependenceGraph *buildSubgraph(LLVMNode *node,\n                                       llvm::Function * /*callFunc*/,\n                                       bool fork = false);\n    void addSubgraphGlobalParameters(LLVMDependenceGraph *subgraph);\n\n    static void addNoreturnDependencies(LLVMNode *noret, LLVMBBlock *from);\n    void\n    addNoreturnDependencies(const LLVMControlDependenceAnalysisOptions &opts);\n\n    void computeControlDependencies(\n            const LLVMControlDependenceAnalysisOptions &opts);\n\n    bool verify() const;\n\n    void setThreads(bool threads);\n\n    /* virtual */\n    void setSlice(uint64_t sid) override {\n        DependenceGraph<LLVMNode>::setSlice(sid);\n        LLVMNode *entry = getEntry();\n        assert(entry);\n\n        // mark even entry node, call-sites are\n        // control dependent on it\n        entry->setSlice(sid);\n    }\n\n    LLVMPointerAnalysis *getPTA() const { return PTA; }\n    LLVMDataDependenceAnalysis *getDDA() const { return DDA; }\n\n    LLVMNode *findNode(llvm::Value *value) const;\n\n    void addDefUseEdges(bool preserveDbg = true);\n    void computeInterferenceDependentEdges(ControlFlowGraph *controlFlowGraph);\n    static void computeForkJoinDependencies(ControlFlowGraph *controlFlowGraph);\n    static void computeCriticalSections(ControlFlowGraph *controlFlowGraph);\n\n  private:\n    void computePostDominators(bool addPostDomFrontiers = false);\n    void computeNonTerminationControlDependencies();\n    void computeNTSCD(const LLVMControlDependenceAnalysisOptions &opts);\n\n    void computeInterferenceDependentEdges(\n            const std::set<const llvm::Instruction *> &loads,\n            const std::set<const llvm::Instruction *> &stores);\n\n    std::set<const llvm::Instruction *> getLoadInstructions(\n            const std::set<const llvm::Instruction *> &llvmInstructions) const;\n    std::set<const llvm::Instruction *> getStoreInstructions(\n            const std::set<const llvm::Instruction *> &llvmInstructions) const;\n\n    static std::set<const llvm::Instruction *> getInstructionsOfType(\n            unsigned opCode,\n            const std::set<const llvm::Instruction *> &llvmInstructions);\n\n    // add formal parameters of the function to the graph\n    // (graph is a graph of one procedure)\n    void addFormalParameters();\n\n    // take action specific to given instruction (while building\n    // the graph). This is like if the value is a call-site,\n    // then build subgraph or similar\n    void handleInstruction(llvm::Value *val, LLVMNode *node,\n                           LLVMNode *prevNode);\n\n    // convert llvm basic block to our basic block\n    // That includes creating all the nodes and adding them\n    // to this graph and creating the basic block and\n    // setting first and last instructions\n    LLVMBBlock *build(llvm::BasicBlock &BB);\n\n    // gather call-sites of functions with given name\n    // when building the graph\n    std::set<LLVMNode *> *gatheredCallsites;\n    const char *gather_callsites{nullptr};\n\n    bool threads{false};\n\n    // all callnodes in this graph - forming call graph\n    std::set<LLVMNode *> callNodes;\n\n    // when we want to slice according to some criterion,\n    // we may gather the call-sites (good points for criterions)\n    // while building the graph\n    llvm::Module *module{nullptr};\n\n    // analyses needed for building the graph\n    LLVMPointerAnalysis *PTA{nullptr};\n    LLVMDataDependenceAnalysis *DDA;\n    // LLVMControlDependenceAnalysis *CDA;\n\n    // verifier needs access to private elements\n    friend class LLVMDGVerifier;\n};\n\nconst std::map<llvm::Value *, LLVMDependenceGraph *> &getConstructedFunctions();\n\nLLVMNode *findInstruction(llvm::Instruction *instruction,\n                          const std::map<llvm::Value *, LLVMDependenceGraph *>\n                                  &constructedFunctions);\n\nllvm::Instruction *castToLLVMInstruction(const llvm::Value *value);\n} // namespace dg\n\n#endif // DEPENDENCE_GRAPH_H_\n"
  },
  {
    "path": "include/dg/llvm/LLVMDependenceGraphBuilder.h",
    "content": "#ifndef DG_LLVM_DEPENDENCE_GRAPH_BUILDER_H_\n#define DG_LLVM_DEPENDENCE_GRAPH_BUILDER_H_\n\n#include <ctime> // std::clock\n#include <string>\n\n#include <llvm/IR/Module.h>\n\n#include \"dg/llvm/ControlDependence/ControlDependence.h\"\n#include \"dg/llvm/ControlDependence/LLVMControlDependenceAnalysisOptions.h\"\n#include \"dg/llvm/DataDependence/DataDependence.h\"\n#include \"dg/llvm/DataDependence/LLVMDataDependenceAnalysisOptions.h\"\n#include \"dg/llvm/LLVMDependenceGraph.h\"\n#include \"dg/llvm/PointerAnalysis/LLVMPointerAnalysisOptions.h\"\n\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n#ifdef HAVE_SVF\n#include \"dg/llvm/PointerAnalysis/SVFPointerAnalysis.h\"\n#endif\n#include \"dg/Offset.h\"\n#include \"dg/PointerAnalysis/Pointer.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFI.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFS.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFSInv.h\"\n\n#include \"dg/llvm/ThreadRegions/ControlFlowGraph.h\"\n\nnamespace llvm {\nclass Module;\nclass Function;\n} // namespace llvm\n\nnamespace dg {\nnamespace llvmdg {\n\nstruct LLVMDependenceGraphOptions {\n    LLVMPointerAnalysisOptions PTAOptions{};\n    LLVMDataDependenceAnalysisOptions DDAOptions{};\n    LLVMControlDependenceAnalysisOptions CDAOptions{};\n\n    bool verifyGraph{true};\n    bool threads{false};\n    bool preserveDbg{true};\n\n    std::string entryFunction{\"main\"};\n\n    void addAllocationFunction(const std::string &name, AllocationFunction F) {\n        PTAOptions.addAllocationFunction(name, F);\n        DDAOptions.addAllocationFunction(name, F);\n    }\n};\n\nclass LLVMDependenceGraphBuilder {\n    llvm::Module *_M;\n    const LLVMDependenceGraphOptions _options;\n    std::unique_ptr<LLVMPointerAnalysis> _PTA{};\n    std::unique_ptr<LLVMDataDependenceAnalysis> _DDA{nullptr};\n    std::unique_ptr<LLVMControlDependenceAnalysis> _CDA{nullptr};\n    std::unique_ptr<LLVMDependenceGraph> _dg{};\n    std::unique_ptr<ControlFlowGraph> _controlFlowGraph{};\n    llvm::Function *_entryFunction{nullptr};\n\n    struct Statistics {\n        uint64_t cdaTime{0};\n        uint64_t ptaTime{0};\n        uint64_t rdaTime{0};\n        uint64_t inferaTime{0};\n        uint64_t joinsTime{0};\n        uint64_t critsecTime{0};\n    } _statistics;\n\n    std::clock_t _time_start;\n    void _timerStart() { _time_start = std::clock(); }\n    uint64_t _timerEnd() const { return (std::clock() - _time_start); }\n\n    void _runPointerAnalysis() {\n        assert(_PTA && \"BUG: No PTA\");\n\n        _timerStart();\n        _PTA->run();\n        _statistics.ptaTime = _timerEnd();\n    }\n\n    void _runDataDependenceAnalysis() {\n        assert(_DDA && \"BUG: No RD\");\n\n        _timerStart();\n        _DDA->run();\n        _statistics.rdaTime = _timerEnd();\n    }\n\n    void _runControlDependenceAnalysis() {\n        _timerStart();\n        //_CDA->run();\n        // FIXME: until we get rid of the legacy code,\n        // use the old way of inserting CD edges directly\n        // into the dg\n        _dg->computeControlDependencies(_options.CDAOptions);\n        _statistics.cdaTime = _timerEnd();\n    }\n\n    void _runInterferenceDependenceAnalysis() {\n        _timerStart();\n        _dg->computeInterferenceDependentEdges(_controlFlowGraph.get());\n        _statistics.inferaTime = _timerEnd();\n    }\n\n    void _runForkJoinAnalysis() {\n        _timerStart();\n        _dg->computeForkJoinDependencies(_controlFlowGraph.get());\n        _statistics.joinsTime = _timerEnd();\n    }\n\n    void _runCriticalSectionAnalysis() {\n        _timerStart();\n        _dg->computeCriticalSections(_controlFlowGraph.get());\n        _statistics.critsecTime = _timerEnd();\n    }\n\n    bool verify() const { return _dg->verify(); }\n\n  public:\n    LLVMDependenceGraphBuilder(llvm::Module *M)\n            : LLVMDependenceGraphBuilder(M, {}) {}\n\n    LLVMDependenceGraphBuilder(llvm::Module *M,\n                               const LLVMDependenceGraphOptions &opts)\n            : _M(M), _options(opts), _PTA(createPTA()),\n              _DDA(new LLVMDataDependenceAnalysis(M, _PTA.get(),\n                                                  _options.DDAOptions)),\n              _CDA(new LLVMControlDependenceAnalysis(M, _options.CDAOptions)),\n              _dg(new LLVMDependenceGraph(opts.threads)),\n              _controlFlowGraph(\n                      _options.threads && !_options.PTAOptions.isSVF()\n                              ? // check SVF due to the static cast...\n                              new ControlFlowGraph(\n                                      static_cast<DGLLVMPointerAnalysis *>(\n                                              _PTA.get()))\n                              : nullptr),\n              _entryFunction(M->getFunction(_options.entryFunction)) {\n        assert(_entryFunction && \"The entry function not found\");\n    }\n\n    LLVMPointerAnalysis *createPTA() {\n#ifdef HAVE_SVF\n        if (_options.PTAOptions.isSVF())\n            return new SVFPointerAnalysis(_M, _options.PTAOptions);\n#endif\n\n        return new DGLLVMPointerAnalysis(_M, _options.PTAOptions);\n    }\n\n    LLVMPointerAnalysis *getPTA() { return _PTA.get(); }\n    LLVMDataDependenceAnalysis *getDDA() { return _DDA.get(); }\n\n    const Statistics &getStatistics() const { return _statistics; }\n\n    // construct the whole graph with all edges\n    std::unique_ptr<LLVMDependenceGraph> &&build() {\n        // compute data dependencies\n        _runPointerAnalysis();\n        _runDataDependenceAnalysis();\n\n        // build the graph itself (the nodes, but without edges)\n        _dg->build(_M, _PTA.get(), _DDA.get(), _entryFunction);\n\n        // insert the data dependencies edges\n        _dg->addDefUseEdges(_options.preserveDbg);\n\n        // compute and fill-in control dependencies\n        _runControlDependenceAnalysis();\n\n        if (_options.threads) {\n            if (_options.PTAOptions.isSVF()) {\n                assert(0 && \"Threading needs the DG pointer analysis, SVF is \"\n                            \"not supported yet\");\n                abort();\n            }\n            _controlFlowGraph->buildFunction(_entryFunction);\n            _runInterferenceDependenceAnalysis();\n            _runForkJoinAnalysis();\n            _runCriticalSectionAnalysis();\n        }\n\n        // verify if the graph is built correctly\n        if (_options.verifyGraph && !_dg->verify()) {\n            _dg.reset();\n            return std::move(_dg);\n        }\n\n        return std::move(_dg);\n    }\n\n    // Build only the graph with CFG edges.\n    // No dependencies between instructions are added.\n    // The dependencies must be filled in by calling computeDependencies()\n    // later.\n    // NOTE: this function still runs pointer analysis as it is needed\n    // for sound construction of CFG in the presence of function pointer calls.\n    std::unique_ptr<LLVMDependenceGraph> &&constructCFGOnly() {\n        // data dependencies\n        _runPointerAnalysis();\n\n        // build the graph itself\n        _dg->build(_M, _PTA.get(), _DDA.get(), _entryFunction);\n\n        if (_options.threads) {\n            _controlFlowGraph->buildFunction(_entryFunction);\n        }\n\n        // verify if the graph is built correctly\n        if (_options.verifyGraph && !_dg->verify()) {\n            _dg.reset();\n            return std::move(_dg);\n        }\n\n        return std::move(_dg);\n    }\n\n    // This method serves to finish the graph construction\n    // after constructCFGOnly was used to build the graph.\n    // This function takes the dg (returned from the constructCFGOnly)\n    // and retains its ownership until it computes the edges.\n    // Then it returns the ownership back to the caller.\n    std::unique_ptr<LLVMDependenceGraph> &&\n    computeDependencies(std::unique_ptr<LLVMDependenceGraph> &&dg) {\n        // get the ownership\n        _dg = std::move(dg);\n\n        // data-dependence edges\n        _runDataDependenceAnalysis();\n        _dg->addDefUseEdges(_options.preserveDbg);\n\n        // fill-in control dependencies\n        _runControlDependenceAnalysis();\n\n        if (_options.threads) {\n            _runInterferenceDependenceAnalysis();\n            _runForkJoinAnalysis();\n            _runCriticalSectionAnalysis();\n        }\n\n        return std::move(_dg);\n    }\n};\n\n} // namespace llvmdg\n} // namespace dg\n\n#endif // DG_LLVM_DEPENDENCE_GRAPH_BUILDER_H_\n"
  },
  {
    "path": "include/dg/llvm/LLVMNode.h",
    "content": "#ifndef LLVM_NODE_H_\n#define LLVM_NODE_H_\n\n#include <map>\n#include <set>\n#include <utility>\n\n#include <llvm/IR/Type.h>\n#include <llvm/IR/Value.h>\n\n#include \"dg/Node.h\"\n\nnamespace dg {\n\nclass LLVMDependenceGraph;\nclass LLVMNode;\n\nusing LLVMBBlock = dg::BBlock<LLVMNode>;\nusing LLVMDGParameter = dg::DGParameterPair<LLVMNode>;\nusing LLVMDGParameters = dg::DGParameters<LLVMNode>;\n\n/// ------------------------------------------------------------------\n//  -- LLVMNode\n/// ------------------------------------------------------------------\nclass LLVMNode : public Node<LLVMDependenceGraph, llvm::Value *, LLVMNode> {\n#if LLVM_VERSION_MAJOR >= 5\n    struct LLVMValueDeleter {\n        void operator()(llvm::Value *val) const { val->deleteValue(); }\n    };\n#endif\n\n  public:\n    LLVMNode(llvm::Value *val, bool owns_value = false)\n            : dg::Node<LLVMDependenceGraph, llvm::Value *, LLVMNode>(val) {\n        if (owns_value)\n#if LLVM_VERSION_MAJOR >= 5\n            owned_key = std::unique_ptr<llvm::Value, LLVMValueDeleter>(val);\n#else\n            owned_key = std::unique_ptr<llvm::Value>(val);\n#endif\n    }\n\n    LLVMNode(llvm::Value *val, LLVMDependenceGraph *dg) : LLVMNode(val) {\n        setDG(dg);\n    }\n\n    LLVMDGParameters *getOrCreateParameters() {\n        auto *params = getParameters();\n        if (!params) {\n            params = new LLVMDGParameters(this);\n            setParameters(params);\n        }\n        return params;\n    }\n\n    llvm::Value *getValue() const { return getKey(); }\n\n    // create new subgraph with actual parameters that are given\n    // by call-site and add parameter edges between actual and\n    // formal parameters. The argument is the graph of called function.\n    // Must be called only when node is call-site.\n    void addActualParameters(LLVMDependenceGraph * /*funcGraph*/);\n    void addActualParameters(LLVMDependenceGraph * /*funcGraph*/,\n                             llvm::Function * /*func*/, bool fork = false);\n\n    bool isVoidTy() const { return getKey()->getType()->isVoidTy(); }\n\n  private:\n    // the owned key will be deleted with this node\n#if LLVM_VERSION_MAJOR >= 5\n    std::unique_ptr<llvm::Value, LLVMValueDeleter> owned_key;\n#else\n    std::unique_ptr<llvm::Value> owned_key;\n#endif\n};\n\n} // namespace dg\n\n#endif // LLVM_NODE_H_\n"
  },
  {
    "path": "include/dg/llvm/LLVMSlicer.h",
    "content": "#ifndef LLVM_DG_SLICER_H_\n#define LLVM_DG_SLICER_H_\n\n#include <llvm/Config/llvm-config.h>\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n#include <llvm/Support/CFG.h>\n#else\n#include <llvm/IR/CFG.h>\n#endif\n\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/GlobalVariable.h>\n#include <llvm/IR/Instruction.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/Value.h>\n#include <llvm/Support/raw_ostream.h>\n\n#include \"dg/Slicing.h\"\n#include \"dg/llvm/LLVMDependenceGraph.h\"\n#include \"dg/llvm/LLVMNode.h\"\n\nnamespace dg {\n\nclass LLVMNode;\n\nextern std::map<const llvm::Value *, LLVMDependenceGraph *>\n        constructedFunctions;\n\nnamespace llvmdg {\n\ntemplate <typename Val>\nstatic void dropAllUses(Val *V) {\n    for (auto I = V->use_begin(), E = V->use_end(); I != E; ++I) {\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n        llvm::Value *use = *I;\n#else\n        llvm::Value *use = I->getUser();\n#endif\n\n        // drop the reference to this value\n        llvm::cast<llvm::Instruction>(use)->replaceUsesOfWith(V, nullptr);\n    }\n}\n\nclass LLVMSlicer : public Slicer<LLVMNode> {\n  public:\n    LLVMSlicer() = default;\n\n    void keepFunctionUntouched(const char *n) { dont_touch.insert(n); }\n\n    bool removeNode(LLVMNode *node) override {\n        using namespace llvm;\n\n        Value *val = node->getKey();\n        // if there are any other uses of this value,\n        // just replace them with undef\n        val->replaceAllUsesWith(UndefValue::get(val->getType()));\n\n        Instruction *Inst = dyn_cast<Instruction>(val);\n        if (Inst) {\n            Inst->eraseFromParent();\n        } else {\n            GlobalVariable *GV = dyn_cast<GlobalVariable>(val);\n            if (GV)\n                GV->eraseFromParent();\n        }\n\n        return true;\n    }\n\n    bool removeBlock(LLVMBBlock *block) override {\n        assert(block);\n\n        llvm::Value *val = block->getKey();\n        if (val == nullptr)\n            return true;\n\n        llvm::BasicBlock *blk = llvm::cast<llvm::BasicBlock>(val);\n        for (const auto &succ : block->successors()) {\n            if (succ.label == LLVMBBlock::ARTIFICIAL_BBLOCK_LABEL)\n                continue;\n\n            // don't adjust phi nodes in this block if this is a self-loop,\n            // we're gonna remove the block anyway\n            if (succ.target == block)\n                continue;\n\n            if (llvm::Value *sval = succ.target->getKey())\n                adjustPhiNodes(llvm::cast<llvm::BasicBlock>(sval), blk);\n        }\n\n        // We need to drop the reference to this block in all\n        // braching instructions that jump to this block.\n        // See #99\n        dropAllUses(blk);\n\n        // we also must drop refrences to instructions that are in\n        // this block (or we would need to delete the blocks in\n        // post-dominator order), see #101\n        for (llvm::Instruction &Inst : *blk)\n            dropAllUses(&Inst);\n\n        // finally, erase the block per se\n        blk->eraseFromParent();\n        return true;\n    }\n\n    // override slice method\n    static uint32_t slice(LLVMNode *start, uint32_t sl_id = 0) {\n        (void) sl_id;\n        (void) start;\n\n        assert(0 && \"Do not use this method with LLVM dg\");\n        return 0;\n    }\n\n    uint32_t slice(LLVMDependenceGraph *dg, LLVMNode *start,\n                   uint32_t sl_id = 0) {\n        // mark nodes for slicing\n        assert(start || sl_id != 0);\n        if (start)\n            sl_id = mark(start, sl_id);\n\n        std::vector<llvm::Function *> to_erase;\n        for (auto &F : *dg->getModule()) {\n            if (dontTouch(F.getName()))\n                continue;\n\n            auto it = constructedFunctions.find(&F);\n            if (it == constructedFunctions.end()) {\n                // remove (defined) functions that we didn't even constructed,\n                // those are irrelevant in the slice\n                if (!F.isDeclaration()) {\n                    to_erase.push_back(&F);\n                }\n            } else {\n                LLVMDependenceGraph *subdg = it->second;\n                sliceGraph(subdg, sl_id);\n            }\n        }\n        for (auto *F : to_erase) {\n            F->replaceAllUsesWith(llvm::UndefValue::get(F->getType()));\n            F->deleteBody();\n            F->eraseFromParent();\n        }\n\n        return sl_id;\n    }\n\n  private:\n    /*\nvoid sliceCallNode(LLVMNode *callNode,\n                   LLVMDependenceGraph *graph, uint32_t slice_id)\n{\n    LLVMDGParameters *actualparams = callNode->getParameters();\n    LLVMDGParameters *formalparams = graph->getParameters();\n\n    if (!actualparams) {\n        assert(!formalparams && \"Have only one of params\");\n        return; // no params - nothing to do\n    }\n\n    assert(formalparams && \"Have only one of params\");\n    assert(formalparams->size() == actualparams->size());\n\n    // FIXME slice arguments away\n}\n\nvoid sliceCallNode(LLVMNode *callNode, uint32_t slice_id)\n{\n    for (LLVMDependenceGraph *subgraph : callNode->getSubgraphs())\n        sliceCallNode(callNode, subgraph, slice_id);\n}\n    */\n\n    static void adjustPhiNodes(llvm::BasicBlock *pred, llvm::BasicBlock *blk) {\n        using namespace llvm;\n\n        for (Instruction &I : *pred) {\n            PHINode *phi = dyn_cast<PHINode>(&I);\n            if (phi) {\n                // don't try remove block that we already removed\n                int idx = phi->getBasicBlockIndex(blk);\n                if (idx < 0)\n                    continue;\n\n                // the second argument is DeletePHIIFEmpty.\n                // We don't want that, since that would make\n                // dependence graph inconsistent. We'll\n                // slice it away later, if it's empty\n                phi->removeIncomingValue(idx, false);\n            } else {\n                // phi nodes are always at the beginning of the block\n                // so if this is the first value that is not PHI,\n                // there won't be any other and we can bail out\n                break;\n            }\n        }\n    }\n\n    static inline bool shouldSliceInst(const llvm::Value *val) {\n        using namespace llvm;\n        const Instruction *Inst = dyn_cast<Instruction>(val);\n        if (!Inst)\n            return true;\n\n        switch (Inst->getOpcode()) {\n        case Instruction::Unreachable:\n#if 0\n            case Instruction::Br:\n            case Instruction::Switch:\n            case Instruction::Ret:\n#endif\n            return false;\n        default:\n            return true;\n        }\n    }\n\n    static LLVMBBlock *createNewExitBB(LLVMDependenceGraph *graph) {\n        using namespace llvm;\n\n        LLVMBBlock *exitBB = new LLVMBBlock();\n\n        Module *M = graph->getModule();\n        LLVMContext &Ctx = M->getContext();\n        BasicBlock *block = BasicBlock::Create(Ctx, \"safe_return\");\n\n        Value *fval = graph->getEntry()->getKey();\n        Function *F = cast<Function>(fval);\n        F->getBasicBlockList().push_back(block);\n\n        // fill in basic block just with return value\n        ReturnInst *RI;\n        if (F->getReturnType()->isVoidTy())\n            RI = ReturnInst::Create(Ctx, block);\n        else if (F->getName().equals(\"main\"))\n            // if this is main, than the safe exit equals to returning 0\n            // (it is just for convenience, we wouldn't need to do this)\n            RI = ReturnInst::Create(\n                    Ctx, ConstantInt::get(Type::getInt32Ty(Ctx), 0), block);\n        else\n            RI = ReturnInst::Create(Ctx, UndefValue::get(F->getReturnType()),\n                                    block);\n\n        LLVMNode *newRet = new LLVMNode(RI);\n        graph->addNode(newRet);\n\n        exitBB->append(newRet);\n        exitBB->setKey(block);\n        exitBB->setDG(graph);\n\n        return exitBB;\n    }\n\n    static LLVMBBlock *addNewExitBB(LLVMDependenceGraph *graph) {\n        // FIXME: don't create new one, create it\n        // when creating graph and just use that one\n        LLVMBBlock *newExitBB = createNewExitBB(graph);\n        graph->setExitBB(newExitBB);\n        graph->setExit(newExitBB->getLastNode());\n        // do not add the block to the graph,\n        // we'll do it at the end of adjustBBlocksSucessors,\n        // because this function is called while iterating\n        // over blocks, so that we won't corrupt the iterator\n\n        return newExitBB;\n    }\n\n    // when we sliced away a branch of CFG, we need to reconnect it\n    // to exit block, since on this path we would silently terminate\n    // (this path won't have any effect on the property anymore)\n    static void adjustBBlocksSucessors(LLVMDependenceGraph *graph,\n                                       uint32_t slice_id) {\n        LLVMBBlock *oldExitBB = graph->getExitBB();\n        assert(oldExitBB && \"Don't have exit BB\");\n\n        LLVMBBlock *newExitBB = nullptr;\n\n        for (auto &it : graph->getBlocks()) {\n            const llvm::BasicBlock *llvmBB =\n                    llvm::cast<llvm::BasicBlock>(it.first);\n            const auto *const tinst = llvmBB->getTerminator();\n            LLVMBBlock *BB = it.second;\n\n            // nothing to do\n            if (BB->successorsNum() == 0)\n                continue;\n\n            // if the BB has two successors and one is self-loop and\n            // the branch inst is going to be removed, then the brach\n            // that created the self-loop has no meaning to the sliced\n            // program and this is going to be an unconditional jump\n            // to the other branch\n            // NOTE: do this before the next action, to rename the label if\n            // needed\n            if (BB->successorsNum() == 2 &&\n                BB->getLastNode()->getSlice() != slice_id &&\n                !BB->successorsAreSame() && BB->hasSuccessor(BB)) {\n                bool found = BB->removeSuccessorsTarget(BB);\n                // we have two different successors, none of them\n                // is self-loop and we're slicing away the brach inst?\n                // This should not happen...\n                if (!found) {\n                    assert(found && \"Self loop did not have self loop...\");\n                    abort();\n                }\n                assert(BB->successorsNum() == 1 &&\n                       \"Should have only one successor\");\n\n                // continue here to rename the only label if needed\n            }\n\n            // if the BB has only one successor and the terminator\n            // instruction is going to be sliced away, it means that\n            // this is going to be an unconditional jump,\n            // so just make the label 0\n            if (BB->successorsNum() == 1 &&\n                BB->getLastNode()->getSlice() != slice_id) {\n                auto edge = *(BB->successors().begin());\n\n                // modify the edge\n                edge.label = 0;\n                if (edge.target == oldExitBB) {\n                    if (!newExitBB)\n                        newExitBB = addNewExitBB(graph);\n\n                    edge.target = newExitBB;\n                }\n\n                // replace the only edge\n                BB->removeSuccessors();\n                BB->addSuccessor(edge);\n\n                continue;\n            }\n\n            // when we have more successors, we need to fill in\n            // jumps under labels that we sliced away\n\n            DGContainer<uint8_t> labels;\n            // go through BBs successors and gather all labels\n            // from edges that go from this BB. Also if there's\n            // a jump to return block, replace it with new\n            // return block\n            for (const auto &succ : BB->successors()) {\n                // skip artificial return basic block.\n                if (succ.label == LLVMBBlock::ARTIFICIAL_BBLOCK_LABEL ||\n                    succ.target == oldExitBB)\n                    continue;\n\n                labels.insert(succ.label);\n            }\n\n            // replace missing labels. Label should be from 0 to some max,\n            // no gaps, so jump to safe exit under missing labels\n            for (unsigned i = 0; i < tinst->getNumSuccessors(); ++i) {\n                if (!labels.contains(i)) {\n                    if (!newExitBB)\n                        newExitBB = addNewExitBB(graph);\n\n#ifndef NDEBUG\n                    bool ret =\n#endif\n                            BB->addSuccessor(newExitBB, i);\n                    assert(ret && \"Already had this CFG edge, that is wrong\");\n                }\n            }\n\n            // this BB is going to be removed\n            if (newExitBB)\n                BB->removeSuccessorsTarget(oldExitBB);\n\n            // if we have all successor edges pointing to the same\n            // block, replace them with one successor (thus making\n            // unconditional jump)\n            if (BB->successorsNum() > 1 && BB->successorsAreSame()) {\n                LLVMBBlock *succ = BB->successors().begin()->target;\n\n                BB->removeSuccessors();\n                BB->addSuccessor(succ, 0);\n#ifdef NDEBUG\n                assert(BB->successorsNum() == 1 &&\n                       \"BUG: in removeSuccessors() or addSuccessor()\");\n#endif\n            }\n\n#ifndef NDEBUG\n            // check the BB\n            labels.clear();\n            for (const auto &succ : BB->successors()) {\n                assert((!newExitBB || succ.target != oldExitBB) &&\n                       \"A block has the old BB as successor\");\n                // we can have more labels with different targets,\n                // but we can not have one target with more labels\n                assert(labels.insert(succ.label) && \"Already have a label\");\n            }\n\n            // check that we have all labels without any gep\n            auto l = labels.begin();\n            for (unsigned i = 0; i < labels.size(); ++i) {\n                // set is ordered, so this must hold\n                assert((*l == LLVMBBlock::MAX_BBLOCK_LABEL || i == *l++) &&\n                       \"Labels have a gap\");\n            }\n#endif\n        }\n\n        if (newExitBB) {\n            graph->addBlock(newExitBB->getKey(), newExitBB);\n            assert(graph->getExitBB() == newExitBB);\n            // NOTE: do not delete the old block\n            // because it is the unified BB that is kept in\n            // unique_ptr, so it will be deleted later automatically.\n            // Deleting it would lead to double-free\n        }\n    }\n\n    void sliceGraph(LLVMDependenceGraph *graph, uint32_t slice_id) {\n        // first slice away bblocks that should go away\n        sliceBBlocks(graph, slice_id);\n\n        // make graph complete\n        adjustBBlocksSucessors(graph, slice_id);\n\n        // now slice away instructions from BBlocks that left\n        for (auto I = graph->begin(), E = graph->end(); I != E;) {\n            LLVMNode *n = I->second;\n            // shift here, so that we won't corrupt the iterator\n            // by deleteing the node\n            ++I;\n\n            // we added this node artificially and\n            // we don't want to slice it away or\n            // take any other action on it\n            if (n == graph->getExit())\n                continue;\n\n            ++statistics.nodesTotal;\n\n            // keep instructions like ret or unreachable\n            // FIXME: if this is ret of some value, then\n            // the value is undef now, so we should\n            // replace it by void ref\n            if (!shouldSliceInst(n->getKey()))\n                continue;\n\n            /*\n            if (llvm::isa<llvm::CallInst>(n->getKey()))\n                sliceCallNode(n, slice_id);\n                */\n\n            if (n->getSlice() != slice_id) {\n                removeNode(n);\n                graph->deleteNode(n);\n                ++statistics.nodesRemoved;\n            }\n        }\n\n        // create new CFG edges between blocks after slicing\n        reconnectLLLVMBasicBlocks(graph);\n\n        // if we sliced away entry block, our new entry block\n        // may have predecessors, which is not allowed in the\n        // LLVM\n        ensureEntryBlock(graph);\n    }\n\n    bool dontTouch(const llvm::StringRef &r) {\n        for (const char *n : dont_touch)\n            if (r.equals(n))\n                return true;\n\n        return false;\n    }\n\n    static void reconnectBBlock(LLVMBBlock *BB, llvm::BasicBlock *llvmBB) {\n        using namespace llvm;\n\n        auto *tinst = llvmBB->getTerminator();\n        assert((!tinst || BB->successorsNum() <= 2 ||\n                llvm::isa<llvm::SwitchInst>(tinst)) &&\n               \"BB has more than two successors (and it's not a switch)\");\n\n        if (!tinst) {\n            // block has no terminator\n            // It may occur for example if we have:\n            //\n            //   call error()\n            //   br %exit\n            //\n            //  The br instruction has no meaning when error() abort,\n            //  but if error is not marked as noreturn, then the br\n            //  will be there and will get sliced, making the block\n            //  unterminated. The same may happen if we remove unconditional\n            //  branch inst\n\n            LLVMContext &Ctx = llvmBB->getContext();\n            Function *F = cast<Function>(llvmBB->getParent());\n            bool create_return = true;\n\n            if (BB->successorsNum() == 1) {\n                const LLVMBBlock::BBlockEdge &edge =\n                        *(BB->successors().begin());\n                if (edge.label != LLVMBBlock::ARTIFICIAL_BBLOCK_LABEL) {\n                    // don't create return, we created branchinst\n                    create_return = false;\n\n                    BasicBlock *succ = cast<BasicBlock>(edge.target->getKey());\n                    BranchInst::Create(succ, llvmBB);\n                }\n            }\n\n            if (create_return) {\n                if (BB->successorsNum() != 0) {\n                    assert(BB->successorsNum() == 0 &&\n                           \"Creating return to BBlock that has successors\");\n                    abort();\n                }\n\n                if (F->getReturnType()->isVoidTy())\n                    ReturnInst::Create(Ctx, llvmBB);\n                else if (F->getName().equals(\"main\"))\n                    // if this is main, than the safe exit equals to returning 0\n                    // (it is just for convenience, we wouldn't need to do this)\n                    ReturnInst::Create(\n                            Ctx, ConstantInt::get(Type::getInt32Ty(Ctx), 0),\n                            llvmBB);\n                else\n                    ReturnInst::Create(Ctx, UndefValue::get(F->getReturnType()),\n                                       llvmBB);\n            }\n\n            // and that is all we can do here\n            return;\n        }\n\n        for (const LLVMBBlock::BBlockEdge &succ : BB->successors()) {\n            // skip artificial return basic block\n            if (succ.label == LLVMBBlock::ARTIFICIAL_BBLOCK_LABEL)\n                continue;\n\n            llvm::Value *val = succ.target->getKey();\n            assert(val && \"nullptr as BB's key\");\n            llvm::BasicBlock *llvmSucc = llvm::cast<llvm::BasicBlock>(val);\n            tinst->setSuccessor(succ.label, llvmSucc);\n        }\n\n        // if the block still does not have terminator\n    }\n\n    static void reconnectLLLVMBasicBlocks(LLVMDependenceGraph *graph) {\n        for (auto &it : graph->getBlocks()) {\n            llvm::BasicBlock *llvmBB = llvm::cast<llvm::BasicBlock>(it.first);\n            LLVMBBlock *BB = it.second;\n\n            reconnectBBlock(BB, llvmBB);\n        }\n    }\n\n    static void ensureEntryBlock(LLVMDependenceGraph *graph) {\n        using namespace llvm;\n\n        Value *val = graph->getEntry()->getKey();\n        Function *F = cast<Function>(val);\n\n        // Function is empty, just bail out\n        if (F->begin() == F->end())\n            return;\n\n        BasicBlock *entryBlock = &F->getEntryBlock();\n\n        if (pred_begin(entryBlock) == pred_end(entryBlock)) {\n            // entry block has no predecessor, we're ok\n            return;\n        }\n\n        // it has some predecessor, create new one, that will just\n        // jump on it\n        LLVMContext &Ctx = graph->getModule()->getContext();\n        BasicBlock *block = BasicBlock::Create(Ctx, \"single_entry\");\n\n        // jump to the old entry block\n        BranchInst::Create(entryBlock, block);\n\n        // set it as a new entry by pusing the block to the front\n        // of the list\n        F->getBasicBlockList().push_front(block);\n\n        // FIXME: propagate this change to dependence graph\n    }\n\n    // do not slice these functions at all\n    std::set<const char *> dont_touch;\n};\n\n} // namespace llvmdg\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/llvm/PointerAnalysis/DGPointerAnalysis.h",
    "content": "#ifndef LLVM_DG_POINTS_TO_ANALYSIS_H_\n#define LLVM_DG_POINTS_TO_ANALYSIS_H_\n\n#include <llvm/IR/DataLayout.h>\n#include <llvm/IR/Function.h>\n#include <llvm/Support/raw_ostream.h>\n\n#include \"dg/PointerAnalysis/Pointer.h\"\n#include \"dg/PointerAnalysis/PointerAnalysis.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFI.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFS.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFSInv.h\"\n#include \"dg/PointerAnalysis/PointerGraph.h\"\n#include \"dg/PointerAnalysis/PointerGraphOptimizations.h\"\n\n#include \"dg/llvm/PointerAnalysis/LLVMPointerAnalysisOptions.h\"\n#include \"dg/llvm/PointerAnalysis/LLVMPointsToSet.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n#include \"dg/llvm/PointerAnalysis/PointerGraph.h\"\n\nnamespace dg {\n\nusing analysis::LLVMPointerAnalysisOptions;\nusing analysis::Offset;\nusing analysis::pta::LLVMPointerGraphBuilder;\nusing analysis::pta::Pointer;\nusing analysis::pta::PointerGraph;\nusing analysis::pta::PSNode;\n\ntemplate <typename PTType>\nclass DGLLVMPointerAnalysisImpl : public PTType {\n    LLVMPointerGraphBuilder *builder;\n\n  public:\n    DGLLVMPointerAnalysisImpl(PointerGraph *PS, LLVMPointerGraphBuilder *b)\n            : PTType(PS), builder(b) {}\n\n    DGLLVMPointerAnalysisImpl(PointerGraph *PS, LLVMPointerGraphBuilder *b,\n                              const LLVMPointerAnalysisOptions &opts)\n            : PTType(PS, opts), builder(b) {}\n\n    // build new subgraphs on calls via pointer\n    bool functionPointerCall(PSNode *callsite, PSNode *called) override {\n        using namespace analysis::pta;\n        const llvm::Function *F = llvm::dyn_cast<llvm::Function>(\n                called->getUserData<llvm::Value>());\n        // with vararg it may happen that we get pointer that\n        // is not to function, so just bail out here in that case\n        if (!F)\n            return false;\n\n        if (F->isDeclaration()) {\n            if (builder->threads()) {\n                if (F->getName() == \"pthread_create\") {\n                    builder->insertPthreadCreateByPtrCall(callsite);\n                    return true;\n                } else if (F->getName() == \"pthread_join\") {\n                    builder->insertPthreadJoinByPtrCall(callsite);\n                    return true;\n                }\n            }\n            return callsite->getPairedNode()->addPointsTo(\n                    analysis::pta::UnknownPointer);\n        }\n\n        if (!LLVMPointerGraphBuilder::callIsCompatible(callsite, called)) {\n            return false;\n        }\n\n        builder->insertFunctionCall(callsite, called);\n\n        // call the original handler that works on generic graphs\n        PTType::functionPointerCall(callsite, called);\n\n#ifndef NDEBUG\n        // check the graph after rebuilding, but do not check for connectivity,\n        // because we can call a function that will disconnect the graph\n        if (!builder->validateSubgraph(true)) {\n            llvm::errs() << \"Pointer Subgraph is broken!\\n\";\n            llvm::errs() << \"This happend after building this function called \"\n                            \"via pointer: \"\n                         << F->getName() << \"\\n\";\n            abort();\n        }\n#endif // NDEBUG\n\n        return true; // we changed the graph\n    }\n\n    bool handleFork(PSNode *forkNode, PSNode *called) override {\n        using namespace llvm;\n        using namespace dg::analysis::pta;\n\n        assert(called->getType() == PSNodeType::FUNCTION &&\n               \"The called value is not a function\");\n\n        PSNodeFork *fork = PSNodeFork::get(forkNode);\n        builder->addFunctionToFork(called, fork);\n\n#ifndef NDEBUG\n        // check the graph after rebuilding, but do not check for connectivity,\n        // because we can call a function that will disconnect the graph\n        if (!builder->validateSubgraph(true)) {\n            const llvm::Function *F = llvm::cast<llvm::Function>(\n                    called->getUserData<llvm::Value>());\n            llvm::errs() << \"Pointer Subgraph is broken!\\n\";\n            llvm::errs() << \"This happend after building this function spawned \"\n                            \"in a thread: \"\n                         << F->getName() << \"\\n\";\n            abort();\n        }\n#endif // NDEBUG\n\n        return true;\n    }\n\n    bool handleJoin(PSNode *joinNode) override {\n        return builder->matchJoinToRightCreate(joinNode);\n    }\n};\n\nclass DGLLVMPointerAnalysis : public LLVMPointerAnalysis {\n    PointerGraph *PS = nullptr;\n    std::unique_ptr<LLVMPointerGraphBuilder> _builder;\n\n    LLVMPointerAnalysisOptions createOptions(const char *entry_func,\n                                             uint64_t field_sensitivity,\n                                             bool threads = false) {\n        LLVMPointerAnalysisOptions opts;\n        opts.threads = threads;\n        opts.setFieldSensitivity(field_sensitivity);\n        opts.setEntryFunction(entry_func);\n        return opts;\n    }\n\n    const PointsToSetT &getUnknownPTSet() const {\n        static const PointsToSetT _unknownPTSet =\n                PointsToSetT({Pointer{analysis::pta::UNKNOWN_MEMORY, 0}});\n        return _unknownPTSet;\n    }\n\n  public:\n    DGLLVMPointerAnalysis(const llvm::Module *m,\n                          const char *entry_func = \"main\",\n                          uint64_t field_sensitivity = Offset::UNKNOWN,\n                          bool threads = false)\n            : DGLLVMPointerAnalysis(\n                      m,\n                      createOptions(entry_func, field_sensitivity, threads)) {}\n\n    DGLLVMPointerAnalysis(const llvm::Module *m,\n                          const LLVMPointerAnalysisOptions opts)\n            : LLVMPointerAnalysis(opts),\n              _builder(new LLVMPointerGraphBuilder(m, opts)) {}\n\n    ///\n    // Get the node from pointer analysis that holds the points-to set.\n    // See: getLLVMPointsTo()\n    PSNode *getPointsTo(const llvm::Value *val) const {\n        return _builder->getPointsTo(val);\n    }\n\n    inline bool threads() const { return _builder->threads(); }\n\n    ///\n    // Get the points-to information for the given LLVM value.\n    // The return object has methods begin(), end() that can be used\n    // for iteration over (llvm::Value *, Offset) pairs of the\n    // points-to set. Moreover, the object has methods hasUnknown()\n    // and hasNull() that reflect whether the points-to set of the\n    // LLVM value contains unknown element of null.\n    LLVMPointsToSet getLLVMPointsTo(const llvm::Value *val) override {\n        if (auto node = getPointsTo(val))\n            return LLVMPointsToSet(node->pointsTo);\n        else\n            return LLVMPointsToSet(getUnknownPTSet());\n    }\n\n    ///\n    // This method is the same as getLLVMPointsTo, but it returns\n    // also the information whether the node of pointer analysis exists\n    // (opposed to the getLLVMPointsTo, which returns a set with\n    // unknown element when the node does not exists)\n    std::pair<bool, LLVMPointsToSet>\n    getLLVMPointsToChecked(const llvm::Value *val) override {\n        if (auto node = getPointsTo(val))\n            return {true, LLVMPointsToSet(node->pointsTo)};\n        else\n            return {false, LLVMPointsToSet(getUnknownPTSet())};\n    }\n\n    const std::vector<std::unique_ptr<PSNode>> &getNodes() {\n        return PS->getNodes();\n    }\n\n    std::vector<PSNode *> getFunctionNodes(const llvm::Function *F) const {\n        return _builder->getFunctionNodes(F);\n    }\n\n    PointerGraph *getPS() { return PS; }\n    const PointerGraph *getPS() const { return PS; }\n\n    LLVMPointerGraphBuilder *getBuilder() { return _builder.get(); }\n    const LLVMPointerGraphBuilder *getBuilder() const { return _builder.get(); }\n\n    bool run() override {\n        if (options.isFSInv())\n            _builder->setInvalidateNodesFlag(true);\n\n        buildSubgraph();\n\n        bool ret = false;\n        if (options.isFS()) {\n            // FIXME: make a interface with run() method\n            DGLLVMPointerAnalysisImpl<analysis::pta::PointerAnalysisFS> PTA(\n                    PS, _builder.get());\n            ret = PTA.run();\n        } else if (options.isFI()) {\n            DGLLVMPointerAnalysisImpl<analysis::pta::PointerAnalysisFI> PTA(\n                    PS, _builder.get());\n            ret = PTA.run();\n        } else if (options.isFSInv()) {\n            DGLLVMPointerAnalysisImpl<analysis::pta::PointerAnalysisFSInv> PTA(\n                    PS, _builder.get());\n            ret = PTA.run();\n        } else {\n            assert(0 && \"Wrong pointer analysis\");\n            abort();\n        }\n\n        return ret;\n    }\n\n    // this method creates PointerAnalysis object and returns it.\n    // It is alternative to run() method, but it does not delete all\n    // the analysis data as the run() (like memory objects and so on).\n    // run() preserves only PointerGraph and the builder\n    template <typename PTType>\n    analysis::pta::PointerAnalysis *createPTA() {\n        buildSubgraph();\n        return new DGLLVMPointerAnalysisImpl<PTType>(PS, _builder.get());\n    }\n};\n\n} // namespace dg\n\n#endif // _LLVM_DG_POINTS_TO_ANALYSIS_H_\n"
  },
  {
    "path": "include/dg/llvm/PointerAnalysis/LLVMPointerAnalysisOptions.h",
    "content": "#ifndef DG_LLVM_POINTER_ANALYSIS_OPTIONS_H_\n#define DG_LLVM_POINTER_ANALYSIS_OPTIONS_H_\n\n#include \"dg/PointerAnalysis/PointerAnalysisOptions.h\"\n#include \"dg/llvm/LLVMAnalysisOptions.h\"\n\nnamespace dg {\n\nstruct LLVMPointerAnalysisOptions : public LLVMAnalysisOptions,\n                                    PointerAnalysisOptions {\n    enum class AnalysisType { fi, fs, inv, svf } analysisType{AnalysisType::fi};\n\n    bool threads{false};\n\n    bool isFS() const { return analysisType == AnalysisType::fs; }\n    bool isFSInv() const { return analysisType == AnalysisType::inv; }\n    bool isFI() const { return analysisType == AnalysisType::fi; }\n    bool isSVF() const { return analysisType == AnalysisType::svf; }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/llvm/PointerAnalysis/LLVMPointsToSet.h",
    "content": "#ifndef LLVM_DG_POINTS_TO_SET_H_\n#define LLVM_DG_POINTS_TO_SET_H_\n\n#include <cassert>\n#include <utility>\n\n#include <llvm/IR/Value.h>\n\n#include \"dg/PointerAnalysis/PointsToSet.h\"\n\nnamespace dg {\n\nusing pta::PointsToSetT;\nusing pta::PSNode;\n\n///\n// LLVM pointer\n//  - value is the allocation site\n//  - offset is offset into the memory\nstruct LLVMPointer {\n    llvm::Value *value;\n    Offset offset;\n\n    LLVMPointer(llvm::Value *val, Offset o) : value(val), offset(o) {\n        assert(val && \"nullptr passed as value\");\n    }\n\n    bool operator==(const LLVMPointer &rhs) const {\n        return value == rhs.value && offset == rhs.offset;\n    }\n\n    ///\n    // Memory locations described by this pointer cover\n    // (are a supperset) the memory locations of the rhs pointer.\n    bool covers(const LLVMPointer &rhs) const {\n        return value == rhs.value &&\n               (offset.isUnknown() || offset == rhs.offset);\n    }\n};\n\n///\n// LLVM memory region\n// Pointer + length of referenced memory\nstruct LLVMMemoryRegion {\n    LLVMPointer pointer;\n    Offset len;\n\n    LLVMMemoryRegion(LLVMPointer ptr, const Offset l)\n            : pointer(std::move(ptr)), len(l) {}\n\n    LLVMMemoryRegion(llvm::Value *val, const Offset off, const Offset l)\n            : pointer(val, off), len(l) {}\n};\n\n///\n// A set of memory regions\n// XXX: we should create more efficient implementation.\nclass LLVMMemoryRegionSet {\n    struct OffsetPair {\n        const Offset offset{0};\n        const Offset len{0};\n\n        OffsetPair() = default;\n        OffsetPair(const OffsetPair &rhs) = default;\n        OffsetPair(const Offset o, const Offset l) : offset(o), len(l) {}\n\n        bool overlaps(const OffsetPair interval) const {\n            return overlaps(interval.offset, interval.len);\n        }\n\n        bool overlaps(const Offset o, const Offset l) const {\n            if (o.isUnknown() || offset.isUnknown())\n                return true;\n\n            if (o < offset) {\n                if (l.isUnknown() || o + l >= offset) {\n                    return true;\n                }\n            } else {\n                return o <= offset + len;\n            }\n\n            return false;\n        }\n\n        bool coveredBy(const OffsetPair &rhs) const {\n            return coveredBy(rhs.offset, rhs.len);\n        }\n\n        bool coveredBy(const Offset o, const Offset l) const {\n            assert(!o.isUnknown() && !offset.isUnknown());\n            // we allow len == UNKNOWN and treat it as infinity\n\n            return (o <= offset && ((l.isUnknown() && len.isUnknown()) ||\n                                    l.isUnknown() || l >= len));\n        }\n\n        bool extends(const OffsetPair &rhs) const {\n            return rhs.coveredBy(*this);\n        }\n\n        bool extends(const Offset o, const Offset l) const {\n            return extends({o, l});\n        }\n    };\n\n    using MappingT = std::map<llvm::Value *, std::vector<OffsetPair>>;\n\n    // intervals of bytes for each memory\n    // (llvm::Value corresponding to the allocation)\n    MappingT _regions;\n\n    static std::pair<Offset, Offset>\n    _extend(const OffsetPair interval, const Offset off, const Offset len) {\n        assert(interval.overlaps(off, len));\n        assert(!off.isUnknown());\n\n        Offset o = interval.offset;\n        Offset l = interval.len;\n\n        if (off < interval.len)\n            o = off;\n        if (interval.len < len || len.isUnknown()) {\n            l = len;\n        }\n\n        return std::make_pair(o, l);\n    }\n\n    const std::vector<OffsetPair> *_get(llvm::Value *v) const {\n        auto it = _regions.find(v);\n        return it == _regions.end() ? nullptr : &it->second;\n    }\n\n  public:\n    // Add a memory region to this set\n    //\n    // not very efficient, but we will use it only\n    // for transfering the results, so it should be fine\n    void add(llvm::Value *mem, const Offset o, const Offset l) {\n        auto &R = _regions[mem];\n        // we do not know the bytes in this region\n        if (o.isUnknown()) {\n            R.clear();\n            R.emplace_back(o, o);\n            return;\n        }\n\n        assert(!o.isUnknown());\n\n        for (auto &interval : R) {\n            if (interval.offset.isUnknown() || interval.extends(o, l)) {\n                return; // nothing to be done\n            }\n        }\n\n        // join all overlapping intervals\n        Offset newO = o;\n        Offset newL = l;\n        for (auto &interval : R) {\n            if (interval.overlaps(newO, newL)) {\n                std::tie(newO, newL) = _extend(interval, newO, newL);\n            }\n        }\n\n        std::vector<OffsetPair> tmp;\n        tmp.reserve(R.size());\n\n        for (auto &interval : R) {\n            // get rid of covered intervals\n            if (interval.coveredBy(newO, newL))\n                continue;\n\n            // if intervals overlap, join them,\n            // otherwise keep the original interval\n            assert(!interval.overlaps(newO, newL));\n            tmp.push_back(interval);\n        }\n\n        tmp.emplace_back(newO, newL);\n        tmp.swap(R);\n\n#ifndef NDEBUG\n        for (auto &interval : R) {\n            assert(((interval.offset == newO && interval.len == newL) ||\n                    !interval.overlaps(newO, newL)) &&\n                   \"Joined intervals incorrectly\");\n        }\n#endif // NDEBUG\n    }\n\n    // XXX: inefficient\n    bool overlaps(const LLVMMemoryRegionSet &rhs) const {\n        for (const auto &it : rhs._regions) {\n            const auto *our = _get(it.first);\n            if (!our) {\n                continue;\n            }\n\n            for (const auto &interval : *our) {\n                for (const auto &interval2 : it.second) {\n                    if (interval.overlaps(interval2))\n                        return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    class const_iterator {\n        size_t pos{0};\n        typename MappingT::const_iterator it;\n\n        const_iterator(const MappingT::const_iterator I) : it(I) {}\n\n      public:\n        LLVMMemoryRegion operator*() const {\n            return LLVMMemoryRegion{it->first, it->second[pos].offset,\n                                    it->second[pos].len};\n        }\n\n        const_iterator &operator++() {\n            ++pos;\n            if (pos >= it->second.size()) {\n                ++it;\n                pos = 0;\n            }\n            return *this;\n        }\n\n        const_iterator operator++(int) {\n            auto tmp = *this;\n            operator++();\n            return tmp;\n        }\n\n        bool operator==(const const_iterator &rhs) const {\n            return it == rhs.it && pos == rhs.pos;\n        }\n\n        bool operator!=(const const_iterator &rhs) const {\n            return !operator==(rhs);\n        }\n\n        friend class LLVMMemoryRegionSet;\n    };\n\n    const_iterator begin() const { return {_regions.begin()}; }\n    const_iterator end() const { return {_regions.end()}; }\n};\n\n///\n// Implementation of LLVMPointsToSet\nclass LLVMPointsToSetImpl {\n  public:\n    ///\n    // NOTE: this may not be O(1) operation\n    virtual bool hasUnknown() const = 0;\n    virtual bool hasNull() const = 0;\n    virtual bool hasNullWithOffset() const = 0;\n    virtual bool hasInvalidated() const = 0;\n    virtual size_t size() const = 0;\n\n    virtual LLVMPointer getKnownSingleton() const = 0;\n\n    // for iterator implementation\n    // XXX: merge position() and end()?\n    virtual int position() const = 0;    // for comparision\n    virtual bool end() const = 0;        // have done iteration?\n    virtual void shift() = 0;            // iterate\n    virtual LLVMPointer get() const = 0; // dereference\n\n    virtual ~LLVMPointsToSetImpl() = default;\n};\n\n///\n// Wrapper for PointsToSet with iterators that yield LLVMPointer,\n// so that mapping pointer analysis results to LLVM is opaque for\n// the user. The special nodes like unknown memory and null\n// are not yield by the iterators. Instead, the class has methods\n// hasUnknown() and hasNull() to express these properties.\n// This also means that it is possible that iterating over the\n// set yields no elements, but empty() == false\n// (the set contains only unknown or null elements)\n// XXX: would it be easier and actually more efficient\n// just to return a std::vector<LLVMPointer> instead\n// of all this wrapping?\nclass LLVMPointsToSet {\n    std::unique_ptr<LLVMPointsToSetImpl> _impl{};\n\n  public:\n    class const_iterator {\n        LLVMPointsToSetImpl *impl{nullptr};\n\n        // impl = null means end iterator\n        void _check_end() {\n            assert(impl);\n            if (impl->end())\n                impl = nullptr;\n        }\n\n        const_iterator(LLVMPointsToSetImpl *impl = nullptr) : impl(impl) {\n            // the iterator (impl) may have been shifted during initialization\n            // to the end() (because it contains no llvm::Values or the\n            // ptset is empty)\n            if (impl)\n                _check_end();\n        }\n\n      public:\n        const_iterator &operator++() {\n            impl->shift();\n            _check_end();\n            return *this;\n        }\n\n        const_iterator operator++(int) {\n            auto tmp = *this;\n            operator++();\n            return tmp;\n        }\n\n        LLVMPointer operator*() const {\n            assert(impl && \"Has no impl\");\n            return impl->get();\n        }\n\n        bool operator==(const const_iterator &rhs) const {\n            if (!impl)\n                return !rhs.impl;\n            if (!rhs.impl)\n                return !impl;\n\n            assert(!impl->end() && rhs.impl->end());\n            assert(impl == rhs.impl &&\n                   \"Compared unrelated iterators\"); // catch bugs\n            llvm::errs() << \"CMP\" << impl << \"+\" << impl->position()\n                         << \" == \" << rhs.impl << \"+\" << rhs.impl->position()\n                         << \"\\n\";\n            return impl == rhs.impl && impl->position() == rhs.impl->position();\n        }\n\n        bool operator!=(const const_iterator &rhs) const {\n            return !operator==(rhs);\n        }\n\n        friend class LLVMPointsToSet;\n    };\n\n    LLVMPointsToSet(LLVMPointsToSetImpl *impl) : _impl(impl) {}\n    LLVMPointsToSet() = default;\n    LLVMPointsToSet(LLVMPointsToSet &&) = default;\n    LLVMPointsToSet &operator=(LLVMPointsToSet &&) = default;\n\n    ///\n    // NOTE: this may not be O(1) operation\n    bool hasUnknown() const { return _impl->hasUnknown(); }\n    bool hasNull() const { return _impl->hasNull(); }\n    bool hasNullWithOffset() const { return _impl->hasNullWithOffset(); }\n    bool hasInvalidated() const { return _impl->hasInvalidated(); }\n    bool empty() const { return _impl->size() == 0; }\n    size_t size() const { return _impl->size(); }\n\n    bool isSingleton() const { return _impl->size() == 1; }\n    bool isKnownSingleton() const {\n        return isSingleton() && !_impl->hasUnknown() && !_impl->hasNull() &&\n               !_impl->hasInvalidated();\n    }\n\n    // matches {unknown}\n    bool isUnknownSingleton() const { return isSingleton() && hasUnknown(); }\n\n    LLVMPointer getKnownSingleton() const { return _impl->getKnownSingleton(); }\n\n    const_iterator begin() const { return {_impl.get()}; }\n    static const_iterator end() { return {nullptr}; }\n};\n\n/// Auxiliary template that may be used when implementing LLVMPointsToSetImpl\ntemplate <typename PTSetT>\nclass LLVMPointsToSetImplTemplate : public LLVMPointsToSetImpl {\n  protected:\n    PTSetT PTSet;\n    decltype(PTSet.begin()) it;\n    size_t _position{0};\n\n    bool issingleton() const {\n        // is there any better way how to do it?\n        auto it = PTSet.begin();\n        return it != PTSet.end() && ++it == PTSet.end();\n    }\n\n    bool isKnownSingleton() const {\n        return issingleton() && !hasUnknown() && !hasNull() &&\n               !hasInvalidated();\n    }\n\n    // find next node that has associated llvm::Value\n    // (i.e. skip null, unknown, etc.)\n    virtual void _findNextReal() = 0;\n\n    void initialize_iterator() {\n        assert(it == PTSet.begin());\n        if (!PTSet.empty())\n            _findNextReal();\n    }\n\n  public:\n    // NOTE: the child constructor must call initialize_iterator().\n    // We cannot call it here since you can't call virtual\n    // functions in ctor/dtor\n    LLVMPointsToSetImplTemplate(PTSetT S) : PTSet(S), it(PTSet.begin()) {}\n\n    void shift() override {\n        assert(it != PTSet.end() && \"Tried to shift end() iterator\");\n        ++it;\n        ++_position;\n        _findNextReal();\n    }\n\n    int position() const override { return _position; }\n    bool end() const override { return it == PTSet.end(); }\n\n    // NOTE: LLVMPointsToSet will overtake the ownership of this\n    // object and will delete it on destruction.\n    LLVMPointsToSet toLLVMPointsToSet() { return LLVMPointsToSet(this); }\n};\n\n/// Implementation of LLVMPointsToSet that iterates\n//  over the DG's points-to set\nclass DGLLVMPointsToSet\n        : public LLVMPointsToSetImplTemplate<const PointsToSetT &> {\n    void _findNextReal() override {\n        while (it != PTSet.end() &&\n               (!(*it).isValid() || (*it).isInvalidated())) {\n            ++it;\n            ++_position;\n        }\n    }\n\n  public:\n    DGLLVMPointsToSet(const PointsToSetT &S) : LLVMPointsToSetImplTemplate(S) {\n        initialize_iterator();\n    }\n\n    ///\n    // NOTE: this may not be O(1) operation\n    bool hasUnknown() const override { return PTSet.hasUnknown(); }\n    bool hasNull() const override { return PTSet.hasNull(); }\n    bool hasNullWithOffset() const override {\n        return PTSet.hasNullWithOffset();\n    }\n    bool hasInvalidated() const override { return PTSet.hasInvalidated(); }\n    size_t size() const override { return PTSet.size(); }\n\n    LLVMPointer getKnownSingleton() const override {\n        assert(isKnownSingleton());\n        auto ptr = (*(PTSet.begin()));\n        return {ptr.target->getUserData<llvm::Value>(), ptr.offset};\n    }\n\n    LLVMPointer get() const override {\n        assert((it != PTSet.end()) && \"Dereferenced end() iterator\");\n        return LLVMPointer{(*it).target->getUserData<llvm::Value>(),\n                           (*it).offset};\n    }\n};\n\n} // namespace dg\n\n#endif // LLVM_DG_POINTS_TO_SET_H_\n"
  },
  {
    "path": "include/dg/llvm/PointerAnalysis/PointerAnalysis.h",
    "content": "#ifndef LLVM_DG_POINTS_TO_ANALYSIS_H_\n#define LLVM_DG_POINTS_TO_ANALYSIS_H_\n\n#include <memory>\n#include <utility>\n\n#include <llvm/IR/DataLayout.h>\n#include <llvm/IR/Function.h>\n#include <llvm/Support/raw_ostream.h>\n\n#include \"dg/PointerAnalysis/Pointer.h\"\n#include \"dg/PointerAnalysis/PointerAnalysis.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFI.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFS.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFSInv.h\"\n#include \"dg/PointerAnalysis/PointerGraph.h\"\n#include \"dg/PointerAnalysis/PointerGraphOptimizations.h\"\n\n#include \"dg/llvm/PointerAnalysis/LLVMPointerAnalysisOptions.h\"\n#include \"dg/llvm/PointerAnalysis/LLVMPointsToSet.h\"\n#include \"dg/llvm/PointerAnalysis/PointerGraph.h\"\n\nnamespace dg {\n\nusing pta::LLVMPointerGraphBuilder;\nusing pta::Pointer;\nusing pta::PointerGraph;\nusing pta::PSNode;\n\n///\n// Interface for LLVM pointer analysis\nclass LLVMPointerAnalysis {\n  protected:\n    const LLVMPointerAnalysisOptions options{};\n\n    LLVMPointerAnalysis(LLVMPointerAnalysisOptions opts)\n            : options(std::move(opts)){};\n\n  public:\n    const LLVMPointerAnalysisOptions &getOptions() const { return options; }\n\n    ///\n    // This method returns true if the pointer analysis\n    //  1) has any points-to set associated to the value 'val'\n    //  2) the points-to set is non-empty\n    virtual bool hasPointsTo(const llvm::Value *val) = 0;\n\n    ///\n    // Get the points-to information for the given LLVM value.\n    // The return object has methods begin(), end() that can be used\n    // for iteration over (llvm::Value *, Offset) pairs of the\n    // points-to set. Moreover, the object has methods hasUnknown(),\n    // hasNull(), and hasInvalidated() that reflect whether the points-to set of\n    // the LLVM value contains unknown element, null, or invalidated.\n    // If the pointer analysis has no or empty points-to set for 'val'\n    // (i.e. hasPointsTo() returns false), a points-to set containing\n    // the only element unknown is returned.\n    virtual LLVMPointsToSet getLLVMPointsTo(const llvm::Value *val) = 0;\n\n    ///\n    // This method is the same as getLLVMPointsTo, but it returns\n    // also the result of hasPointsTo(), so one can check whether the unknown\n    // pointer in the set is present because hasPointsTo() was false,\n    // or wether it has been propagated there during the analysis.\n    virtual std::pair<bool, LLVMPointsToSet>\n    getLLVMPointsToChecked(const llvm::Value *val) = 0;\n\n    // A convenient wrapper around getLLVMPointsTo\n    // that takes an instruction and returns a set of\n    // memory regions that are accessed (read/written)\n    // by this instruction. It also returns a boolean\n    // set to true if this information is not known (i.e.,\n    // the points-to set did contain 'unknown' element\n    // or was empty). For CallInst, it returns memory\n    // regions that may be accessed via the passed arguments.\n    std::pair<bool, LLVMMemoryRegionSet>\n    getAccessedMemory(const llvm::Instruction *I);\n\n    virtual bool run() = 0;\n\n    virtual ~LLVMPointerAnalysis() = default;\n};\n\ntemplate <typename PTType>\nclass DGLLVMPointerAnalysisImpl : public PTType {\n    LLVMPointerGraphBuilder *builder;\n\n  public:\n    DGLLVMPointerAnalysisImpl(PointerGraph *PS, LLVMPointerGraphBuilder *b)\n            : PTType(PS), builder(b) {}\n\n    DGLLVMPointerAnalysisImpl(PointerGraph *PS, LLVMPointerGraphBuilder *b,\n                              const LLVMPointerAnalysisOptions &opts)\n            : PTType(PS, opts), builder(b) {}\n\n    // build new subgraphs on calls via pointer\n    bool functionPointerCall(PSNode *callsite, PSNode *called) override {\n        using namespace pta;\n        const llvm::Function *F = llvm::dyn_cast<llvm::Function>(\n                called->getUserData<llvm::Value>());\n        // with vararg it may happen that we get pointer that\n        // is not to function, so just bail out here in that case\n        if (!F)\n            return false;\n\n        if (F->isDeclaration()) {\n            if (builder->threads()) {\n                if (F->getName() == \"pthread_create\") {\n                    builder->insertPthreadCreateByPtrCall(callsite);\n                    return true;\n                }\n                if (F->getName() == \"pthread_join\") {\n                    builder->insertPthreadJoinByPtrCall(callsite);\n                    return true;\n                }\n            }\n        }\n\n        if (!LLVMPointerGraphBuilder::callIsCompatible(callsite, called)) {\n            return false;\n        }\n\n        builder->insertFunctionCall(callsite, called);\n\n        // call the original handler that works on generic graphs\n        PTType::functionPointerCall(callsite, called);\n\n#ifndef NDEBUG\n        // check the graph after rebuilding, but do not check for connectivity,\n        // because we can call a function that will disconnect the graph\n        if (!builder->validateSubgraph(true)) {\n            llvm::errs() << \"Pointer Subgraph is broken!\\n\";\n            llvm::errs() << \"This happend after building this function called \"\n                            \"via pointer: \"\n                         << F->getName() << \"\\n\";\n            abort();\n        }\n#endif // NDEBUG\n\n        return true; // we changed the graph\n    }\n\n    bool handleFork(PSNode *forkNode, PSNode *called) override {\n        using namespace llvm;\n        using namespace dg::pta;\n\n        assert(called->getType() == PSNodeType::FUNCTION &&\n               \"The called value is not a function\");\n\n        PSNodeFork *fork = PSNodeFork::get(forkNode);\n        builder->addFunctionToFork(called, fork);\n\n#ifndef NDEBUG\n        // check the graph after rebuilding, but do not check for connectivity,\n        // because we can call a function that will disconnect the graph\n        if (!builder->validateSubgraph(true)) {\n            const llvm::Function *F = llvm::cast<llvm::Function>(\n                    called->getUserData<llvm::Value>());\n            llvm::errs() << \"Pointer Subgraph is broken!\\n\";\n            llvm::errs() << \"This happend after building this function spawned \"\n                            \"in a thread: \"\n                         << F->getName() << \"\\n\";\n            abort();\n        }\n#endif // NDEBUG\n\n        return true;\n    }\n\n    bool handleJoin(PSNode *joinNode) override {\n        return builder->matchJoinToRightCreate(joinNode);\n    }\n};\n\nclass DGLLVMPointerAnalysis : public LLVMPointerAnalysis {\n    PointerGraph *PS = nullptr;\n    std::unique_ptr<pta::PointerAnalysis> PTA{}; // dg pointer analysis object\n    std::unique_ptr<LLVMPointerGraphBuilder> _builder;\n\n    static LLVMPointerAnalysisOptions createOptions(const char *entry_func,\n                                                    uint64_t field_sensitivity,\n                                                    bool threads = false) {\n        LLVMPointerAnalysisOptions opts;\n        opts.threads = threads;\n        opts.setFieldSensitivity(field_sensitivity);\n        opts.setEntryFunction(entry_func);\n        return opts;\n    }\n\n    static const PointsToSetT &getUnknownPTSet() {\n        static const PointsToSetT _unknownPTSet =\n                PointsToSetT({Pointer{pta::UNKNOWN_MEMORY, 0}});\n        return _unknownPTSet;\n    }\n\n  public:\n    DGLLVMPointerAnalysis(const llvm::Module *m,\n                          const char *entry_func = \"main\",\n                          uint64_t field_sensitivity = Offset::UNKNOWN,\n                          bool threads = false)\n            : DGLLVMPointerAnalysis(\n                      m,\n                      createOptions(entry_func, field_sensitivity, threads)) {}\n\n    DGLLVMPointerAnalysis(const llvm::Module *m,\n                          const LLVMPointerAnalysisOptions opts)\n            : LLVMPointerAnalysis(opts),\n              _builder(new LLVMPointerGraphBuilder(m, opts)) {}\n\n    ///\n    // Get the node from pointer analysis that holds the points-to set.\n    // See: getLLVMPointsTo()\n    PSNode *getPointsToNode(const llvm::Value *val) const {\n        return _builder->getPointsToNode(val);\n    }\n\n    pta::PointerAnalysis *getPTA() { return PTA.get(); }\n    const pta::PointerAnalysis *getPTA() const { return PTA.get(); }\n\n    bool threads() const { return _builder->threads(); }\n\n    bool hasPointsTo(const llvm::Value *val) override {\n        if (auto *node = getPointsToNode(val)) {\n            return !node->pointsTo.empty();\n        }\n        return false;\n    }\n\n    ///\n    // Get the points-to information for the given LLVM value.\n    // The return object has methods begin(), end() that can be used\n    // for iteration over (llvm::Value *, Offset) pairs of the\n    // points-to set. Moreover, the object has methods hasUnknown()\n    // and hasNull() that reflect whether the points-to set of the\n    // LLVM value contains unknown element of null.\n    LLVMPointsToSet getLLVMPointsTo(const llvm::Value *val) override {\n        DGLLVMPointsToSet *pts;\n        if (auto *node = getPointsToNode(val)) {\n            if (node->pointsTo.empty()) {\n                pts = new DGLLVMPointsToSet(getUnknownPTSet());\n            } else {\n                pts = new DGLLVMPointsToSet(node->pointsTo);\n            }\n        } else {\n            pts = new DGLLVMPointsToSet(getUnknownPTSet());\n        }\n        return pts->toLLVMPointsToSet();\n    }\n\n    ///\n    // This method is the same as getLLVMPointsTo, but it returns\n    // also the information whether the node of pointer analysis exists\n    // (opposed to the getLLVMPointsTo, which returns a set with\n    // unknown element when the node does not exists)\n    std::pair<bool, LLVMPointsToSet>\n    getLLVMPointsToChecked(const llvm::Value *val) override {\n        DGLLVMPointsToSet *pts;\n        if (auto *node = getPointsToNode(val)) {\n            if (node->pointsTo.empty()) {\n                pts = new DGLLVMPointsToSet(getUnknownPTSet());\n                return {false, pts->toLLVMPointsToSet()};\n            }\n            pts = new DGLLVMPointsToSet(node->pointsTo);\n            return {true, pts->toLLVMPointsToSet()};\n        }\n        pts = new DGLLVMPointsToSet(getUnknownPTSet());\n        return {false, pts->toLLVMPointsToSet()};\n    }\n\n    const std::vector<std::unique_ptr<PSNode>> &getNodes() {\n        return PS->getNodes();\n    }\n\n    std::vector<PSNode *> getFunctionNodes(const llvm::Function *F) const {\n        return _builder->getFunctionNodes(F);\n    }\n\n    PointerGraph *getPS() { return PS; }\n    const PointerGraph *getPS() const { return PS; }\n\n    LLVMPointerGraphBuilder *getBuilder() { return _builder.get(); }\n    const LLVMPointerGraphBuilder *getBuilder() const { return _builder.get(); }\n\n    void buildSubgraph() {\n        // run the analysis itself\n        assert(_builder && \"Incorrectly constructed PTA, missing builder\");\n\n        PS = _builder->buildLLVMPointerGraph();\n        if (!PS) {\n            llvm::errs() << \"Pointer Subgraph was not built, aborting\\n\";\n            abort();\n        }\n\n        /*\n        pta::PointerGraphOptimizer optimizer(PS);\n        optimizer.run();\n\n        if (optimizer.getNumOfRemovedNodes() > 0)\n            _builder->composeMapping(std::move(optimizer.getMapping()));\n\n        llvm::errs() << \"PS optimization removed \" <<\n        optimizer.getNumOfRemovedNodes() << \" nodes\\n\";\n        */\n    }\n\n    void initialize() {\n        if (options.isFSInv())\n            _builder->setInvalidateNodesFlag(true);\n\n        buildSubgraph();\n\n        if (options.isFS()) {\n            // FIXME: make a interface with run() method\n            PTA.reset(new DGLLVMPointerAnalysisImpl<pta::PointerAnalysisFS>(\n                    PS, _builder.get(), options));\n        } else if (options.isFI()) {\n            PTA.reset(new DGLLVMPointerAnalysisImpl<pta::PointerAnalysisFI>(\n                    PS, _builder.get(), options));\n        } else if (options.isFSInv()) {\n            PTA.reset(new DGLLVMPointerAnalysisImpl<pta::PointerAnalysisFSInv>(\n                    PS, _builder.get(), options));\n        } else {\n            assert(0 && \"Wrong pointer analysis\");\n            abort();\n        }\n    }\n\n    bool run() override {\n        if (!PTA) {\n            initialize();\n        }\n        return PTA->run();\n    }\n};\n\n// an auxiliary function\ninline std::vector<const llvm::Function *>\ngetCalledFunctions(const llvm::Value *calledValue, LLVMPointerAnalysis *PTA) {\n    std::vector<const llvm::Function *> functions;\n    for (const auto &llvmptr : PTA->getLLVMPointsTo(calledValue)) {\n        if (auto *const F = llvm::dyn_cast<llvm::Function>(llvmptr.value)) {\n            functions.push_back(F);\n        }\n    }\n    return functions;\n}\n\n} // namespace dg\n\n#endif // LLVM_DG_POINTS_TO_ANALYSIS_H_\n"
  },
  {
    "path": "include/dg/llvm/PointerAnalysis/PointerGraph.h",
    "content": "#ifndef LLVM_DG_POINTER_SUBGRAPH_H_\n#define LLVM_DG_POINTER_SUBGRAPH_H_\n\n#include <unordered_map>\n\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/DataLayout.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/IntrinsicInst.h>\n#include <llvm/IR/Module.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#include \"dg/llvm/PointerAnalysis/LLVMPointerAnalysisOptions.h\"\n\n#include \"dg/PointerAnalysis/Pointer.h\"\n#include \"dg/PointerAnalysis/PointerGraph.h\"\n#include \"dg/PointerAnalysis/PointsToMapping.h\"\n\nnamespace dg {\nnamespace pta {\n\nclass LLVMPointerGraphBuilder {\n    PointerGraph PS{};\n    // mapping from llvm values to PSNodes that contain\n    // the points-to information\n    PointsToMapping<const llvm::Value *> mapping;\n\n    const llvm::Module *M;\n    LLVMPointerAnalysisOptions _options;\n\n    // flag that says whether we are building normally,\n    // or the analysis is already running and we are building\n    // some new parts of already built graph.\n    // This is important with function pointer calls\n    bool ad_hoc_building = false;\n    // flag that determines whether invalidate nodes\n    // should be created\n    bool invalidate_nodes = false;\n\n    bool threads_ = false;\n\n    class PSNodesSeq {\n        using NodesT = std::vector<PSNode *>;\n        NodesT _nodes;\n        // representant that holds the final points-to set after\n        // generated by this sequence of instructions\n        PSNode *_repr{nullptr};\n\n      public:\n        PSNodesSeq() = default;\n        PSNodesSeq(PSNode *n) { _nodes.push_back(n); }\n        PSNodesSeq(const std::initializer_list<PSNode *> &l) {\n            for (auto *n : l)\n                _nodes.push_back(n);\n        }\n\n        void setRepresentant(PSNode *r) { _repr = r; }\n        PSNode *getRepresentant() { return _repr ? _repr : _nodes.back(); }\n        const PSNode *getRepresentant() const {\n            return _repr ? _repr : _nodes.back();\n        }\n\n        PSNode *getSingleNode() {\n            assert(_nodes.size() == 1);\n            return _nodes.front();\n        }\n        const PSNode *getSingleNode() const {\n            assert(_nodes.size() == 1);\n            return _nodes.front();\n        }\n\n        void append(PSNode *n) { _nodes.push_back(n); }\n        bool empty() const { return _nodes.empty(); }\n\n        PSNode *getFirst() {\n            assert(!_nodes.empty());\n            return _nodes.front();\n        }\n        PSNode *getLast() {\n            assert(!_nodes.empty());\n            return _nodes.back();\n        }\n\n        NodesT::iterator begin() { return _nodes.begin(); }\n        NodesT::const_iterator begin() const { return _nodes.begin(); }\n        NodesT::iterator end() { return _nodes.end(); }\n        NodesT::const_iterator end() const { return _nodes.end(); }\n    };\n\n    class PSNodesBlock {\n        using NodesT = std::vector<PSNodesSeq *>;\n        NodesT _nodes;\n\n      public:\n        PSNodesBlock() = default;\n        PSNodesBlock(PSNodesSeq *s) { append(s); }\n        void append(PSNodesSeq *s) { _nodes.push_back(s); }\n        bool empty() const { return _nodes.empty(); }\n\n        PSNodesSeq &getFirst() {\n            assert(!empty());\n            return *_nodes.front();\n        }\n        PSNodesSeq &getLast() {\n            assert(!empty());\n            return *_nodes.back();\n        }\n        PSNode *getFirstNode() {\n            assert(!empty());\n            return _nodes.front()->getFirst();\n        }\n        PSNode *getLastNode() {\n            assert(!empty());\n            return _nodes.back()->getLast();\n        }\n\n        NodesT::iterator begin() { return _nodes.begin(); }\n        NodesT::const_iterator begin() const { return _nodes.begin(); }\n        NodesT::iterator end() { return _nodes.end(); }\n        NodesT::const_iterator end() const { return _nodes.end(); }\n    };\n\n    struct FuncGraph {\n        // reachable LLVM block (those block for which we built the\n        // instructions)\n        std::map<const llvm::BasicBlock *, PSNodesBlock> llvmBlocks{};\n        bool has_structure{false};\n\n        FuncGraph() = default;\n        FuncGraph(const FuncGraph &) = delete;\n\n        void\n        blockAddSuccessors(std::set<const llvm::BasicBlock *> &found_blocks,\n                           LLVMPointerGraphBuilder::PSNodesBlock &blk,\n                           const llvm::BasicBlock &block);\n    };\n\n    // helper function that add CFG edges between instructions\n    static void PSNodesSequenceAddSuccessors(PSNodesSeq &seq) {\n        if (seq.empty())\n            return;\n\n        PSNode *last = nullptr;\n        for (auto *nd : seq) {\n            if (last)\n                last->addSuccessor(nd);\n\n            last = nd;\n        }\n    }\n\n    static void PSNodesBlockAddSuccessors(PSNodesBlock &blk,\n                                          bool withSeqEdges = false) {\n        if (blk.empty())\n            return;\n\n        PSNodesSeq *last = nullptr;\n        for (auto *seq : blk) {\n            if (withSeqEdges)\n                PSNodesSequenceAddSuccessors(*seq);\n\n            if (last)\n                last->getLast()->addSuccessor(seq->getFirst());\n\n            last = seq;\n        }\n    }\n\n    std::unordered_map<const llvm::Function *, FuncGraph> _funcInfo;\n\n    // build pointer state subgraph for given graph\n    // \\return   root node of the graph\n    PointerSubgraph &buildFunction(const llvm::Function &F);\n    PSNodesSeq &buildInstruction(const llvm::Instruction & /*Inst*/);\n\n    PSNodesBlock buildPointerGraphBlock(const llvm::BasicBlock &block,\n                                        PointerSubgraph *parent);\n\n    void buildArguments(const llvm::Function &F, PointerSubgraph *parent);\n    PSNodesBlock buildArgumentsStructure(const llvm::Function &F);\n    void buildGlobals();\n\n    // add edges that are derived from CFG to the subgraph\n    void addProgramStructure();\n    void addProgramStructure(const llvm::Function *F, PointerSubgraph &subg);\n    void blockAddCalls(const llvm::BasicBlock &block);\n\n    static void addCFGEdges(const llvm::Function *F,\n                            LLVMPointerGraphBuilder::FuncGraph &finfo,\n                            PSNode *lastNode);\n\n    static PSNode *connectArguments(const llvm::Function *F,\n                                    PSNodesBlock &argsBlk,\n                                    PointerSubgraph &subg);\n\n    // map of all nodes we created - use to look up operands\n    std::unordered_map<const llvm::Value *, PSNodesSeq> nodes_map;\n    // map of all built subgraphs - the value type is a pair (root, return)\n    std::unordered_map<const llvm::Function *, PointerSubgraph *> subgraphs_map;\n\n    std::vector<PSNodeFork *> forkNodes;\n    std::vector<PSNodeJoin *> joinNodes;\n\n  public:\n    const PointerGraph *getPS() const { return &PS; }\n\n    inline bool threads() const { return threads_; }\n\n    LLVMPointerGraphBuilder(const llvm::Module *m,\n                            const LLVMPointerAnalysisOptions &opts)\n            : M(m), _options(opts), threads_(opts.threads) {}\n\n    PointerGraph *buildLLVMPointerGraph();\n\n    bool validateSubgraph(bool no_connectivity = false) const;\n\n    void setAdHocBuilding(bool adHoc) { ad_hoc_building = adHoc; }\n\n    PSNodesSeq &createFuncptrCall(const llvm::CallInst *CInst,\n                                  const llvm::Function *F);\n\n    static bool callIsCompatible(PSNode *call, PSNode *func);\n\n    // Insert a call of a function into an already existing graph.\n    // The call will be inserted betwee the callsite and\n    // the return from the call nodes.\n    void insertFunctionCall(PSNode *callsite, PSNode *called);\n    void insertPthreadCreateByPtrCall(PSNode *callsite);\n    void insertPthreadJoinByPtrCall(PSNode *callsite);\n\n    PSNodeFork *createForkNode(const llvm::CallInst *CInst,\n                               PSNode * /*callNode*/);\n    PSNodeJoin *createJoinNode(const llvm::CallInst *CInst,\n                               PSNode * /*callNode*/);\n    PSNodesSeq createPthreadCreate(const llvm::CallInst *CInst);\n    PSNodesSeq createPthreadJoin(const llvm::CallInst *CInst);\n    PSNodesSeq createPthreadExit(const llvm::CallInst *CInst);\n\n    bool addFunctionToFork(PSNode *function, PSNodeFork *forkNode);\n    bool addFunctionToJoin(PSNode *function, PSNodeJoin *joinNode);\n\n    bool matchJoinToRightCreate(PSNode *joinNode);\n    // let the user get the nodes map, so that we can\n    // map the points-to informatio back to LLVM nodes\n    const std::unordered_map<const llvm::Value *, PSNodesSeq> &\n    getNodesMap() const {\n        return nodes_map;\n    }\n\n    std::vector<PSNode *> getFunctionNodes(const llvm::Function *F) const;\n\n    // this is the same as the getNode, but it creates ConstantExpr\n    PSNode *getPointsToNode(const llvm::Value *val) {\n        PSNode *n = getPointsToNodeOrNull(val);\n        if (!n)\n            n = getConstant(val);\n\n        return n;\n    }\n\n    std::vector<PSNode *> getPointsToFunctions(const llvm::Value *calledValue);\n\n    std::vector<PSNodeJoin *> &getJoins() { return joinNodes; }\n    std::vector<PSNodeFork *> &getForks() { return forkNodes; }\n    const std::vector<PSNodeJoin *> &getJoins() const { return joinNodes; }\n    const std::vector<PSNodeFork *> &getForks() const { return forkNodes; }\n\n    PSNodeJoin *findJoin(const llvm::CallInst *callInst) const;\n    void setInvalidateNodesFlag(bool value) {\n        assert(PS.getEntry() == nullptr &&\n               \"This function must be called before building PS\");\n        this->invalidate_nodes = value;\n    }\n\n    void composeMapping(PointsToMapping<PSNode *> &&rhs) {\n        mapping.compose(std::move(rhs));\n    }\n\n    PointerSubgraph *getSubgraph(const llvm::Function * /*F*/);\n\n  private:\n    // create subgraph of function @F (the nodes)\n    // and call+return nodes to/from it. This function\n    // won't add the CFG edges if not 'ad_hoc_building'\n    // is set to true\n    PSNodesSeq &createCallToFunction(const llvm::CallInst * /*CInst*/,\n                                     const llvm::Function * /*F*/);\n\n    PSNode *getPointsToNodeOrNull(const llvm::Value *val) {\n        // if we have a mapping for this node (e.g. the original\n        // node was optimized away and replaced by mapping),\n        // return it\n        if (auto *mp = mapping.get(val))\n            return mp;\n        if (auto *nds = getNodes(val)) {\n            // otherwise get the representant of the built nodes\n            return nds->getRepresentant();\n        }\n\n        // not built!\n        return nullptr;\n    }\n\n    // get the built nodes for this value or null\n    PSNodesSeq *getNodes(const llvm::Value *val) {\n        auto it = nodes_map.find(val);\n        if (it == nodes_map.end())\n            return nullptr;\n\n        // the node corresponding to the real llvm value\n        // is always the last\n        return &it->second;\n    }\n\n    PSNodesSeq &addNode(const llvm::Value *val, PSNode *node) {\n        assert(nodes_map.find(val) == nodes_map.end());\n        auto it = nodes_map.emplace(val, node);\n        node->setUserData(const_cast<llvm::Value *>(val));\n\n        return it.first->second;\n    }\n\n    PSNodesSeq &addNode(const llvm::Value *val, PSNodesSeq seq) {\n        assert(nodes_map.find(val) == nodes_map.end());\n        seq.getRepresentant()->setUserData(const_cast<llvm::Value *>(val));\n        auto it = nodes_map.emplace(val, std::move(seq));\n\n        return it.first->second;\n    }\n\n    bool isRelevantInstruction(const llvm::Instruction &Inst);\n\n    PSNodesSeq &createAlloc(const llvm::Instruction *Inst);\n    PSNode *createDynamicAlloc(const llvm::CallInst *CInst,\n                               AllocationFunction type);\n    PSNodesSeq &createStore(const llvm::Instruction *Inst);\n    PSNodesSeq &createLoad(const llvm::Instruction *Inst);\n    PSNodesSeq &createGEP(const llvm::Instruction *Inst);\n    PSNodesSeq &createSelect(const llvm::Instruction *Inst);\n    PSNodesSeq &createPHI(const llvm::Instruction *Inst);\n    PSNodesSeq &createCast(const llvm::Instruction *Inst);\n    PSNodesSeq &createReturn(const llvm::Instruction *Inst);\n    PSNodesSeq &createPtrToInt(const llvm::Instruction *Inst);\n    PSNodesSeq &createIntToPtr(const llvm::Instruction *Inst);\n    PSNodesSeq &createAsm(const llvm::Instruction *Inst);\n    PSNodesSeq &createInsertElement(const llvm::Instruction *Inst);\n    PSNodesSeq &createExtractElement(const llvm::Instruction *Inst);\n    PSNodesSeq &createAtomicRMW(const llvm::Instruction *Inst);\n    PSNodesSeq &createConstantExpr(const llvm::ConstantExpr *CE);\n\n    PSNode *createInternalLoad(const llvm::Instruction *Inst);\n    PSNodesSeq &createIrrelevantInst(const llvm::Value *,\n                                     bool build_uses = false);\n    PSNodesSeq &createArgument(const llvm::Argument * /*farg*/);\n    void createIrrelevantUses(const llvm::Value *val);\n\n    PSNodesSeq &createAdd(const llvm::Instruction *Inst);\n    PSNodesSeq &createArithmetic(const llvm::Instruction *Inst);\n    PSNodesSeq &createUnknown(const llvm::Value *val);\n    PSNode *createFree(const llvm::Instruction *Inst);\n    PSNode *createLifetimeEnd(const llvm::Instruction *Inst);\n\n    PSNode *getOperand(const llvm::Value *val);\n    PSNode *tryGetOperand(const llvm::Value *val);\n    PSNode *getConstant(const llvm::Value *val);\n    Pointer handleConstantGep(const llvm::GetElementPtrInst *GEP);\n    Pointer handleConstantBitCast(const llvm::CastInst *BC);\n    Pointer handleConstantPtrToInt(const llvm::PtrToIntInst *P2I);\n    Pointer handleConstantIntToPtr(const llvm::IntToPtrInst *I2P);\n    Pointer handleConstantAdd(const llvm::Instruction *Inst);\n    Pointer handleConstantArithmetic(const llvm::Instruction *Inst);\n    Pointer getConstantExprPointer(const llvm::ConstantExpr *CE);\n\n    void checkMemSet(const llvm::Instruction *Inst);\n    void addPHIOperands(PSNode *node, const llvm::PHINode *PHI);\n    void addPHIOperands(const llvm::Function &F);\n    void addArgumentOperands(const llvm::Function *F, PSNode *arg,\n                             unsigned idx);\n    void addArgumentOperands(const llvm::CallInst *CI, PSNode *arg,\n                             unsigned idx);\n    void addArgumentOperands(const llvm::CallInst &CI, PSNode &node);\n    void addArgumentsOperands(const llvm::Function *F,\n                              const llvm::CallInst *CI = nullptr,\n                              unsigned index = 0);\n    void addVariadicArgumentOperands(const llvm::Function *F, PSNode *arg);\n    void addVariadicArgumentOperands(const llvm::Function *F,\n                                     const llvm::CallInst *CI, PSNode *arg);\n\n    void addReturnNodesOperands(const llvm::Function *F, PointerSubgraph &subg,\n                                PSNode *callNode = nullptr);\n\n    static void addReturnNodeOperand(PSNode *callNode, PSNode *ret);\n    void addReturnNodeOperand(const llvm::Function *F, PSNode *op);\n    void addInterproceduralOperands(const llvm::Function *F,\n                                    PointerSubgraph &subg,\n                                    const llvm::CallInst *CI = nullptr,\n                                    PSNode *callNode = nullptr);\n    void addInterproceduralPthreadOperands(const llvm::Function *F,\n                                           const llvm::CallInst *CI = nullptr);\n\n    PSNodesSeq &createExtract(const llvm::Instruction *Inst);\n    PSNodesSeq &createCall(const llvm::Instruction *Inst);\n    PSNodesSeq &createFunctionCall(const llvm::CallInst *,\n                                   const llvm::Function *);\n    PSNodesSeq createUndefFunctionCall(const llvm::CallInst * /*CInst*/,\n                                       const llvm::Function * /*func*/);\n    PSNodesSeq &createFuncptrCall(const llvm::CallInst * /*CInst*/,\n                                  const llvm::Value * /*calledVal*/);\n\n    PointerSubgraph &createOrGetSubgraph(const llvm::Function * /*F*/);\n    PointerSubgraph &getAndConnectSubgraph(const llvm::Function *F,\n                                           const llvm::CallInst *CInst,\n                                           PSNode *callNode);\n\n    void handleGlobalVariableInitializer(const llvm::Constant *C,\n                                         PSNodeAlloc *node,\n                                         uint64_t offset = 0);\n\n    PSNode *createMemTransfer(const llvm::IntrinsicInst *Inst);\n    PSNodesSeq createMemSet(const llvm::Instruction * /*Inst*/);\n    PSNodesSeq createDynamicMemAlloc(const llvm::CallInst *CInst,\n                                     AllocationFunction type);\n    PSNodesSeq createRealloc(const llvm::CallInst *CInst);\n    PSNode *createUnknownCall();\n    PSNodesSeq createIntrinsic(const llvm::Instruction *Inst);\n    PSNodesSeq createVarArg(const llvm::IntrinsicInst *Inst);\n};\n\n/// --------------------------------------------------------\n// Helper functions\n/// --------------------------------------------------------\ninline bool isRelevantIntrinsic(const llvm::Function *func,\n                                bool invalidate_nodes) {\n    using namespace llvm;\n\n    switch (func->getIntrinsicID()) {\n    case Intrinsic::memmove:\n    case Intrinsic::memcpy:\n    case Intrinsic::vastart:\n    case Intrinsic::stacksave:\n    case Intrinsic::stackrestore:\n        return true;\n    case Intrinsic::lifetime_end:\n        return invalidate_nodes;\n    // case Intrinsic::memset:\n    default:\n        return false;\n    }\n}\n\ninline bool isInvalid(const llvm::Value *val, bool invalidate_nodes) {\n    using namespace llvm;\n\n    if (!isa<Instruction>(val)) {\n        if (!isa<Argument>(val) && !isa<GlobalValue>(val))\n            return true;\n    } else {\n        if (isa<ICmpInst>(val) || isa<FCmpInst>(val) ||\n            isa<DbgValueInst>(val) || isa<BranchInst>(val) ||\n            isa<SwitchInst>(val))\n            return true;\n\n        const CallInst *CI = dyn_cast<CallInst>(val);\n        if (CI) {\n            const Function *F = CI->getCalledFunction();\n            if (F && F->isIntrinsic() &&\n                !isRelevantIntrinsic(F, invalidate_nodes))\n                return true;\n        }\n    }\n\n    return false;\n}\n\n} // namespace pta\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "include/dg/llvm/PointerAnalysis/SVFPointerAnalysis.h",
    "content": "#ifndef DG_SVF_POINTER_ANALYSIS_H_\n#define DG_SVF_POINTER_ANALYSIS_H_\n\n#include <llvm/IR/DataLayout.h>\n#include <llvm/IR/Function.h>\n#include <llvm/Support/raw_ostream.h>\n\n#include <SVF-FE/LLVMModule.h> // LLVMModuleSet\n#include <SVF-FE/PAGBuilder.h> // PAGBuilder\n#include <WPA/Andersen.h>      // Andersen analysis from SVF\n\n#include \"dg/PointerAnalysis/Pointer.h\"\n\n#include \"dg/llvm/PointerAnalysis/LLVMPointerAnalysisOptions.h\"\n#include \"dg/llvm/PointerAnalysis/LLVMPointsToSet.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n\n#include \"dg/util/debug.h\"\n\nnamespace dg {\n\nusing pta::Pointer;\n\nusing SVF::LLVMModuleSet;\nusing SVF::PAG;\nusing SVF::PointsTo;\n\n/// Implementation of LLVMPointsToSet that iterates\n//  over the DG's points-to set\nclass SvfLLVMPointsToSet : public LLVMPointsToSetImplTemplate<const PointsTo> {\n    PAG *_pag;\n    size_t _position{0};\n\n    llvm::Value *_getValue(unsigned id) const {\n        auto *pagnode = _pag->getPAGNode(id);\n        if (pagnode->hasValue())\n            return const_cast<llvm::Value *>(pagnode->getValue());\n\n        // for debugging right now\n        llvm::errs() << \"[SVF] No value in PAG NODE\\n\";\n        llvm::errs() << *pagnode << \"\\n\";\n        return nullptr;\n    }\n\n    void _findNextReal() override {\n        while (it != PTSet.end()) {\n            if (_pag->getPAGNode(*it)->hasValue())\n                break;\n\n            // else\n            //     llvm::errs() << \"no val\" << *_pag->getPAGNode(*it) << \"\\n\";\n\n            ++it;\n            ++_position;\n        }\n    }\n\n  public:\n    SvfLLVMPointsToSet(PointsTo &S, PAG *pag)\n            : LLVMPointsToSetImplTemplate(std::move(S)), _pag(pag) {\n        initialize_iterator();\n    }\n\n    bool hasUnknown() const override {\n        return PTSet.test(_pag->getBlackHoleNode());\n    }\n\n    bool hasNull() const override { return PTSet.test(_pag->getNullPtr()); }\n\n    bool hasNullWithOffset() const override {\n        // we are field-insensitive now...\n        return hasNull();\n    }\n\n    bool hasInvalidated() const override { return false; }\n    size_t size() const override { return PTSet.count(); }\n\n    LLVMPointer getKnownSingleton() const override {\n        assert(isKnownSingleton());\n        return {_getValue(*PTSet.begin()), Offset::UNKNOWN};\n    }\n\n    LLVMPointer get() const override {\n        assert(it != PTSet.end() && \"Dereferenced end() iterator\");\n        return {_getValue(*it), Offset::UNKNOWN};\n    }\n};\n\n///\n// Integration of pointer analysis from SVF\nclass SVFPointerAnalysis : public LLVMPointerAnalysis {\n    const llvm::Module *_module{nullptr};\n    SVF::SVFModule *_svfModule{nullptr};\n    std::unique_ptr<SVF::PointerAnalysis> _pta{};\n\n    PointsTo &getUnknownPTSet() const {\n        static PointsTo _unknownPTSet;\n        if (_unknownPTSet.empty())\n            _unknownPTSet.set(_pta->getPAG()->getBlackHoleNode());\n        return _unknownPTSet;\n    }\n\n    LLVMPointsToSet mapSVFPointsTo(PointsTo &S, PAG *pag) {\n        auto *pts =\n                new SvfLLVMPointsToSet(S.empty() ? getUnknownPTSet() : S, pag);\n        return pts->toLLVMPointsToSet();\n    }\n\n  public:\n    SVFPointerAnalysis(const llvm::Module *M,\n                       const LLVMPointerAnalysisOptions &opts)\n            : LLVMPointerAnalysis(opts), _module(M) {}\n\n    ~SVFPointerAnalysis() override {\n        // _svfModule overtook the ownership of llvm::Module,\n        // we must re-take it to avoid double free\n        LLVMModuleSet::releaseLLVMModuleSet();\n    }\n\n    bool hasPointsTo(const llvm::Value *val) override {\n        PAG *pag = _pta->getPAG();\n        auto pts = _pta->getPts(pag->getValueNode(val));\n        return !pts.empty();\n    }\n\n    ///\n    // Get the points-to information for the given LLVM value.\n    // The return object has methods begin(), end() that can be used\n    // for iteration over (llvm::Value *, Offset) pairs of the\n    // points-to set. Moreover, the object has methods hasUnknown()\n    // and hasNull() that reflect whether the points-to set of the\n    // LLVM value contains unknown element of null.\n    LLVMPointsToSet getLLVMPointsTo(const llvm::Value *val) override {\n        PAG *pag = _pta->getPAG();\n        auto pts = _pta->getPts(pag->getValueNode(val));\n        return mapSVFPointsTo(pts, pag);\n    }\n\n    ///\n    // This method is the same as getLLVMPointsTo, but it returns\n    // also the information whether the node of pointer analysis exists\n    // (opposed to the getLLVMPointsTo, which returns a set with\n    // unknown element when the node does not exists)\n    std::pair<bool, LLVMPointsToSet>\n    getLLVMPointsToChecked(const llvm::Value *val) override {\n        PAG *pag = _pta->getPAG();\n        auto pts = _pta->getPts(pag->getValueNode(val));\n        return {!pts.empty(), mapSVFPointsTo(pts, pag)};\n    }\n\n    bool run() override {\n        using namespace SVF;\n\n        DBG_SECTION_BEGIN(pta, \"Running SVF pointer analysis (Andersen)\");\n\n        auto *moduleset = LLVMModuleSet::getLLVMModuleSet();\n        _svfModule =\n                moduleset->buildSVFModule(*const_cast<llvm::Module *>(_module));\n        assert(_svfModule && \"Failed building SVF module\");\n\n        _svfModule->buildSymbolTableInfo();\n\n        PAGBuilder builder;\n        PAG *pag = builder.build(_svfModule);\n\n        _pta.reset(new Andersen(pag));\n        _pta->disablePrintStat();\n        _pta->analyze();\n\n        DBG_SECTION_END(pta, \"Done running SVF pointer analysis (Andersen)\");\n        return true;\n    }\n};\n\n} // namespace dg\n\n#endif // DG_SVF_POINTER_ANALYSIS_H_\n"
  },
  {
    "path": "include/dg/llvm/SystemDependenceGraph/SDG2Dot.h",
    "content": "#ifndef DG_LLVM_SDG2DOT_H_\n#define DG_LLVM_SDG2DOT_H_\n\n#include <fstream>\n#include <iostream>\n#include <sstream>\n#include <string>\n\n#include \"llvm/IR/Instructions.h\"\n\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR <= 4))\n#include \"llvm/DebugInfo.h\" //DIScope\n#else\n#include \"llvm/IR/DebugInfo.h\" //DIScope\n#endif\n\n#include \"dg/SystemDependenceGraph/DGNodeCall.h\"\n#include \"dg/llvm/SystemDependenceGraph/SystemDependenceGraph.h\"\n\nnamespace dg {\nnamespace llvmdg {\n\n/*\nFIXME: move to one file...\nstatic std::ostream& operator<<(std::ostream& os, const analysis::Offset& off)\n{\n    if (off.offset == Offset::UNKNOWN)\n        os << \"UNKNOWN\";\n    else\n        os << off.offset;\n\n    return os;\n}\n*/\n\nnamespace {\ninline std::ostream &printLLVMVal(std::ostream &os, const llvm::Value *val) {\n    if (!val) {\n        os << \"(null)\";\n        return os;\n    }\n\n    std::ostringstream ostr;\n    llvm::raw_os_ostream ro(ostr);\n\n    if (llvm::isa<llvm::Function>(val)) {\n        ro << \"FUN \" << val->getName();\n    } else if (const auto *B = llvm::dyn_cast<llvm::BasicBlock>(val)) {\n        ro << B->getParent()->getName() << \"::\";\n        ro << \"label \" << val->getName();\n    } else if (const auto *I = llvm::dyn_cast<llvm::Instruction>(val)) {\n        const auto *const B = I->getParent();\n        if (B) {\n            ro << B->getParent()->getName() << \"::\";\n        } else {\n            ro << \"<null>::\";\n        }\n        ro << *val;\n    } else {\n        ro << *val;\n    }\n\n    ro.flush();\n\n    // break the string if it is too long\n    std::string str = ostr.str();\n    if (str.length() > 50) {\n        str.resize(40);\n    }\n\n    // escape the \"\n    size_t pos = 0;\n    while ((pos = str.find('\"', pos)) != std::string::npos) {\n        str.replace(pos, 1, \"\\\\\\\"\");\n        // we replaced one char with two, so we must shift after the new \"\n        pos += 2;\n    }\n\n    os << str;\n\n    return os;\n}\n} // anonymous namespace\n\nstatic std::ostream &operator<<(std::ostream &os, const sdg::DGElement &nd) {\n    os << \"elem\" << nd.getDG().getID() << \"_\" << nd.getID();\n    return os;\n}\n\nclass SDG2Dot {\n    SystemDependenceGraph *_llvmsdg;\n\n    // keep track of dumped nodes for checking that we dumped all\n    mutable std::set<sdg::DGNode *> dumpedNodes;\n\n    void dumpNode(std::ostream &out, sdg::DGNode &nd,\n                  const llvm::Value *v = nullptr,\n                  const char *descr = nullptr) const {\n        assert(sdg::DGNode::get(&nd) && \"Wrong type\");\n\n        auto &dg = nd.getDG();\n        out << \"      \" << nd << \" [label=\\\"[\" << dg.getID() << \".\"\n            << nd.getID() << \"] \";\n        if (v) {\n            // this node is associated to this value\n            printLLVMVal(out, v);\n        } else {\n            printLLVMVal(out, _llvmsdg->getValue(&nd));\n        }\n        if (descr) {\n            out << \" \" << descr;\n        }\n        out << \"\\\"]\\n\";\n    }\n\n    void dumpParams(std::ostream &out, sdg::DGParameters &params,\n                    const std::string &name) const {\n        /// input parameters\n        out << \"    subgraph cluster_params_in_\" << &params << \" {\\n\";\n        out << \"      label=\\\"\" << name << \" (input)\\\"\\n\";\n        for (auto &param : params) {\n            auto &nd = param.getInputArgument();\n            dumpedNodes.insert(&nd);\n            dumpNode(out, nd, _llvmsdg->getValue(&param));\n        }\n        out << \"    }\\n\";\n\n        /// output parameters\n        out << \"    subgraph cluster_params_out_\" << &params << \" {\\n\";\n        out << \"      label=\\\"\" << name << \" (output)\\\"\\n\";\n        for (auto &param : params) {\n            auto &nd = param.getOutputArgument();\n            dumpedNodes.insert(&nd);\n            dumpNode(out, nd, _llvmsdg->getValue(&param));\n        }\n        if (auto *noret = params.getNoReturn()) {\n            dumpedNodes.insert(noret);\n            dumpNode(out, *noret, nullptr, \"noret\");\n        }\n        if (auto *ret = params.getReturn()) {\n            dumpedNodes.insert(ret);\n            dumpNode(out, *ret, nullptr, \"ret\");\n        }\n        out << \"    }\\n\";\n    }\n\n    void dumpParamEdges(std::ostream &out, sdg::DGParameters &params) const {\n        /// input parameters\n        for (auto &param : params) {\n            dumpEdges(out, param.getInputArgument());\n        }\n\n        /// output parameters\n        for (auto &param : params) {\n            dumpEdges(out, param.getOutputArgument());\n        }\n        if (auto *noret = params.getNoReturn()) {\n            dumpEdges(out, *noret);\n        }\n        if (auto *ret = params.getReturn()) {\n            dumpEdges(out, *ret);\n        }\n    }\n\n    void bindParamsToCall(std::ostream &out, sdg::DGParameters &params,\n                          sdg::DGNode *call) const {\n        /// input parameters\n        for (auto &param : params) {\n            auto &nd = param.getOutputArgument();\n            out << \"      \" << *call << \" -> \" << nd << \"[style=dashed]\\n\";\n        }\n\n        if (auto *noret = params.getNoReturn()) {\n            out << \"      \" << *call << \" -> \" << *noret << \"[style=dashed]\\n\";\n        }\n        if (auto *ret = params.getReturn()) {\n            out << \"      \" << *call << \" -> \" << *ret << \"[style=dashed]\\n\";\n        }\n    }\n\n    void dumpEdges(std::ostream &out, sdg::DGNode &nd) const {\n        for (auto *use : nd.uses()) {\n            out << \"    \" << nd << \" -> \" << *use << \"[style=\\\"dashed\\\"]\\n\";\n        }\n        for (auto *def : nd.memdep()) {\n            out << \"    \" << *def << \" -> \" << nd << \"[color=red]\\n\";\n        }\n        for (auto *ctrl : nd.controls()) {\n            out << \"    \" << nd << \" -> \" << *ctrl << \"[color=blue]\\n\";\n        }\n    }\n\n  public:\n    SDG2Dot(SystemDependenceGraph *sdg) : _llvmsdg(sdg) {}\n\n    void dump(const std::string &file) const {\n        std::ofstream out(file);\n        std::set<sdg::DGNodeCall *> calls;\n\n        out << \"digraph SDG {\\n\";\n        out << \"  compound=\\\"true\\\"\\n\";\n\n        for (auto *dg : _llvmsdg->getSDG()) {\n            ///\n            // Dependence graphs (functions)\n            out << \"  subgraph cluster_dg_\" << dg->getID() << \" {\\n\";\n            out << \"    color=black;\\n\";\n            out << \"    style=filled;\\n\";\n            out << \"    fillcolor=grey95;\\n\";\n            out << \"    label=\\\"\" << dg->getName() << \" (id \" << dg->getID()\n                << \")\\\";\\n\";\n            out << \"\\n\";\n\n            ///\n            // Parameters of the DG\n            //\n            /// Formal input parameters\n            dumpParams(out, dg->getParameters(), \"formal parameters\");\n\n            ///\n            // Basic blocks\n            for (auto *blk : dg->getBBlocks()) {\n                out << \"    subgraph cluster_dg_\" << dg->getID() << \"_bb_\"\n                    << blk->getID() << \" {\\n\";\n                out << \"      label=\\\"bblock #\" << blk->getID() << \"\\\"\\n\";\n                for (auto *nd : blk->getNodes()) {\n                    dumpedNodes.insert(nd);\n                    dumpNode(out, *nd);\n\n                    if (auto *C = sdg::DGNodeCall::get(nd)) {\n                        // store the node for later use (dumping of call edges\n                        // etc.)\n                        calls.insert(C);\n                        // dump actual parameters\n                        dumpParams(out, C->getParameters(),\n                                   \"actual parameters\");\n                    }\n                }\n                out << \"    }\\n\";\n            }\n\n            ///\n            // -- edges --\n            out << \"    /* edges */\\n\";\n            for (auto *nd : dg->getNodes()) {\n                dumpEdges(out, *nd);\n            }\n            out << \"    /* block edges */\\n\";\n            for (auto *blk : dg->getBBlocks()) {\n                for (auto *ctrl : blk->controls()) {\n                    out << \"    \" << *blk->back() << \" -> \";\n                    if (auto *ctrlB = sdg::DGBBlock::get(ctrl)) {\n                        out << *ctrlB->front();\n                    } else {\n                        out << *ctrl;\n                    }\n\n                    out << \"[color=blue penwidth=2 \"\n                        << \" ltail=cluster_dg_\" << dg->getID() << \"_bb_\"\n                        << blk->getID();\n\n                    if (ctrl->getType() == sdg::DGElementType::BBLOCK) {\n                        out << \" lhead=cluster_dg_\" << dg->getID() << \"_bb_\"\n                            << ctrl->getID();\n                    }\n                    out << \"]\\n\";\n                }\n            }\n\n            out << \"  }\\n\";\n\n            // formal parameters edges\n            dumpParamEdges(out, dg->getParameters());\n\n            dumpedNodes.clear();\n        }\n\n        ////\n        // -- Interprocedural edges and parameter edges--\n\n        if (!calls.empty()) {\n            out << \" /* call and param edges */\\n\";\n        }\n        for (auto *C : calls) {\n            bindParamsToCall(out, C->getParameters(), C);\n            dumpParamEdges(out, C->getParameters());\n            for (auto *dg : C->getCallees()) {\n                out << \"  \" << *C << \" -> \" << *dg->getFirstNode()\n                    << \"[lhead=cluster_dg_\" << dg->getID() << \" label=\\\"call '\"\n                    << dg->getName() << \"'\\\"\"\n                    << \" style=dashed penwidth=3]\\n\";\n            }\n        }\n\n        out << \"}\\n\";\n    }\n};\n\n} // namespace llvmdg\n} // namespace dg\n\n#endif // DG_LLVM_SDG2DOT_H_\n"
  },
  {
    "path": "include/dg/llvm/SystemDependenceGraph/SystemDependenceGraph.h",
    "content": "#ifndef DG_LLVM_SYSTEM_DEPENDNECE_GRAPH_H_\n#define DG_LLVM_SYSTEM_DEPENDNECE_GRAPH_H_\n\n#include <map>\n#include <utility>\n\n#include \"dg/SystemDependenceGraph/SystemDependenceGraph.h\"\n#include \"dg/llvm/ControlDependence/ControlDependence.h\"\n#include \"dg/llvm/DataDependence/DataDependence.h\"\n#include \"dg/llvm/LLVMAnalysisOptions.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n\nnamespace llvm {\nclass Module;\nclass Value;\n} // namespace llvm\n\nnamespace dg {\nnamespace llvmdg {\n\nclass SystemDependenceGraphOptions : public LLVMAnalysisOptions {};\n\n/* FIXME: hide this from the world */\nstruct SDGBuilder;\n\nclass SystemDependenceGraph {\n    const SystemDependenceGraphOptions _options;\n    llvm::Module *_module;\n    sdg::SystemDependenceGraph _sdg;\n    LLVMPointerAnalysis *_pta{nullptr};\n    dda::LLVMDataDependenceAnalysis *_dda{nullptr};\n    LLVMControlDependenceAnalysis *_cda{nullptr};\n\n    // SystemDependenceGraphBuilder _builder;\n    // FIXME: do this unordered maps\n    std::map<const llvm::Value *, sdg::DGElement *> _mapping;\n    std::map<const sdg::DGElement *, llvm::Value *> _rev_mapping;\n    // built functions\n    std::map<const llvm::Function *, sdg::DependenceGraph *> _fun_mapping;\n    std::map<const llvm::BasicBlock *, sdg::DGBBlock *> _blk_mapping;\n\n    void buildNodes();\n    void buildEdges();\n    void buildSDG();\n\n    void addMapping(llvm::Value *v, sdg::DGElement *n) {\n        assert(_mapping.find(v) == _mapping.end() && \"Already have this value\");\n        _mapping[v] = n;\n        _rev_mapping[n] = v;\n    }\n\n    void addFunMapping(llvm::Function *F, sdg::DependenceGraph *g) {\n        assert(_mapping.find(F) == _mapping.end() &&\n               \"Already have this function\");\n        _fun_mapping[F] = g;\n    }\n\n    void addBlkMapping(llvm::BasicBlock *b, sdg::DGBBlock *dgb) {\n        assert(_blk_mapping.find(b) == _blk_mapping.end() &&\n               \"Already have this block\");\n        _blk_mapping[b] = dgb;\n    }\n\n    friend struct SDGBuilder;\n\n  public:\n    SystemDependenceGraph(llvm::Module *M, LLVMPointerAnalysis *PTA,\n                          dda::LLVMDataDependenceAnalysis *DDA,\n                          LLVMControlDependenceAnalysis *CDA,\n                          SystemDependenceGraphOptions opts = {})\n            : _options(std::move(opts)), _module(M), _pta(PTA), _dda(DDA),\n              _cda(CDA) {\n        buildSDG();\n    }\n\n    llvm::Module *getModule() { return _module; }\n    const llvm::Module *getModule() const { return _module; }\n\n    sdg::DGElement *getNode(const llvm::Value *v) const {\n        auto it = _mapping.find(v);\n        return it == _mapping.end() ? nullptr : it->second;\n    }\n\n    sdg::DGBBlock *getBBlock(const llvm::BasicBlock *b) const {\n        auto it = _blk_mapping.find(b);\n        return it == _blk_mapping.end() ? nullptr : it->second;\n    }\n\n    llvm::Value *getValue(const sdg::DGElement *n) const {\n        auto it = _rev_mapping.find(n);\n        return it == _rev_mapping.end() ? nullptr : it->second;\n    }\n\n    sdg::DependenceGraph *getDG(const llvm::Function *F) const {\n        auto it = _fun_mapping.find(F);\n        return it == _fun_mapping.end() ? nullptr : it->second;\n    }\n\n    sdg::SystemDependenceGraph &getSDG() { return _sdg; }\n    const sdg::SystemDependenceGraph &getSDG() const { return _sdg; }\n};\n\n} // namespace llvmdg\n} // namespace dg\n\n#endif // DG_LLVM_SYSTEM_DEPENDNECE_GRAPH_H_\n"
  },
  {
    "path": "include/dg/llvm/SystemDependenceGraph/SystemDependenceGraphBuilder.h",
    "content": "#ifndef DG_LLVM_SYSTEM_DEPENDENCE_GRAPH_BUILDER_H_\n#define DG_LLVM_SYSTEM_DEPENDENCE_GRAPH_BUILDER_H_\n\n#include <ctime> // std::clock\n#include <string>\n\n#include <llvm/IR/Module.h>\n\n#include \"dg/llvm/DataDependence/DataDependence.h\"\n#include \"dg/llvm/DataDependence/LLVMDataDependenceAnalysisOptions.h\"\n#include \"dg/llvm/LLVMDependenceGraph.h\"\n#include \"dg/llvm/PointerAnalysis/LLVMPointerAnalysisOptions.h\"\n\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n#ifdef HAVE_SVF\n#include \"dg/llvm/PointerAnalysis/SVFPointerAnalysis.h\"\n#endif\n#include \"dg/Offset.h\"\n#include \"dg/PointerAnalysis/Pointer.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFI.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFS.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFSInv.h\"\n\nnamespace llvm {\nclass Module;\nclass Function;\n} // namespace llvm\n\nnamespace dg {\nnamespace llvmdg {\n\nclass LLVMPointerAnalysisOptions;\nclass LLVMDataDependenceAnalysisOptions;\n\nclass SystemDependenceGraphBuilder {\n    llvm::Module *_M;\n    const SystemDependenceGraphOptions _options;\n    std::unique_ptr<LLVMPointerAnalysis> _PTA{};\n    std::unique_ptr<LLVMDataDependenceAnalysis> _DDA{nullptr};\n    std::unique_ptr<SystemDependenceGraph> _sdg{};\n    std::unique_ptr<ControlFlowGraph> _controlFlowGraph{};\n    llvm::Function *_entryFunction{nullptr};\n\n    struct Statistics {\n        uint64_t cdTime{0};\n        uint64_t ptaTime{0};\n        uint64_t rdaTime{0};\n        uint64_t inferaTime{0};\n        uint64_t joinsTime{0};\n        uint64_t critsecTime{0};\n    } _statistics;\n\n    std::clock_t _time_start;\n    void _timerStart() { _time_start = std::clock(); }\n    uint64_t _timerEnd() { return (std::clock() - _time_start); }\n\n    void _runPointerAnalysis() {\n        assert(_PTA && \"BUG: No PTA\");\n\n        _timerStart();\n        _PTA->run();\n        _statistics.ptaTime = _timerEnd();\n    }\n\n    void _runDataDependenceAnalysis() {\n        assert(_DDA && \"BUG: No RD\");\n\n        _timerStart();\n        _DDA->run();\n        _statistics.rdaTime = _timerEnd();\n    }\n\n    void _runControlDependenceAnalysis() {\n        _timerStart();\n        _sdg->computeControlDependencies(_options.cdAlgorithm,\n                                         _options.interprocCd);\n        _statistics.cdTime = _timerEnd();\n    }\n\n    void _runInterferenceDependenceAnalysis() {\n        _timerStart();\n        _sdg->computeInterferenceDependentEdges(_controlFlowGraph.get());\n        _statistics.inferaTime = _timerEnd();\n    }\n\n    void _runForkJoinAnalysis() {\n        _timerStart();\n        _sdg->computeForkJoinDependencies(_controlFlowGraph.get());\n        _statistics.joinsTime = _timerEnd();\n    }\n\n    void _runCriticalSectionAnalysis() {\n        _timerStart();\n        _sdg->computeCriticalSections(_controlFlowGraph.get());\n        _statistics.critsecTime = _timerEnd();\n    }\n\n    bool verify() const { return _sdg->verify(); }\n\n  public:\n    SystemDependenceGraphBuilder(llvm::Module *M)\n            : SystemDependenceGraphBuilder(M, {}) {}\n\n    SystemDependenceGraphBuilder(llvm::Module *M,\n                                 const SystemDependenceGraphOptions &opts)\n            : _M(M), _options(opts), _PTA(createPTA()),\n              _DDA(new LLVMDataDependenceAnalysis(M, _PTA.get(),\n                                                  _options.DDAOptions)),\n              _sdg(new LLVMDependenceGraph(opts.threads)),\n              _controlFlowGraph(\n                      _options.threads && !_options.PTAOptions.isSVF()\n                              ? // check SVF due to the static cast...\n                              new ControlFlowGraph(\n                                      static_cast<DGLLVMPointerAnalysis *>(\n                                              _PTA.get()))\n                              : nullptr),\n              _entryFunction(M->getFunction(_options.entryFunction)) {\n        assert(_entryFunction && \"The entry function not found\");\n    }\n\n    LLVMPointerAnalysis *createPTA() {\n        if (_options.PTAOptions.isSVF())\n            return new SVFPointerAnalysis(_M, _options.PTAOptions);\n\n        return new DGLLVMPointerAnalysis(_M, _options.PTAOptions);\n    }\n\n    LLVMPointerAnalysis *getPTA() { return _PTA.get(); }\n    LLVMDataDependenceAnalysis *getRDA() { return _DDA.get(); }\n\n    const Statistics &getStatistics() const { return _statistics; }\n\n    // construct the whole graph with all edges\n    std::unique_ptr<SystemDependenceGraph> &&build() {\n        // compute data dependencies\n        _runPointerAnalysis();\n        _runDataDependenceAnalysis();\n\n        // build the graph itself (the nodes, but without edges)\n        _sdg->build(_M, _PTA.get(), _DDA.get(), _entryFunction);\n\n        // insert the data dependencies edges\n        _sdg->addDefUseEdges();\n\n        // compute and fill-in control dependencies\n        _runControlDependenceAnalysis();\n\n        if (_options.threads) {\n            if (_options.PTAOptions.isSVF()) {\n                assert(0 && \"Threading needs the DG pointer analysis, SVF is \"\n                            \"not supported yet\");\n                abort();\n            }\n            _controlFlowGraph->buildFunction(_entryFunction);\n            _runInterferenceDependenceAnalysis();\n            _runForkJoinAnalysis();\n            _runCriticalSectionAnalysis();\n        }\n\n        // verify if the graph is built correctly\n        if (_options.verifyGraph && !_sdg->verify()) {\n            _sdg.reset();\n            return std::move(_sdg);\n        }\n\n        return std::move(_sdg);\n    }\n\n    // Build only the graph with CFG edges.\n    // No dependencies between instructions are added.\n    // The dependencies must be filled in by calling computeDependencies()\n    // later.\n    // NOTE: this function still runs pointer analysis as it is needed\n    // for sound construction of CFG in the presence of function pointer calls.\n    std::unique_ptr<LLVMDependenceGraph> &&constructCFGOnly() {\n        // data dependencies\n        _runPointerAnalysis();\n\n        // build the graph itself\n        _sdg->build(_M, _PTA.get(), _DDA.get(), _entryFunction);\n\n        if (_options.threads) {\n            _controlFlowGraph->buildFunction(_entryFunction);\n        }\n\n        // verify if the graph is built correctly\n        if (_options.verifyGraph && !_sdg->verify()) {\n            _sdg.reset();\n            return std::move(_sdg);\n        }\n\n        return std::move(_sdg);\n    }\n\n    // This method serves to finish the graph construction\n    // after constructCFGOnly was used to build the graph.\n    // This function takes the dg (returned from the constructCFGOnly)\n    // and retains its ownership until it computes the edges.\n    // Then it returns the ownership back to the caller.\n    std::unique_ptr<LLVMDependenceGraph> &&\n    computeDependencies(std::unique_ptr<LLVMDependenceGraph> &&dg) {\n        // get the ownership\n        _sdg = std::move(dg);\n\n        // data-dependence edges\n        _runDataDependenceAnalysis();\n        _sdg->addDefUseEdges();\n\n        // fill-in control dependencies\n        _runControlDependenceAnalysis();\n\n        if (_options.threads) {\n            _runInterferenceDependenceAnalysis();\n            _runForkJoinAnalysis();\n            _runCriticalSectionAnalysis();\n        }\n\n        return std::move(_sdg);\n    }\n};\n\n} // namespace llvmdg\n} // namespace dg\n\n#endif // DG_LLVM_SYSTEM_DEPENDENCE_GRAPH_BUILDER_H_\n"
  },
  {
    "path": "include/dg/llvm/ThreadRegions/ControlFlowGraph.h",
    "content": "#ifndef CONTROLFLOWGRAPH_H\n#define CONTROLFLOWGRAPH_H\n\n#include <memory>\n#include <set>\n\n#include <llvm/IR/Instructions.h>\n\nnamespace dg {\nclass DGLLVMPointerAnalysis;\n}\n\nnamespace llvm {\nclass Function;\n}\n\nclass ThreadRegion;\nclass GraphBuilder;\nclass ThreadRegionsBuilder;\nclass CriticalSectionsBuilder;\n\nclass ControlFlowGraph {\n  private:\n    std::unique_ptr<GraphBuilder> graphBuilder;\n    std::unique_ptr<ThreadRegionsBuilder> threadRegionsBuilder;\n    std::unique_ptr<CriticalSectionsBuilder> criticalSectionsBuilder;\n\n  public:\n    ControlFlowGraph(dg::DGLLVMPointerAnalysis *pointsToAnalysis);\n\n    ~ControlFlowGraph();\n\n    std::set<const llvm::CallInst *> getJoins() const;\n\n    std::set<const llvm::CallInst *>\n    getCorrespondingForks(const llvm::CallInst *callInst) const;\n\n    std::set<const llvm::CallInst *> getLocks() const;\n\n    std::set<const llvm::CallInst *>\n    getCorrespongingUnlocks(const llvm::CallInst *callInst) const;\n\n    std::set<const llvm::Instruction *>\n    getCorrespondingCriticalSection(const llvm::CallInst *callInst) const;\n\n    void buildFunction(const llvm::Function *function);\n\n    void printWithRegions(std::ostream &ostream) const;\n\n    void printWithoutRegions(std::ostream &ostream) const;\n\n    std::set<ThreadRegion *> threadRegions();\n};\n\n#endif // CONTROLFLOWGRAPH_H\n"
  },
  {
    "path": "include/dg/llvm/ThreadRegions/MayHappenInParallel.h",
    "content": "#ifndef MAYHAPPENINPARALLEL_H\n#define MAYHAPPENINPARALLEL_H\n\n#include <set>\n\n#include \"ThreadRegion.h\"\n\nclass MayHappenInParallel {\n  private:\n    std::set<ThreadRegion *> threadRegions_;\n\n  public:\n    MayHappenInParallel(std::set<ThreadRegion *> threadRegions);\n\n    std::set<ThreadRegion *> parallelRegions(ThreadRegion *threadRegion);\n};\n\n#endif // MAYHAPPENINPARALLEL_H\n"
  },
  {
    "path": "include/dg/llvm/ThreadRegions/ThreadRegion.h",
    "content": "#ifndef THREADREGION_H\n#define THREADREGION_H\n\n#include <iosfwd>\n#include <set>\n\nclass Node;\nclass ControlFlowGraph;\n\nnamespace llvm {\nclass Instruction;\n}\n\nclass ThreadRegion {\n    int id_;\n    Node *foundingNode_;\n    std::set<Node *> nodes_;\n    std::set<ThreadRegion *> predecessors_;\n    std::set<ThreadRegion *> successors_;\n\n    static int lastId;\n\n  public:\n    ThreadRegion(Node *node);\n\n    int id() const;\n\n    bool addPredecessor(ThreadRegion *predecessor);\n    bool addSuccessor(ThreadRegion *threadRegion);\n\n    bool removePredecessor(ThreadRegion *predecessor);\n    bool removeSuccessor(ThreadRegion *successor);\n\n    const std::set<ThreadRegion *> &predecessors() const;\n    std::set<ThreadRegion *> predecessors();\n\n    const std::set<ThreadRegion *> &successors() const;\n    std::set<ThreadRegion *> successors();\n\n    bool insertNode(Node *node);\n    bool removeNode(Node *node);\n\n    Node *foundingNode() const;\n\n    const std::set<Node *> &nodes() const;\n    std::set<Node *> nodes();\n\n    void printNodes(std::ostream &ostream);\n    void printEdges(std::ostream &ostream);\n\n    std::string dotName();\n    /**\n     * @brief returns all llvm instructions contained in the thread region\n     * @return\n     */\n    std::set<const llvm::Instruction *> llvmInstructions() const;\n};\n\n#endif // THREADREGION_H\n"
  },
  {
    "path": "include/dg/llvm/ValueRelations/GraphBuilder.h",
    "content": "#ifndef DG_LLVM_VALUE_RELATIONS_GRAPH_BUILDER_H_\n#define DG_LLVM_VALUE_RELATIONS_GRAPH_BUILDER_H_\n\n#include \"GraphElements.h\"\n\n#include <llvm/IR/Module.h>\n\nnamespace dg {\nnamespace vr {\n\nclass GraphBuilder {\n    const llvm::Module &module;\n    VRCodeGraph &codeGraph;\n\n    std::map<const llvm::BasicBlock *, VRLocation *> fronts;\n    std::map<const llvm::BasicBlock *, VRLocation *> backs;\n\n    void buildBlocks(const llvm::Function &function);\n\n    void buildTerminators(const llvm::Function &function);\n\n    void buildBranch(const llvm::BranchInst *inst, VRLocation &last);\n\n    void buildSwitch(const llvm::SwitchInst *swtch, VRLocation &last);\n\n    static void buildReturn(const llvm::ReturnInst *inst, VRLocation &last);\n\n    void buildBlock(const llvm::BasicBlock &block);\n\n  public:\n    GraphBuilder(const llvm::Module &m, VRCodeGraph &c)\n            : module(m), codeGraph(c) {}\n\n    void build();\n};\n\n} // namespace vr\n} // namespace dg\n\n#endif // DG_LLVM_VALUE_RELATIONS_GRAPH_BUILDER_H_\n"
  },
  {
    "path": "include/dg/llvm/ValueRelations/GraphElements.h",
    "content": "#ifndef DG_LLVM_VALUE_RELATIONS_GRAPH_ELEMENTS_H_\n#define DG_LLVM_VALUE_RELATIONS_GRAPH_ELEMENTS_H_\n\n#include <cassert>\n#include <list>\n#include <queue>\n\n#include \"UniquePtrVector.h\"\n#include \"ValueRelations.h\"\n\n#include <llvm/IR/Instructions.h>\n\n#ifndef NDEBUG\n#include \"getValName.h\"\n#endif\n\nnamespace dg {\nnamespace vr {\n\nclass VROp {\n  protected:\n    enum class VROpType { NOOP, INSTRUCTION, ASSUME_BOOL, ASSUME_EQUAL } type;\n    VROp(VROpType t) : type(t) {}\n\n  public:\n    bool isNoop() const { return type == VROpType::NOOP; }\n    bool isInstruction() const { return type == VROpType::INSTRUCTION; }\n    bool isAssume() const { return isAssumeBool() || isAssumeEqual(); }\n    bool isAssumeBool() const { return type == VROpType::ASSUME_BOOL; }\n    bool isAssumeEqual() const { return type == VROpType::ASSUME_EQUAL; }\n\n    virtual ~VROp() = default;\n\n#ifndef NDEBUG\n    virtual std::string toStr() const = 0;\n\n    void generalDump(std::ostream &stream) const { stream << toStr(); }\n\n    void dump() const { generalDump(std::cout); }\n#endif\n};\n\nstruct VRNoop : public VROp {\n    VRNoop() : VROp(VROpType::NOOP) {}\n\n#ifndef NDEBUG\n    std::string toStr() const override { return \"(noop)\"; }\n#endif\n};\n\nstruct VRInstruction : public VROp {\n    const llvm::Instruction *instruction;\n\n    VRInstruction(const llvm::Instruction *I)\n            : VROp(VROpType::INSTRUCTION), instruction(I) {}\n\n    VRInstruction(const llvm::Instruction &I) : VRInstruction(&I) {}\n\n    const llvm::Instruction *getInstruction() const { return instruction; }\n\n#ifndef NDEBUG\n    std::string toStr() const override {\n        return debug::getValName(instruction);\n    }\n#endif\n};\n\nstruct VRAssume : public VROp {\n    const llvm::Value *val;\n\n    const llvm::Value *getValue() const { return val; }\n\n  protected:\n    VRAssume(VROpType type, const llvm::Value *v) : VROp(type), val(v) {}\n\n#ifndef NDEBUG\n    std::string toStr() const override {\n        return \"assuming \" + debug::getValName(val) + \" is \";\n    }\n#endif\n};\n\nstruct VRAssumeBool : public VRAssume {\n    bool assumption;\n\n    VRAssumeBool(const llvm::Value *v, bool b)\n            : VRAssume(VROpType::ASSUME_BOOL, v), assumption(b) {}\n\n    bool getAssumption() const { return assumption; }\n\n#ifndef NDEBUG\n    std::string toStr() const override {\n        return VRAssume::toStr() + (assumption ? \"true\" : \"false\");\n    }\n#endif\n};\n\nstruct VRAssumeEqual : public VRAssume {\n    const llvm::Value *assumption;\n\n    VRAssumeEqual(const llvm::Value *v, const llvm::Value *a)\n            : VRAssume(VROpType::ASSUME_EQUAL, v), assumption(a) {}\n\n    const llvm::Value *getAssumption() const { return assumption; }\n\n#ifndef NDEBUG\n    std::string toStr() const override {\n        return VRAssume::toStr() + debug::getValName(assumption);\n    }\n#endif\n};\n\nstruct VRLocation;\n\nenum class EdgeType {\n    TREE,\n    BACK,\n    FORWARD,\n    DEFAULT\n    // DANGER ignores cross\n};\n\nstruct VREdge {\n    VRLocation *source;\n    VRLocation *target;\n\n    std::unique_ptr<VROp> op;\n\n    EdgeType type = EdgeType::DEFAULT;\n\n    VREdge(VRLocation *s, VRLocation *t, std::unique_ptr<VROp> &&op)\n            : source(s), target(t), op(std::move(op)) {}\n\n    VREdge(VRLocation *s, VRLocation *t, VROp *opRaw)\n            : source(s), target(t), op(opRaw) {}\n};\n\nstruct VRLocation {\n    const unsigned id;\n\n    ValueRelations relations;\n\n    std::vector<VREdge *> predecessors;\n    std::vector<std::unique_ptr<VREdge>> successors;\n\n    std::vector<const VREdge *> loopEnds;\n    const VRLocation *join = nullptr;\n\n    VRLocation(unsigned _id) : id(_id) {}\n\n    void connect(std::unique_ptr<VREdge> &&edge);\n    void connect(VRLocation *target, std::unique_ptr<VROp> &&op);\n    void connect(VRLocation *target, VROp *op);\n    void connect(VRLocation &target, VROp *op);\n\n    unsigned predsSize() const { return predecessors.size(); }\n    unsigned succsSize() const { return successors.size(); }\n\n    VREdge *getPredEdge(unsigned i) const { return predecessors[i]; }\n    VREdge *getSuccEdge(unsigned i) const { return successors[i].get(); }\n\n    VRLocation *getPredLocation(unsigned i) const {\n        return predecessors[i]->source;\n    }\n    VRLocation *getSuccLocation(unsigned i) const {\n        return successors[i]->target;\n    }\n\n    std::vector<VRLocation *> getPredLocations();\n    std::vector<VRLocation *> getSuccLocations();\n\n    bool isJoin() const;\n    bool isJustBranchJoin() const;\n    bool isJustLoopJoin() const;\n\n    VRLocation &getTreePredecessor() const;\n\n#ifndef NDEBUG\n    void dump() const { std::cout << id << \"\\n\"; }\n#endif\n};\n\nclass VRCodeGraph {\n    friend class GraphBuilder;\n\n    UniquePtrVector<VRLocation> locations;\n    std::map<const llvm::Function *, VRLocation *> functionMapping;\n    // VRLocation corresponding to the state of the program BEFORE executing the\n    // instruction\n    std::map<const llvm::Instruction *, VRLocation *> locationMapping;\n\n    bool categorizedEdges = false;\n\n    VRLocation &newVRLocation();\n    VRLocation &newVRLocation(const llvm::Instruction *inst);\n    void setEntryLocation(const llvm::Function *f, VRLocation &loc);\n\n  public:\n    /* return VRLocation corresponding to the state of the program BEFORE\n     * executing the passed instruction */\n    VRLocation &getVRLocation(const llvm::Instruction *ptr) const;\n    VRLocation &getEntryLocation(const llvm::Function &f) const;\n\n    void hasCategorizedEdges();\n\n    /* ************ function iterator stuff ************ */\n\n  private:\n    class SimpleVisit {\n        std::set<VRLocation *> visited;\n\n      protected:\n        void find(VRLocation *loc);\n        static bool shouldVisit(__attribute__((unused)) VRLocation *loc) {\n            return true;\n        }\n\n      public:\n        bool wasVisited(VRLocation *loc) const;\n    };\n\n    class LazyVisit {\n        std::map<VRLocation *, unsigned> visited;\n\n        static unsigned getPrevEdgesSize(VRLocation *loc);\n\n      protected:\n        void find(VRLocation *loc);\n        bool shouldVisit(VRLocation *loc) const {\n            return visited.find(loc)->second >= getPrevEdgesSize(loc);\n        }\n\n      public:\n        bool wasVisited(VRLocation *loc) const;\n    };\n\n    enum class Dir { FORWARD, BACKWARD };\n\n    template <typename Visit>\n    class DFSIt : public Visit {\n        const llvm::Function *function;\n        std::vector<std::tuple<VRLocation *, unsigned, VREdge *>> stack;\n        Dir dir = Dir::FORWARD;\n\n        VREdge *getNextEdge(VRLocation *loc, unsigned i) const {\n            return dir == Dir::FORWARD ? loc->getSuccEdge(i)\n                                       : loc->getPredEdge(i);\n        }\n        VRLocation *getNextLocation(VREdge *edge) const {\n            return dir == Dir::FORWARD ? edge->target : edge->source;\n        }\n\n        bool inOtherFunction(VREdge *edge) const {\n            if (edge->op->isInstruction()) {\n                const llvm::Instruction *inst =\n                        static_cast<VRInstruction *>(edge->op.get())\n                                ->getInstruction();\n                if (inst->getFunction() != function) {\n                    assert(0 && \"has edge to other function\");\n                    return true;\n                }\n            }\n            return false;\n        }\n        // is null or target was visited or leads to other function\n        bool isIrrelevant(VREdge *edge) const {\n            VRLocation *next = getNextLocation(edge);\n            return !next || Visit::wasVisited(next) || inOtherFunction(edge);\n        }\n\n        void visit(VRLocation *loc) {\n            while (!Visit::wasVisited(loc))\n                Visit::find(loc);\n        }\n\n      public:\n        DFSIt() = default;\n        DFSIt(const llvm::Function &f, const VRLocation *start, Dir d)\n                : function(&f), dir(d) {\n            stack.emplace_back(const_cast<VRLocation *>(start), 0, nullptr);\n            visit(const_cast<VRLocation *>(start));\n        }\n\n        friend bool operator==(const DFSIt &lt, const DFSIt &rt) {\n            return lt.stack == rt.stack;\n        }\n        friend bool operator!=(const DFSIt &lt, const DFSIt &rt) {\n            return !(lt == rt);\n        }\n\n        DFSIt &operator++() {\n            while (!stack.empty()) {\n                VRLocation *current;\n                unsigned index;\n                VREdge *prevEdge;\n                std::tie(current, index, prevEdge) = stack.back();\n                stack.pop_back();\n\n                unsigned nextSize = dir == Dir::FORWARD ? current->succsSize()\n                                                        : current->predsSize();\n                // do not explore if there is no target or if target was already\n                // explored or if is in other function\n\n                while (index < nextSize &&\n                       isIrrelevant(getNextEdge(current, index)))\n                    ++index;\n\n                if (index >= nextSize)\n                    continue;\n                stack.emplace_back(current, index + 1, prevEdge);\n\n                VREdge *nextEdge = getNextEdge(current, index);\n                VRLocation *next = getNextLocation(nextEdge);\n\n                Visit::find(next);\n                if (Visit::shouldVisit(next)) {\n                    stack.emplace_back(next, 0, nextEdge);\n                    break;\n                }\n            }\n            return *this;\n        }\n\n        VRLocation &operator*() const { return *std::get<0>(stack.back()); }\n        VRLocation *operator->() const { return std::get<0>(stack.back()); }\n\n        bool onStack(VRLocation *loc) const {\n            for (const auto &elem : stack)\n                if (loc == std::get<0>(elem))\n                    return true;\n            return false;\n        }\n        VREdge *getEdge() const { return std::get<2>(stack.back()); }\n\n        void skipSuccessors() { stack.pop_back(); }\n    };\n\n  public:\n    using SimpleDFS = DFSIt<SimpleVisit>;\n    using LazyDFS = DFSIt<LazyVisit>;\n\n    LazyDFS lazy_dfs_begin(const llvm::Function &f) const;\n    LazyDFS lazy_dfs_begin(const llvm::Function &f,\n                           const VRLocation &start) const;\n    static LazyDFS lazy_dfs_end();\n\n    SimpleDFS dfs_begin(const llvm::Function &f) const;\n    SimpleDFS dfs_begin(const llvm::Function &f, const VRLocation &start) const;\n    static SimpleDFS dfs_end();\n\n    static SimpleDFS backward_dfs_begin(const llvm::Function &f,\n                                        const VRLocation &start);\n    static SimpleDFS backward_dfs_end();\n\n    /* ************ code graph iterator stuff ************ */\n\n    struct VRCodeGraphIterator {\n        using FunctionMapping = std::map<const llvm::Function *, VRLocation *>;\n        using MappingIterator = typename FunctionMapping::const_iterator;\n\n        VRCodeGraphIterator() = default;\n        VRCodeGraphIterator(MappingIterator end);\n        VRCodeGraphIterator(MappingIterator begin, MappingIterator end);\n\n        VRLocation &operator*() { return *intoFunction; }\n        VRLocation *operator->() { return &operator*(); }\n\n        friend bool operator==(const VRCodeGraphIterator &lt,\n                               const VRCodeGraphIterator &rt);\n        friend bool operator!=(const VRCodeGraphIterator &lt,\n                               const VRCodeGraphIterator &rt) {\n            return !(lt == rt);\n        }\n\n        VRCodeGraphIterator &operator++();\n        VRCodeGraphIterator operator++(int);\n\n      private:\n        MappingIterator intoMapping;\n        MappingIterator endMapping;\n\n        LazyDFS intoFunction;\n    };\n\n    VRCodeGraphIterator begin() const;\n    VRCodeGraphIterator end() const;\n};\n\n} // namespace vr\n} // namespace dg\n\n#endif // DG_LLVM_VALUE_RELATIONS_GRAPH_ELEMENTS_H_\n"
  },
  {
    "path": "include/dg/llvm/ValueRelations/RelationsAnalyzer.h",
    "content": "#ifndef DG_LLVM_VALUE_RELATION_RELATIONS_ANALYZER_H_\n#define DG_LLVM_VALUE_RELATION_RELATIONS_ANALYZER_H_\n\n#include <llvm/IR/CFG.h>\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/IntrinsicInst.h>\n#include <llvm/IR/Module.h>\n#include <llvm/IR/Value.h>\n\n#include <vector>\n\n#include \"GraphElements.h\"\n#include \"StructureAnalyzer.h\"\n#include \"ValueRelations.h\"\n\n#ifndef NDEBUG\n#include \"getValName.h\"\n#endif\n\nnamespace dg {\nnamespace vr {\n\nclass RelationsAnalyzer {\n    using Handle = ValueRelations::Handle;\n    using HandlePtr = ValueRelations::HandlePtr;\n    using HandleRef = ValueRelations::BRef;\n    using Relation = Relations::Type;\n    using V = ValueRelations::V;\n    using C = ValueRelations::C;\n    using I = const llvm::Instruction *;\n\n    const std::set<std::string> safeFunctions = {\"__VERIFIER_nondet_int\",\n                                                 \"__VERIFIER_nondet_char\"};\n\n    const llvm::Module &module;\n    const VRCodeGraph &codeGraph;\n\n    // holds information about structural properties of analyzed module\n    // like set of instructions executed in loop starging at given location\n    // or possibly set of values defined at given location\n    StructureAnalyzer &structure;\n\n    // ********************** points to invalidation ********************** //\n    static bool isIgnorableIntrinsic(llvm::Intrinsic::ID id);\n    bool isSafe(I inst) const;\n    static bool isDangerous(I inst);\n    bool mayHaveAlias(const ValueRelations &graph, V val) const;\n    bool mayHaveAlias(V val) const;\n    static bool hasKnownOrigin(const ValueRelations &graph, V from);\n    static bool hasKnownOrigin(V from);\n    bool mayOverwrite(I inst, V address) const;\n\n    // ************************ operation helpers ************************* //\n    static bool operandsEqual(ValueRelations &graph, I fst, I snd,\n                              bool sameOrder);\n    void solveByOperands(ValueRelations &graph,\n                         const llvm::BinaryOperator *operation, bool sameOrder);\n    void solveEquality(ValueRelations &graph,\n                       const llvm::BinaryOperator *operation);\n    void solveCommutativity(ValueRelations &graph,\n                            const llvm::BinaryOperator *operation);\n    enum class Shift { INC, DEC, EQ, UNKNOWN };\n    static Shift getShift(const llvm::BinaryOperator *op,\n                          const VectorSet<V> &froms);\n    static Shift getShift(const llvm::GetElementPtrInst *op,\n                          const VectorSet<V> &froms);\n    static Shift getShift(const llvm::Value *val, const VectorSet<V> &froms);\n    Shift getShift(const std::vector<const VRLocation *> &changeLocations,\n                   const VectorSet<V> &froms) const;\n    bool canShift(const ValueRelations &graph, V param, Relations::Type shift);\n    void solveDifferent(ValueRelations &graph, const llvm::BinaryOperator *op);\n    void inferFromNEPointers(ValueRelations &newGraph,\n                             VRAssumeBool *assume) const;\n    bool findEqualBorderBucket(const ValueRelations &relations,\n                               const llvm::Value *mBorderV,\n                               const llvm::Value *comparedV);\n\n    // ******************** gen from instruction ************************** //\n    static void storeGen(ValueRelations &graph, const llvm::StoreInst *store);\n    static void loadGen(ValueRelations &graph, const llvm::LoadInst *load);\n    static void gepGen(ValueRelations &graph,\n                       const llvm::GetElementPtrInst *gep);\n    static void extGen(ValueRelations &graph, const llvm::CastInst *ext);\n    void opGen(ValueRelations &graph, const llvm::BinaryOperator *op);\n    static void remGen(ValueRelations &graph, const llvm::BinaryOperator *rem);\n    void castGen(ValueRelations &graph, const llvm::CastInst *cast);\n\n    // ******************** process assumption ************************** //\n    static Relation ICMPToRel(const llvm::ICmpInst *icmp, bool assumption);\n    bool processICMP(const ValueRelations &oldGraph, ValueRelations &newGraph,\n                     VRAssumeBool *assume);\n    bool processPhi(ValueRelations &newGraph, VRAssumeBool *assume);\n\n    // *********************** merge helpers **************************** //\n    template <typename X, typename Y>\n    static Relations getCommon(const VRLocation &location, const X &lt,\n                               Relations known, const Y &rt) {\n        for (VREdge *predEdge : location.predecessors) {\n            const ValueRelations &predRels = predEdge->source->relations;\n            known &= predRels.between(lt, rt);\n            if (!known.any())\n                return Relations();\n        }\n        return known;\n    }\n    static void inferFromPreds(VRLocation &location, Handle lt, Relations known,\n                               Handle rt);\n    template <typename X>\n    static Relations\n    getCommonByPointedTo(const VectorSet<V> &froms,\n                         const std::vector<const VRLocation *> &changeLocations,\n                         const X &val, Relations rels) {\n        for (unsigned i = 1; i < changeLocations.size(); ++i) {\n            const ValueRelations &graph = changeLocations[i]->relations;\n            HandlePtr from = getCorrespondingByContent(graph, froms);\n            if (!from)\n                return Relations();\n            assert(graph.hasLoad(*from));\n            Handle loaded = graph.getPointedTo(*from);\n\n            rels &= graph.between(loaded, val);\n            if (!rels.any())\n                break;\n        }\n        return rels;\n    }\n    std::vector<const VRLocation *>\n    getBranchChangeLocations(const VRLocation &join,\n                             const VectorSet<V> &froms) const;\n    std::vector<const VRLocation *>\n    getLoopChangeLocations(const VRLocation &join,\n                           const VectorSet<V> &froms) const;\n\n    // get target locations of changing instructions\n    std::vector<const VRLocation *>\n    getChangeLocations(const VRLocation &join, const VectorSet<V> &froms);\n    static std::pair<C, Relations> getBoundOnPointedToValue(\n            const std::vector<const VRLocation *> &changeLocations,\n            const VectorSet<V> &froms, Relation rel);\n    std::vector<const llvm::ICmpInst *> getEQICmp(const VRLocation &join);\n    void inferFromNonEquality(VRLocation &join, const VectorSet<V> &froms,\n                              Shift s, Handle placeholder);\n    void\n    inferShiftInLoop(const std::vector<const VRLocation *> &changeLocations,\n                     const VectorSet<V> &froms, ValueRelations &newGraph,\n                     Handle placeholder);\n    static void\n    relateBounds(const std::vector<const VRLocation *> &changeLocations,\n                 const VectorSet<V> &froms, ValueRelations &newGraph,\n                 Handle placeholder);\n    static void\n    relateValues(const std::vector<const VRLocation *> &changeLocations,\n                 const VectorSet<V> &froms, ValueRelations &newGraph,\n                 Handle placeholder);\n\n    // **************************** merge ******************************* //\n    static void mergeRelations(VRLocation &location);\n    void mergeRelationsByPointedTo(VRLocation &location);\n\n    // ***************************** edge ******************************* //\n    void processInstruction(ValueRelations &graph, I inst);\n    void rememberValidated(const ValueRelations &prev, ValueRelations &graph,\n                           I inst) const;\n    bool processAssumeBool(const ValueRelations &oldGraph,\n                           ValueRelations &newGraph, VRAssumeBool *assume);\n    static bool processAssumeEqual(const ValueRelations &oldGraph,\n                                   ValueRelations &newGraph,\n                                   VRAssumeEqual *assume);\n\n    // ************************* topmost ******************************* //\n    void processOperation(VRLocation *source, VRLocation *target, VROp *op);\n    bool passFunction(const llvm::Function &function, bool print);\n\n  public:\n    RelationsAnalyzer(const llvm::Module &m, const VRCodeGraph &g,\n                      StructureAnalyzer &sa)\n            : module(m), codeGraph(g), structure(sa) {}\n\n    unsigned analyze(unsigned maxPass);\n\n    static std::vector<V> getFroms(const ValueRelations &rels, V val);\n    static HandlePtr getHandleFromFroms(const ValueRelations &rels,\n                                        const std::vector<V> &froms);\n    static HandlePtr getHandleFromFroms(const ValueRelations &toRels,\n                                        const ValueRelations &fromRels, V val);\n\n    static HandlePtr getCorrespondingByContent(const ValueRelations &toRels,\n                                               const ValueRelations &fromRels,\n                                               Handle h);\n    static HandlePtr getCorrespondingByContent(const ValueRelations &toRels,\n                                               const VectorSet<V> &vals);\n\n    static HandlePtr getCorrespondingByFrom(const ValueRelations &toRels,\n                                            const ValueRelations &fromRels,\n                                            Handle h);\n\n    static const llvm::AllocaInst *getOrigin(const ValueRelations &rels, V val);\n};\n\n} // namespace vr\n} // namespace dg\n\n#endif // DG_LLVM_VALUE_RELATION_RELATIONS_ANALYZER_H_\n"
  },
  {
    "path": "include/dg/llvm/ValueRelations/StructureAnalyzer.h",
    "content": "#ifndef DG_LLVM_VALUE_RELATION_STRUCTURE_ANALYZER_H_\n#define DG_LLVM_VALUE_RELATION_STRUCTURE_ANALYZER_H_\n\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/IntrinsicInst.h>\n#include <llvm/IR/Module.h>\n#include <llvm/IR/Value.h>\n\n#include <algorithm>\n\n#include \"GraphElements.h\"\n#include \"StructureElements.h\"\n#include \"dg/AnalysisOptions.h\"\n\nnamespace dg {\nnamespace vr {\n\nclass StructureAnalyzer {\n    const llvm::Module &module;\n    VRCodeGraph &codeGraph;\n\n    // holds vector of instructions, which are processed on any path back to\n    // given location is computed only for locations with more than one\n    // predecessor\n    std::map<const VRLocation *, std::vector<const llvm::Instruction *>>\n            inloopValues;\n\n    // holds vector of values, which are defined at given location\n    std::map<VRLocation *, std::set<const llvm::Value *>> defined;\n\n    const std::vector<unsigned> collected = {llvm::Instruction::Add,\n                                             llvm::Instruction::Sub,\n                                             llvm::Instruction::Mul};\n    std::map<unsigned, std::set<const llvm::Instruction *>> instructionSets;\n\n    std::vector<AllocatedArea> allocatedAreas;\n\n    std::map<const llvm::Function *, std::vector<CallRelation>>\n            callRelationsMap;\n\n    std::map<const llvm::Function *, std::vector<Precondition>>\n            preconditionsMap;\n    std::map<const llvm::Function *, std::vector<BorderValue>> borderValues;\n\n    void categorizeEdges();\n\n    void findLoops();\n\n    std::set<VRLocation *> collectBackward(const llvm::Function &f,\n                                           VRLocation &from);\n\n    void initializeDefined();\n\n    void collectInstructionSet();\n\n    static bool isValidAllocationCall(const llvm::Value *val);\n\n    void collectAllocatedAreas();\n\n    void setValidAreasFromNoPredecessors(std::vector<bool> &validAreas) const;\n\n    std::pair<unsigned, const AllocatedArea *>\n    getEqualArea(const ValueRelations &graph, const llvm::Value *ptr) const;\n\n    void invalidateHeapAllocatedAreas(std::vector<bool> &validAreas) const;\n\n    void setValidAreasByInstruction(VRLocation &location,\n                                    std::vector<bool> &validAreas,\n                                    VRInstruction *vrinst) const;\n\n    void setValidArea(std::vector<bool> &validAreas, const AllocatedArea *area,\n                      unsigned index, bool validateThis) const;\n\n    // if heap allocation call was just checked as successful, mark memory valid\n    void setValidAreasByAssumeBool(VRLocation &location,\n                                   std::vector<bool> &validAreas,\n                                   VRAssumeBool *assume) const;\n\n    void\n    setValidAreasFromSinglePredecessor(VRLocation &location,\n                                       std::vector<bool> &validAreas) const;\n\n    static bool trueInAll(const std::vector<std::vector<bool>> &validInPreds,\n                          unsigned index);\n\n    // in returned vector, false signifies that corresponding area is\n    // invalidated by some of the passed instructions\n    std::vector<bool> getInvalidatedAreas(\n            const std::vector<const llvm::Instruction *> &instructions) const;\n\n    void\n    setValidAreasFromMultiplePredecessors(VRLocation &location,\n                                          std::vector<bool> &validAreas) const;\n\n    void computeValidAreas() const;\n\n    void initializeCallRelations();\n\n  public:\n    StructureAnalyzer(const llvm::Module &m, VRCodeGraph &g)\n            : module(m), codeGraph(g){};\n\n    void analyzeBeforeRelationsAnalysis();\n\n    void analyzeAfterRelationsAnalysis();\n\n    bool isDefined(VRLocation *loc, const llvm::Value *val) const;\n\n    std::vector<const VREdge *> possibleSources(const llvm::PHINode *phi,\n                                                bool bval) const;\n    std::vector<const llvm::ICmpInst *>\n    getRelevantConditions(const VRAssumeBool *assume) const;\n\n    // assumes that location is valid loop start (join of tree and back edges)\n    const std::vector<const llvm::Instruction *> &\n    getInloopValues(const VRLocation &location) const {\n        return inloopValues.at(&location);\n    }\n\n    const std::set<const llvm::Instruction *> &\n    getInstructionSetFor(unsigned opcode) const {\n        return instructionSets.at(opcode);\n    }\n\n    std::pair<unsigned, const AllocatedArea *>\n    getAllocatedAreaFor(const llvm::Value *ptr) const;\n\n    unsigned getNumberOfAllocatedAreas() const { return allocatedAreas.size(); }\n\n    const std::vector<CallRelation> &\n    getCallRelationsFor(const llvm::Instruction *inst) const;\n\n    void addPrecondition(const llvm::Function *func, const llvm::Argument *lt,\n                         Relations::Type rel, const llvm::Value *rt);\n\n    bool hasPreconditions(const llvm::Function *func) const;\n\n    const std::vector<Precondition> &\n    getPreconditionsFor(const llvm::Function *func) const;\n\n    size_t addBorderValue(const llvm::Function *func,\n                          const llvm::Argument *from,\n                          const llvm::Value *stored);\n\n    bool hasBorderValues(const llvm::Function *func) const;\n\n    const std::vector<BorderValue> &\n    getBorderValuesFor(const llvm::Function *func) const;\n\n    BorderValue getBorderValueFor(const llvm::Function *func, size_t id) const;\n\n#ifndef NDEBUG\n    void dumpBorderValues(std::ostream &out = std::cerr) const;\n#endif\n};\n\n} // namespace vr\n} // namespace dg\n\n#endif // DG_LLVM_VALUE_RELATION_STRUCTURE_ANALYZER_H_\n"
  },
  {
    "path": "include/dg/llvm/ValueRelations/StructureElements.h",
    "content": "#ifndef DG_LLVM_VALUE_RELATION_STRUCTURE_ELEMENTS_H_\n#define DG_LLVM_VALUE_RELATION_STRUCTURE_ELEMENTS_H_\n\n#include <llvm/IR/Value.h>\n\n#include \"GraphElements.h\"\n\nnamespace dg {\nnamespace vr {\n\nstruct AllocatedSizeView {\n    const llvm::Value *elementCount = nullptr;\n    uint64_t elementSize = 0; // in bytes\n\n    AllocatedSizeView() = default;\n    AllocatedSizeView(const llvm::Value *count, uint64_t size)\n            : elementCount(count), elementSize(size) {}\n};\n\nclass AllocatedArea {\n    const llvm::Value *ptr;\n    // used only if memory was allocated with realloc, as fallback when realloc\n    // fails\n    const llvm::Value *reallocatedPtr = nullptr;\n    AllocatedSizeView originalSizeView;\n\n  public:\n    static const llvm::Value *stripCasts(const llvm::Value *inst);\n\n    static uint64_t getBytes(const llvm::Type *type);\n\n    AllocatedArea(const llvm::AllocaInst *alloca);\n\n    AllocatedArea(const llvm::CallInst *call);\n\n    const llvm::Value *getPtr() const { return ptr; }\n    const llvm::Value *getReallocatedPtr() const { return reallocatedPtr; }\n\n    std::vector<AllocatedSizeView> getAllocatedSizeViews() const;\n\n#ifndef NDEBUG\n    void ddump() const;\n#endif\n};\n\nstruct CallRelation {\n    std::vector<std::pair<const llvm::Argument *, const llvm::Value *>>\n            equalPairs;\n    VRLocation *callSite = nullptr;\n};\n\nstruct Precondition {\n    const llvm::Argument *arg;\n    Relations::Type rel;\n    const llvm::Value *val;\n\n    Precondition(const llvm::Argument *a, Relations::Type r,\n                 const llvm::Value *v)\n            : arg(a), rel(r), val(v) {}\n};\n\nstruct BorderValue {\n    size_t id;\n    const llvm::Argument *from;\n    const llvm::Value *stored;\n\n    BorderValue(size_t i, const llvm::Argument *f, const llvm::Value *s)\n            : id(i), from(f), stored(s) {}\n};\n\n} // namespace vr\n} // namespace dg\n\n#endif // DG_LLVM_VALUE_RELATION_STRUCTURE_ELEMENTS_H_\n"
  },
  {
    "path": "include/dg/llvm/ValueRelations/UniquePtrVector.h",
    "content": "#ifndef DG_LLVM_VALUE_RELATIONS_UNIQUE_PTR_VECTOR_H_\n#define DG_LLVM_VALUE_RELATIONS_UNIQUE_PTR_VECTOR_H_\n\n#include <memory>\n#include <vector>\n\nnamespace dg {\nnamespace vr {\n\ntemplate <typename T>\nclass UniquePtrVector {\n    using Container = std::vector<std::unique_ptr<T>>;\n    using size_type = typename Container::size_type;\n    using value_type = T;\n    using reference = value_type &;\n\n    Container _v;\n\n  public:\n    struct iterator {\n        friend class UniquePtrVector<T>;\n\n        using ContainerIterator = typename Container::const_iterator;\n\n        using value_type = T;\n        using reference = value_type &;\n        using pointer = value_type *;\n        using difference_type = typename ContainerIterator::difference_type;\n        using iterator_category =\n                std::bidirectional_iterator_tag; // std::forward_iterator_tag;\n\n        iterator() = default;\n        iterator(ContainerIterator i) : it(i) {}\n\n        reference operator*() const { return **it; }\n        pointer operator->() const { return &operator*(); }\n\n        friend bool operator==(const iterator &lt, const iterator &rt) {\n            return lt.it == rt.it;\n        }\n\n        friend bool operator!=(const iterator &lt, const iterator &rt) {\n            return !(lt == rt);\n        }\n\n        iterator &operator++() {\n            ++it;\n            return *this;\n        }\n\n        iterator operator++(int) {\n            auto copy = *this;\n            ++*this;\n            return copy;\n        }\n\n        iterator &operator--() {\n            --it;\n            return *this;\n        }\n\n        iterator operator--(int) {\n            auto copy = *this;\n            --*this;\n            return copy;\n        }\n\n      private:\n        ContainerIterator it;\n    };\n\n    reference at(size_type pos) const { return *_v.at(pos); }\n    reference operator[](size_type pos) const { return *_v[pos]; }\n\n    reference front() const { return *_v.front(); }\n    reference back() const { return *_v.back(); }\n\n    bool empty() const { return _v.empty(); }\n    size_type size() const { return _v.size(); }\n\n    void clear() { _v.clear(); }\n\n    iterator begin() const { return iterator(_v.begin()); }\n    iterator end() const { return iterator(_v.end()); }\n\n    template <typename TT>\n    void push_back(TT &&val) {\n        _v.emplace_back(new T(std::forward<TT>(val)));\n    }\n\n    template <typename... Args>\n    void emplace_back(Args &&...args) {\n        _v.emplace_back(new T(std::forward<Args>(args)...));\n    }\n\n    iterator erase(iterator pos) { return iterator(_v.erase(pos.it)); }\n\n    iterator erase(iterator b, iterator e) {\n        return iterator(_v.erase(b.it, e.it));\n    }\n\n    void swap(UniquePtrVector &other) {\n        using std::swap;\n        swap(_v, other._v);\n    }\n\n    friend void swap(UniquePtrVector &lt, UniquePtrVector &rt) { lt.swap(rt); }\n};\n\n} // namespace vr\n} // namespace dg\n\n#endif // DG_LLVM_VALUE_RELATIONS_UNIQUE_PTR_VECTOR_H_\n"
  },
  {
    "path": "include/dg/llvm/ValueRelations/ValueRelations.h",
    "content": "#ifndef DG_LLVM_VALUE_RELATIONS_VALUE_RELATIONS_H_\n#define DG_LLVM_VALUE_RELATIONS_VALUE_RELATIONS_H_\n\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/Value.h>\n\n#include <map>\n\n#ifndef NDEBUG\n#include \"getValName.h\"\n#include <iostream>\n#endif\n\n#include \"dg/ValueRelations/RelationsGraph.h\"\n\nnamespace dg {\nnamespace vr {\n\nstruct ValueRelations {\n    using RelGraph = RelationsGraph<ValueRelations>;\n    using Handle = const Bucket &;\n    using HandlePtr = const Bucket *;\n    using BRef = std::reference_wrapper<const Bucket>;\n    using RelationsMap = RelGraph::RelationsMap;\n    using V = const llvm::Value *;\n    using C = const llvm::ConstantInt *;\n\n    using ValToBucket = std::map<V, BRef>;\n    using BucketToVals = std::map<BRef, VectorSet<V>>;\n\n  private:\n    using BareC = llvm::ConstantInt;\n\n    template <typename T>\n    friend class RelationsGraph;\n    friend class ValueIterator;\n\n    RelGraph graph;\n\n    ValToBucket valToBucket;\n    BucketToVals bucketToVals;\n    std::vector<bool> validAreas;\n\n    bool changed = false;\n\n    // ****************************** get ********************************* //\n    static HandlePtr maybeGet(Handle h) { return &h; }\n    HandlePtr maybeGet(V val) const;\n\n    static std::pair<BRef, bool> get(Handle h) { return {h, false}; }\n    std::pair<BRef, bool> get(size_t id);\n    std::pair<BRef, bool> get(V val);\n\n    V getAny(Handle h) const;\n    ValueRelations::C getAnyConst(Handle h) const;\n\n    std::pair<ValueRelations::C, Relations> getBound(Handle h,\n                                                     Relations rel) const;\n    std::pair<ValueRelations::C, Relations> getBound(V val,\n                                                     Relations rel) const;\n\n    static HandlePtr getHandleByPtr(Handle h);\n\n    // ************************* general unset **************************** //\n    void unset(Relations rels) {\n        assert(!rels.has(Relations::EQ));\n        bool ch = graph.unset(rels);\n        updateChanged(ch);\n    }\n    void unset(Relations::Type rel) { unset(Relations().set(rel)); }\n    template <typename X>\n    void unset(const X &val, Relations rels) {\n        if (HandlePtr mH = maybeGet(val)) {\n            bool ch = graph.unset(*mH, rels);\n            updateChanged(ch);\n        }\n    }\n    template <typename X>\n    void unset(const X &val, Relations::Type rel) {\n        unset(val, Relations().set(rel));\n    }\n\n    // *********************** general between *************************** //\n    Relations _between(Handle lt, Handle rt) const;\n    Relations _between(Handle lt, V rt) const;\n    Relations _between(Handle lt, C rt) const;\n    Relations _between(V lt, Handle rt) const;\n    Relations _between(C lt, Handle rt) const;\n    Relations _between(V lt, V rt) const;\n    template <typename X>\n    Relations _between(size_t lt, const X &rt) const {\n        HandlePtr mH = getBorderH(lt);\n        return mH ? _between(*mH, rt) : Relations();\n    }\n    Relations _between(Handle lt, size_t rt) const;\n    Relations _between(V lt, size_t rt) const;\n\n    // *************************** iterators ***************************** //\n    class RelatedValueIterator {\n        using RelatedIterator = RelationsMap::iterator;\n        using ValIterator = typename VectorSet<V>::const_iterator;\n\n        const ValueRelations &vr;\n\n        RelationsMap related;\n        RelatedIterator bucketIt;\n        ValIterator valueIt;\n\n        std::pair<V, Relations> current;\n\n        bool isEnd = false;\n\n        const VectorSet<V> &getCurrentEqual() const {\n            return vr.bucketToVals.find(bucketIt->first)->second;\n        }\n\n        void updateCurrent() {\n            current = std::make_pair(*valueIt, bucketIt->second);\n        }\n\n        void nextViableValue() {\n            while (valueIt == getCurrentEqual().end()) {\n                ++bucketIt;\n                if (bucketIt == related.end()) {\n                    isEnd = true;\n                    return;\n                }\n                valueIt = getCurrentEqual().begin();\n            }\n            updateCurrent();\n        }\n\n      public:\n        using value_type = decltype(current);\n        using difference_type = int64_t;\n        using iterator_category = std::input_iterator_tag;\n\n        using reference = value_type &;\n        using pointer = value_type *;\n\n        // for end iterator\n        RelatedValueIterator(const ValueRelations &v) : vr(v), isEnd(true) {}\n        // for begin iterator\n        RelatedValueIterator(const ValueRelations &v, Handle start,\n                             const Relations &allowedEdges)\n                : vr(v), related(vr.graph.getRelated(start, allowedEdges)),\n                  bucketIt(related.begin()),\n                  valueIt(getCurrentEqual().begin()) {\n            assert(allowedEdges.has(Relations::EQ) &&\n                   \"at least one related bucket\");\n            nextViableValue();\n        }\n\n        friend bool operator==(const RelatedValueIterator &lt,\n                               const RelatedValueIterator &rt) {\n            return (lt.isEnd && rt.isEnd) ||\n                   (!lt.isEnd && !rt.isEnd && lt.bucketIt == rt.bucketIt &&\n                    lt.valueIt == rt.valueIt);\n        }\n        friend bool operator!=(const RelatedValueIterator &lt,\n                               const RelatedValueIterator &rt) {\n            return !(lt == rt);\n        }\n\n        RelatedValueIterator &operator++() {\n            ++valueIt;\n            nextViableValue();\n            return *this;\n        }\n        RelatedValueIterator operator++(int) {\n            auto copy = *this;\n            ++*this;\n            return copy;\n        }\n\n        reference operator*() { return current; }\n        pointer operator->() { return &current; }\n    };\n\n    class PlainValueIterator {\n        using BucketIterator = std::map<BRef, VectorSet<V>>::const_iterator;\n        using ValIterator = VectorSet<V>::const_iterator;\n\n        BucketIterator bucketIt;\n        BucketIterator endIt;\n        ValIterator valueIt;\n\n        bool nextViableValue() {\n            while (valueIt == bucketIt->second.end()) {\n                if (++bucketIt == endIt)\n                    return false;\n                valueIt = bucketIt->second.begin();\n            }\n            return true;\n        }\n\n      public:\n        using value_type = V;\n        using difference_type = int64_t;\n        using iterator_category = std::input_iterator_tag;\n\n        using reference = value_type;\n        using pointer = const value_type *;\n\n        // for end iterator\n        PlainValueIterator(BucketIterator e) : bucketIt(e) {}\n        // for begin iterator\n        PlainValueIterator(BucketIterator b, BucketIterator e)\n                : bucketIt(b), endIt(e), valueIt(b->second.begin()) {\n            nextViableValue();\n        }\n\n        friend bool operator==(const PlainValueIterator &lt,\n                               const PlainValueIterator &rt) {\n            return lt.bucketIt == rt.bucketIt;\n        }\n        friend bool operator!=(const PlainValueIterator &lt,\n                               const PlainValueIterator &rt) {\n            return !(lt == rt);\n        }\n\n        PlainValueIterator &operator++() {\n            ++valueIt;\n            nextViableValue();\n            return *this;\n        }\n\n        PlainValueIterator operator++(int) {\n            auto copy = *this;\n            ++*this;\n            return copy;\n        }\n\n        reference operator*() const { return *valueIt; }\n        pointer operator->() const { return &(*valueIt); }\n    };\n\n    // ***************************** other ******************************** //\n    HandlePtr getCorresponding(const ValueRelations &other, Handle otherH,\n                               const VectorSet<V> &otherEqual);\n    HandlePtr getCorresponding(const ValueRelations &other, Handle otherH);\n    HandlePtr getAndMerge(const ValueRelations &other, Handle otherH);\n    void add(V val, Handle h, VectorSet<V> &vals);\n    std::pair<BRef, bool> add(V val, Handle h);\n    void areMerged(Handle to, Handle from);\n    void updateChanged(bool ch) { changed |= ch; }\n\n  public:\n    ValueRelations() : graph(*this) {}\n    ValueRelations(const ValueRelations &) = delete;\n\n    using rel_iterator = RelatedValueIterator;\n    using plain_iterator = PlainValueIterator;\n\n    // ****************************** get ********************************* //\n    HandlePtr getHandle(V val) const;\n\n    template <typename I>\n    const I *getInstance(V v) const {\n        HandlePtr mH = maybeGet(v);\n        if (!mH)\n            return llvm::dyn_cast<I>(v);\n        return getInstance<I>(*mH);\n    }\n\n    template <typename I>\n    const I *getInstance(Handle h) const {\n        for (const auto *val : getEqual(h)) {\n            if (const auto *inst = llvm::dyn_cast<I>(val))\n                return inst;\n        }\n        return nullptr;\n    }\n\n    // ****************************** set ********************************* //\n    template <typename X, typename Y>\n    void set(const X &lt, Relations::Type rel, const Y &rt) {\n        auto ltHPair = get(lt);\n        auto rtHPair = get(rt);\n        if (rtHPair.second) {\n            ltHPair = get(lt);\n            assert(!ltHPair.second);\n        }\n        bool ch = graph.addRelation(ltHPair.first, rel, rtHPair.first);\n        updateChanged(ch);\n    }\n    template <typename X, typename Y>\n    void set(const X &lt, Relations rels, const Y &rt) {\n        Relations::Type rel = rels.get();\n        set(lt, rel, rt);\n        Relations other = rels & Relations().ult().ule().ugt().uge();\n        if (other.any() && !Relations().set(rel).addImplied().has(other.get()))\n            set(lt, other.get(), rt);\n    }\n    template <typename X, typename Y>\n    void setEqual(const X &lt, const Y &rt) {\n        set(lt, Relations::EQ, rt);\n    }\n    template <typename X, typename Y>\n    void setNonEqual(const X &lt, const Y &rt) {\n        set(lt, Relations::NE, rt);\n    }\n    template <typename X, typename Y>\n    void setLesser(const X &lt, const Y &rt) {\n        set(lt, Relations::SLT, rt);\n    }\n    template <typename X, typename Y>\n    void setLesserEqual(const X &lt, const Y &rt) {\n        set(lt, Relations::SLE, rt);\n    }\n    template <typename X, typename Y>\n    void setLoad(const X &from, const Y &to) {\n        set(from, Relations::PT, to);\n    }\n\n    // ***************************** unset ******************************** //\n    template <typename X>\n    void unsetAllLoadsByPtr(const X &from) {\n        unset(from, Relations::PT);\n    }\n    void unsetAllLoads() { unset(Relations::PT); }\n    template <typename X>\n    void unsetComparativeRelations(const X &val) {\n        unset(val, Relations(comparative).set(Relations::EQ, false));\n    }\n\n    // ******************************* is ********************************** //\n    template <typename X, typename Y>\n    Relations between(const X &lt, const Y &rt) const {\n        return _between(lt, rt);\n    }\n    template <typename X, typename Y>\n    bool are(const X &lt, Relations rels, const Y &rt) const {\n        return (_between(lt, rt) & rels) == rels;\n    }\n    template <typename X, typename Y>\n    bool are(const X &lt, Relations::Type rel, const Y &rt) const {\n        return _between(lt, rt).has(rel);\n    }\n    template <typename X, typename Y>\n    bool isEqual(const X &lt, const Y &rt) const {\n        return are(lt, Relations::EQ, rt);\n    }\n    template <typename X, typename Y>\n    bool isNonEqual(const X &lt, const Y &rt) const {\n        return are(lt, Relations::NE, rt);\n    }\n    template <typename X, typename Y>\n    bool isLesser(const X &lt, const Y &rt) const {\n        return are(lt, Relations::SLT, rt);\n    }\n    template <typename X, typename Y>\n    bool isLesserEqual(const X &lt, const Y &rt) const {\n        return are(lt, Relations::SLE, rt);\n    }\n    template <typename X, typename Y>\n    bool isLoad(const X &from, const Y &to) const {\n        return are(from, Relations::PT, to);\n    }\n\n    // ****************************** has ********************************* //\n    template <typename X>\n    bool has(const X &val, Relations::Type rel) const {\n        HandlePtr mVal = maybeGet(val);\n        return mVal && mVal->hasRelation(rel);\n    }\n    template <typename X>\n    bool has(const X &val, Relations rels) const {\n        HandlePtr mVal = maybeGet(val);\n        return mVal && ((rels.has(Relations::EQ) &&\n                         bucketToVals.find(*mVal)->second.size() > 1) ||\n                        mVal->hasAnyRelation(rels.set(Relations::EQ, false)));\n    }\n    template <typename X>\n    bool hasLoad(const X &from) const {\n        return has(from, Relations::PT);\n    }\n    template <typename X, typename Y>\n    bool haveConflictingRelations(const X &lt, Relations::Type rel,\n                                  const Y &rt) const {\n        HandlePtr mLt = maybeGet(lt);\n        HandlePtr mRt = maybeGet(rt);\n\n        return mLt && mRt && graph.haveConflictingRelation(*mLt, rel, *mRt);\n    }\n    template <typename X, typename Y>\n    bool hasConflictingRelation(const X &lt, const Y &rt,\n                                Relations::Type rel) const {\n        return haveConflictingRelations(lt, rel, rt);\n    }\n    template <typename X>\n    bool hasComparativeRelations(const X &val) const {\n        return has(val, comparative);\n    }\n    template <typename X>\n    bool hasAnyRelation(const X &val) const {\n        return has(val, allRelations);\n    }\n    template <typename X>\n    bool hasEqual(const X &val) const {\n        return has(val, Relations().eq());\n    }\n    template <typename X>\n    bool contains(const X &val) const {\n        return maybeGet(val);\n    }\n\n    // *************************** iterators ****************************** //\n    rel_iterator begin_related(V val, const Relations &rels = restricted) const;\n    rel_iterator end_related(V val) const;\n\n    RelGraph::iterator begin_related(Handle h,\n                                     const Relations &rels = restricted) const;\n    RelGraph::iterator end_related(Handle h) const;\n\n    plain_iterator begin() const;\n    plain_iterator end() const;\n\n    RelGraph::iterator\n    begin_buckets(const Relations &rels = allRelations) const;\n    RelGraph::iterator end_buckets() const;\n\n    const ValToBucket &getValToBucket() const { return valToBucket; }\n    const BucketToVals &getBucketToVals() const { return bucketToVals; }\n\n    // ****************************** get ********************************* //\n    const VectorSet<V> &getEqual(Handle h) const;\n    VectorSet<V> getEqual(V val) const;\n\n    template <typename X>\n    RelGraph::RelationsMap getAllRelated(const X &val) const {\n        return getRelated(val, allRelations);\n    }\n    template <typename X>\n    RelGraph::RelationsMap getRelated(const X &val,\n                                      const Relations &rels) const {\n        HandlePtr mH = maybeGet(val);\n        if (!mH)\n            return {};\n        return graph.getRelated(*mH, rels);\n    }\n\n    std::vector<V> getDirectlyRelated(V val, const Relations &rels) const;\n\n    template <typename X>\n    std::pair<C, Relations> getBound(const X &val, Relations::Type rel) const {\n        assert(nonStrict.has(rel));\n        return getBound(val, Relations().set(rel));\n    }\n    template <typename X>\n    std::pair<C, Relations> getLowerBound(const X &val) const {\n        return getBound(val, Relations().sge());\n    }\n    template <typename X>\n    std::pair<C, Relations> getUpperBound(const X &val) const {\n        return getBound(val, Relations().sle());\n    }\n\n    C getLesserEqualBound(V val) const;\n    C getGreaterEqualBound(V val) const;\n\n    VectorSet<V> getValsByPtr(V from) const;\n\n    template <typename X>\n    Handle getPointedTo(const X &from) const {\n        HandlePtr mH = maybeGet(from);\n        assert(mH);\n        return mH->getRelated(Relations::PT);\n    }\n\n    std::vector<bool> &getValidAreas() { return validAreas; }\n    const std::vector<bool> &getValidAreas() const { return validAreas; }\n\n    // ************************** placeholder ***************************** //\n    Handle newBorderBucket(size_t id) {\n        Handle h = graph.getBorderBucket(id);\n        bucketToVals[h];\n        return h;\n    }\n\n    template <typename X>\n    Handle newPlaceholderBucket(const X &from) {\n        HandlePtr mH = maybeGet(from);\n        if (mH && mH->hasRelation(Relations::PT)) {\n            return mH->getRelated(Relations::PT);\n        }\n\n        Handle h = graph.getNewBucket();\n        bucketToVals[h];\n        return h;\n    }\n    void erasePlaceholderBucket(Handle h);\n\n    // ***************************** other ******************************** //\n    static bool compare(C lt, Relations::Type rel, C rt);\n    static bool compare(C lt, Relations rels, C rt);\n    static Relations compare(C lt, C rt);\n    bool merge(const ValueRelations &other, Relations relations = allRelations);\n    bool unsetChanged() {\n        bool old = changed;\n        changed = false;\n        return old;\n    }\n    bool holdsAnyRelations() const;\n\n    HandlePtr getBorderH(size_t id) const;\n    size_t getBorderId(Handle h) const;\n\n#ifndef NDEBUG\n    void dump(ValueRelations::Handle h, std::ostream &out = std::cerr) const;\n    void dotDump(std::ostream &out = std::cerr) const;\n    friend std::ostream &operator<<(std::ostream &out,\n                                    const ValueRelations &vr);\n#endif\n};\n\n} // namespace vr\n} // namespace dg\n\n#endif // DG_LLVM_VALUE_RELATIONS_VALUE_RELATIONS_H_\n"
  },
  {
    "path": "include/dg/llvm/ValueRelations/getValName.h",
    "content": "#ifndef DG_LLVM_GET_VAL_NAME_H_\n#define DG_LLVM_GET_VAL_NAME_H_\n\n#include <fstream>\n#include <iostream>\n#include <llvm/Support/raw_os_ostream.h>\n#include <sstream>\n#include <string>\n\nnamespace dg {\nnamespace debug {\ninline std::string getValName(const llvm::Value *val) {\n    std::ostringstream ostr;\n    llvm::raw_os_ostream ro(ostr);\n\n    assert(val);\n    ro << *val;\n    ro.flush();\n\n    std::string result = ostr.str();\n    size_t quote = result.find(\"\\\"\");\n    while (quote != std::string::npos) {\n        result.replace(quote, 1, \"\\\\\\\"\");\n        quote = result.find(\"\\\"\", quote + 2);\n    }\n    size_t start = result.find_first_not_of(\" \");\n    assert(start != std::string::npos);\n\n    // break the string if it is too long\n    return result.substr(start);\n}\n\ninline std::string getTypeName(const llvm::Type *type) {\n    std::ostringstream ostr;\n    llvm::raw_os_ostream ro(ostr);\n\n    assert(type);\n#if LLVM_VERSION_MAJOR <= 4\n    ro << *const_cast<llvm::Type *>(type);\n#else\n    ro << *type;\n#endif\n    ro.flush();\n\n    std::string result = ostr.str();\n    size_t start = result.find_first_not_of(\" \");\n    assert(start != std::string::npos);\n\n    // break the string if it is too long\n    return result.substr(start);\n}\n\n} // namespace debug\n} // namespace dg\n\n#endif // DG_LLVM_GET_VAL_NAME_H_\n"
  },
  {
    "path": "include/dg/util/TimeMeasure.h",
    "content": "#ifndef DG_TIME_UTILS_H_\n#define DG_TIME_UTILS_H_\n\n#include <chrono>\n#include <iostream>\n\nnamespace dg {\nnamespace debug {\n\nclass TimeMeasure {\n    using Clock = std::chrono::steady_clock;\n    using TimePointT = Clock::time_point;\n    using DurationT = Clock::duration;\n\n    TimePointT s, e;\n    DurationT elapsed;\n\n    constexpr static auto ms_in_sec =\n            std::chrono::milliseconds(std::chrono::seconds{1}).count();\n\n  public:\n    TimeMeasure() = default;\n\n    void start() { s = Clock::now(); };\n\n    void stop() { e = Clock::now(); };\n\n    const DurationT &duration() {\n        elapsed = e - s;\n        return elapsed;\n    }\n\n    void report(const std::string &prefix = \"\", std::ostream &out = std::cerr) {\n        // compute the duration\n        duration();\n\n        out << prefix << \" \";\n\n        const auto msec =\n                std::chrono::duration_cast<std::chrono::milliseconds>(elapsed)\n                        .count() %\n                ms_in_sec;\n        const auto sec =\n                std::chrono::duration_cast<std::chrono::seconds>(elapsed)\n                        .count();\n        out << sec << \" sec \" << msec << \" ms\" << std::endl;\n    }\n};\n} // namespace debug\n} // namespace dg\n\n#endif // DG_TIME_UTILS_H_\n"
  },
  {
    "path": "include/dg/util/cow_shared_ptr.h",
    "content": "#ifndef COW_SHARED_PTR_H_\n#define COW_SHARED_PTR_H_\n\n#include <cassert>\n#include <memory>\n\n///\n// Shared pointer with copy-on-write support\ntemplate <typename T>\nclass cow_shared_ptr : public std::shared_ptr<T> {\n    // am I the owner of the copy?\n    bool owner{true};\n\n  public:\n    cow_shared_ptr() = default;\n    cow_shared_ptr(T *p) : std::shared_ptr<T>(p) {}\n    cow_shared_ptr(cow_shared_ptr &&) = delete;\n    cow_shared_ptr(const cow_shared_ptr &rhs)\n            : std::shared_ptr<T>(rhs), owner(false) {}\n\n    void reset(T *p) {\n        owner = true;\n        std::shared_ptr<T>::reset(p);\n    }\n\n    const T *get() const { return std::shared_ptr<T>::get(); }\n    const T *operator->() const { return get(); }\n    const T *operator*() const { return get(); }\n\n    T *getWritable() {\n        if (owner)\n            return std::shared_ptr<T>::get();\n\n        // create a copy of the object and claim the ownership\n        assert(!owner);\n        if (get() != nullptr) {\n            reset(new T(*get()));\n        } else {\n            reset(new T());\n        }\n        assert(owner); // set in reset() method\n        return std::shared_ptr<T>::get();\n    }\n};\n\n/*\ntemplate <typename T>\nclass cow_shared_ptr {\n    std::shared_ptr<T> ptr{nullptr};\n    // am I the owner of the copy?\n    bool owner{false};\n\n    public:\n    cow_shared_ptr() = default;\n    cow_shared_ptr(T *p) : ptr(p), owner(true) {}\n    cow_shared_ptr(cow_shared_ptr&&) = delete;\n    cow_shared_ptr(const cow_shared_ptr& rhs)\n        : ptr(rhs.ptr), owner(false) {}\n\n    const T *get() const { return ptr.get(); }\n\n    T *getWritable() {\n        if (owner)\n            return ptr.get();\n        // create a copy of the object and claim the ownership\n        if (ptr) {\n            ptr.reset(new T(*get()));\n        } else {\n            ptr.reset(new T());\n        }\n        owner = true;\n        return ptr.get();\n    }\n\n    auto use_count() const -> decltype(ptr.use_count()) {\n        return ptr.use_count();\n    }\n};\n*/\n\n#endif // COW_SHARED_PTR_H_\n"
  },
  {
    "path": "include/dg/util/debug.h",
    "content": "#ifndef DG_UTIL_DEBUG_H_\n#define DG_UTIL_DEBUG_H_\n\n#ifdef DEBUG_ENABLED\n#include <cassert>\n#include <ctime>\n#include <iostream>\n#endif\n\nnamespace dg {\nnamespace debug {\n\n#ifdef DEBUG_ENABLED\n\nextern unsigned _debug_lvl;\nextern unsigned _ind;\n\nnamespace {\ninline unsigned &_getDebugLvl() { return _debug_lvl; }\n\ninline void _setDebugLvl(unsigned int x) { _getDebugLvl() = x; }\n\ninline unsigned &_getInd() { return _ind; }\n\ninline std::ostream &_stream() { return std::cerr; }\n\ninline void _dump_ind() {\n    auto ind = _getInd();\n    for (unsigned i = 0; i < ind; ++i)\n        _stream() << \" \";\n}\n\ninline void _dump_prefix(const char *domain, const char *add = nullptr) {\n    std::cerr << \"[\" << std::clock() << \"]\";\n    if (domain)\n        _stream() << \"[\" << domain << \"]\";\n\n    _stream() << \" \";\n\n    _dump_ind();\n    if (add) {\n        _stream() << add;\n    }\n}\n} // namespace\n\n/*\nstatic inline bool dbg_should_print(unsigned int x) {\n    return _getDebugLvl() > x;\n}\n*/\n\ninline void dbg_enable() { _setDebugLvl(1); }\n\ninline bool dbg_is_enabled() { return _getDebugLvl() > 0; }\n\ninline std::ostream &dbg_section_begin(const char *domain = nullptr) {\n    _dump_prefix(domain, \"-> \");\n    _getInd() += 3;\n    return _stream();\n}\n\ninline std::ostream &dbg_section_end(const char *domain = nullptr) {\n    assert(_getInd() >= 3);\n    _getInd() -= 3;\n    _dump_prefix(domain, \"<- \");\n    return _stream();\n}\n\ninline std::ostream &dbg(const char *domain = nullptr) {\n    _dump_prefix(domain);\n    return _stream();\n}\n\n#define DBG_ENABLE()                                                           \\\n    do {                                                                       \\\n        ::dg::debug::dbg_enable();                                             \\\n    } while (0)\n\n#define DBG_SECTION_BEGIN(dom, S)                                              \\\n    do {                                                                       \\\n        if (::dg::debug::dbg_is_enabled()) {                                   \\\n            ::dg::debug::dbg_section_begin((#dom)) << S << \"\\n\";               \\\n        }                                                                      \\\n    } while (0)\n\n#define DBG_SECTION_END(dom, S)                                                \\\n    do {                                                                       \\\n        if (::dg::debug::dbg_is_enabled()) {                                   \\\n            ::dg::debug::dbg_section_end((#dom)) << S << \"\\n\";                 \\\n        }                                                                      \\\n    } while (0)\n\n#define DBG(dom, S)                                                            \\\n    do {                                                                       \\\n        if (::dg::debug::dbg_is_enabled()) {                                   \\\n            ::dg::debug::dbg((#dom)) << S << \"\\n\";                             \\\n        }                                                                      \\\n    } while (0)\n\n#else // not DEBUG_ENABLED\n\n#define DBG_ENABLE()\n#define DBG_SECTION_BEGIN(dom, S)\n#define DBG_SECTION_END(dom, S)\n#define DBG(dom, S)\n\n#endif // DEBUG_ENABLED\n\n} // namespace debug\n} // namespace dg\n\n#endif // DG_UTIL_DEBUG_H_\n"
  },
  {
    "path": "include/dg/util/iterators.h",
    "content": "#ifndef DG_ITERATORS_UTILS_H_\n#define DG_ITERATORS_UTILS_H_\n\n#include <algorithm>\n\nnamespace dg {\n\ntemplate <typename It, typename Predicate>\nstruct iterator_filter : public It {\n    It _current;\n    It _end;\n    const Predicate &pred;\n\n    iterator_filter(const It &b, const It &e, const Predicate &p)\n            : _current(b), _end(e), pred(p) {}\n    template <typename Range>\n    iterator_filter(Range &r, const Predicate &p)\n            : _current(r.begin()), _end(r.end()), pred(p) {}\n\n    iterator_filter &operator++() {\n        It::operator++();\n        while (_current != _end && !pred(It::operator*())) {\n            It::operator++();\n        }\n        return *this;\n    }\n\n    iterator_filter operator++(int) {\n        auto tmp = *this;\n        operator++();\n        return tmp;\n    }\n};\n\ntemplate <typename Range, typename Fun>\nbool any_of(Range &R, const Fun &fun) {\n    return std::any_of(R.begin(), R.end(), fun);\n}\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/BBlockBase.cpp",
    "content": "#include \"dg/BBlockBase.h\"\n\nnamespace dg {\n\nunsigned ElemId::idcnt = 0;\n\n}\n"
  },
  {
    "path": "lib/CMakeLists.txt",
    "content": "add_library(dganalysis SHARED\n\tOffset.cpp\n        Debug.cpp\n        BBlockBase.cpp\n)\n\nadd_library(dgpta SHARED\n\tPointerAnalysis/Pointer.cpp\n\tPointerAnalysis/PointerAnalysis.cpp\n\tPointerAnalysis/PointerGraph.cpp\n\tPointerAnalysis/PointerGraphOptimizations.cpp\n\tPointerAnalysis/PointerGraphValidator.cpp\n\tPointerAnalysis/PointsToSet.cpp\n)\ntarget_link_libraries(dgpta PUBLIC dganalysis)\n\nadd_library(dgdda SHARED\n\tReadWriteGraph/ReadWriteGraph.cpp\n\tMemorySSA/MemorySSA.cpp\n        MemorySSA/ModRef.cpp\n        MemorySSA/Definitions.cpp\n)\ntarget_link_libraries(dgdda PUBLIC dganalysis)\n\nadd_library(dgcda SHARED\n        ControlDependence/NTSCD.cpp\n)\n\nadd_library(dgsdg SHARED\n    SystemDependenceGraph/DependenceGraph.cpp\n)\ntarget_link_libraries(dgsdg PUBLIC dgpta\n                            PUBLIC dgdda)\n\nadd_library(dgvra SHARED\n\tValueRelations/Relations.cpp\n)\n\ninstall(TARGETS dganalysis dgcda dgpta dgdda dgsdg dgvra\n        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})\n\nif (LLVM_DG)\n\nadd_library(dgllvmpta SHARED\n\tllvm/PointerAnalysis/PointerAnalysis.cpp\n\tllvm/PointerAnalysis/PointerGraph.cpp\n\tllvm/PointerAnalysis/PointerGraphValidator.cpp\n\tllvm/PointerAnalysis/Block.cpp\n\tllvm/PointerAnalysis/Interprocedural.cpp\n\tllvm/PointerAnalysis/Structure.cpp\n\tllvm/PointerAnalysis/Globals.cpp\n\tllvm/PointerAnalysis/Constants.cpp\n\tllvm/PointerAnalysis/Instructions.cpp\n\tllvm/PointerAnalysis/Calls.cpp\n\tllvm/PointerAnalysis/Threads.cpp\n)\ntarget_link_libraries(dgllvmpta PUBLIC dgpta\n                                PUBLIC ${llvm}) # only for shared LLVM\n\nadd_library(dgllvmforkjoin SHARED\n\tllvm/ForkJoin/ForkJoin.cpp\n)\ntarget_link_libraries(dgllvmforkjoin PRIVATE dgllvmpta)\n\nadd_library(dgllvmdda SHARED\n\tllvm/ReadWriteGraph/LLVMReadWriteGraphBuilder.cpp\n\tllvm/ReadWriteGraph/Instructions.cpp\n\tllvm/ReadWriteGraph/Calls.cpp\n\tllvm/DataDependenceAnalysis/LLVMDataDependenceAnalysis.cpp\n\tllvm/ForkJoin/ForkJoin.cpp\n)\ntarget_link_libraries(dgllvmdda\n\t\t\tPUBLIC dgllvmpta\n\t\t\tPUBLIC dgdda\n\t\t\tPUBLIC dgllvmforkjoin)\n\nadd_library(dgllvmthreadregions SHARED\n            llvm/ThreadRegions/Nodes/Node.cpp\n            llvm/ThreadRegions/Nodes/GeneralNode.cpp\n            llvm/ThreadRegions/Nodes/ForkNode.cpp\n            llvm/ThreadRegions/Nodes/JoinNode.cpp\n            llvm/ThreadRegions/Nodes/LockNode.cpp\n            llvm/ThreadRegions/Nodes/UnlockNode.cpp\n            llvm/ThreadRegions/Nodes/EntryNode.cpp\n            llvm/ThreadRegions/Nodes/ExitNode.cpp\n            llvm/ThreadRegions/Nodes/CallNode.cpp\n            llvm/ThreadRegions/Nodes/CallFuncPtrNode.cpp\n            llvm/ThreadRegions/Nodes/CallReturnNode.cpp\n            llvm/ThreadRegions/Nodes/ReturnNode.cpp\n            llvm/ThreadRegions/Nodes/NodeIterator.cpp\n            llvm/ThreadRegions/Graphs/BlockGraph.cpp\n            llvm/ThreadRegions/Graphs/FunctionGraph.cpp\n            llvm/ThreadRegions/Graphs/GraphBuilder.cpp\n            llvm/ThreadRegions/Graphs/ThreadRegionsBuilder.cpp\n            llvm/ThreadRegions/Graphs/CriticalSectionsBuilder.cpp\n            llvm/ThreadRegions/Graphs/ControlFlowGraph.cpp\n\t    llvm/ThreadRegions/ThreadRegion.cpp\n            llvm/ThreadRegions/MayHappenInParallel.cpp\n)\ntarget_link_libraries(dgllvmthreadregions PUBLIC dgllvmpta\n                                          PRIVATE dgllvmforkjoin)\n\nadd_library(dgllvmcda SHARED\n            llvm/ControlDependence/legacy/Block.cpp\n            llvm/ControlDependence/legacy/Function.cpp\n            llvm/ControlDependence/legacy/GraphBuilder.cpp\n            llvm/ControlDependence/legacy/NTSCD.cpp\n            llvm/ControlDependence/ControlDependence.cpp\n            llvm/ControlDependence/InterproceduralCD.cpp\n            llvm/ControlDependence/SCD.cpp\n)\ntarget_link_libraries(dgllvmcda PUBLIC dgllvmpta\n                                PUBLIC dgcda\n                                PRIVATE dgllvmforkjoin)\n\nadd_library(dgllvmdg SHARED\n\tllvm/LLVMNode.cpp\n\tllvm/LLVMDependenceGraph.cpp\n\tllvm/LLVMDGVerifier.cpp\n\tllvm/Dominators/PostDominators.cpp\n\tllvm/DefUse/DefUse.cpp\n)\n\ntarget_link_libraries(dgllvmdg\n\t\t\tPUBLIC dgllvmpta\n\t\t\tPUBLIC dgllvmdda\n\t\t\tPUBLIC dgllvmthreadregions\n\t\t\tPUBLIC dgllvmcda\n\t\t\tINTERFACE ${llvm_analysis}) # only for static LLVM\n\nadd_library(dgllvmvra SHARED\n\tllvm/ValueRelations/GraphBuilder.cpp\n\tllvm/ValueRelations/GraphElements.cpp\n\tllvm/ValueRelations/RelationsAnalyzer.cpp\n\tllvm/ValueRelations/StructureAnalyzer.cpp\n\tllvm/ValueRelations/ValueRelations.cpp\n)\ntarget_link_libraries(dgllvmvra PUBLIC dgvra\n                                PRIVATE dganalysis\n\t\t\t\t\t\t\t\tPUBLIC ${llvm}) # only for shared LLVM\n\nadd_library(dgllvmsdg SHARED\n\tllvm/SystemDependenceGraph/SystemDependenceGraph.cpp\n\tllvm/SystemDependenceGraph/Dependencies.cpp\n)\ntarget_link_libraries(dgllvmsdg PUBLIC dgsdg\n                                PRIVATE dgllvmdda)\n\ninstall(TARGETS dgllvmdg dgllvmthreadregions dgllvmcda\n                dgllvmpta dgllvmdda dgllvmforkjoin dgllvmsdg dgllvmvra\n        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})\n\nendif(LLVM_DG)\n"
  },
  {
    "path": "lib/ControlDependence/CDGraph.h",
    "content": "#ifndef DG_LLVM_CDGRAPH_H_\n#define DG_LLVM_CDGRAPH_H_\n\n#include <cassert>\n#include <memory>\n#include <set>\n#include <string>\n#include <utility>\n\n#include \"dg/BBlockBase.h\"\n\nnamespace dg {\n\n//////////////////////////////////////////////////////////////////\n/// Basic graph elements from which all other elements inherit.\n//////////////////////////////////////////////////////////////////\n\n/////\n/// The basic class for the graph. It is either an instruction or a block,\n/// depending on the chosen granularity of CFG.\n/////\nclass CDNode;\nclass CDGraph;\nclass CDNode : public ElemWithEdges<CDNode> {\n    friend class CDGraph;\n\n    unsigned _id;\n    CDNode(unsigned id) : _id(id) {}\n\n  public:\n    unsigned getID() const { return _id; }\n};\n\n/////\n/// CDGraph - a graph that is used for the computation of control dependencies.\n/// It contains nodes that correspond either to basic blocks or instructions\n/// along with the successor relation.\n/////\nclass CDGraph {\n    using NodesVecT = std::vector<std::unique_ptr<CDNode>>;\n    // using NodesPtrVecT = ADT::SparseBitvector;\n    // FIXME ^^\n    using PredicatesT = std::set<CDNode *>;\n\n    std::string _name;\n    NodesVecT _nodes;\n    // NodesPtrVecT _predicates;\n    PredicatesT _predicates;\n\n    // iterator over the subgraphs that unwraps the unique_ptr\n    struct node_iterator : public NodesVecT::iterator {\n        using ContainedType = typename std::remove_reference<decltype(*(\n                std::declval<NodesVecT::iterator>()->get()))>::type;\n\n        node_iterator(const typename NodesVecT::iterator &it)\n                : NodesVecT::iterator(it) {}\n        node_iterator(const node_iterator &) = default;\n        node_iterator() = default;\n\n        ContainedType *operator*() {\n            return (NodesVecT::iterator::operator*()).get();\n        };\n        ContainedType *operator->() {\n            return ((NodesVecT::iterator::operator*()).get());\n        };\n    };\n\n    struct nodes_range {\n        NodesVecT &nodes;\n        nodes_range(NodesVecT &b) : nodes(b) {}\n\n        node_iterator begin() { return node_iterator(nodes.begin()); }\n        node_iterator end() { return node_iterator(nodes.end()); }\n    };\n\n    // iterator over the predicates\n    /*\n    struct predicate_iterator : public NodesPtrVecT::const_iterator {\n        NodesVecT& _nodes;\n\n        predicate_iterator(NodesVecT& nodes, const typename\n    NodesPtrVecT::const_iterator& it) : NodesPtrVecT::const_iterator(it),\n    _nodes(nodes) {} predicate_iterator(const predicate_iterator&) = default;\n\n        CDNode *operator*() {\n            auto id = NodesPtrVecT::const_iterator::operator*();\n            assert(id - 1 < _nodes.size());\n            return this->_nodes[id - 1].get();\n        };\n        CDNode *operator->() {\n            auto id = NodesPtrVecT::const_iterator::operator*();\n            assert(id - 1 < _nodes.size());\n            return this->_nodes[id - 1].get();\n        };\n    };\n\n    struct predicates_range {\n        NodesVecT& nodes;\n        NodesPtrVecT& predicates;\n        predicates_range(NodesVecT& n, NodesPtrVecT& b) : nodes(n),\n    predicates(b) {}\n\n        predicate_iterator begin() { return predicate_iterator(nodes,\n    predicates.begin()); } predicate_iterator end() { return\n    predicate_iterator(nodes, predicates.end()); }\n    };\n    */\n\n  public:\n    CDGraph(std::string name = \"\") : _name(std::move(name)) {}\n    CDGraph(const CDGraph &rhs) = delete;\n    CDGraph &operator=(const CDGraph &) = delete;\n    CDGraph(CDGraph &&) = default;\n    CDGraph &operator=(CDGraph &&) = default;\n\n    CDNode &createNode() {\n        auto *nd = new CDNode(_nodes.size() + 1);\n        _nodes.emplace_back(nd);\n        assert(_nodes.back()->getID() == _nodes.size() &&\n               \"BUG: we rely on the ordering by ids\");\n        return *nd;\n    }\n\n    // add an edge between two nodes in the graph.\n    // This method registers also what nodes have more than successor\n    void addNodeSuccessor(CDNode &nd, CDNode &succ) {\n        nd.addSuccessor(&succ);\n        if (nd.successors().size() > 1) {\n            _predicates.insert(&nd);\n        }\n    }\n\n    node_iterator begin() { return node_iterator(_nodes.begin()); }\n    node_iterator end() { return node_iterator(_nodes.end()); }\n    nodes_range nodes() { return {_nodes}; }\n\n    CDNode *getNode(unsigned id) {\n        assert(id - 1 < _nodes.size());\n        return _nodes[id - 1].get();\n    }\n\n    const CDNode *getNode(unsigned id) const {\n        assert(id - 1 < _nodes.size());\n        return _nodes[id - 1].get();\n    }\n\n    size_t size() const { return _nodes.size(); }\n    bool empty() const { return _nodes.empty(); }\n\n    /*\n    predicate_iterator predicates_begin() { return predicate_iterator(_nodes,\n    _predicates.begin()); } predicate_iterator predicates_end() { return\n    predicate_iterator(_nodes, _predicates.end()); } predicates_range\n    predicates() { return predicates_range(_nodes, _predicates); }\n    */\n\n    decltype(_predicates.begin()) predicates_begin() {\n        return _predicates.begin();\n    }\n    decltype(_predicates.end()) predicates_end() { return _predicates.end(); }\n    decltype(_predicates.begin()) predicates_begin() const {\n        return _predicates.begin();\n    }\n    decltype(_predicates.end()) predicates_end() const {\n        return _predicates.end();\n    }\n    PredicatesT &predicates() { return _predicates; }\n    const PredicatesT &predicates() const { return _predicates; }\n\n    /*\n    bool isPredicate(const CDNode& nd) const {\n        return _predicates.get(nd.getID());\n    }\n    */\n\n    bool isPredicate(const CDNode &nd) const {\n        return _predicates.count(const_cast<CDNode *>(&nd)) > 0;\n    }\n\n    const std::string &getName() const { return _name; }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/ControlDependence/ControlClosure.h",
    "content": "#ifndef CD_CONTROL_CLOSURE_H_\n#define CD_CONTROL_CLOSURE_H_\n\n#include <set>\n#include <vector>\n\n#include \"CDGraph.h\"\n\n#include \"dg/ADT/Queue.h\"\n#include \"dg/ADT/SetQueue.h\"\n\nnamespace dg {\n\nclass StrongControlClosure {\n    // this is basically the \\Theta function from the paper\n    template <typename Nodes, typename FunT>\n    void foreachFirstReachable(const Nodes &nodes, CDNode *from,\n                               const FunT &fun) {\n        ADT::SetQueue<ADT::QueueLIFO<CDNode *>> queue;\n        for (auto *s : from->successors()) {\n            queue.push(s);\n        }\n\n        while (!queue.empty()) {\n            auto *cur = queue.pop();\n            if (nodes.count(cur) > 0) { // the node is from Ap?\n                fun(cur);\n            } else {\n                for (auto *s : cur->successors()) {\n                    queue.push(s);\n                }\n            }\n        }\n    }\n\n    // this is the \\Gamma function from the paper\n    // (a bit different implementation)\n    static std::set<CDNode *> gamma(CDGraph &graph,\n                                    const std::set<CDNode *> &targets) {\n        struct Info {\n            unsigned colored{false};\n            unsigned short counter;\n        };\n\n        std::unordered_map<CDNode *, Info> data;\n        data.reserve(graph.size());\n        ADT::QueueLIFO<CDNode *> queue;\n\n        // initialize nodes\n        for (auto *nd : graph) {\n            auto &D = data[nd];\n            D.colored = false;\n            D.counter = nd->successors().size();\n        }\n\n        // initialize the search\n        for (auto *target : targets) {\n            data[target].colored = true;\n            queue.push(target);\n        }\n\n        // search!\n        while (!queue.empty()) {\n            auto *node = queue.pop();\n            assert(data[node].colored && \"A non-colored node in queue\");\n\n            for (auto *pred : node->predecessors()) {\n                auto &D = data[pred];\n                --D.counter;\n                if (D.counter == 0) {\n                    D.colored = true;\n                    queue.push(pred);\n                }\n            }\n        }\n\n        std::set<CDNode *> retval;\n        for (auto *n : graph) {\n            if (!data[n].colored) {\n                retval.insert(n);\n            }\n        }\n        return retval;\n    }\n\n    std::set<CDNode *> theta(const std::set<CDNode *> &X, CDNode *n) {\n        std::set<CDNode *> retval;\n        if (X.count(n) > 0) {\n            retval.insert(n);\n            return retval;\n        }\n        foreachFirstReachable(X, n, [&](CDNode *cur) { retval.insert(cur); });\n        return retval;\n    }\n\n  public:\n    using ValVecT = std::vector<CDNode *>;\n\n    void closeSet(CDGraph &G, std::set<CDNode *> &X) {\n        while (true) {\n            ADT::SetQueue<ADT::QueueLIFO<CDNode *>> queue;\n            for (auto *n : X) {\n                for (auto *s : n->successors()) {\n                    queue.push(s);\n                }\n            }\n\n            CDNode *toadd = nullptr;\n            while (!queue.empty()) {\n                assert(toadd == nullptr);\n                auto *p = queue.pop();\n                assert(p && \"popped nullptr\");\n                for (auto *r : p->successors()) {\n                    assert(toadd == nullptr);\n                    // DBG(cda, \"Checking edge \" << p->getID() << \"->\" <<\n                    // r->getID());\n                    // (a)\n                    if (theta(X, r).size() != 1)\n                        continue;\n\n                    // (b)\n                    auto gam = gamma(G, X);\n                    if (gam.count(r) > 0)\n                        continue;\n\n                    // (c)\n                    if (theta(X, p).size() < 2 && gam.count(p) == 0)\n                        continue;\n\n                    // all conditions met, we got our edge\n                    // DBG(cda, \"Found edge \" << p->getID() << \"->\" <<\n                    // r->getID());\n                    assert(toadd == nullptr);\n                    toadd = p;\n                    break;\n                }\n\n                if (toadd)\n                    break;\n\n                for (auto *s : p->successors()) {\n                    queue.push(s);\n                }\n            }\n\n            if (toadd) {\n                // DBG(cda, \"Adding \" << toadd->getID() << \" to closure\");\n                X.insert(toadd);\n                continue;\n            } // no other edge to process\n            break;\n        }\n    }\n\n    ValVecT getClosure(CDGraph &G, const std::set<CDNode *> &nodes) {\n        auto X = nodes;\n        closeSet(G, X);\n        return {X.begin(), X.end()};\n    }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/ControlDependence/DOD.h",
    "content": "#ifndef DG_DOD_H_\n#define DG_DOD_H_\n\n#include <functional>\n#include <map>\n#include <set>\n#include <unordered_map>\n\n#include <dg/ADT/Bitvector.h>\n#include <dg/ADT/Queue.h>\n#include <dg/ADT/SetQueue.h>\n\n#include \"CDGraph.h\"\n\nnamespace dg {\n\n// compute which nodes lie on all max paths from a given node\n// (for all nodes). It is basically the same as NTSCD class\n// but we remember the results of calls to compute()\nclass AllMaxPath {\n  public:\n    using ResultT = std::map<CDNode *, const ADT::SparseBitvector &>;\n\n  private:\n    struct Info {\n        ADT::SparseBitvector colors;\n        unsigned short counter;\n    };\n\n    std::unordered_map<CDNode *, Info> data;\n\n    void compute(CDGraph &graph, CDNode *target) {\n        // initialize nodes\n        for (auto *nd : graph) {\n            data[nd].counter = nd->successors().size();\n        }\n\n        // initialize the search\n        data[target].colors.set(target->getID());\n        ADT::QueueLIFO<CDNode *> queue;\n        queue.push(target);\n\n        // search!\n        while (!queue.empty()) {\n            auto *node = queue.pop();\n            assert(data[node].colors.get(target->getID()) &&\n                   \"A non-colored node in queue\");\n\n            for (auto *pred : node->predecessors()) {\n                auto &D = data[pred];\n                --D.counter;\n                if (D.counter == 0) {\n                    D.colors.set(target->getID());\n                    queue.push(pred);\n                }\n            }\n        }\n    }\n\n  public:\n    // returns mapping CDNode -> Set of CDNodes (where the set is implemented as\n    // a bitvector)\n    ResultT compute(CDGraph &graph) {\n        ResultT res;\n\n        data.reserve(graph.size());\n\n        for (auto *nd : graph) {\n            compute(graph, nd);\n            res.emplace(nd, data[nd].colors);\n        }\n\n        return res;\n    }\n};\n\nclass DOD {\n  public:\n    // using ResultT = std::map<CDNode *, std::set<std::pair<CDNode *, CDNode\n    // *>>>;\n    // NOTE: although DOD is a ternary relation, we treat it as binary\n    // by breaking a->(b, c) to (a, b) and (a, c). It over-approximates\n    // the ternary relation. However, the effect on the results of slicing\n    // is usually small. There is a flag that computes the relation\n    // as ternary.\n    using ResultT = std::map<CDNode *, std::set<CDNode *>>;\n    using ColoringT = ADT::SparseBitvector;\n\n  private:\n    struct ColoredAp {\n        CDGraph Ap;\n        ColoringT blues;\n        ColoringT reds;\n\n        // mapping G -> Ap\n        std::unordered_map<CDNode *, CDNode *> _mapping{};\n        // mapping Ap -> G\n        std::unordered_map<CDNode *, CDNode *> _rev_mapping{};\n\n        CDNode *createNode(CDNode *gnode) {\n            auto *nd = &Ap.createNode();\n            _mapping[gnode] = nd;\n            _rev_mapping[nd] = gnode;\n            return nd;\n        }\n\n        CDNode *getNode(CDNode *gnode) {\n            auto it = _mapping.find(gnode);\n            return it == _mapping.end() ? nullptr : it->second;\n        }\n\n        CDNode *getGNode(CDNode *apnode) {\n            auto it = _rev_mapping.find(apnode);\n            return it == _rev_mapping.end() ? nullptr : it->second;\n        }\n\n        ColoredAp() = default;\n        ColoredAp(CDGraph &&g, ColoringT &&b, ColoringT &&r)\n                : Ap(std::move(g)), blues(std::move(b)), reds(std::move(r)) {}\n        ColoredAp(ColoredAp &&) = default;\n        ColoredAp(const ColoredAp &) = delete;\n\n        bool isBlue(CDNode *n) const { return blues.get(n->getID()); }\n        bool isRed(CDNode *n) const { return reds.get(n->getID()); }\n    };\n\n    template <typename Nodes, typename FunT>\n    void foreachFirstReachable(const Nodes &nodes, CDNode *from,\n                               const FunT &fun) {\n        // FIXME: this breaks the complexity (it uses std::set)\n        ADT::SetQueue<ADT::QueueLIFO<CDNode *>> queue;\n        for (auto *s : from->successors()) {\n            queue.push(s);\n        }\n\n        while (!queue.empty()) {\n            auto *cur = queue.pop();\n            if (nodes.get(cur->getID())) { // the node is from Ap?\n                fun(cur);\n            } else {\n                for (auto *s : cur->successors()) {\n                    queue.push(s);\n                }\n            }\n        }\n    }\n\n    // Create the Ap graph (nodes and edges)\n    ColoredAp createAp(const ADT::SparseBitvector &nodes, CDGraph &graph,\n                       CDNode *node) {\n        ColoredAp CAp;\n        CDGraph &Ap = CAp.Ap;\n\n        // create nodes of graph\n        for (auto *n : graph) {\n            if (nodes.get(n->getID())) {\n                CAp.createNode(n);\n                // DBG(cda, \"  - Ap has node \" << n->getID() << \" (which is \" <<\n                // nd->getID() << \" in Ap)\");\n            }\n        }\n\n        assert(CAp.getNode(node) != nullptr);\n\n        if (CAp.Ap.size() < 3) {\n            return {}; // no DOD possible, bail out early\n        }\n\n        // Add edges. FIXME: we can use a better implementation\n        for (auto *n : Ap) {\n            auto *gn = CAp.getGNode(n);\n\n            foreachFirstReachable(nodes, gn, [&](CDNode *cur) {\n                auto *apn = CAp.getNode(cur);\n                assert(apn);\n                n->addSuccessor(apn);\n                // DBG(cda, \"  - Ap edge \" << gn->getID() << \" -> \" <<\n                // cur->getID());\n            });\n        }\n\n        assert(CAp.getNode(node) && \"node is not in Ap\");\n        if (CAp.getNode(node)->successors().size() < 2) {\n            return {}; // no DOD possible, skip the rest of building colored Ap\n        }\n\n        return CAp;\n    }\n\n    // create the Ap graph (calls createAp) and color the nodes in the Ap graph\n    ColoredAp createColoredAp(AllMaxPath::ResultT &allpaths, CDGraph &graph,\n                              CDNode *node) {\n        auto it = allpaths.find(node);\n        if (it == allpaths.end()) {\n            return {};\n        }\n        const auto &nodes = it->second;\n\n        ColoredAp CAp = createAp(nodes, graph, node);\n        if (CAp.Ap.empty()) {\n            return {};\n        }\n\n        // initialize the colors\n        assert(node->successors().size() == 2 &&\n               \"Node is not the right predicate\");\n\n        // FIXME: refactor...\n        // color nodes\n        const auto &succs = node->successors();\n        auto sit = succs.begin();\n        CDNode *bluesucc = *sit;\n        CDNode *redsucc = *(++sit);\n        // DBG(cda, \"Blue successor: \" << bluesucc->getID());\n        // DBG(cda, \"Red successor: \" << redsucc->getID());\n        assert(++sit == succs.end());\n\n        if (nodes.get(bluesucc->getID())) { // is blue successor in Ap?\n            auto *apn = CAp.getNode(bluesucc);\n            assert(apn);\n            CAp.blues.set(apn->getID());\n            // DBG(cda, \"  - Ap blue: \" << apn->getID() << \" (\"\n            //                         << bluesucc->getID() << \" in original)\");\n        } else {\n            foreachFirstReachable(nodes, bluesucc, [&](CDNode *cur) {\n                auto *apn = CAp.getNode(cur);\n                assert(apn);\n                CAp.blues.set(apn->getID());\n                // DBG(cda, \"  - Ap blue: \" << apn->getID() << \" (\"\n                //                         << cur->getID() << \" in original)\");\n            });\n        }\n\n        bool twocolors = false;\n        if (nodes.get(redsucc->getID())) { // is red successor in Ap?\n            auto *apn = CAp.getNode(redsucc);\n            assert(apn);\n            if (CAp.blues.get(apn->getID())) {\n                twocolors = true;\n            }\n            CAp.reds.set(apn->getID());\n            // DBG(cda, \"  - Ap red: \" << redsucc->getID());\n        } else {\n            foreachFirstReachable(nodes, redsucc, [&](CDNode *cur) {\n                auto *apn = CAp.getNode(cur);\n                assert(apn);\n                CAp.reds.set(apn->getID());\n                if (CAp.blues.get(apn->getID())) {\n                    twocolors = true;\n                }\n                // DBG(cda, \"  - Ap red: \" << apn->getID() << \" (\"\n                //                        << cur->getID() << \" in original)\");\n            });\n        }\n\n        if (twocolors) {\n            return {};\n        }\n\n        return CAp;\n    }\n\n    static bool checkAp(CDGraph &Ap) {\n        // for (auto *nd : CAp.Ap) {\n        //      DBG(tmp, \">> Ap: \" << nd->getID() << \" b: \" <<\n        //      CAp.blues.get(nd->getID())\n        //                                        << \" r: \" <<\n        //                                        CAp.reds.get(nd->getID()));\n        //}\n        // for (auto *nd : CAp.Ap) {\n        //    for (auto *succ: nd->successors()) {\n        //      DBG(tmp, \">> Ap:   \" << nd->getID() << \" -> \" << succ->getID());\n        //    }\n        //}\n\n        // we can have only a single node with multiple successors\n        CDNode *p = nullptr;\n        for (auto *n : Ap) {\n            if (p) {\n                assert(n->successors().size() == 1);\n                assert(n->getSingleSuccessor() != n);\n            } else {\n                if (n->successors().size() > 1) {\n                    p = n;\n                }\n            }\n        }\n        assert(p && \"No entry node of Ap\");\n\n        // from the p node there are edges that go into a cycle\n        // that contains the rest of the nodes\n        std::set<CDNode *> visited;\n        auto *n = *(p->successors().begin());\n        auto *cur = n;\n        do {\n            assert(cur != p);\n\n            bool notseen = visited.insert(cur).second;\n            assert(notseen && \"Visited a node twice\");\n            (void) notseen; // c++17 TODO: replace with [[maybe_unused]]\n\n            cur = cur->getSingleSuccessor();\n            assert(cur && \"Node on the cycle does not have a unique successor\");\n        } while (cur != n);\n\n        assert(visited.size() == Ap.size() - 1 &&\n               \"Cycle does not contain all the nodes except p\");\n        return true;\n    }\n\n    template <typename Pred1, typename Pred2>\n    std::pair<CDNode *, CDNode *> find(CDNode *start, CDNode *end,\n                                       const Pred1 &P1, const Pred2 &P2) {\n        CDNode *n1 = nullptr, *n2 = nullptr;\n        CDNode *n = start;\n        do {\n            if (P1(n)) {\n                n1 = n;\n            }\n            if (P2(n)) {\n                n2 = n;\n                break;\n            }\n            n = n->getSingleSuccessor();\n            assert(n && \"A node on the cycle has not a single successor\");\n        } while (n != end);\n\n        return {n1, n2};\n    }\n\n    void computeDOD(ColoredAp &CAp, CDNode *p, ResultT &CD, ResultT &revCD,\n                    bool asTernary = false) {\n        assert(checkAp(CAp.Ap)); // sanity check\n\n        CDNode *b1 = nullptr, *b2 = nullptr, *b3 = nullptr;\n        CDNode *r1 = nullptr, *r2 = nullptr;\n\n        // get some blue node to have a starting point\n        auto bid = *(CAp.blues.begin());\n        // DBG(tmp, \"Blue node with id \" << bid);\n        b1 = CAp.Ap.getNode(bid);\n        assert(b1 && \"The blue node is not on Ap\");\n        // DBG(tmp, \"Starting from blue: \" << b1->getID());\n        assert(CAp.isBlue(b1));\n\n        auto isblue = [&](CDNode *x) -> bool { return CAp.isBlue(x); };\n        auto isred = [&](CDNode *x) -> bool { return CAp.isRed(x); };\n\n        std::tie(b2, r1) = find(b1, b1, isblue, isred);\n        std::tie(r2, b3) = find(r1, b1, isred, isblue);\n        if (b3 != nullptr) {\n            if (find(b3, b1, isred, isred).first != nullptr) {\n                // there is another red, no DOD\n                return;\n            }\n        } else {\n            b3 = b1;\n        }\n\n        assert(b1);\n        assert(b2);\n        assert(b3);\n        assert(r1);\n        assert(r2);\n\n        if (asTernary) {\n            constructTernaryRelation(CAp, p, CD, revCD, b2, b3, r1, r2);\n        } else { // break into binary relation\n            constructBinaryRelation(CAp, p, CD, revCD, b2, b3, r1, r2);\n        }\n    }\n\n    static void constructTernaryRelation(ColoredAp &CAp, CDNode *p, ResultT &CD,\n                                         ResultT &revCD, CDNode *b2, CDNode *b3,\n                                         CDNode *r1, CDNode *r2) {\n        auto *cur = b2;\n        do {\n            auto *gcur = CAp.getGNode(cur);\n            assert(gcur);\n\n            auto *ncur = r2;\n            do {\n                auto *gncur = CAp.getGNode(ncur);\n                assert(gncur);\n                // DBG(cda, p->getID() << \" - dod -> {\" << gcur->getID() << \", \"\n                //                                     << gncur->getID() <<\n                //                                     \"}\");\n\n                CD[gcur].insert(p);\n                CD[gncur].insert(p);\n                revCD[p].insert(gcur);\n                revCD[p].insert(gncur);\n\n                ncur = ncur->getSingleSuccessor();\n            } while (!(CAp.isBlue(ncur) || CAp.isRed(ncur)));\n            assert(ncur == b3);\n            (void) b3;\n\n            cur = cur->getSingleSuccessor();\n        } while (!(CAp.isBlue(cur) || CAp.isRed(cur)));\n        assert(cur == r1);\n        (void) r1;\n    }\n\n    static void constructBinaryRelation(ColoredAp &CAp, CDNode *p, ResultT &CD,\n                                        ResultT &revCD, CDNode *b2, CDNode *b3,\n                                        CDNode *r1, CDNode *r2) {\n        auto *cur = b2;\n        do {\n            auto *gcur = CAp.getGNode(cur);\n            assert(gcur);\n            CD[gcur].insert(p);\n            revCD[p].insert(gcur);\n            // DBG(cda, p->getID() << \" - dod -> \" << gcur->getID());\n            cur = cur->getSingleSuccessor();\n        } while (!(CAp.isBlue(cur) || CAp.isRed(cur)));\n        assert(cur == r1);\n        (void) r1;\n\n        cur = r2;\n        do {\n            auto *gcur = CAp.getGNode(cur);\n            assert(gcur);\n            CD[gcur].insert(p);\n            revCD[p].insert(gcur);\n            // DBG(cda, p->getID() << \" - dod -> \" << gcur->getID());\n            cur = cur->getSingleSuccessor();\n        } while (!(CAp.isBlue(cur) || CAp.isRed(cur)));\n        assert(cur == b3);\n        (void) b3;\n    }\n\n  protected:\n    // make this public, so that we can use it in NTSCD+DOD algorithm\n    template <typename OnAllPaths>\n    void computeDOD(CDNode *p, CDGraph &graph, OnAllPaths &allpaths,\n                    ResultT &CD, ResultT &revCD) {\n        assert(p->successors().size() == 2 &&\n               \"We work with at most 2 successors\");\n\n        DBG_SECTION_BEGIN(cda, \"Creating Ap graph for fun \" << graph.getName()\n                                                            << \" node \"\n                                                            << p->getID());\n        auto res = createColoredAp(allpaths, graph, p);\n        DBG_SECTION_END(cda, \"Done creating Ap graph\");\n        if (res.Ap.empty()) {\n            DBG(cda, \"No DOD in the Ap are possible\");\n            // no DOD possible\n            return;\n        }\n\n        DBG(cda, \"Computing DOD from the Ap\");\n        computeDOD(res, p, CD, revCD);\n    }\n\n  public:\n    std::pair<ResultT, ResultT> compute(CDGraph &graph) {\n        ResultT CD;\n        ResultT revCD;\n\n        DBG_SECTION_BEGIN(cda, \"Computing DOD for all predicates\");\n\n        AllMaxPath allmaxpath;\n        DBG_SECTION_BEGIN(\n                cda,\n                \"Coputing nodes that are on all max paths from nodes for fun \"\n                        << graph.getName());\n        auto allpaths = allmaxpath.compute(graph);\n        DBG_SECTION_END(\n                cda,\n                \"Done computing nodes that are on all max paths from nodes\");\n\n        for (auto *p : graph.predicates()) {\n            computeDOD(p, graph, allpaths, CD, revCD);\n        }\n\n        DBG_SECTION_END(cda, \"Finished computing DOD for all predicates\");\n        return {CD, revCD};\n    }\n};\n\nclass DODRanganath {\n    // using ResultT = std::map<CDNode *, std::set<std::pair<CDNode *, CDNode\n    // *>>>;\n    // NOTE: although DOD is a ternary relation, we treat it as binary\n    // by breaking a->(b, c) to (a, b) and (a, c). It is less precise,\n    // but our API is not prepared for the ternary relation.\n    using ResultT = std::map<CDNode *, std::set<CDNode *>>;\n    enum class Color { WHITE, BLACK, UNCOLORED };\n\n    struct Info {\n        Color color{Color::UNCOLORED};\n    };\n\n    std::unordered_map<CDNode *, Info> data;\n\n    void coloredDAG(CDGraph &graph, CDNode *n, std::set<CDNode *> &visited) {\n        if (visited.insert(n).second) {\n            const auto &successors = n->successors();\n            if (successors.empty())\n                return;\n\n            for (auto *q : successors) {\n                coloredDAG(graph, q, visited);\n            }\n            auto *s = *(successors.begin());\n            auto c = data[s].color;\n            for (auto *q : successors) {\n                if (data[q].color != c) {\n                    c = Color::UNCOLORED;\n                    break;\n                }\n            }\n            data[n].color = c;\n        }\n    }\n\n    bool dependence(CDNode *n, CDNode *m, CDNode *p, CDGraph &G) {\n        for (auto *n : G) {\n            data[n].color = Color::UNCOLORED;\n        }\n        data[m].color = Color::WHITE;\n        data[p].color = Color::BLACK;\n\n        std::set<CDNode *> visited;\n        visited.insert(m);\n        visited.insert(p);\n\n        coloredDAG(G, n, visited);\n\n        bool whiteChild = false;\n        bool blackChild = false;\n\n        for (auto *q : n->successors()) {\n            if (data[q].color == Color::WHITE)\n                whiteChild = true;\n            if (data[q].color == Color::BLACK)\n                blackChild = true;\n        }\n\n        return whiteChild && blackChild;\n    }\n\n    // the paper uses 'reachable', but it is wrong\n    // Keep the method for now anyway.\n    static bool reachable(CDNode *from, CDNode *n) {\n        ADT::SetQueue<ADT::QueueLIFO<CDNode *>> queue;\n        queue.push(from);\n\n        while (!queue.empty()) {\n            auto *cur = queue.pop();\n            if (n == cur) {\n                return true;\n            }\n\n            for (auto *s : cur->successors()) {\n                queue.push(s);\n            }\n        }\n        return false;\n    }\n\n    static bool onallpaths(CDNode *from, CDNode *n, CDGraph &G) {\n        if (from == n) // fast path\n            return true;\n\n        struct NodeInf {\n            bool onstack{false};\n            bool visited{false};\n        };\n        std::unordered_map<CDNode *, NodeInf> data;\n\n        data.reserve(G.size());\n\n        const std::function<bool(CDNode *, CDNode *)> onallpths =\n                [&](CDNode *node, CDNode *target) -> bool {\n            if (node == target)\n                return true;\n\n            data[node].visited = true;\n\n            if (!node->hasSuccessors())\n                return false;\n\n            for (auto *s : node->successors()) {\n                if (data[s].onstack)\n                    return false;\n                if (!data[s].visited) {\n                    data[s].onstack = true;\n                    if (!onallpths(s, target))\n                        return false;\n                    data[s].onstack = false;\n                }\n            }\n            // if we have successors and got here,\n            // then all successors reach target\n            return true;\n        };\n\n        data[from].onstack = true;\n        // DBG(tmp, \"on all paths:\" << from->getID() << \", \" << n->getID() << \":\n        // \" << r );\n        return onallpths(from, n);\n    }\n\n  public:\n    std::pair<ResultT, ResultT> compute(CDGraph &graph) {\n        ResultT CD;\n        ResultT revCD;\n\n        DBG(cda, \"Computing DOD (Ranganath)\");\n\n        data.reserve(graph.size());\n\n        for (auto *n : graph.predicates()) {\n            for (auto *m : graph) {\n                for (auto *p : graph) {\n                    if (p == m) {\n                        continue;\n                    }\n\n                    if (onallpaths(m, p, graph) && onallpaths(p, m, graph) &&\n                        dependence(n, p, m, graph)) {\n                        // DBG(cda, \"DOD: \" << n->getID() << \" -> {\"\n                        //                 << p->getID() << \", \" << m->getID()\n                        //                 << \"}\");\n                        CD[m].insert(n);\n                        CD[p].insert(n);\n                        revCD[n].insert(m);\n                        revCD[n].insert(n);\n                    }\n                }\n            }\n        }\n\n        return {CD, revCD};\n    }\n};\n\n}; // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/ControlDependence/DODNTSCD.h",
    "content": "#ifndef DG_DODNTSCD_H_\n#define DG_DODNTSCD_H_\n\n#include <dg/ADT/Bitvector.h>\n#include <dg/ADT/Queue.h>\n#include <dg/ADT/SetQueue.h>\n\n#include \"CDGraph.h\"\n#include \"DOD.h\"\n\nnamespace dg {\n\nclass DODNTSCD : public DOD {\n    using ResultT = DOD::ResultT;\n\n    template <typename OnAllPathsT>\n    void computeNTSCD(CDNode *p, CDGraph &graph, const OnAllPathsT &onallpaths,\n                      ResultT &CD, ResultT &revCD) {\n        const auto &succs = p->successors();\n        assert(succs.size() == 2);\n        auto succit = succs.begin();\n        auto *s1 = *succit;\n        auto *s2 = *(++succit);\n        assert(++succit == succs.end());\n\n        auto it1 = onallpaths.find(s1);\n        if (it1 == onallpaths.end())\n            return;\n        auto it2 = onallpaths.find(s2);\n        if (it2 == onallpaths.end())\n            return;\n\n        const auto &nodes1 = it1->second;\n        const auto &nodes2 = it2->second;\n        // FIXME: we could do that faster\n        for (auto *n : graph) {\n            if (nodes1.get(n->getID()) ^ nodes2.get(n->getID())) {\n                CD[n].insert(p);\n                revCD[p].insert(n);\n            }\n        }\n    }\n\n  public:\n    std::pair<ResultT, ResultT> compute(CDGraph &graph) {\n        ResultT CD;\n        ResultT revCD;\n\n        DBG_SECTION_BEGIN(cda, \"Computing DOD for all predicates\");\n\n        AllMaxPath allmaxpath;\n        DBG_SECTION_BEGIN(\n                cda,\n                \"Coputing nodes that are on all max paths from nodes for fun \"\n                        << graph.getName());\n        auto allpaths = allmaxpath.compute(graph);\n        DBG_SECTION_END(\n                cda,\n                \"Done coputing nodes that are on all max paths from nodes\");\n\n        for (auto *p : graph.predicates()) {\n            computeDOD(p, graph, allpaths, CD, revCD);\n            computeNTSCD(p, graph, allpaths, CD, revCD);\n        }\n\n        DBG_SECTION_END(cda, \"Finished computing DOD for all predicates\");\n        return {CD, revCD};\n    }\n};\n\n}; // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/ControlDependence/NTSCD.cpp",
    "content": "\n"
  },
  {
    "path": "lib/ControlDependence/NTSCD.h",
    "content": "#ifndef DG_NTSCD_H\n#define DG_NTSCD_H\n\n#include <map>\n#include <set>\n#include <unordered_map>\n#include <vector>\n\n#include \"CDGraph.h\"\n#include \"dg/ADT/Queue.h\"\n#include \"dg/ADT/SetQueue.h\"\n\nnamespace dg {\n\nclass NTSCD {\n    using ResultT = std::map<CDNode *, std::set<CDNode *>>;\n\n    struct Info {\n        unsigned color{0};\n    };\n\n    std::unordered_map<CDNode *, Info> data;\n\n    void compute(CDGraph &graph, CDNode *target, ResultT &CD, ResultT &revCD) {\n        std::set<CDNode *> frontier;\n        std::set<CDNode *> new_frontier;\n\n        // color the target node\n        data[target].color = target->getID();\n        for (auto *pred : target->predecessors()) {\n            if (data[pred].color != target->getID()) {\n                frontier.insert(pred);\n            }\n        }\n\n        bool progress;\n        do {\n            progress = false;\n            new_frontier.clear();\n\n            for (auto *nd : frontier) {\n                assert(!nd->successors().empty());\n                // do all successors have the right color?\n                bool colorit = true;\n                for (auto *succ : nd->successors()) {\n                    if (data[succ].color != target->getID()) {\n                        colorit = false;\n                        break;\n                    }\n                }\n\n                // color the node and enqueue its predecessors\n                if (colorit) {\n                    data[nd].color = target->getID();\n                    for (auto *pred : nd->predecessors()) {\n                        if (data[pred].color != target->getID()) {\n                            new_frontier.insert(pred);\n                        }\n                    }\n                    progress = true;\n                } else {\n                    // re-queue the node as nothing happend\n                    new_frontier.insert(nd);\n                }\n            }\n\n            new_frontier.swap(frontier);\n        } while (progress);\n\n        // iterate over frontier set, not over predicates -- only\n        // the predicates that are in the frontier set may have colored\n        // and uncolored successors\n        for (auto *predicate : frontier) {\n            if (!graph.isPredicate(*predicate))\n                continue;\n            bool has_colored = false;\n            bool has_uncolored = false;\n            for (auto *succ : predicate->successors()) {\n                if (data[succ].color == target->getID())\n                    has_colored = true;\n                if (data[succ].color != target->getID())\n                    has_uncolored = true;\n            }\n\n            if (has_colored && has_uncolored) {\n                CD[target].insert(predicate);\n                revCD[predicate].insert(target);\n            }\n        }\n    }\n\n  public:\n    // returns control dependencies and reverse control dependencies\n    std::pair<ResultT, ResultT> compute(CDGraph &graph) {\n        ResultT CD;\n        ResultT revCD;\n\n        data.reserve(graph.size());\n\n        for (auto *nd : graph) {\n            compute(graph, nd, CD, revCD);\n        }\n\n        return {CD, revCD};\n    }\n};\n\nclass NTSCD2 {\n    using ResultT = std::map<CDNode *, std::set<CDNode *>>;\n\n    struct Info {\n        unsigned colored{false};\n        unsigned short counter;\n    };\n\n    std::unordered_map<CDNode *, Info> data;\n\n    void compute(CDGraph &graph, CDNode *target) {\n        // initialize nodes\n        for (auto *nd : graph) {\n            auto &D = data[nd];\n            D.colored = false;\n            D.counter = nd->successors().size();\n        }\n\n        // initialize the search\n        data[target].colored = true;\n        ADT::QueueLIFO<CDNode *> queue;\n        queue.push(target);\n\n        // search!\n        while (!queue.empty()) {\n            auto *node = queue.pop();\n            assert(data[node].colored && \"A non-colored node in queue\");\n\n            for (auto *pred : node->predecessors()) {\n                auto &D = data[pred];\n                --D.counter;\n                if (D.counter == 0) {\n                    D.colored = true;\n                    queue.push(pred);\n                }\n            }\n        }\n    }\n\n  public:\n    // returns control dependencies and reverse control dependencies\n    std::pair<ResultT, ResultT> compute(CDGraph &graph) {\n        ResultT CD;\n        ResultT revCD;\n\n        data.reserve(graph.size());\n\n        for (auto *nd : graph) {\n            compute(graph, nd);\n\n            for (auto *predicate : graph.predicates()) {\n                bool has_colored = false;\n                bool has_uncolored = false;\n                for (auto *succ : predicate->successors()) {\n                    if (data[succ].colored)\n                        has_colored = true;\n                    if (!data[succ].colored)\n                        has_uncolored = true;\n                }\n\n                if (has_colored && has_uncolored) {\n                    CD[nd].insert(predicate);\n                    revCD[predicate].insert(nd);\n                }\n            }\n        }\n\n        return {CD, revCD};\n    }\n};\n\n/// Implementation of the original algorithm for the computation of NTSCD\n/// that is due to Ranganath et al. This algorithm is wrong and\n/// can compute incorrect results (it behaves differently when\n/// LIFO or FIFO or some other type of queue is used).\nclass NTSCDRanganath {\n    using ResultT = std::map<CDNode *, std::set<CDNode *>>;\n\n    // symbol t_{mn}\n    struct Symbol : public std::pair<CDNode *, CDNode *> {\n        Symbol(CDNode *a, CDNode *b) : std::pair<CDNode *, CDNode *>(a, b) {}\n    };\n\n    std::unordered_map<CDNode *, std::unordered_map<CDNode *, std::set<Symbol>>>\n            S;\n\n    ADT::SetQueue<ADT::QueueFIFO<CDNode *>> workbag;\n\n    bool processNode(CDGraph &graph, CDNode *n) {\n        bool changed = false;\n        auto *s = n->getSingleSuccessor();\n        if (s && s != n) { // (2.1) single successor case\n            for (auto *p : graph.predicates()) {\n                auto &Ssp = S[s][p];\n                for (const Symbol &symb : S[n][p]) {\n                    if (Ssp.insert(symb).second) {\n                        DBG(tmp, \"(1) S[\" << s->getID() << \", \" << p->getID()\n                                          << \"] <- t(\" << symb.first->getID()\n                                          << \", \" << symb.second->getID()\n                                          << \")\");\n                        DBG(tmp, \"(2.1) queuing node: \" << s->getID());\n                        changed = true;\n                        workbag.push(s);\n                    }\n                }\n            }\n        } else if (n->successors().size() >\n                   1) { // (2.2) multiple successors case\n            for (auto *m : graph) {\n                auto &Smn = S[m][n];\n                if (Smn.size() == n->successors().size()) {\n                    for (auto *p : graph.predicates()) {\n                        if (p == n) {\n                            continue;\n                        }\n                        auto &Smp = S[m][p];\n                        for (const Symbol &symb : S[n][p]) {\n                            if (Smp.insert(symb).second) {\n                                changed = true;\n                                workbag.push(m);\n                                DBG(tmp, \"(1) S[\" << m->getID() << \", \"\n                                                  << p->getID() << \"] <- t(\"\n                                                  << symb.first->getID() << \", \"\n                                                  << symb.second->getID()\n                                                  << \")\");\n                                DBG(tmp, \"(2.2) queuing node: \" << m->getID());\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        return changed;\n    }\n\n  public:\n    // returns control dependencies and reverse control dependencies\n    // doFixpoint turns on the fix of the ranganath's algorithm\n    // XXX: we should create a new fixed algorithm completely, as we do not need\n    // the workbag and so on.\n    std::pair<ResultT, ResultT> compute(CDGraph &graph,\n                                        bool doFixpoint = true) {\n        ResultT CD;\n        ResultT revCD;\n\n        S.reserve(2 * graph.predicates().size());\n\n        // (1) initialize\n        for (auto *p : graph.predicates()) {\n            for (auto *n : p->successors()) {\n                S[n][p].insert(Symbol{p, n});\n                // DBG(tmp, \"(1) S[\" << n->getID() << \", \" << p->getID()\n                //                  << \"] <- t(\" << p->getID() << \", \" <<\n                //                  n->getID() << \")\");\n                // DBG(tmp, \"(1) queuing node: \" << n->getID());\n                workbag.push(n);\n            }\n        }\n\n        // (2) calculate all-path reachability\n        if (doFixpoint) {\n            DBG(cda, \"Performing fixpoint of Ranganath's algorithm\");\n            bool changed;\n            do {\n                changed = false;\n                for (auto *n : graph) {\n                    changed |= processNode(graph, n);\n                }\n            } while (changed);\n        } else {\n            DBG(cda, \"Running the original (wrong) Ranganath's algorithm\");\n            while (!workbag.empty()) {\n                auto *n = workbag.pop();\n                // DBG(cda, \"Processing node: \" << n->getID());\n                processNode(graph, n);\n            }\n        }\n\n        // (3) compute NTSCD\n        for (auto *n : graph) {\n            for (auto *p : graph.predicates()) {\n                auto &Snp = S[n][p];\n\n                // DBG(tmp, \"(1) S[\" << n->getID() << \", \" << p->getID() << \"]\n                // =\"); for (auto & symb : Snp) {\n                //    DBG(tmp, \"  t(\" << symb.first->getID() << \", \" <<\n                //    symb.second->getID() << \")\");\n                //}\n                if (!Snp.empty() && Snp.size() < p->successors().size()) {\n                    CD[n].insert(p);\n                    revCD[p].insert(n);\n                }\n            }\n        }\n\n        return {CD, revCD};\n    }\n};\n\n} // namespace dg\n\n#endif // DG_NTSCD_H\n"
  },
  {
    "path": "lib/Debug.cpp",
    "content": "#ifdef DEBUG_ENABLED\nnamespace dg {\nnamespace debug {\n\nunsigned _debug_lvl = 0;\nunsigned _ind = 0;\n\n} // namespace debug\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/MemorySSA/Definitions.cpp",
    "content": "#include \"dg/MemorySSA/MemorySSA.h\"\n\n#include \"dg/util/debug.h\"\n\n#ifndef NDEBUG\n#include <iostream>\n#endif\n\nnamespace dg {\nnamespace dda {\n\n/// ------------------------------------------------------------------\n// class Definitions\n/// ------------------------------------------------------------------\n///\n// Update Definitions object with definitions from 'node'.\n// 'defnode' is the node that should be added as the\n// node that performs these definitions. Usually, defnode == node\n// (defnode was added to correctly handle call nodes where the\n// definitions are stored separately, but we want to have the call node\n// as the node that defines the memory.\n///\nvoid Definitions::update(RWNode *node, RWNode *defnode) {\n    if (!defnode)\n        defnode = node;\n\n    // possible definitions\n    for (const auto &ds : node->getDefines()) {\n        if (ds.target->isUnknown()) {\n            // add the definition to every known set of definitions\n            // that we have so far\n            definitions.addAll(defnode);\n            // add the definition also as a proper target for Gvn,\n            // since the previous step is not enough\n            addUnknownWrite(defnode);\n        } else {\n            definitions.add(ds, defnode);\n        }\n    }\n\n    // definitive definitions\n    for (const auto &ds : node->getOverwrites()) {\n        assert((defnode->isPhi() || // we allow ? for PHI nodes\n                !ds.offset.isUnknown()) &&\n               \"Update on unknown offset\");\n        assert(!ds.target->isUnknown() && \"Update on unknown memory\");\n\n        kills.add(ds, defnode);\n        definitions.update(ds, defnode);\n    }\n}\n\nvoid Definitions::join(const Definitions &rhs) {\n    definitions.add(rhs.definitions);\n    kills = kills.intersect(rhs.kills);\n    unknownWrites.insert(unknownWrites.end(), rhs.unknownWrites.begin(),\n                         rhs.unknownWrites.end());\n}\n\n#ifndef NDEBUG\nvoid Definitions::dump() const {\n    std::cout << \"processed: \" << _processed << \"\\n\";\n    std::cout << \" -- defines -- \\n\";\n    definitions.dump();\n    std::cout << \" -- kills -- \\n\";\n    kills.dump();\n    std::cout << \"\\n\";\n    std::cout << \" -- unknown writes -- \\n\";\n    for (auto *nd : unknownWrites) {\n        std::cout << nd->getID() << \" \";\n    }\n    std::cout << std::endl;\n}\n#endif\n\n} // namespace dda\n} // namespace dg\n"
  },
  {
    "path": "lib/MemorySSA/MemorySSA.cpp",
    "content": "#include <set>\n#include <vector>\n\n#include \"dg/ADT/Bitvector.h\"\n#include \"dg/MemorySSA/MemorySSA.h\"\n//#include \"dg/BBlocksBuilder.h\"\n\n#include \"dg/util/debug.h\"\n\nnamespace dg {\nnamespace dda {\n\n/// ------------------------------------------------------------------\n// class MemorySSATransformation\n/// ------------------------------------------------------------------\n\n// find definitions of a given node\nstd::vector<RWNode *> MemorySSATransformation::findDefinitions(RWNode *node) {\n    DBG_SECTION_BEGIN(dda, \"Searching definitions for node \" << node->getID());\n\n    assert(node->isUse() && \"Searching definitions for non-use node\");\n\n    // handle reads from unknown memory\n    if (node->usesUnknown()) {\n        return findAllDefinitions(node);\n    }\n\n    auto *block = node->getBBlock();\n    if (!block) {\n        // no basic block means that this node is either\n        // a subnode of a CALL node or that it is\n        // in unreachable part of program (and therefore\n        // the block was not built).\n        // In either case, we're safe to return nothing\n        return {};\n    }\n\n    // gather all definitions from the beginning of the block\n    // to the node (we must do that always, because adding PHI\n    // nodes changes the definitions)\n    auto D = findDefinitionsInBlock(node);\n    std::vector<RWNode *> defs;\n\n    for (const auto &ds : node->getUses()) {\n        assert(ds.target && \"Target is null\");\n\n        // add the definitions from the beginning of this block to the defs\n        // container\n        auto defSet = D.get(ds);\n        assert((!defSet.empty() || D.unknownWrites.empty()) &&\n               \"BUG: if we found no definitions, also unknown writes must be \"\n               \"empty\");\n        defs.insert(defs.end(), defSet.begin(), defSet.end());\n\n        addUncoveredFromPredecessors(block, D, ds, defs);\n    }\n\n    DBG_SECTION_END(dda,\n                    \"Done searching definitions for node \" << node->getID());\n    return defs;\n}\n\n// find definitions of a given node\nstd::vector<RWNode *>\nMemorySSATransformation::findDefinitions(RWNode *node, const DefSite &ds) {\n    DBG(dda, \"Searching definitions for node \" << node->getID());\n\n    // we use this only for PHI nodes\n    assert(ds.target && \"Target is null\");\n    assert(!ds.target->isUnknown() && \"Searching unknown memory\");\n\n    auto *block = node->getBBlock();\n    assert(block && \"Need bblock\");\n\n    // gather all definitions from the beginning of the block\n    // to the node (we must do that always, because adding PHI\n    // nodes changes the definitions)\n    auto D = findDefinitionsInBlock(node);\n    std::vector<RWNode *> defs;\n\n    // add the definitions from the beginning of this block to the defs\n    // container\n    auto defSet = D.get(ds);\n    assert((!defSet.empty() || D.unknownWrites.empty()) &&\n           \"BUG: if we found no definitions, also unknown writes must be \"\n           \"empty\");\n    defs.insert(defs.end(), defSet.begin(), defSet.end());\n\n    addUncoveredFromPredecessors(block, D, ds, defs);\n\n    return defs;\n}\n\nRWNode *MemorySSATransformation::createPhi(const DefSite &ds, RWNodeType type) {\n    // This phi is the definition that we are looking for.\n    _phis.emplace_back(&graph.create(type));\n    auto *phi = _phis.back();\n    assert(phi->isPhi() && \"Got wrong type\");\n\n    phi->addOverwrites(ds);\n\n    DBG(dda, \"Created PHI with ID \" << phi->getID());\n    return phi;\n}\n\nRWNode *MemorySSATransformation::createPhi(Definitions &D, const DefSite &ds,\n                                           RWNodeType type) {\n    auto *phi = createPhi(ds, type);\n\n    // update definitions in the block -- this\n    // phi node defines previously uncovered memory\n    auto uncovered = D.uncovered(ds);\n    for (auto &interval : uncovered) {\n        DefSite uds{ds.target, interval.start, interval.length()};\n        // NOTE: add, not update! D can already have some weak definitions\n        // of this memory (but they are \"uncovered\" as they are only weak\n        D.definitions.add(uds, phi);\n        assert(D.kills.get(uds).empty() &&\n               \"BUG: Basic block already kills this memory\");\n        D.kills.add(uds, phi);\n\n        // to simulate the whole LVN, we must add also writes to unknown memory\n        if (!D.getUnknownWrites().empty()) {\n            D.definitions.add(uds, D.getUnknownWrites());\n        }\n    }\n\n    return phi;\n}\n\nRWNode *MemorySSATransformation::createAndPlacePhi(RWBBlock *block,\n                                                   const DefSite &ds) {\n    // create PHI node and find definitions for the PHI node\n    auto &D = getBBlockDefinitions(block, &ds);\n    auto *phi = createPhi(D, ds);\n    block->prepend(phi);\n    return phi;\n}\n\nstatic inline bool canBeInput(const RWNode *node, RWSubgraph *subg) {\n    // can escape or already escaped\n    if (node->canEscape())\n        return true;\n    if (node->getBBlock())\n        return node->getBBlock()->getSubgraph() != subg;\n    return false;\n}\n\nvoid MemorySSATransformation::findDefinitionsInMultiplePredecessors(\n        RWBBlock *block, const DefSite &ds, std::vector<RWNode *> &defs) {\n    RWNode *phi = nullptr;\n    if (block->hasPredecessors()) {\n        // The phi node will be placed at the beginning of the block,\n        // so the iterator should not be invalidated.\n        phi = createAndPlacePhi(block, ds);\n        // recursively find definitions for this phi node\n        findPhiDefinitions(phi);\n    } else if (canBeInput(ds.target, block->getSubgraph())) {\n        // this is the entry block, so we add a PHI node\n        // representing \"input\" into this procedure\n        // (but only if the input can be used from the called procedure)\n        phi = createPhi(getBBlockDefinitions(block, &ds), ds,\n                        /* type = */ RWNodeType::INARG);\n        auto *subg = block->getSubgraph();\n        auto &summary = getSubgraphSummary(subg);\n        summary.addInput(ds, phi);\n\n        findDefinitionsFromCalledFun(phi, subg, ds);\n    }\n\n    if (phi) {\n        defs.push_back(phi);\n    }\n}\n\n///\n// Find the nodes that define the given def-site in the predecessors\n// of block.  Create PHI nodes if needed.\nstd::vector<RWNode *>\nMemorySSATransformation::findDefinitionsInPredecessors(RWBBlock *block,\n                                                       const DefSite &ds) {\n    assert(block);\n    assert(ds.target && \"Target is null\");\n    assert(!ds.target->isUnknown() &&\n           \"Finding uknown memory\"); // this is handled differently\n\n    std::vector<RWNode *> defs;\n\n    // if we have a unique predecessor,\n    // we can find the definitions there and continue searching in the\n    // predecessor if something is missing\n    if (auto *pred = block->getSinglePredecessor()) {\n        auto pdefs = findDefinitions(pred, ds);\n#ifndef NDEBUG\n        auto &D = getBBlockDefinitions(pred, &ds);\n        assert((!pdefs.empty() || D.unknownWrites.empty()) &&\n               \"BUG: if we found no definitions, also unknown writes must be \"\n               \"empty\");\n#endif // not NDEBUG\n        defs.insert(defs.end(), pdefs.begin(), pdefs.end());\n    } else { // multiple or no predecessors\n        findDefinitionsInMultiplePredecessors(block, ds, defs);\n    }\n\n    return defs;\n}\n\n///\n// Find the nodes that define the given def-site in this block\n// (using the definitions computed for each single block)\n// Create PHI nodes if needed.\nvoid MemorySSATransformation::findPhiDefinitions(RWNode *phi) {\n    auto *block = phi->getBBlock();\n\n    assert(block);\n    assert(!block->getSinglePredecessor() &&\n           \"Phi in a block with single predecessor\");\n\n    findPhiDefinitions(phi, block->predecessors());\n}\n\nvoid MemorySSATransformation::addUncoveredFromPredecessors(\n        RWBBlock *block, Definitions &D, const DefSite &ds,\n        std::vector<RWNode *> &defs) {\n    auto uncovered = D.uncovered(ds);\n    for (auto &interval : uncovered) {\n        auto preddefs = findDefinitionsInPredecessors(\n                block, {ds.target, interval.start, interval.length()});\n        defs.insert(defs.end(), preddefs.begin(), preddefs.end());\n    }\n}\n\n///\n// Find the nodes that define the given def-site in this block\n// (using the definitions computed for each single block)\n// Create PHI nodes if needed.\nstd::vector<RWNode *>\nMemorySSATransformation::findDefinitions(RWBBlock *block, const DefSite &ds) {\n    assert(ds.target && \"Target is null\");\n    assert(block && \"Block is null\");\n\n    // Find known definitions.\n    auto &D = getBBlockDefinitions(block, &ds);\n    auto defSet = D.get(ds);\n    assert((!defSet.empty() || D.unknownWrites.empty()) &&\n           \"BUG: if we found no definitions, also unknown writes must be \"\n           \"empty\");\n    std::vector<RWNode *> defs(defSet.begin(), defSet.end());\n\n    addUncoveredFromPredecessors(block, D, ds, defs);\n\n    return defs;\n}\n\nbool MemorySSATransformation::callMayDefineTarget(RWNodeCall *C,\n                                                  RWNode *target) {\n    // check if this call may define the memory at all\n    for (auto &callee : C->getCallees()) {\n        auto *subg = callee.getSubgraph();\n        if (!subg) {\n            auto *cv = callee.getCalledValue();\n            if (cv->defines(target)) {\n                return true;\n            }\n        } else {\n            auto &si = getSubgraphInfo(subg);\n            computeModRef(subg, si);\n            assert(si.modref.isInitialized());\n            if (si.modref.mayDefineOrUnknown(target)) {\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\nvoid MemorySSATransformation::findDefinitionsInSubgraph(RWNode *phi,\n                                                        RWNodeCall *C,\n                                                        const DefSite &ds,\n                                                        RWSubgraph *subg) {\n    DBG_SECTION_BEGIN(tmp,\n                      \"Searching definitions in subgraph \" << subg->getName());\n    auto &summary = getSubgraphSummary(subg);\n    auto &si = getSubgraphInfo(subg);\n    computeModRef(subg, si);\n    assert(si.modref.isInitialized());\n\n    // Add the definitions that we have found in previous exploration\n    phi->addDefUse(summary.getOutputs(ds));\n\n    // search the definitions that we have not found yet\n    for (auto &subginterval : summary.getUncoveredOutputs(ds)) {\n        // we must create a new phi for each subgraph inside the subgraph\n        // (these phis will be merged by the single 'phi').\n        // Of course, we create them only when not already present.\n        auto subgds =\n                DefSite{ds.target, subginterval.start, subginterval.length()};\n\n        // do not search the procedure if it cannot define the memory\n        // (this saves creating PHI nodes). If it may define only\n        // unknown memory, add that definitions directly and continue searching\n        // before the call.\n        if (!si.modref.mayDefine(ds.target)) {\n            if (si.modref.mayDefineUnknown()) {\n                auto *subgphi =\n                        createPhi(subgds, /* type = */ RWNodeType::OUTARG);\n                summary.addOutput(subgds, subgphi);\n                for (const auto &it : si.modref.getMayDef(UNKNOWN_MEMORY)) {\n                    subgphi->addDefUse(it);\n                }\n                phi->addDefUse(subgphi);\n            }\n            // continue the search before the call\n            phi->addDefUse(findDefinitions(C, subgds));\n            continue;\n        }\n\n        auto *subgphi = createPhi(subgds, /* type = */ RWNodeType::OUTARG);\n        summary.addOutput(subgds, subgphi);\n        phi->addDefUse(subgphi);\n\n        // find the new phi operands\n        for (auto *subgblock : subg->bblocks()) {\n            if (subgblock->hasSuccessors()) {\n                continue;\n            }\n            if (!subgblock->isReturnBBlock()) {\n                // ignore blocks that does not return to this subgraph\n                continue;\n            }\n            subgphi->addDefUse(findDefinitions(subgblock, ds));\n        }\n    }\n    DBG_SECTION_END(tmp, \"Done searching definitions in subgraph \"\n                                 << subg->getName());\n}\n\nvoid MemorySSATransformation::addDefinitionsFromCalledValue(\n        RWNode *phi, RWNodeCall *C, const DefSite &ds, RWNode *calledValue) {\n    std::vector<RWNode *> defs;\n    Definitions D;\n    // FIXME: cache this somehow ?\n    D.update(calledValue);\n\n    auto defSet = D.get(ds);\n    assert((!defSet.empty() || D.unknownWrites.empty()) &&\n           \"BUG: if we found no definitions, also unknown writes must be \"\n           \"empty\");\n    defs.insert(defs.end(), defSet.begin(), defSet.end());\n    addUncoveredFromPredecessors(C->getBBlock(), D, ds, defs);\n    phi->addDefUse(defs);\n}\n\nvoid MemorySSATransformation::fillDefinitionsFromCall(Definitions &D,\n                                                      RWNodeCall *C,\n                                                      const DefSite &ds) {\n    if (!callMayDefineTarget(C, ds.target))\n        return;\n\n    // find the uncovered parts of the sought definition\n    auto uncovered = D.uncovered(ds);\n    for (auto &interval : uncovered) {\n        auto uncoveredds =\n                DefSite{ds.target, interval.start, interval.length()};\n        // this phi will merge the definitions from all the\n        // possibly called subgraphs\n        auto *phi = createPhi(D, uncoveredds, RWNodeType::CALLOUT);\n        C->getBBlock()->append(phi);\n        C->addOutput(phi);\n\n        // recursively find definitions for this phi node\n        for (auto &callee : C->getCallees()) {\n            if (auto *subg = callee.getSubgraph()) {\n                findDefinitionsInSubgraph(phi, C, uncoveredds, subg);\n            } else {\n                addDefinitionsFromCalledValue(phi, C, uncoveredds,\n                                              callee.getCalledValue());\n            }\n        }\n    }\n}\n\n// get all callers of the function and find the given definitions reaching these\n// call-sites\nvoid MemorySSATransformation::findDefinitionsFromCalledFun(RWNode *phi,\n                                                           RWSubgraph *subg,\n                                                           const DefSite &ds) {\n    for (auto *callsite : subg->getCallers()) {\n        auto *C = RWNodeCall::get(callsite);\n        assert(C && \"Callsite is not a call\");\n\n        auto *bblock = callsite->getBBlock();\n        assert(bblock && getBBlockInfo(bblock).isCallBlock());\n\n        // create input PHI for this call\n        auto *callphi = createPhi(ds, RWNodeType::CALLIN);\n        bblock->insertBefore(callphi, C);\n        C->addInput(callphi);\n\n        phi->addDefUse(callphi);\n        callphi->addDefUse(findDefinitions(callphi, ds));\n    }\n}\n\n///\n/// Get Definitions object for a bblock. Optionally, a definition site due to\n///  which we are getting the definitions can be specified (used when searching\n///  in call blocks on demand).\n/// The on-demand for calls was such that we retrive the sought definitions\n/// and store them into the Definitions object. This object is then\n/// returned and can be queried.\n///\nDefinitions &MemorySSATransformation::getBBlockDefinitions(RWBBlock *b,\n                                                           const DefSite *ds) {\n    auto &bi = getBBlockInfo(b);\n    auto &D = bi.getDefinitions();\n\n    if (D.isProcessed()) {\n        DBG(dda, \"Retrived processed definitions for block \" << b->getID());\n        return D;\n    }\n\n    if (bi.isCallBlock()) {\n        if (ds) {\n            fillDefinitionsFromCall(D, bi.getCall(), *ds);\n            DBG(dda,\n                \"Retrived (partial) definitions for call block \" << b->getID());\n        } else {\n            DBG(dda, \"Filling all definitions for call block \" << b->getID());\n            fillDefinitionsFromCall(D, bi.getCall());\n            assert(D.isProcessed());\n        }\n    } else {\n        performLvn(D, b); // normal basic block\n        assert(D.isProcessed());\n        DBG(dda, \"Retrived LVN'd definitions for block \" << b->getID());\n    }\n    return D;\n}\n\n// perform Lvn for one block\nvoid MemorySSATransformation::performLvn(Definitions &D, RWBBlock *block) {\n    DBG_SECTION_BEGIN(dda, \"Starting LVN for block \" << block->getID());\n\n    assert(!D.isProcessed() && \"Processing a block multiple times\");\n\n    for (RWNode *node : block->getNodes()) {\n        D.update(node);\n    }\n\n    D.setProcessed();\n    DBG_SECTION_END(dda, \"LVN of block \" << block->getID() << \" finished\");\n}\n\n///\n// The same as performLVN() but only up to some point (and returns the map).\n// Also, if mem is specified, then search for effects only to this memory.\nDefinitions MemorySSATransformation::findDefinitionsInBlock(RWNode *to,\n                                                            const RWNode *mem) {\n    auto *block = to->getBBlock();\n    // perform LVN up to the node\n    Definitions D;\n    for (RWNode *node : block->getNodes()) {\n        if (node == to)\n            break;\n        if (!mem || node->defines(mem)) {\n            D.update(node);\n        }\n    }\n\n    return D;\n}\n\nDefinitions\nMemorySSATransformation::findEscapingDefinitionsInBlock(RWNode *to) {\n    auto *block = to->getBBlock();\n    // perform LVN up to the node\n    Definitions D;\n    for (RWNode *node : block->getNodes()) {\n        if (node == to)\n            break;\n        if (node->canEscape()) {\n            D.update(node);\n        }\n    }\n\n    return D;\n}\n\n///\n/// Copy definitions from 'from' map to 'to' map.\n/// Copy only those that are not already killed by 'to' map\n/// (thus simulating the state when 'to' is executed after 'from')\n///\nstatic void joinDefinitions(DefinitionsMap<RWNode> &from,\n                            DefinitionsMap<RWNode> &to, bool escaping = false) {\n    for (const auto &it : from) {\n        if (escaping && !it.first->canEscape()) {\n            continue;\n        }\n\n        if (!to.definesTarget(it.first)) {\n            // just copy the definitions\n            to.add(it.first, it.second);\n            continue;\n        }\n\n        for (const auto &it2 : it.second) {\n            const auto &interv = it2.first;\n            auto uncovered = to.undefinedIntervals(\n                    {it.first, interv.start, interv.length()});\n            for (auto &undefInterv : uncovered) {\n                // we still do not have definitions for these bytes, add it\n                to.add({it.first, undefInterv.start, undefInterv.length()},\n                       it2.second);\n            }\n        }\n    }\n}\n\nstatic void joinDefinitions(Definitions &from, Definitions &to,\n                            bool escaping = false) {\n    joinDefinitions(from.definitions, to.definitions, escaping);\n    to.unknownWrites.insert(to.unknownWrites.end(), from.unknownWrites.begin(),\n                            from.unknownWrites.end());\n    // we ignore 'kills' and 'unknownReads' as this function is used\n    // only when searching for all definitions\n}\n\nvoid MemorySSATransformation::fillDefinitionsFromCall(Definitions &D,\n                                                      RWNodeCall *C) {\n    if (D.isProcessed()) {\n        return;\n    }\n\n    DBG_SECTION_BEGIN(dda, \"Finding all definitions for a call \" << C);\n\n    for (auto &callee : C->getCallees()) {\n        auto *subg = callee.getSubgraph();\n        if (!subg) {\n            auto *called = callee.getCalledValue();\n            for (const auto &ds : called->getDefines()) {\n                fillDefinitionsFromCall(D, C, ds);\n            }\n            for (const auto &ds : called->getOverwrites()) {\n                fillDefinitionsFromCall(D, C, ds);\n            }\n        } else {\n            auto &si = getSubgraphInfo(subg);\n            computeModRef(subg, si);\n            assert(si.modref.isInitialized());\n\n            for (const auto &it : si.modref.maydef) {\n                if (it.first->isUnknown()) {\n                    for (const auto &it2 : it.second) {\n                        D.unknownWrites.insert(D.unknownWrites.end(),\n                                               it2.second.begin(),\n                                               it2.second.end());\n                    }\n                    continue;\n                }\n                for (const auto &it2 : it.second) {\n                    fillDefinitionsFromCall(\n                            D, C,\n                            {it.first, it2.first.start, it2.first.length()});\n                }\n            }\n        }\n    }\n\n    DBG_SECTION_BEGIN(dda, \"Finding all definitions for a call \"\n                                   << C << \" finished\");\n    D.setProcessed();\n}\n\nvoid MemorySSATransformation::collectAllDefinitions(\n        Definitions &defs, RWBBlock *from, std::set<RWBBlock *> &visitedBlocks,\n        bool escaping) {\n    assert(from);\n\n    if (!visitedBlocks.insert(from).second) {\n        return; // we already visited this block\n    }\n\n    // get the definitions from this block\n    joinDefinitions(getBBlockDefinitions(from), defs, escaping);\n\n    // recur into predecessors\n    if (auto *singlePred = from->getSinglePredecessor()) {\n        collectAllDefinitions(defs, singlePred, visitedBlocks, escaping);\n    } else {\n        auto olddefinitions = defs.definitions;\n        for (auto I = from->pred_begin(), E = from->pred_end(); I != E; ++I) {\n            Definitions tmpDefs;\n            tmpDefs.definitions = olddefinitions;\n            collectAllDefinitions(tmpDefs, *I, visitedBlocks, escaping);\n            defs.definitions.add(tmpDefs.definitions);\n            defs.unknownWrites.insert(defs.unknownWrites.end(),\n                                      tmpDefs.unknownWrites.begin(),\n                                      tmpDefs.unknownWrites.end());\n        }\n    }\n}\n\nDefinitions MemorySSATransformation::collectAllDefinitions(RWNode *from) {\n    Definitions defs; // auxiliary map for finding defintions\n    collectAllDefinitions(from, defs);\n    return defs;\n}\n\nvoid MemorySSATransformation::collectAllDefinitionsInCallers(Definitions &defs,\n                                                             RWSubgraph *subg) {\n    auto &callers = subg->getCallers();\n    if (callers.empty()) {\n        return;\n    }\n\n    // create an input PHI node\n    auto &summary = getSubgraphSummary(subg);\n    DefSite ds{UNKNOWN_MEMORY};\n    RWNode *phi = summary.getUnknownPhi();\n    if (!phi) {\n        phi = createPhi(ds, /* type = */ RWNodeType::INARG);\n        summary.addInput(ds, phi);\n    }\n\n    defs.unknownWrites.push_back(phi);\n\n    for (auto *callsite : subg->getCallers()) {\n        // create input PHI for this call\n        auto *C = RWNodeCall::get(callsite);\n        auto *callphi = C->getUnknownPhi();\n        if (callphi) {\n            phi->addDefUse(callphi);\n            continue;\n        }\n\n        callphi = createPhi(ds, RWNodeType::CALLIN);\n        C->addUnknownInput(callphi);\n        phi->addDefUse(callphi);\n\n        // NOTE: search _all_ definitions, not only those that are\n        // not covered by 'defs'. Therefore, we can reuse this search\n        // in all later searches.\n        // auto tmpDefs = defs;\n        Definitions tmpDefs;\n        collectAllDefinitions(callsite, tmpDefs, /* escaping = */ true);\n        for (const auto &it : tmpDefs.definitions) {\n            for (const auto &it2 : it.second) {\n                callphi->addDefUse(it2.second);\n            }\n        }\n        callphi->addDefUse(tmpDefs.unknownWrites);\n    }\n}\n\nvoid MemorySSATransformation::collectAllDefinitions(RWNode *from,\n                                                    Definitions &defs,\n                                                    bool escaping) {\n    assert(from->getBBlock() && \"The node has no BBlock\");\n\n    auto *block = from->getBBlock();\n    std::set<RWBBlock *> visitedBlocks; // for terminating the search\n\n    Definitions D;\n    if (escaping) {\n        D = findEscapingDefinitionsInBlock(from);\n    } else {\n        D = findDefinitionsInBlock(from);\n    }\n\n    ///\n    // -- Get the definitions from predecessors in this subgraph --\n    //\n    // NOTE: do not add block to visitedBlocks, it may be its own predecessor,\n    // in which case we want to process it again\n    if (auto *singlePred = block->getSinglePredecessor()) {\n        collectAllDefinitions(defs, singlePred, visitedBlocks, escaping);\n    } else {\n        // multiple predecessors\n        for (auto I = block->pred_begin(), E = block->pred_end(); I != E; ++I) {\n            // assign 'kills' to not to search for what we already have\n            Definitions tmpDefs;\n            tmpDefs.definitions = D.kills;\n            collectAllDefinitions(tmpDefs, *I, visitedBlocks, escaping);\n            defs.definitions.add(tmpDefs.definitions);\n            defs.unknownWrites.insert(defs.unknownWrites.end(),\n                                      tmpDefs.unknownWrites.begin(),\n                                      tmpDefs.unknownWrites.end());\n        }\n    }\n\n    ///\n    // -- Get the definitions from predecessors\n    //    in the callers of this subgraph --\n    //\n    collectAllDefinitionsInCallers(defs, block->getSubgraph());\n\n    // create the final map of definitions reaching the 'from' node\n    joinDefinitions(defs, D);\n    defs.swap(D);\n}\n\nstd::vector<RWNode *>\nMemorySSATransformation::findAllDefinitions(RWNode *from) {\n    DBG_SECTION_BEGIN(dda, \"MemorySSA - finding all definitions for node \"\n                                   << from->getID());\n\n    auto defs = collectAllDefinitions(from);\n\n    DBG_SECTION_END(dda, \"MemorySSA - finding all definitions for node \"\n                                 << from->getID() << \" done\");\n\n    auto values = defs.definitions.values();\n    values.insert(defs.unknownWrites.begin(), defs.unknownWrites.end());\n    return std::vector<RWNode *>(values.begin(), values.end());\n}\n\nvoid MemorySSATransformation::computeAllDefinitions() {\n    DBG_SECTION_BEGIN(dda, \"Computing definitions for all uses (requested)\");\n    for (auto *subg : graph.subgraphs()) {\n        for (auto *b : subg->bblocks()) {\n            for (auto *n : b->getNodes()) {\n                if (n->isUse()) {\n                    if (!n->defuse.initialized()) {\n                        n->addDefUse(findDefinitions(n));\n                        assert(n->defuse.initialized());\n                    }\n                }\n            }\n        }\n    }\n    DBG_SECTION_END(dda, \"Computing definitions for all uses finished\");\n}\n\nvoid MemorySSATransformation::initialize() {\n    // we need each call (of a defined function) in its own basic block\n    graph.splitBBlocksOnCalls();\n    // remove useless blocks and nodes\n    graph.optimize();\n\n    // make sure we have a constant-time access to information\n    _subgraphs_info.reserve(graph.size());\n\n    for (auto *subg : graph.subgraphs()) {\n        auto &si = _subgraphs_info[subg];\n        si._bblock_infos.reserve(subg->size());\n\n        // initialize information about basic blocks\n        for (auto *bb : subg->bblocks()) {\n            if (bb->size() == 1) {\n                if (auto *C = RWNodeCall::get(bb->getFirst())) {\n                    if (C->callsDefined()) {\n                        si._bblock_infos[bb].setCallBlock(C);\n                    }\n                }\n            }\n        }\n    }\n}\n\nRWNode *MemorySSATransformation::insertUse(RWNode *where, RWNode *mem,\n                                           const Offset &off,\n                                           const Offset &len) {\n    // DBG_SECTION_BEGIN(dda, \"Adding MU node\");\n    auto &use = graph.create(RWNodeType::MU);\n    use.addUse({mem, off, len});\n    use.insertBefore(where);\n    where->getBBlock()->insertBefore(&use, where);\n    // DBG_SECTION_END(dda, \"Created MU node \" << use->getID());\n\n    return &use;\n}\n\nstatic void recGatherNonPhisDefs(RWNode *phi,\n                                 dg::ADT::SparseBitvectorHashImpl &phis,\n                                 dg::ADT::SparseBitvectorHashImpl &ret,\n                                 bool intraproc = false) {\n    assert(phi->isPhi());\n    // set returns the previous value, so if its 'true',\n    // we already had the phi\n    if (phis.set(phi->getID()))\n        return; // we already visited this phi\n\n    for (auto *n : phi->defuse) {\n        if (!n->isPhi()) {\n            ret.set(n->getID());\n        } else {\n            if (intraproc && n->isInOut()) {\n                ret.set(n->getID());\n            } else {\n                recGatherNonPhisDefs(n, phis, ret, intraproc);\n            }\n        }\n    }\n}\n\n// recursivelu replace all phi values with its non-phi definitions\ntemplate <typename ContT>\nstd::vector<RWNode *> gatherNonPhisDefs(ReadWriteGraph *graph,\n                                        const ContT &nodes,\n                                        bool intraproc = false) {\n    dg::ADT::SparseBitvectorHashImpl ret; // use set to get rid of duplicates\n    dg::ADT::SparseBitvectorHashImpl\n            phis; // set of visited phi nodes - to check the fixpoint\n\n    for (auto n : nodes) {\n        if (!n->isPhi()) {\n            assert(n->getID() > 0);\n            ret.set(n->getID());\n        } else {\n            if (intraproc && n->isInOut()) {\n                assert(n->getID() > 0);\n                ret.set(n->getID());\n            } else {\n                recGatherNonPhisDefs(n, phis, ret, intraproc);\n            }\n        }\n    }\n\n    std::vector<RWNode *> retval;\n    retval.reserve(ret.size());\n    for (auto i : ret) {\n        retval.push_back(graph->getNode(i));\n    }\n    return retval;\n}\n\nstd::vector<RWNode *> MemorySSATransformation::getDefinitions(RWNode *use) {\n    // on demand triggering finding the definitions\n    if (!use->defuse.initialized()) {\n        use->addDefUse(findDefinitions(use));\n        assert(use->defuse.initialized());\n    }\n    return gatherNonPhisDefs(getGraph(), use->defuse);\n}\n\n// return the reaching definitions of ('mem', 'off', 'len')\n// at the location 'where'\nstd::vector<RWNode *>\nMemorySSATransformation::getDefinitions(RWNode *where, RWNode *mem,\n                                        const Offset &off, const Offset &len) {\n    auto *use = insertUse(where, mem, off, len);\n    return getDefinitions(use);\n}\n\nvoid MemorySSATransformation::run() {\n    DBG_SECTION_BEGIN(dda, \"Initializing MemorySSA analysis\");\n\n    initialize();\n\n    // the rest is on-demand :)\n\n    DBG_SECTION_END(dda, \"Initializing MemorySSA analysis finished\");\n}\n\n} // namespace dda\n} // namespace dg\n"
  },
  {
    "path": "lib/MemorySSA/ModRef.cpp",
    "content": "#include \"dg/MemorySSA/MemorySSA.h\"\n#include \"dg/util/debug.h\"\n\nnamespace dg {\nnamespace dda {\n\nstatic inline bool canBeOutput(const RWNode *node, RWSubgraph *subg) {\n    // can escape or already escaped\n    return node->canEscape() ||\n           (!node->getBBlock() || node->getBBlock()->getSubgraph() != subg);\n}\n\ntemplate <typename MR, typename C>\nstatic void modRefAdd(MR &modref, const C &c, RWNode *node, RWSubgraph *subg) {\n    assert(node && \"Node the definion node\");\n    for (const DefSite &ds : c) {\n        // can escape\n        if (canBeOutput(ds.target, subg)) {\n            modref.add(ds, node);\n        }\n    }\n}\n\nvoid MemorySSATransformation::computeModRef(RWSubgraph *subg,\n                                            SubgraphInfo &si) {\n    if (si.modref.isInitialized()) {\n        return;\n    }\n\n    DBG_SECTION_BEGIN(dda, \"Computing modref for subgraph \" << subg->getName());\n\n    // set it here due to recursive procedures\n    si.modref.setInitialized();\n\n    // iterate over the blocks (note: not over the infos, those\n    // may not be created if the block was not used yet\n    for (auto *b : subg->bblocks()) {\n        auto &bi = si.getBBlockInfo(b);\n        if (bi.isCallBlock()) {\n            auto *C = bi.getCall();\n            for (auto &callee : C->getCallees()) {\n                auto *csubg = callee.getSubgraph();\n                if (csubg) {\n                    auto &callsi = getSubgraphInfo(csubg);\n                    computeModRef(csubg, callsi);\n                    assert(callsi.modref.isInitialized());\n\n                    si.modref.add(callsi.modref);\n                } else {\n                    // undefined function\n                    modRefAdd(si.modref.maydef,\n                              callee.getCalledValue()->getDefines(), C, csubg);\n                    modRefAdd(si.modref.maydef,\n                              callee.getCalledValue()->getOverwrites(), C,\n                              csubg);\n                    modRefAdd(si.modref.mayref,\n                              callee.getCalledValue()->getUses(), C, csubg);\n                }\n            }\n        } else {\n            // do not perform LVN if not needed, just scan the nodes\n            for (auto *node : b->getNodes()) {\n                modRefAdd(si.modref.maydef, node->getDefines(), node, subg);\n                modRefAdd(si.modref.maydef, node->getOverwrites(), node, subg);\n                modRefAdd(si.modref.mayref, node->getUses(), node, subg);\n            }\n        }\n    }\n    DBG_SECTION_END(dda, \"Computing modref for subgraph \" << subg->getName()\n                                                          << \" done\");\n}\n\n} // namespace dda\n} // namespace dg\n"
  },
  {
    "path": "lib/Offset.cpp",
    "content": "#include \"dg/Offset.h\"\n\nnamespace dg {\n// set the value of UNKNOWN offset\nconst Offset::type Offset::UNKNOWN = ~(static_cast<Offset::type>(0));\n} // namespace dg\n"
  },
  {
    "path": "lib/PointerAnalysis/Pointer.cpp",
    "content": "#include \"dg/PointerAnalysis/Pointer.h\"\n#include \"dg/PointerAnalysis/PSNode.h\"\n\n#ifndef NDEBUG\n#include <iostream>\n\nnamespace dg {\nnamespace pta {\n\nvoid Pointer::dump() const {\n    target->dump();\n    std::cout << \" + \";\n    offset.dump();\n}\n\nvoid Pointer::print() const {\n    dump();\n    std::cout << \"\\n\";\n}\n\nsize_t Pointer::hash() const {\n    static_assert(sizeof(size_t) == 8, \"We relay on 64-bit size_t\");\n\n    // we relay on the fact the offsets are usually small. Therefore,\n    // cropping them to 4 bytes and putting them together with ID (which is 4\n    // byte) into one uint64_t should not have much collisions... we'll see.\n    constexpr unsigned mask = 0xffffffff;\n    constexpr unsigned short shift = 32;\n    return (static_cast<uint64_t>(target->getID()) << shift) | (*offset & mask);\n}\n\n} // namespace pta\n} // namespace dg\n\n#endif // not NDEBUG\n"
  },
  {
    "path": "lib/PointerAnalysis/PointerAnalysis.cpp",
    "content": "#include \"dg/PointerAnalysis/PointerAnalysis.h\"\n#include \"dg/PointerAnalysis/Pointer.h\"\n#include \"dg/PointerAnalysis/PointsToSet.h\"\n\n#include \"dg/util/debug.h\"\n\nnamespace dg {\nnamespace pta {\n\n// Return true if it makes sense to dereference this pointer.\n// PTA is over-approximation, so this is a filter.\nstatic inline bool canBeDereferenced(const Pointer &ptr) {\n    if (!ptr.isValid() || ptr.isInvalidated() || ptr.isUnknown())\n        return false;\n\n    // if the pointer points to a function, we can not dereference it\n    if (ptr.target->getType() == PSNodeType::FUNCTION)\n        return false;\n\n    return true;\n}\n\nstatic bool funHasAddressTaken(PSNode *node) {\n    if (node->getType() != PSNodeType::FUNCTION)\n        return false;\n\n    return dg::any_of(node->getUsers(), [node](PSNode *user) {\n        return node->getType() != PSNodeType::CALL ||\n               // call but is not called\n               node->getOperand(0) != user;\n    });\n}\n\nbool PointerAnalysis::processLoad(PSNode *node) {\n    bool changed = false;\n    PSNode *operand = node->getOperand(0);\n\n    if (operand->pointsTo.empty())\n        return error(operand, \"Load's operand has no points-to set\");\n\n    for (const Pointer &ptr : operand->pointsTo) {\n        if (ptr.isUnknown()) {\n            // load from unknown pointer yields unknown pointer\n            changed |= node->addPointsTo(UnknownPointer);\n            continue;\n        }\n\n        if (!canBeDereferenced(ptr))\n            continue;\n\n        // find memory objects holding relevant points-to\n        // information\n        std::vector<MemoryObject *> objects;\n        getMemoryObjects(node, ptr, objects);\n\n        PSNodeAlloc *target = PSNodeAlloc::get(ptr.target);\n        assert(target && \"Target is not memory allocation\");\n\n        // no objects found for this target? That is\n        // load from unknown memory\n        if (objects.empty()) {\n            if (target->isZeroInitialized())\n                // if the memory is zero initialized, then everything\n                // is fine, we add nullptr\n                changed |= node->addPointsTo(NullPointer);\n            else\n                changed |= errorEmptyPointsTo(node, target);\n\n            continue;\n        }\n\n        for (MemoryObject *o : objects) {\n            // is the offset to the memory unknown?\n            // In that case everything can be referenced,\n            // so we need to copy the whole points-to\n            if (ptr.offset.isUnknown()) {\n                // we should load from memory that has\n                // no pointers in it - it may be an error\n                // FIXME: don't duplicate the code\n                if (o->pointsTo.empty()) {\n                    if (target->isZeroInitialized())\n                        changed |= node->addPointsTo(NullPointer);\n                    else if (objects.size() == 1)\n                        changed |= errorEmptyPointsTo(node, target);\n                }\n\n                // we have some pointers - copy them all,\n                // since the offset is unknown\n                for (auto &it : o->pointsTo) {\n                    changed |= node->addPointsTo(it.second);\n                }\n\n                // this is all that we can do here...\n                continue;\n            }\n\n            // load from empty points-to set\n            // - that is load from unknown memory\n            auto it = o->pointsTo.find(ptr.offset);\n            if (it == o->pointsTo.end()) {\n                // if the memory is zero initialized, then everything\n                // is fine, we add nullptr\n                if (target->isZeroInitialized())\n                    changed |= node->addPointsTo(NullPointer);\n                // if we don't have a definition even with unknown offset\n                // it is an error\n                // FIXME: don't triplicate the code!\n                else if (!o->pointsTo.count(Offset::UNKNOWN))\n                    changed |= errorEmptyPointsTo(node, target);\n            } else {\n                // we have pointers on that memory, so we can\n                // do the work\n                changed |= node->addPointsTo(it->second);\n            }\n\n            // plus always add the pointers at unknown offset,\n            // since these can be what we need too\n            it = o->pointsTo.find(Offset::UNKNOWN);\n            if (it != o->pointsTo.end()) {\n                changed |= node->addPointsTo(it->second);\n            }\n        }\n    }\n\n    return changed;\n}\n\nbool PointerAnalysis::processMemcpy(PSNode *node) {\n    bool changed = false;\n    PSNodeMemcpy *memcpy = PSNodeMemcpy::get(node);\n    PSNode *srcNode = memcpy->getSource();\n    PSNode *destNode = memcpy->getDestination();\n\n    std::vector<MemoryObject *> srcObjects;\n    std::vector<MemoryObject *> destObjects;\n\n    // gather srcNode pointer objects\n    for (const Pointer &ptr : srcNode->pointsTo) {\n        assert(ptr.target && \"Got nullptr as target\");\n\n        if (!canBeDereferenced(ptr))\n            continue;\n\n        srcObjects.clear();\n        getMemoryObjects(node, ptr, srcObjects);\n\n        if (srcObjects.empty()) {\n            abort();\n            return changed;\n        }\n\n        // gather destNode objects\n        for (const Pointer &dptr : destNode->pointsTo) {\n            assert(dptr.target && \"Got nullptr as target\");\n\n            if (!canBeDereferenced(dptr))\n                continue;\n\n            destObjects.clear();\n            getMemoryObjects(node, dptr, destObjects);\n\n            if (destObjects.empty()) {\n                abort();\n                return changed;\n            }\n\n            changed |= processMemcpy(srcObjects, destObjects, ptr, dptr,\n                                     memcpy->getLength());\n        }\n    }\n\n    return changed;\n}\n\nstatic Pointer unwrapConstants(const Pointer &ptr) {\n    Offset offset = ptr.offset;\n    PSNode *target = ptr.target;\n    while (auto *C = PSNodeConstant::get(target)) {\n        target = C->getTarget();\n        offset += C->getOffset();\n    }\n    return {target, offset};\n}\n\nbool PointerAnalysis::processMemcpy(std::vector<MemoryObject *> &srcObjects,\n                                    std::vector<MemoryObject *> &destObjects,\n                                    const Pointer &sptr, const Pointer &dptr,\n                                    Offset len) {\n    assert(len > 0 && \"Memcpy of length 0\");\n\n    bool changed = false;\n\n    Pointer tmp = unwrapConstants(sptr);\n    Offset srcOffset = tmp.offset;\n    PSNodeAlloc *sourceAlloc = PSNodeAlloc::get(tmp.target);\n    assert(sourceAlloc && \"Source in memcpy is invalid\");\n\n    tmp = unwrapConstants(dptr);\n    Offset destOffset = tmp.offset;\n    PSNodeAlloc *destAlloc = PSNodeAlloc::get(tmp.target);\n    assert(destAlloc && \"Destination in memcpy is invalid\");\n\n    // set to true if the contents of destination memory\n    // can contain null\n    bool contains_null_somewhere = false;\n\n    // if the source is zero initialized, we may copy null pointer\n    if (sourceAlloc->isZeroInitialized()) {\n        // if we really copy the whole object, just set it zero-initialized\n        if ((sourceAlloc->getSize() != Offset::UNKNOWN) &&\n            (sourceAlloc->getSize() == destAlloc->getSize()) &&\n            len == sourceAlloc->getSize() && sptr.offset == 0) {\n            destAlloc->setZeroInitialized();\n        } else {\n            // we could analyze in a lot of cases where\n            // shoulde be stored the nullptr, but the question\n            // is whether it is worth it... For now, just say\n            // that somewhere may be null in the destination\n            contains_null_somewhere = true;\n        }\n    }\n\n    for (MemoryObject *destO : destObjects) {\n        if (contains_null_somewhere)\n            changed |= destO->addPointsTo(Offset::UNKNOWN, NullPointer);\n\n        // copy every pointer from srcObjects that is in\n        // the range to destination's objects\n        for (MemoryObject *so : srcObjects) {\n            for (auto &src : so->pointsTo) { // src.first is offset,\n                                             // src.second is a PointToSet\n\n                // if the offset is inbound of the copied memory\n                // or we copy from unknown offset, or this pointer\n                // is on unknown offset, copy this pointer\n                if (src.first.isUnknown() || srcOffset.isUnknown() ||\n                    (srcOffset <= src.first &&\n                     (len.isUnknown() || *src.first - *srcOffset < *len))) {\n                    // copy the pointer, but shift it by the offsets\n                    // we are working with\n                    if (!src.first.isUnknown() && !srcOffset.isUnknown() &&\n                        !destOffset.isUnknown()) {\n                        // check that new offset does not overflow\n                        // Offset::UNKNOWN\n                        if (Offset::UNKNOWN - *destOffset <=\n                            *src.first - *srcOffset) {\n                            changed |= destO->addPointsTo(Offset::UNKNOWN,\n                                                          src.second);\n                            continue;\n                        }\n\n                        Offset newOff = *src.first - *srcOffset + *destOffset;\n                        if (newOff >= destO->node->getSize() ||\n                            newOff >= options.fieldSensitivity) {\n                            changed |= destO->addPointsTo(Offset::UNKNOWN,\n                                                          src.second);\n                        } else {\n                            changed |= destO->addPointsTo(newOff, src.second);\n                        }\n                    } else {\n                        changed |=\n                                destO->addPointsTo(Offset::UNKNOWN, src.second);\n                    }\n                }\n            }\n        }\n    }\n\n    return changed;\n}\n\nbool PointerAnalysis::processGep(PSNode *node) {\n    bool changed = false;\n\n    PSNodeGep *gep = PSNodeGep::get(node);\n    assert(gep && \"Non-GEP given\");\n\n    for (const Pointer &ptr : gep->getSource()->pointsTo) {\n        Offset::type new_offset;\n        if (ptr.offset.isUnknown() || gep->getOffset().isUnknown())\n            // set it like this to avoid overflow when adding\n            new_offset = Offset::UNKNOWN;\n        else\n            new_offset = *ptr.offset + *gep->getOffset();\n\n        // in the case PSNodeType::the memory has size 0, then every pointer\n        // will have unknown offset with the exception that it points\n        // to the begining of the memory - therefore make 0 exception\n        if ((new_offset == 0 || new_offset < ptr.target->getSize()) &&\n            new_offset < *options.fieldSensitivity)\n            changed |= node->addPointsTo(ptr.target, new_offset);\n        else\n            changed |= node->addPointsTo(ptr.target, Offset::UNKNOWN);\n    }\n\n    return changed;\n}\n\nbool PointerAnalysis::processNode(PSNode *node) {\n    bool changed = false;\n    std::vector<MemoryObject *> objects;\n\n#ifdef DEBUG_ENABLED\n    size_t prev_size = node->pointsTo.size();\n#endif\n\n    switch (node->type) {\n    case PSNodeType::LOAD:\n        changed |= processLoad(node);\n        break;\n    case PSNodeType::STORE:\n        for (const Pointer &ptr : node->getOperand(1)->pointsTo) {\n            assert(ptr.target && \"Got nullptr as target\");\n\n            if (!canBeDereferenced(ptr))\n                continue;\n\n            objects.clear();\n            getMemoryObjects(node, ptr, objects);\n            for (MemoryObject *o : objects) {\n                changed |= o->addPointsTo(ptr.offset,\n                                          node->getOperand(0)->pointsTo);\n            }\n        }\n        break;\n    case PSNodeType::INVALIDATE_OBJECT:\n    case PSNodeType::FREE:\n        break;\n    case PSNodeType::INVALIDATE_LOCALS:\n        // FIXME: get rid of this type of node\n        // (make the analysis extendable and move it there)\n        node->setParent(node->getOperand(0)->getSingleSuccessor()->getParent());\n        break;\n    case PSNodeType::GEP:\n        changed |= processGep(node);\n        break;\n    case PSNodeType::CAST:\n        // cast only copies the pointers\n        changed |= node->addPointsTo(node->getOperand(0)->pointsTo);\n        break;\n    case PSNodeType::CONSTANT:\n        // maybe warn? It has no sense to insert the constants into the graph.\n        // On the other hand it is harmless. We can at least check if it is\n        // correctly initialized 8-)\n        assert(node->pointsTo.size() == 1 &&\n               \"Constant should have exactly one pointer\");\n        break;\n    case PSNodeType::CALL_RETURN:\n        if (options.invalidateNodes) {\n            for (PSNode *op : node->operands) {\n                for (const Pointer &ptr : op->pointsTo) {\n                    if (!canBeDereferenced(ptr))\n                        continue;\n                    PSNodeAlloc *target = PSNodeAlloc::get(ptr.target);\n                    assert(target && \"Target is not memory allocation\");\n                    if (!target->isHeap() && !target->isGlobal()) {\n                        changed |= node->addPointsTo(INVALIDATED, 0);\n                    }\n                }\n            }\n        }\n        // fall-through\n    case PSNodeType::RETURN:\n        // gather pointers returned from subprocedure - the same way\n        // as PHI works\n    case PSNodeType::PHI:\n        for (PSNode *op : node->operands)\n            changed |= node->addPointsTo(op->pointsTo);\n        break;\n    case PSNodeType::CALL_FUNCPTR:\n        // call via function pointer:\n        // first gather the pointers that can be used to the\n        // call and if something changes, let backend take some action\n        // (for example build relevant subgraph)\n        for (const Pointer &ptr : node->getOperand(0)->pointsTo) {\n            // do not add pointers that do not point to functions\n            // (but do not do that when we are looking for invalidated\n            // memory as this may lead to undefined behavior)\n            if (!options.invalidateNodes &&\n                ptr.target->getType() != PSNodeType::FUNCTION)\n                continue;\n            // Functions that have not address taken cannot\n            // be called via a pointer\n            if (!funHasAddressTaken(ptr.target)) {\n                continue;\n            }\n            if (node->addPointsTo(ptr)) {\n                changed = true;\n\n                if (ptr.isValid() && !ptr.isInvalidated()) {\n                    functionPointerCall(node, ptr.target);\n                } else {\n                    error(node, \"Calling invalid pointer as a function!\");\n                    continue;\n                }\n            }\n        }\n        break;\n    case PSNodeType::FORK: // FORK works basically the same as FUNCPTR\n        for (const Pointer &ptr : node->getOperand(0)->pointsTo) {\n            // do not add pointers that do not point to functions\n            // (but do not do that when we are looking for invalidated\n            // memory as this may lead to undefined behavior)\n            if (!options.invalidateNodes &&\n                ptr.target->getType() != PSNodeType::FUNCTION)\n                continue;\n\n            if (node->addPointsTo(ptr)) {\n                changed = true;\n\n                if (ptr.isValid() && !ptr.isInvalidated()) {\n                    handleFork(node, ptr.target);\n                } else {\n                    error(node, \"Calling invalid pointer in fork!\");\n                    continue;\n                }\n            }\n        }\n        break;\n    case PSNodeType::JOIN:\n        changed |= handleJoin(node);\n        break;\n    case PSNodeType::MEMCPY:\n        changed |= processMemcpy(node);\n        break;\n    case PSNodeType::ALLOC:\n    case PSNodeType::FUNCTION:\n        // these two always points to itself\n        assert(node->doesPointsTo(node, 0));\n        assert(node->pointsTo.size() == 1);\n    case PSNodeType::CALL:\n    case PSNodeType::ENTRY:\n    case PSNodeType::NOOP:\n        // just no op\n        break;\n    default:\n        assert(0 && \"Unknown type\");\n    }\n\n#ifdef DEBUG_ENABLED\n    // the change of points-to set is not the only\n    // change that can happen, so we don't use it as an\n    // indicator and we use the 'changed' variable instead.\n    // However, this assertion must hold:\n    assert((node->pointsTo.size() == prev_size || changed) &&\n           \"BUG: Did not set change but changed points-to sets\");\n#endif\n\n    return changed;\n}\n\nvoid PointerAnalysis::sanityCheck() {\n#ifndef NDEBUG\n    assert(NULLPTR->pointsTo.size() == 1 && \"Null has been assigned a pointer\");\n    assert(NULLPTR->doesPointsTo(NULLPTR) &&\n           \"Null points to a different location\");\n    assert(UNKNOWN_MEMORY->pointsTo.size() == 1 &&\n           \"Unknown memory has been assigned a pointer\");\n    assert(UNKNOWN_MEMORY->doesPointsTo(UNKNOWN_MEMORY, Offset::UNKNOWN) &&\n           \"Unknown memory has been assigned a pointer\");\n    assert(INVALIDATED->pointsTo.empty() &&\n           \"Unknown memory has been assigned a pointer\");\n\n    auto nodes = PG->getNodes(PG->getEntry()->getRoot());\n    std::set<unsigned> ids;\n    for (auto *nd : nodes) {\n        assert(ids.insert(nd->getID()).second && \"Duplicated node ID\");\n\n        if (nd->getType() == PSNodeType::ALLOC) {\n            assert(nd->pointsTo.size() == 1 &&\n                   \"Alloc does not point only to itself\");\n            assert(nd->doesPointsTo(nd, 0) &&\n                   \"Alloc does not point only to itself\");\n        }\n    }\n#endif // not NDEBUG\n}\n\nstatic void setToEmpty(std::vector<PSNode *> &nodes) {\n    for (auto *n : nodes) {\n        if (n->getType() != PSNodeType::ALLOC &&\n            n->getType() != PSNodeType::CONSTANT) {\n            n->pointsTo.clear();\n        }\n    }\n}\n\nbool PointerAnalysis::run() {\n    DBG_SECTION_BEGIN(pta, \"Running pointer analysis\");\n\n    preprocess();\n\n    // check that the current state of pointer analysis makes sense\n    sanityCheck();\n\n    // process global nodes, these must reach fixpoint after one iteration\n    DBG(pta, \"Processing global nodes\");\n    queue_globals();\n    iteration();\n    assert((to_process.clear(), changed.clear(), queue_globals(),\n            !iteration()) &&\n           \"Globals did not reach fixpoint\");\n    to_process.clear();\n    changed.clear();\n\n    initialize_queue();\n\n    // override the pre-set value\n    if (options.maxIterations > 0) {\n        DBG(pta, \"The maximal number of iterations is set to \"\n                         << options.maxIterations);\n    }\n\n    size_t n = 0;\n    // do fixpoint\n    do {\n        if (options.maxIterations > 0 && n > options.maxIterations) {\n            DBG(pta, \"Reached the maximum number of iterations: \" << n);\n            setToEmpty(to_process);\n            to_process.clear();\n            break;\n        }\n#if DEBUG_ENABLED\n#define DUMP_NTH_ITER 100\n        if (n % DUMP_NTH_ITER == 0) {\n            DBG(pta, \"Iteration \" << n << \", queue size \" << to_process.size());\n        }\n#endif\n        ++n;\n\n        iteration();\n        queue_changed();\n    } while (!to_process.empty());\n\n    DBG(pta, \"Reached fixpoint after \" << n << \" iterations\\n\");\n\n    assert(to_process.empty());\n    assert(changed.empty());\n\n    // NOTE: With flow-insensitive analysis, it may happen that\n    // we have not reached the fixpoint here. This is beacuse\n    // we queue only reachable nodes from the nodes that changed\n    // something. So if in the rechable nodes something generates\n    // new information, than this information could be added to some\n    // node in a new iteration over all nodes. But this information\n    // can never get to that node in runtime, since that node is\n    // unreachable from the point where the information is\n    // generated, so this is OK.\n\n    sanityCheck();\n\n    DBG_SECTION_END(pta, \"Running pointer analysis done\");\n\n    return options.maxIterations > 0 ? n <= options.maxIterations : true;\n}\n\n} // namespace pta\n} // namespace dg\n"
  },
  {
    "path": "lib/PointerAnalysis/PointerGraph.cpp",
    "content": "#include <cassert>\n\n#include \"dg/PointerAnalysis/PSNode.h\"\n#include \"dg/PointerAnalysis/PointerGraph.h\"\n\n#include \"dg/util/debug.h\"\n\nnamespace dg {\nnamespace pta {\n\n// nodes representing NULL, unknown memory\n// and invalidated memory\nPSNode NULLPTR_LOC(PointerGraphReservedIDs::ID_NULL, PSNodeType::NULL_ADDR);\nPSNode UNKNOWN_MEMLOC(PointerGraphReservedIDs::ID_UNKNOWN,\n                      PSNodeType::UNKNOWN_MEM);\nPSNode INVALIDATED_LOC(PointerGraphReservedIDs::ID_INVALIDATED,\n                       PSNodeType::INVALIDATED);\n\nPSNode *NULLPTR = &NULLPTR_LOC;\nPSNode *UNKNOWN_MEMORY = &UNKNOWN_MEMLOC;\nPSNode *INVALIDATED = &INVALIDATED_LOC;\n\n// pointers to those memory\nconst Pointer UnknownPointer(UNKNOWN_MEMORY, Offset::UNKNOWN);\nconst Pointer NullPointer(NULLPTR, 0);\n\nvoid PointerGraph::remove(PSNode *nd) {\n    assert(nd && \"nullptr passed as nd\");\n    // the node must be isolated\n    assert(nd->successors().empty() && \"The node is still in graph\");\n    assert(nd->predecessors().empty() && \"The node is still in graph\");\n    assert(nd->getID() < size() && \"Invalid ID\");\n    assert(nd->getID() > 0 && \"Invalid ID\");\n    assert(nd->users.empty() && \"This node is used by other nodes\");\n    // if the node has operands, it means that the operands\n    // have a reference (an user edge to this node).\n    // We do not want to create dangling references.\n    assert(nd->operands.empty() && \"This node uses other nodes\");\n    assert(nodes[nd->getID()].get() == nd && \"Inconsistency in nodes\");\n\n    // clear the nodes entry\n    nodes[nd->getID()].reset();\n}\n\nvoid PointerGraph::initStaticNodes() {\n    NULLPTR->pointsTo.clear();\n    UNKNOWN_MEMORY->pointsTo.clear();\n    NULLPTR->pointsTo.add(Pointer(NULLPTR, 0));\n    UNKNOWN_MEMORY->pointsTo.add(Pointer(UNKNOWN_MEMORY, Offset::UNKNOWN));\n}\n\nvoid PointerGraph::computeLoops() {\n    DBG(pta, \"Computing information about loops for the whole graph\");\n\n    for (auto &it : _subgraphs) {\n        if (!it->computedLoops())\n            it->computeLoops();\n    }\n}\n\nvoid PointerGraph::setEntry(PointerSubgraph *e) {\n#if DEBUG_ENABLED\n    bool found = false;\n    for (auto &n : _subgraphs) {\n        if (n.get() == e) {\n            found = true;\n            break;\n        }\n    }\n    assert(found && \"The entry is not a subgraph of the graph\");\n#endif\n    _entry = e;\n}\n\nvoid PointerSubgraph::computeLoops() {\n    // FIXME: remember just that a node is on loop, not the whole loops\n\n    assert(root);\n    assert(!computedLoops() && \"computeLoops() called repeatedly\");\n    _computed_loops = true;\n\n    DBG(pta, \"Computing information about loops\");\n\n    // compute the strongly connected components\n    auto SCCs = SCC<PSNode>().compute(root);\n    for (auto &scc : SCCs) {\n        if (scc.empty())\n            continue;\n        // self-loop is also loop\n        if (scc.size() == 1 && scc[0]->getSingleSuccessorOrNull() != scc[0])\n            continue;\n\n        _loops.push_back(std::move(scc));\n\n        for (auto *nd : _loops.back()) {\n            assert(_node_to_loop.find(nd) == _node_to_loop.end());\n            _node_to_loop[nd] = _loops.size() - 1;\n        }\n    }\n}\n\n} // namespace pta\n} // namespace dg\n"
  },
  {
    "path": "lib/PointerAnalysis/PointerGraphOptimizations.cpp",
    "content": "#include \"dg/PointerAnalysis/PointerGraphOptimizations.h\"\n#include \"dg/PointerAnalysis/PointerGraph.h\"\n\nnamespace dg {\nnamespace pta {\n\nstatic inline bool isStoreOfUnknown(PSNode *S, PSNode *to) {\n    return (S->getType() == PSNodeType::STORE && S->getOperand(1) == to &&\n            S->getOperand(0)->isUnknownMemory());\n}\n\nstatic inline bool usersImplyUnknown(PSNode *alloc) {\n    assert(alloc->getType() == PSNodeType::ALLOC);\n\n    for (PSNode *user : alloc->getUsers()) {\n        // we store only unknown to this memory\n        // and the only other thing that we do is that\n        // we load from it\n        if ((user->getType() != PSNodeType::LOAD) &&\n            // 'user' is not store of 'unknown' to 'nd'\n            !isStoreOfUnknown(user, alloc))\n            return false;\n    }\n\n    return true;\n}\n\nvoid removeNode(PointerGraph *G, PSNode *nd) {\n    // llvm::errs() << \"Remove node \" << nd->getID() << \"\\n\";\n\n    assert(nd->getUsers().empty() && \"Removing node that has users\");\n    // remove from CFG\n    nd->isolate();\n    // clear its operands (so that the operands do not\n    // have a dangling reference to this node in 'users')\n    nd->removeAllOperands();\n    // delete it from the graph\n    G->remove(nd);\n}\n\nvoid PSUnknownsReducer::processAllocs() {\n    for (const auto &nd : G->getNodes()) {\n        if (!nd)\n            continue;\n\n        if (nd->getType() == PSNodeType::ALLOC) {\n            // this is an allocation that has only stores of unknown memory to\n            // it (and its address is not stored anywhere) and there are only\n            // loads from this memory (that must result to unknown)\n            if (usersImplyUnknown(nd.get())) {\n                // create a copy of users, as we will modify the container\n                auto tmp = nd->getUsers();\n                for (PSNode *user : tmp) {\n                    if (user->getType() == PSNodeType::LOAD) {\n                        // replace the uses of the load value by unknown\n                        // (this is what would happen in the analysis)\n                        user->replaceAllUsesWith(UNKNOWN_MEMORY);\n                        mapping.add(user, UNKNOWN_MEMORY);\n                    }\n                    // store can be removed directly\n                    removeNode(G, user);\n                    ++removed;\n                }\n\n                // NOTE: keep the alloca, as it contains the\n                // pointer to itself and may be queried for this pointer\n            }\n        } else if (nd->getType() == PSNodeType::PHI &&\n                   nd->getOperandsNum() == 0) {\n            auto tmp = nd->getUsers();\n            for (PSNode *user : tmp) {\n                // replace the uses of this value with unknown\n                user->replaceAllUsesWith(UNKNOWN_MEMORY);\n                mapping.add(user, UNKNOWN_MEMORY);\n\n                // store can be removed directly\n                removeNode(G, user);\n                ++removed;\n            }\n\n            removeNode(G, nd.get());\n            ++removed;\n        }\n    }\n}\n\nstatic inline bool allOperandsAreSame(PSNode *nd) {\n    auto opNum = nd->getOperandsNum();\n    if (opNum < 1)\n        return true;\n\n    PSNode *op0 = nd->getOperand(0);\n    for (decltype(opNum) i = 1; i < opNum; ++i) {\n        if (op0 != nd->getOperand(i))\n            return false;\n    }\n\n    return true;\n}\n\n// get rid of all casts\nvoid PSEquivalentNodesMerger::mergeCasts() {\n    for (const auto &nodeptr : G->getNodes()) {\n        if (!nodeptr)\n            continue;\n\n        PSNode *node = nodeptr.get();\n\n        // cast is always 'a proxy' to the real value,\n        // it does not change the pointers\n        if (node->getType() == PSNodeType::CAST ||\n            (node->getType() == PSNodeType::PHI && node->getOperandsNum() > 0 &&\n             allOperandsAreSame(node))) {\n            merge(node, node->getOperand(0));\n        } else if (PSNodeGep *GEP = PSNodeGep::get(node)) {\n            if (GEP->getOffset().isZero()) // GEP with 0 offest is cast\n                merge(node, GEP->getSource());\n        }\n    }\n}\n\nvoid PSEquivalentNodesMerger::merge(PSNode *node1, PSNode *node2) {\n    // remove node1\n    node1->replaceAllUsesWith(node2);\n    removeNode(G, node1);\n\n    // update the mapping\n    mapping.add(node1, node2);\n\n    ++merged_nodes_num;\n}\n\nunsigned PSNoopRemover::run() {\n    unsigned removed = 0;\n    for (const auto &nd : G->getNodes()) {\n        if (!nd)\n            continue;\n\n        if (nd->getType() == PSNodeType::NOOP) {\n            // this should not break the iterator\n            removeNode(G, nd.get());\n            ++removed;\n        }\n    }\n    return removed;\n}\n\n} // namespace pta\n} // namespace dg\n"
  },
  {
    "path": "lib/PointerAnalysis/PointerGraphValidator.cpp",
    "content": "#include <string>\n\n#include \"dg/PointerAnalysis/PointerGraphValidator.h\"\n#include \"dg/PointerAnalysis/PointsToSet.h\"\n#include \"dg/util/iterators.h\"\n\nnamespace dg {\nnamespace pta {\n\nstatic void dumpNode(const PSNode *nd, std::string &errors) {\n    errors += std::string(PSNodeTypeToCString(nd->getType())) + \" with ID \" +\n              std::to_string(nd->getID()) + \"\\n  - operands: [\";\n    for (unsigned i = 0, e = nd->getOperandsNum(); i < e; ++i) {\n        const PSNode *op = nd->getOperand(i);\n        errors += std::to_string(op->getID()) += \" \";\n        errors += std::string(PSNodeTypeToCString(op->getType()));\n        if (i != e - 1)\n            errors += \", \";\n    }\n    errors += \"]\\n\";\n}\n\nbool PointerGraphValidator::warn(const PSNode *nd, const std::string &warning) {\n    warnings += \"Warning: \" + warning + \"\\n\";\n    dumpNode(nd, warnings);\n\n    return true;\n}\n\nbool PointerGraphValidator::reportInvalOperands(const PSNode *nd,\n                                                const std::string &user_err) {\n    errors += \"Invalid operands:\\n\";\n    dumpNode(nd, errors);\n\n    if (!user_err.empty())\n        errors += \"(\" + user_err + \")\\n\";\n\n    return true;\n}\n\nbool PointerGraphValidator::reportInvalEdges(const PSNode *nd,\n                                             const std::string &user_err) {\n    errors += \"Invalid number of edges:\\n\";\n    dumpNode(nd, errors);\n\n    if (!user_err.empty())\n        errors += \"(\" + user_err + \")\\n\";\n    return true;\n}\n\nbool PointerGraphValidator::reportInvalNode(const PSNode *nd,\n                                            const std::string &user_err) {\n    errors += \"Invalid node:\\n\";\n    dumpNode(nd, errors);\n    if (!user_err.empty())\n        errors += \"(\" + user_err + \")\\n\";\n    return true;\n}\n\nbool PointerGraphValidator::reportUnreachableNode(const PSNode *nd) {\n    errors += \"Unreachable node:\\n\";\n    dumpNode(nd, errors);\n    return true;\n}\n\nstatic bool hasDuplicateOperand(const PSNode *nd) {\n    std::set<const PSNode *> ops;\n    for (const PSNode *op : nd->getOperands()) {\n        if (!ops.insert(op).second)\n            return true;\n    }\n\n    return false;\n}\n\nstatic bool hasNonpointerOperand(const PSNode *nd) {\n    return dg::any_of(nd->getOperands(), [](const PSNode *op) {\n        return (op->getType() == PSNodeType::NOOP ||\n                op->getType() == PSNodeType::FREE ||\n                op->getType() == PSNodeType::ENTRY ||\n                op->getType() == PSNodeType::INVALIDATE_LOCALS ||\n                op->getType() == PSNodeType::INVALIDATE_OBJECT ||\n                op->getType() == PSNodeType::MEMCPY ||\n                op->getType() == PSNodeType::STORE);\n    });\n}\n\nbool PointerGraphValidator::checkOperands() {\n    bool invalid = false;\n\n    std::set<const PSNode *> known_nodes;\n    const auto &nodes = PS->getNodes();\n\n    for (const auto *g : PS->getGlobals()) {\n        if (!known_nodes.insert(g).second)\n            invalid |= reportInvalNode(\n                    g, \"Global node multiple times in the graph\");\n    }\n\n    // globals are also normal nodes, so we must forget them now\n    known_nodes.clear();\n\n    for (const auto &nd : nodes) {\n        if (!nd)\n            continue;\n\n        if (!known_nodes.insert(nd.get()).second)\n            invalid |= reportInvalNode(nd.get(),\n                                       \"Node multiple times in the graph\");\n    }\n\n    for (const auto &ndptr : nodes) {\n        if (!ndptr)\n            continue;\n\n        PSNode *nd = ndptr.get();\n        for (const PSNode *op : nd->getOperands()) {\n            if (op != NULLPTR && op != UNKNOWN_MEMORY && op != INVALIDATED &&\n                known_nodes.count(op) == 0) {\n                invalid |= reportInvalOperands(\n                        nd, \"Node has unknown (maybe dangling) operand\");\n            }\n        }\n\n        switch (nd->getType()) {\n        case PSNodeType::PHI:\n            if (nd->getOperandsNum() == 0) {\n                // this may not be always an error\n                // (say this is a phi of an uninitialized pointer\n                // for which we do not have any points to)\n                warn(nd, \"Empty PHI\");\n            } else if (hasDuplicateOperand(nd)) {\n                // this is not an error, but warn the user\n                // as this is redundant\n                warn(nd, \"PHI Node contains duplicated operand\");\n            } else if (hasNonpointerOperand(nd)) {\n                invalid |= reportInvalOperands(\n                        nd, \"PHI Node contains non-pointer operand\");\n            }\n            break;\n        case PSNodeType::NULL_ADDR:\n        case PSNodeType::UNKNOWN_MEM:\n        case PSNodeType::NOOP:\n        case PSNodeType::FUNCTION:\n            if (nd->getOperandsNum() != 0) {\n                invalid |=\n                        reportInvalOperands(nd, \"Should not have an operand\");\n            }\n            break;\n        case PSNodeType::GEP:\n        case PSNodeType::LOAD:\n        case PSNodeType::CAST:\n        case PSNodeType::INVALIDATE_OBJECT:\n        case PSNodeType::CONSTANT:\n        case PSNodeType::FREE:\n            if (hasNonpointerOperand(nd)) {\n                invalid |=\n                        reportInvalOperands(nd, \"Node has non-pointer operand\");\n            }\n            if (nd->getOperandsNum() != 1) {\n                invalid |= reportInvalOperands(\n                        nd, \"Should have exactly one operand\");\n            }\n            break;\n        case PSNodeType::STORE:\n        case PSNodeType::MEMCPY:\n            if (hasNonpointerOperand(nd)) {\n                invalid |=\n                        reportInvalOperands(nd, \"Node has non-pointer operand\");\n            }\n            if (nd->getOperandsNum() != 2) {\n                invalid |= reportInvalOperands(\n                        nd, \"Should have exactly two operands\");\n            }\n            break;\n        }\n    }\n\n    return invalid;\n}\n\nstatic inline bool isInPredecessors(const PSNode *nd, const PSNode *of) {\n    return dg::any_of(of->predecessors(),\n                      [nd](const PSNode *pred) { return pred == nd; });\n}\n\nstatic inline bool canBeOutsideGraph(const PSNode *nd) {\n    if (const PSNodeAlloc *A = PSNodeAlloc::get(nd))\n        return A->isGlobal();\n\n    return (nd->getType() == PSNodeType::FUNCTION ||\n            nd->getType() == PSNodeType::CONSTANT ||\n            nd->getType() == PSNodeType::UNKNOWN_MEM ||\n            nd->getType() == PSNodeType::NULL_ADDR);\n}\n\nstd::set<const PSNode *> reachableNodes(const PSNode *nd) {\n    std::set<const PSNode *> reachable;\n    reachable.insert(nd);\n\n    std::vector<const PSNode *> to_process;\n    to_process.reserve(4);\n    to_process.push_back(nd);\n\n    while (!to_process.empty()) {\n        std::vector<const PSNode *> new_to_process;\n        new_to_process.reserve(to_process.size());\n\n        for (const PSNode *cur : to_process) {\n            for (const PSNode *succ : cur->successors()) {\n                if (reachable.insert(succ).second)\n                    new_to_process.push_back(succ);\n            }\n        }\n\n        new_to_process.swap(to_process);\n    }\n\n    return reachable;\n}\n\nbool PointerGraphValidator::checkEdges() {\n    bool invalid = false;\n\n    // check incoming/outcoming edges of all nodes\n    const auto &nodes = PS->getNodes();\n    for (const auto &nd : nodes) {\n        if (!nd)\n            continue;\n\n        if (!no_connectivity) {\n            if (nd->predecessorsNum() == 0 && nd.get() &&\n                nd->getType() != PSNodeType::ENTRY &&\n                !canBeOutsideGraph(nd.get())) {\n                invalid |= reportInvalEdges(\n                        nd.get(), \"Non-entry node has no predecessors\");\n            }\n        }\n\n        for (const PSNode *succ : nd->successors()) {\n            if (!isInPredecessors(nd.get(), succ))\n                invalid |= reportInvalEdges(nd.get(),\n                                            \"Node not set as a predecessor of \"\n                                            \"some of its successors\");\n        }\n    }\n\n    if (no_connectivity)\n        return invalid;\n\n    // check that all nodes are reachable from the root\n    const auto reachable = getReachableNodes(PS->getEntry()->getRoot());\n    for (const auto &nd : nodes) {\n        if (!nd)\n            continue;\n\n        if (reachable.count(nd.get()) < 1 && !canBeOutsideGraph(nd.get())) {\n            invalid |= reportUnreachableNode(nd.get());\n        }\n    }\n\n    return invalid;\n}\n\nbool PointerGraphValidator::validate() {\n    bool invalid = false;\n\n    invalid |= checkOperands();\n    invalid |= checkEdges();\n\n    return invalid;\n}\n\n} // namespace pta\n} // namespace dg\n"
  },
  {
    "path": "lib/PointerAnalysis/PointsToSet.cpp",
    "content": "#include <functional>\n#include <map>\n#include <vector>\n\n#include \"dg/PointerAnalysis/PSNode.h\"\n#include \"dg/PointerAnalysis/Pointer.h\"\n#include \"dg/PointerAnalysis/PointsToSet.h\"\n#include \"dg/PointerAnalysis/PointsToSets/LookupTable.h\"\n\nnamespace dg {\nnamespace pta {\n\nstd::vector<PSNode *> SeparateOffsetsPointsToSet::idVector;\nstd::vector<PSNode *> SmallOffsetsPointsToSet::idVector;\nstd::vector<PSNode *> AlignedSmallOffsetsPointsToSet::idVector;\nstd::vector<Pointer> AlignedPointerIdPointsToSet::idVector;\nstd::map<PSNode *, size_t> SeparateOffsetsPointsToSet::ids;\ndg::PointerIDLookupTable PointerIdPointsToSet::lookupTable;\nstd::map<PSNode *, size_t> SmallOffsetsPointsToSet::ids;\nstd::map<PSNode *, size_t> AlignedSmallOffsetsPointsToSet::ids;\nstd::map<Pointer, size_t> AlignedPointerIdPointsToSet::ids;\n\n} // namespace pta\n\n} // namespace dg\n"
  },
  {
    "path": "lib/ReadWriteGraph/ReadWriteGraph.cpp",
    "content": "#include <set>\n#include <vector>\n\n#include \"dg/BBlocksBuilder.h\"\n#include \"dg/ReadWriteGraph/ReadWriteGraph.h\"\n\nnamespace dg {\nnamespace dda {\n\nRWNode UNKNOWN_MEMLOC;\nRWNode *UNKNOWN_MEMORY = &UNKNOWN_MEMLOC;\n\n#ifndef NDEBUG\nvoid RWNode::dump() const { std::cout << getID() << \"\\n\"; }\n\nvoid RWNodeCall::dump() const {\n    std::cout << getID() << \" calls [\";\n    unsigned n = 0;\n    for (const auto &cv : callees) {\n        if (n++ > 0) {\n            std::cout << \", \";\n        }\n\n        if (const auto *subg = cv.getSubgraph()) {\n            const auto &nm = subg->getName();\n            if (nm.empty()) {\n                std::cout << subg;\n            } else {\n                std::cout << nm;\n            }\n        } else {\n            std::cout << cv.getCalledValue()->getID();\n        }\n    }\n    std::cout << \"]\\n\";\n}\n\nvoid RWBBlock::dump() const {\n    std::cout << \"bblock \" << getID() << \"(\" << this << \")\\n\";\n    for (auto *n : getNodes()) {\n        std::cout << \"  \";\n        n->dump();\n    }\n}\n\n#endif\n\nbool RWNode::isDynAlloc() const {\n    if (getType() == RWNodeType::DYN_ALLOC)\n        return true;\n\n    if (const auto *C = RWNodeCall::get(this)) {\n        for (const auto &cv : C->getCallees()) {\n            if (const auto *val = cv.getCalledValue()) {\n                if (val->getType() == RWNodeType::DYN_ALLOC) {\n                    return true;\n                }\n            }\n        }\n    }\n\n    return false;\n}\n\nvoid RWNodeCall::addCallee(RWSubgraph *s) {\n    callees.emplace_back(s);\n    s->addCaller(this);\n}\n\nvoid ReadWriteGraph::removeUselessNodes() {}\n\nvoid RWSubgraph::buildBBlocks(bool /*dce*/) {\n    assert(getRoot() && \"No root node\");\n    DBG(dda, \"Building basic blocks\");\n\n    BBlocksBuilder<RWBBlock> builder;\n    _bblocks = std::move(builder.buildAndGetBlocks(getRoot()));\n\n    assert(getRoot()->getBBlock() && \"Root node has no BBlock\");\n\n    // should we eliminate dead code?\n    // The dead code are the nodes that have no basic block assigned\n    // (follows from the DFS nature of the block builder algorithm)\n    /*\n    if (!dce)\n        return;\n\n    for (auto& nd : _nodes) {\n        if (nd->getBBlock() == nullptr) {\n            nd->isolate();\n            nd.reset();\n        }\n    }\n    */\n}\n\n// split the block on the first call and return the\n// block containing the rest of the instructions\n// (or nullptr if there's nothing else to do)\nstatic RWBBlock *\nsplitBlockOnFirstCall(RWBBlock *block,\n                      std::vector<std::unique_ptr<RWBBlock>> &newblocks) {\n    for (auto *node : block->getNodes()) {\n        if (auto *call = RWNodeCall::get(node)) {\n            if (call->callsOneUndefined()) {\n                // ignore calls that call one udefined function,\n                // those behave just like usual read/write\n                continue;\n            }\n            DBG(dda, \"Splitting basic block around \" << node->getID());\n            auto blks = block->splitAround(node);\n            if (blks.first)\n                newblocks.push_back(std::move(blks.first));\n            if (blks.second) {\n                newblocks.push_back(std::move(blks.second));\n                return newblocks.back().get();\n            }\n            return nullptr;\n        }\n    }\n    return nullptr;\n}\n\nvoid RWSubgraph::splitBBlocksOnCalls() {\n    DBG_SECTION_BEGIN(dda, \"Splitting basic blocks on calls\");\n    if (_bblocks.empty()) {\n        DBG_SECTION_END(dda, \"Splitting basic blocks on calls finished\");\n        return;\n    }\n\n#ifndef NDEBUG\n    auto *entry = _bblocks[0].get();\n#endif\n\n    std::vector<std::unique_ptr<RWBBlock>> newblocks;\n\n    for (auto &bblock : _bblocks) {\n        auto *cur = bblock.get();\n        while (cur) {\n            cur = splitBlockOnFirstCall(cur, newblocks);\n        }\n    }\n\n    for (auto &bblock : newblocks) {\n        _bblocks.push_back(std::move(bblock));\n    }\n\n    assert(entry == _bblocks[0].get() &&\n           \"splitBBlocksOnCalls() changed the entry\");\n    DBG_SECTION_END(dda, \"Splitting basic blocks on calls finished\");\n}\n\n} // namespace dda\n} // namespace dg\n"
  },
  {
    "path": "lib/SystemDependenceGraph/DependenceGraph.cpp",
    "content": "#include <cassert>\n\n#include \"dg/SystemDependenceGraph/DGArgumentPair.h\"\n#include \"dg/SystemDependenceGraph/DGNode.h\"\n#include \"dg/SystemDependenceGraph/DGNodeCall.h\"\n#include \"dg/SystemDependenceGraph/DGParameters.h\"\n#include \"dg/SystemDependenceGraph/DependenceGraph.h\"\n\nnamespace dg {\nnamespace sdg {\n\n// ------------------------------------------------------------------\n// -- Parameters --\n// ------------------------------------------------------------------\n\nDGArgumentPair::DGArgumentPair(DGParameters &p)\n        : DGElement(p.getDG(), DGElementType::ARG_PAIR), _parameters(p),\n          _input(p.getDG()), _output(p.getDG()) {}\n\nDGActualParameters::DGActualParameters(DGNodeCall &call)\n        : DGParameters(call.getDG()), _call(call) {}\n\nDGNodeArtificial &DGFormalParameters::createVarArg() {\n    auto &dg = getDG();\n    _vararg.reset(&dg.createArtificial());\n    return *_vararg;\n}\n\nDGNode &DGParameters::createNoReturn() {\n    auto &dg = getDG();\n    _noreturn = &dg.createArtificial();\n    return *_noreturn;\n}\n\nDGNode &DGParameters::createReturn() {\n    auto &dg = getDG();\n    _return = &dg.createArtificial();\n    return *_return;\n}\n\n// ------------------------------------------------------------------\n// -- DGElem --\n// ------------------------------------------------------------------\n\nunsigned DGElement::getNewID(DependenceGraph &g) { return g.getNextNodeID(); }\n\nDGElement::DGElement(DependenceGraph &g, DGElementType t)\n        : _id(getNewID(g)), _type(t), _dg(g) {}\n\n// ------------------------------------------------------------------\n// -- Node --\n// ------------------------------------------------------------------\n\nDGNode::DGNode(DependenceGraph &g, DGElementType t) : DepDGElement(g, t) {\n    assert(t > DGElementType::NODE && \"Invalid node type\");\n}\n\nbool DGNodeCall::addCallee(DependenceGraph &g) {\n    g.addCaller(this);\n    return _callees.insert(&g).second;\n}\n\n} // namespace sdg\n} // namespace dg\n"
  },
  {
    "path": "lib/ValueRelations/Relations.cpp",
    "content": "#include \"dg/ValueRelations/Relations.h\"\n\n#include <algorithm>\n#include <cassert>\n#include <cmath>\n\nnamespace dg {\nnamespace vr {\n\nconst std::array<Relations::Type, Relations::total> Relations::all = {\n        EQ, NE, SLE, SLT, ULE, ULT, SGE, SGT, UGE, UGT, PT, PF};\n\nRelations::Type Relations::inverted(Relations::Type type) {\n    switch (type) {\n    case EQ:\n        return EQ;\n    case NE:\n        return NE;\n    case SLE:\n        return SGE;\n    case SLT:\n        return SGT;\n    case ULE:\n        return UGE;\n    case ULT:\n        return UGT;\n    case SGE:\n        return SLE;\n    case SGT:\n        return SLT;\n    case UGE:\n        return ULE;\n    case UGT:\n        return ULT;\n    case PT:\n        return PF;\n    case PF:\n        return PT;\n    }\n    assert(0 && \"unreachable\");\n    abort();\n}\n\nRelations::Type Relations::negated(Type type) {\n    switch (type) {\n    case EQ:\n        return NE;\n    case NE:\n        return EQ;\n    case SLE:\n        return SGT;\n    case SLT:\n        return SGE;\n    case ULE:\n        return UGT;\n    case ULT:\n        return UGE;\n    case SGE:\n        return SLT;\n    case SGT:\n        return SLE;\n    case UGE:\n        return ULT;\n    case UGT:\n        return ULE;\n    case PT:\n    case PF:\n        break;\n    }\n    assert(0 && \"no negation for relation\");\n    abort();\n}\n\nRelations Relations::conflicting(Relations::Type type) {\n    switch (type) {\n    case EQ:\n        return Relations().ne().slt().ult().sgt().ugt();\n    case NE:\n        return Relations().eq();\n    case SLT:\n        return Relations().eq().sgt().sge();\n    case ULT:\n        return Relations().eq().ugt().uge();\n    case SGT:\n        return Relations().eq().slt().sle();\n    case UGT:\n        return Relations().eq().ult().ule();\n    case SLE:\n        return Relations().sgt();\n    case ULE:\n        return Relations().ugt();\n    case SGE:\n        return Relations().slt();\n    case UGE:\n        return Relations().ult();\n    case PT:\n    case PF:\n        return {};\n    }\n    assert(0 && \"unreachable\");\n    abort();\n}\n\nRelations::Type Relations::get() const {\n    for (Type rel : {EQ, SLT, ULT, SGT, UGT, NE, SLE, ULE, SGE, UGE, PT, PF}) {\n        if (has(rel))\n            return rel;\n    }\n    assert(0 && \"unreachable\");\n    abort();\n}\n\nRelations &Relations::addImplied() {\n    if (has(EQ))\n        sle().ule().sge().uge();\n    if (has(SLT))\n        sle().ne();\n    if (has(ULT))\n        ule().ne();\n    if (has(SGT))\n        sge().ne();\n    if (has(UGT))\n        uge().ne();\n    return *this;\n}\n\nRelations &Relations::invert() {\n    std::bitset<Relations::total> newBits;\n    for (Type rel : Relations::all) {\n        if (has(rel)) {\n            newBits.set(inverted(rel));\n        }\n    }\n\n    std::swap(bits, newBits);\n    return *this;\n}\n\nRelations Relations::getAugmented(Relations rels) {\n    Relations augmented = rels;\n    for (Relations::Type type : Relations::all) {\n        if (!strict.has(type))\n            continue;\n\n        if (augmented.has(type)) {\n            augmented.set(Relations::getNonStrict(type));\n        } else if (augmented.has(Relations::getNonStrict(type))) {\n            augmented.set(type);\n            augmented.eq();\n        }\n    }\n    return augmented;\n}\n\nbool Relations::isSigned(Type type) {\n    switch (type) {\n    case SLT:\n    case SLE:\n    case SGT:\n    case SGE:\n        return true;\n    case ULT:\n    case ULE:\n    case UGT:\n    case UGE:\n        return false;\n    default:\n        assert(0 && \"unreachable\");\n        abort();\n    }\n}\n\nRelations compose(const Relations &lt, const Relations &rt) {\n    if (lt.has(Relations::EQ))\n        return rt;\n    if (rt.has(Relations::EQ))\n        return lt;\n    Relations result;\n    for (Relations::Type ltRel : Relations::all) {\n        if (!lt.has(ltRel))\n            continue;\n\n        for (Relations::Type rtRel : Relations::all) {\n            if (rt.has(rtRel) && Relations::transitiveOver(ltRel, rtRel)) {\n                if (Relations::isStrict(ltRel) || Relations::isStrict(rtRel))\n                    result.set(Relations::getStrict(ltRel));\n                else\n                    result.set(ltRel);\n            }\n        }\n    }\n    return result.addImplied();\n}\n\nbool Relations::transitiveOver(Type fst, Type snd) {\n    switch (fst) {\n    case SLE:\n    case SLT:\n        return snd == SLE || snd == SLT;\n    case ULE:\n    case ULT:\n        return snd == ULE || snd == ULT;\n    case SGE:\n    case SGT:\n        return snd == SGE || snd == SGT;\n    case UGE:\n    case UGT:\n        return snd == UGE || snd == UGT;\n    case EQ:\n    case NE:\n    case PT:\n    case PF:\n        return false;\n    }\n    assert(0 && \"unreachable\");\n    abort();\n}\n\nbool Relations::isStrict(Type type) { return strict.has(type); }\n\nbool Relations::isNonStrict(Type type) { return nonStrict.has(type); }\n\nRelations::Type Relations::getStrict(Type type) {\n    switch (type) {\n    case Relations::SLT:\n    case Relations::SLE:\n        return Relations::SLT;\n    case Relations::ULT:\n    case Relations::ULE:\n        return Relations::ULT;\n    case Relations::SGT:\n    case Relations::SGE:\n        return Relations::SGT;\n    case Relations::UGT:\n    case Relations::UGE:\n        return Relations::UGT;\n    default:\n        assert(0 && \"no strict variant\");\n        abort();\n    }\n}\n\nRelations::Type Relations::getNonStrict(Type type) {\n    switch (type) {\n    case Relations::SLT:\n        return Relations::SLE;\n    case Relations::ULT:\n        return Relations::ULE;\n    case Relations::SGT:\n        return Relations::SGE;\n    case Relations::UGT:\n        return Relations::UGE;\n    default:\n        assert(0 && \"no nonstrict variant\");\n        abort();\n    }\n}\n\n#ifndef NDEBUG\nstd::ostream &operator<<(std::ostream &out, Relations::Type r) {\n    switch (r) {\n    case Relations::EQ:\n        out << \"EQ\";\n        break;\n    case Relations::NE:\n        out << \"NE\";\n        break;\n    case Relations::SLE:\n        out << \"SLE\";\n        break;\n    case Relations::SLT:\n        out << \"SLT\";\n        break;\n    case Relations::ULE:\n        out << \"ULE\";\n        break;\n    case Relations::ULT:\n        out << \"ULT\";\n        break;\n    case Relations::SGE:\n        out << \"SGE\";\n        break;\n    case Relations::SGT:\n        out << \"SGT\";\n        break;\n    case Relations::UGE:\n        out << \"UGE\";\n        break;\n    case Relations::UGT:\n        out << \"UGT\";\n        break;\n    case Relations::PT:\n        out << \"PT\";\n        break;\n    case Relations::PF:\n        out << \"PF\";\n        break;\n    }\n    return out;\n}\n\nstd::ostream &operator<<(std::ostream &out, const Relations &rels) {\n    out << \"[ \";\n    for (Relations::Type type : Relations::all) {\n        if (rels.has(type))\n            out << type << \" \";\n    }\n    out << \"]\";\n    return out;\n}\n#endif\n\n} // namespace vr\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ControlDependence/ControlClosure.h",
    "content": "#ifndef DG_LLVM_CONTROL_CLOSURE_H_\n#define DG_LLVM_CONTROL_CLOSURE_H_\n\n#include <llvm/IR/Module.h>\n\n#include \"GraphBuilder.h\"\n#include \"dg/llvm/ControlDependence/ControlDependence.h\"\n\n#include \"ControlDependence/ControlClosure.h\"\n\n#include <map>\n#include <set>\n#include <unordered_map>\n\nnamespace llvm {\nclass Function;\n}\n\nnamespace dg {\nnamespace llvmdg {\n\nclass StrongControlClosure : public LLVMControlDependenceAnalysisImpl {\n    CDGraphBuilder graphBuilder{};\n\n    using CDResultT = std::map<CDNode *, std::set<CDNode *>>;\n\n    struct Info {\n        CDGraph graph;\n\n        //// forward edges (from branchings to dependent blocks)\n        // CDResultT controlDependence{};\n        //// reverse edges (from dependent blocks to branchings)\n        // CDResultT revControlDependence{};\n\n        Info(CDGraph &&graph) : graph(std::move(graph)) {}\n    };\n\n    std::unordered_map<const llvm::Function *, Info> _graphs;\n\n  public:\n    using ValVec = LLVMControlDependenceAnalysis::ValVec;\n\n    StrongControlClosure(const llvm::Module *module,\n                         const LLVMControlDependenceAnalysisOptions &opts = {})\n            : LLVMControlDependenceAnalysisImpl(module, opts) {\n        _graphs.reserve(module->size());\n    }\n\n    /// Getters of dependencies for a value\n    ValVec getDependencies(const llvm::Instruction * /*unused*/) override {\n        assert(false && \"Not supported\");\n        abort();\n    }\n\n    ValVec getDependent(const llvm::Instruction * /*unused*/) override {\n        assert(false && \"Not supported\");\n        abort();\n    }\n\n    /// Getters of dependencies for a basic block\n    ValVec getDependencies(const llvm::BasicBlock * /*unused*/) override {\n        assert(false && \"Not supported\");\n        abort();\n    }\n\n    ValVec getDependent(const llvm::BasicBlock * /*unused*/) override {\n        assert(false && \"Not supported\");\n        abort();\n    }\n\n    ValVec getClosure(const llvm::Function *F,\n                      const std::set<llvm::Value *> &vals) override {\n        DBG(cda,\n            \"Computing closure of nodes in function \" << F->getName().str());\n        auto *graph = getGraph(F);\n        if (!graph) {\n            auto tmpgraph =\n                    graphBuilder.build(F, getOptions().nodePerInstruction());\n            // FIXME: we can actually just forget the graph if we do not want to\n            // dump it to the user\n            auto it = _graphs.emplace(F, std::move(tmpgraph));\n            graph = &it.first->second.graph;\n        }\n\n        assert(graph);\n\n        // TODO map values...\n        dg::StrongControlClosure sclosure;\n        std::set<CDNode *> X;\n        for (auto *v : vals) {\n            X.insert(graphBuilder.getNode(v));\n        }\n        auto cls = sclosure.getClosure(*graph, X);\n        std::vector<llvm::Value *> retval;\n        for (auto *n : cls) {\n            retval.push_back(\n                    const_cast<llvm::Value *>(graphBuilder.getValue(n)));\n        }\n        return retval;\n    }\n\n    // We run on demand\n    void compute(const llvm::Function *F) override {\n        unsigned n = 0;\n        for (const auto &B : *F) {\n            if (n == F->size() / 2)\n                getClosure(F, {const_cast<llvm::BasicBlock *>(&B)});\n            ++n;\n        }\n        /* we run on demand */\n    }\n\n    CDGraph *getGraph(const llvm::Function *f) override { return _getGraph(f); }\n    const CDGraph *getGraph(const llvm::Function *f) const override {\n        return _getGraph(f);\n    }\n\n    // make this one public so that we can dump it in llvm-cda-dump\n    // (keep the _ prefix so that we can see that it should not be normally\n    // used...)\n    const Info *_getFunInfo(const llvm::Function *f) const {\n        auto it = _graphs.find(f);\n        return it == _graphs.end() ? nullptr : &it->second;\n    }\n\n    Info *_getFunInfo(const llvm::Function *f) {\n        auto it = _graphs.find(f);\n        return it == _graphs.end() ? nullptr : &it->second;\n    }\n\n  private:\n    const CDGraph *_getGraph(const llvm::Function *f) const {\n        auto it = _graphs.find(f);\n        return it == _graphs.end() ? nullptr : &it->second.graph;\n    }\n\n    CDGraph *_getGraph(const llvm::Function *f) {\n        auto it = _graphs.find(f);\n        return it == _graphs.end() ? nullptr : &it->second.graph;\n    }\n};\n\n} // namespace llvmdg\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/llvm/ControlDependence/ControlDependence.cpp",
    "content": "#include \"dg/llvm/ControlDependence/ControlDependence.h\"\n#include \"llvm/ControlDependence/ControlClosure.h\"\n#include \"llvm/ControlDependence/DOD.h\"\n#include \"llvm/ControlDependence/InterproceduralCD.h\"\n#include \"llvm/ControlDependence/NTSCD.h\"\n#include \"llvm/ControlDependence/SCD.h\"\n#include \"llvm/ControlDependence/legacy/NTSCD.h\"\n\nnamespace dg {\n\nvoid LLVMControlDependenceAnalysis::initializeImpl(LLVMPointerAnalysis *pta,\n                                                   llvmdg::CallGraph *cg) {\n    bool icfg = getOptions().ICFG();\n\n    if (getOptions().standardCD()) {\n        if (icfg) {\n            assert(false && \"SCD does not support ICFG\");\n            abort();\n        }\n        _impl.reset(new llvmdg::SCD(_module, _options));\n    } else if (getOptions().ntscdCD() || getOptions().ntscd2CD() ||\n               getOptions().ntscdRanganathCD() ||\n               getOptions().ntscdRanganathOrigCD()) {\n        if (icfg) {\n            _impl.reset(new llvmdg::InterproceduralNTSCD(_module, _options, pta,\n                                                         cg));\n        } else {\n            _impl.reset(new llvmdg::NTSCD(_module, _options));\n        }\n    } else if (getOptions().strongCC()) {\n        _impl.reset(new llvmdg::StrongControlClosure(_module, _options));\n    } else if (getOptions().ntscdLegacyCD()) {\n        // legacy NTSCD is ICFG always...\n        _impl.reset(new llvmdg::legacy::NTSCD(_module, _options));\n    } else if (getOptions().dodCD() || getOptions().dodRanganathCD() ||\n               getOptions().dodntscdCD()) {\n        // DOD on itself makes no sense, but allow it due to debugging\n        if (icfg) {\n            _impl.reset(\n                    new llvmdg::InterproceduralDOD(_module, _options, pta, cg));\n        } else {\n            _impl.reset(new llvmdg::DOD(_module, _options));\n        }\n    } else {\n        assert(false && \"Unhandled analysis type\");\n        abort();\n    }\n\n    _interprocImpl.reset(\n            new llvmdg::LLVMInterprocCD(_module, _options, pta, cg));\n}\n\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ControlDependence/DOD.h",
    "content": "#ifndef DG_LLVM_DOD_H_\n#define DG_LLVM_DOD_H_\n\n#include <llvm/IR/Module.h>\n\n#include \"GraphBuilder.h\"\n#include \"IGraphBuilder.h\"\n#include \"dg/llvm/ControlDependence/ControlDependence.h\"\n\n#include \"ControlDependence/DOD.h\"\n#include \"ControlDependence/DODNTSCD.h\"\n\n#include <map>\n#include <set>\n#include <unordered_map>\n\nnamespace llvm {\nclass Function;\n}\n\nnamespace dg {\nnamespace llvmdg {\n\nclass DOD : public LLVMControlDependenceAnalysisImpl {\n    CDGraphBuilder graphBuilder{};\n\n    // although DOD is a ternary relation, we treat it as binary relation\n    // by forgetting the connection between dependant nodes. That is,\n    // for each p -> {a, b}, we have (p, a) and (p, b).\n    // This has no effect on slicing. If we will need that in the future,\n    // we can change this.\n    using CDResultT = std::map<CDNode *, std::set<CDNode *>>;\n\n    struct Info {\n        CDGraph graph;\n\n        // forward edges (from branchings to dependent blocks)\n        CDResultT controlDependence{};\n        // reverse edges (from dependent blocks to branchings)\n        CDResultT revControlDependence{};\n\n        Info(CDGraph &&graph) : graph(std::move(graph)) {}\n    };\n\n    std::unordered_map<const llvm::Function *, Info> _graphs;\n\n  public:\n    using ValVec = LLVMControlDependenceAnalysis::ValVec;\n\n    DOD(const llvm::Module *module,\n        const LLVMControlDependenceAnalysisOptions &opts = {})\n            : LLVMControlDependenceAnalysisImpl(module, opts) {\n        _graphs.reserve(module->size());\n    }\n\n    /// Getters of dependencies for a value\n    ValVec getDependencies(const llvm::Instruction *I) override {\n        if (!getOptions().nodePerInstruction()) {\n            return {};\n        }\n\n        // XXX: this could be computed on-demand per one node (block)\n        // (in contrary to getDependent())\n        const auto *f = I->getParent()->getParent();\n        if (_getGraph(f) == nullptr) {\n            /// FIXME: get rid of the const cast\n            computeOnDemand(const_cast<llvm::Function *>(f));\n        }\n\n        assert(_getGraph(f) != nullptr);\n\n        auto *node = graphBuilder.getNode(I);\n        if (!node) {\n            return {};\n        }\n        auto *info = _getFunInfo(f);\n        assert(info && \"Did not compute CD\");\n\n        auto dit = info->controlDependence.find(node);\n        if (dit == info->controlDependence.end())\n            return {};\n\n        std::set<llvm::Value *> ret;\n        for (auto *dep : dit->second) {\n            const auto *val = graphBuilder.getValue(dep);\n            assert(val && \"Invalid value\");\n            ret.insert(const_cast<llvm::Value *>(val));\n        }\n\n        return ValVec{ret.begin(), ret.end()};\n    }\n\n    ValVec getDependent(const llvm::Instruction * /*unused*/) override {\n        return {};\n    }\n\n    /// Getters of dependencies for a basic block\n    ValVec getDependencies(const llvm::BasicBlock *b) override {\n        if (getOptions().nodePerInstruction()) {\n            return {};\n        }\n\n        if (_getGraph(b->getParent()) == nullptr) {\n            /// FIXME: get rid of the const cast\n            computeOnDemand(const_cast<llvm::Function *>(b->getParent()));\n        }\n        assert(_getGraph(b->getParent()) != nullptr);\n\n        auto *block = graphBuilder.getNode(b);\n        if (!block) {\n            return {};\n        }\n        auto *info = _getFunInfo(b->getParent());\n        assert(info && \"Did not compute CD\");\n\n        auto dit = info->controlDependence.find(block);\n        if (dit == info->controlDependence.end())\n            return {};\n\n        std::set<llvm::Value *> ret;\n        for (auto *dep : dit->second) {\n            const auto *val = graphBuilder.getValue(dep);\n            assert(val && \"Invalid value\");\n            ret.insert(const_cast<llvm::Value *>(val));\n        }\n\n        return ValVec{ret.begin(), ret.end()};\n    }\n\n    ValVec getDependent(const llvm::BasicBlock * /*unused*/) override {\n        assert(false && \"Not supported\");\n        abort();\n    }\n\n    // We run on demand but this method can trigger the computation\n    void compute(const llvm::Function *F = nullptr) override {\n        DBG(cda, \"Triggering computation of all dependencies\");\n        if (F && !F->isDeclaration() && (_getGraph(F) == nullptr)) {\n            computeOnDemand(const_cast<llvm::Function *>(F));\n        } else {\n            for (const auto &f : *getModule()) {\n                if (!f.isDeclaration() && (_getGraph(&f) == nullptr)) {\n                    computeOnDemand(const_cast<llvm::Function *>(&f));\n                }\n            }\n        }\n    }\n\n    CDGraph *getGraph(const llvm::Function *f) override { return _getGraph(f); }\n    const CDGraph *getGraph(const llvm::Function *f) const override {\n        return _getGraph(f);\n    }\n\n    // make this one public so that we can dump it in llvm-cda-dump\n    // (keep the _ prefix so that we can see that it should not be normally\n    // used...)\n    const Info *_getFunInfo(const llvm::Function *f) const {\n        auto it = _graphs.find(f);\n        return it == _graphs.end() ? nullptr : &it->second;\n    }\n\n    Info *_getFunInfo(const llvm::Function *f) {\n        auto it = _graphs.find(f);\n        return it == _graphs.end() ? nullptr : &it->second;\n    }\n\n  private:\n    const CDGraph *_getGraph(const llvm::Function *f) const {\n        auto it = _graphs.find(f);\n        return it == _graphs.end() ? nullptr : &it->second.graph;\n    }\n\n    CDGraph *_getGraph(const llvm::Function *f) {\n        auto it = _graphs.find(f);\n        return it == _graphs.end() ? nullptr : &it->second.graph;\n    }\n\n    void computeOnDemand(llvm::Function *F) {\n        DBG(cda, \"Triggering on-demand computation for \" << F->getName().str());\n        assert(_getGraph(F) == nullptr && \"Already have the graph\");\n\n        auto tmpgraph =\n                graphBuilder.build(F, getOptions().nodePerInstruction());\n        // FIXME: we can actually just forget the graph if we do not want to\n        // dump it to the user\n        auto it = _graphs.emplace(F, std::move(tmpgraph));\n\n        auto &info = it.first->second;\n\n        if (getOptions().dodRanganathCD()) {\n            dg::DODRanganath dod;\n            auto result = dod.compute(info.graph);\n            info.controlDependence = std::move(result.first);\n            info.revControlDependence = std::move(result.second);\n        } else if (getOptions().dodCD()) {\n            dg::DOD dod;\n            auto result = dod.compute(info.graph);\n            info.controlDependence = std::move(result.first);\n            info.revControlDependence = std::move(result.second);\n        } else if (getOptions().dodntscdCD()) {\n            dg::DODNTSCD dodntscd;\n            auto result = dodntscd.compute(info.graph);\n            info.controlDependence = std::move(result.first);\n            info.revControlDependence = std::move(result.second);\n        } else {\n            assert(false && \"Wrong analysis type\");\n            abort();\n        }\n    }\n};\n\n// FIXME: this basically copies InterproceduralNTSCD, create\n// a shared superclass...\nclass InterproceduralDOD : public LLVMControlDependenceAnalysisImpl {\n    ICDGraphBuilder igraphBuilder{};\n    CDGraph graph;\n\n    using CDResultT = std::map<CDNode *, std::set<CDNode *>>;\n    // forward edges (from branchings to dependent blocks)\n    CDResultT controlDependence{};\n    // reverse edges (from dependent blocks to branchings)\n    CDResultT revControlDependence{};\n    bool _computed{false};\n\n  public:\n    using ValVec = LLVMControlDependenceAnalysis::ValVec;\n\n    ///\n    // Note: use this only when you know what you want.\n    // Computing intraprocedural CD + interprocedural CD\n    // separately is more efficient.\n    InterproceduralDOD(const llvm::Module *module,\n                       const LLVMControlDependenceAnalysisOptions &opts = {},\n                       LLVMPointerAnalysis *pta = nullptr,\n                       CallGraph *cg = nullptr)\n            : LLVMControlDependenceAnalysisImpl(module, opts),\n              igraphBuilder(pta, cg) {}\n\n    /// Getters of dependencies for a value\n    ValVec getDependencies(const llvm::Instruction *I) override {\n        if (!getOptions().nodePerInstruction()) {\n            return {};\n        }\n\n        _compute();\n\n        auto *node = igraphBuilder.getNode(I);\n        if (!node) {\n            return {};\n        }\n\n        assert(_computed && \"CD is not computed\");\n        auto dit = controlDependence.find(node);\n        if (dit == controlDependence.end())\n            return {};\n\n        std::set<llvm::Value *> ret;\n        for (auto *dep : dit->second) {\n            const auto *val = igraphBuilder.getValue(dep);\n            assert(val && \"Invalid value\");\n            ret.insert(const_cast<llvm::Value *>(val));\n        }\n\n        return ValVec{ret.begin(), ret.end()};\n    }\n\n    ValVec getDependent(const llvm::Instruction * /*unused*/) override {\n        return {};\n    }\n\n    /// Getters of dependencies for a basic block\n    ValVec getDependencies(const llvm::BasicBlock *b) override {\n        if (getOptions().nodePerInstruction()) {\n            return {};\n        }\n\n        _compute();\n\n        auto *block = igraphBuilder.getNode(b);\n        if (!block) {\n            return {};\n        }\n\n        assert(_computed && \"Did not compute CD\");\n        auto dit = controlDependence.find(block);\n        if (dit == controlDependence.end())\n            return {};\n\n        std::set<llvm::Value *> ret;\n        for (auto *dep : dit->second) {\n            const auto *val = igraphBuilder.getValue(dep);\n            assert(val && \"Invalid value\");\n            ret.insert(const_cast<llvm::Value *>(val));\n        }\n\n        return ValVec{ret.begin(), ret.end()};\n    }\n\n    ValVec getDependent(const llvm::BasicBlock * /*unused*/) override {\n        assert(false && \"Not supported\");\n        abort();\n    }\n\n    // We run on demand but this method can trigger the computation\n    void compute(const llvm::Function * /*F*/) override { _compute(); }\n\n    /// Getter for noreturn nodes in function (for interprocedural analysis)\n    ValVec getNoReturns(const llvm::Function * /*unused*/) override {\n        assert(false && \"Unsupported\");\n        abort();\n    }\n\n    CDGraph *getGraph(const llvm::Function * /*unused*/) override {\n        return &graph;\n    }\n    const CDGraph *getGraph(const llvm::Function * /*unused*/) const override {\n        return &graph;\n    }\n\n  private:\n    void _compute() {\n        if (_computed)\n            return;\n\n        DBG(cda, \"Triggering computation of interprocedural NTSCD\");\n\n        graph = igraphBuilder.build(getModule(),\n                                    getOptions().nodePerInstruction());\n\n        if (getOptions().dodRanganathCD()) {\n            dg::DODRanganath dod;\n            auto result = dod.compute(graph);\n            controlDependence = std::move(result.first);\n            revControlDependence = std::move(result.second);\n        } else if (getOptions().dodCD()) {\n            dg::DOD dod;\n            auto result = dod.compute(graph);\n            controlDependence = std::move(result.first);\n            revControlDependence = std::move(result.second);\n        } else if (getOptions().dodntscdCD()) {\n            dg::DODNTSCD dodntscd;\n            auto result = dodntscd.compute(graph);\n            controlDependence = std::move(result.first);\n            revControlDependence = std::move(result.second);\n        } else {\n            assert(false && \"Wrong analysis type\");\n            abort();\n        }\n\n        _computed = true;\n    }\n};\n\n} // namespace llvmdg\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/llvm/ControlDependence/GraphBuilder.h",
    "content": "#ifndef DG_CDA_GRAPHBUILDER_H_\n#define DG_CDA_GRAPHBUILDER_H_\n\n#include <unordered_map>\n\n#include \"llvm/IR/CFG.h\"\n\n#include \"ControlDependence/CDGraph.h\"\n#include \"dg/util/debug.h\"\n\nnamespace dg {\nnamespace llvmdg {\n\nclass CDGraphBuilder {\n    using CDGraph = dg::CDGraph;\n\n    // FIXME: store this per function (i.e., Function -> (Value -> CDNode))\n    std::unordered_map<const llvm::Value *, CDNode *> _nodes;\n    std::unordered_map<const CDNode *, const llvm::Value *> _rev_mapping;\n\n    CDGraph buildInstructions(const llvm::Function *F) {\n        DBG_SECTION_BEGIN(cda, \"Building graph (of instructions) for \"\n                                       << F->getName().str());\n\n        CDGraph graph(F->getName().str());\n\n        struct BBlock {\n            std::vector<CDNode *> nodes;\n        };\n\n        std::unordered_map<const llvm::BasicBlock *, BBlock> _mapping;\n        _mapping.reserve(F->size());\n\n        // create nodes for blocks\n        for (const auto &BB : *F) {\n            auto it = _mapping.emplace(&BB, BBlock());\n            BBlock &block = it.first->second;\n            block.nodes.reserve(BB.size());\n            for (const auto &I : BB) {\n                auto &nd = graph.createNode();\n                _rev_mapping[&nd] = &I;\n                _nodes[&I] = &nd;\n                block.nodes.push_back(&nd);\n            }\n        }\n\n        // add successor edges\n        for (const auto &BB : *F) {\n            auto &bblock = _mapping[&BB];\n            CDNode *last = nullptr;\n            // successors inside the block\n            for (auto *nd : bblock.nodes) {\n                if (last)\n                    graph.addNodeSuccessor(*last, *nd);\n                last = nd;\n            }\n            assert(last || BB.empty());\n\n            if (!last)\n                continue;\n\n            // successors between blocks\n            for (const auto *bbsucc : successors(&BB)) {\n                auto &succblk = _mapping[bbsucc];\n                if (succblk.nodes.empty()) {\n                    assert(bbsucc->empty());\n                    continue;\n                }\n\n                graph.addNodeSuccessor(*last, *succblk.nodes.front());\n            }\n        }\n\n        DBG_SECTION_END(cda, \"Done building graph for \" << F->getName().str());\n\n        return graph;\n    }\n\n    CDGraph buildBlocks(const llvm::Function *F) {\n        DBG_SECTION_BEGIN(cda, \"Building graph (of blocks) for \"\n                                       << F->getName().str());\n\n        CDGraph graph(F->getName().str());\n\n        std::unordered_map<const llvm::BasicBlock *, CDNode *> _mapping;\n        _mapping.reserve(F->size());\n        _nodes.reserve(F->size() + _nodes.size());\n        _rev_mapping.reserve(F->size() + _rev_mapping.size());\n\n        // create nodes for blocks\n        for (const auto &BB : *F) {\n            auto &nd = graph.createNode();\n            _mapping[&BB] = &nd;\n            _nodes[&BB] = &nd;\n            _rev_mapping[&nd] = &BB;\n        }\n\n        // add successor edges\n        for (const auto &BB : *F) {\n            auto *nd = _mapping[&BB];\n            assert(nd && \"BUG: creating nodes for bblocks\");\n\n            for (const auto *bbsucc : successors(&BB)) {\n                auto *succ = _mapping[bbsucc];\n                assert(succ && \"BUG: do not have a bblock created\");\n                graph.addNodeSuccessor(*nd, *succ);\n            }\n        }\n\n        DBG_SECTION_END(cda, \"Done building graph for function \"\n                                     << F->getName().str());\n\n        return graph;\n    }\n\n  public:\n    // \\param instructions  true if we should build nodes for the instructions\n    //                      instead of for basic blocks?\n    CDGraph build(const llvm::Function *F, bool instructions = false) {\n        if (instructions) {\n            return buildInstructions(F);\n        }\n\n        return buildBlocks(F);\n    }\n\n    CDNode *getNode(const llvm::Value *v) {\n        auto it = _nodes.find(v);\n        return it == _nodes.end() ? nullptr : it->second;\n    }\n\n    const CDNode *getNode(const llvm::Value *v) const {\n        auto it = _nodes.find(v);\n        return it == _nodes.end() ? nullptr : it->second;\n    }\n\n    const llvm::Value *getValue(const CDNode *n) const {\n        auto it = _rev_mapping.find(n);\n        return it == _rev_mapping.end() ? nullptr : it->second;\n    }\n};\n\n} // namespace llvmdg\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/llvm/ControlDependence/IGraphBuilder.h",
    "content": "#ifndef DG_CDA_IGRAPHBUILDER_H_\n#define DG_CDA_IGRAPHBUILDER_H_\n\n#include <unordered_map>\n\n#include \"llvm/IR/CFG.h\"\n#include \"llvm/IR/Instructions.h\"\n\n#include \"dg/llvm/CallGraph/CallGraph.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n\n#include \"ControlDependence/CDGraph.h\"\n#include \"GraphBuilder.h\"\n#include \"dg/util/debug.h\"\n\nnamespace dg {\nnamespace llvmdg {\n\nnamespace {\nconst llvm::Instruction *\ngetNextNonDebugInstruction(const llvm::Instruction *I) {\n#if LLVM_VERSION_MAJOR >= 7\n    return I->getNextNonDebugInstruction();\n#else\n    // this is the implementation of Instruction::getNextNonDebugInstruction()\n    // from LLVM 12 (adjusted)\n    for (const auto *NI = I->getNextNode(); NI; NI = NI->getNextNode())\n        if (!llvm::isa<llvm::DbgInfoIntrinsic>(NI))\n            return NI;\n    return nullptr;\n#endif\n}\n\ninline const llvm::Value *_getCalledValue(const llvm::CallInst *C) {\n#if LLVM_VERSION_MAJOR >= 8\n    return C->getCalledOperand()->stripPointerCasts();\n#else\n    return C->getCalledValue()->stripPointerCasts();\n#endif\n}\n\n} // namespace\n\n///\n// Whole-program graph for interprocedural analysis.\n// Note that control dependencies include separate interprocedural analysis\n// that fills in interprocedural CD into intraprocedural result.\n// But this is another way how to do that.... (not used by default)\nclass ICDGraphBuilder {\n    using CDGraph = dg::CDGraph;\n\n    struct CallInfo {\n        // called functions\n        std::vector<const llvm::Function *> funs;\n\n        CallInfo(std::vector<const llvm::Function *> &&f)\n                : funs(std::move(f)) {}\n        CallInfo(CallInfo &&) = default;\n        CallInfo(const CallInfo &) = delete;\n    };\n\n    std::unordered_map<const llvm::Value *, CDNode *> _nodes;\n    std::unordered_map<const CDNode *, const llvm::Value *> _rev_mapping;\n    std::map<const llvm::CallInst *, CallInfo> calls;\n\n    LLVMPointerAnalysis *_pta{nullptr};\n    CallGraph *_cg{nullptr};\n\n    std::vector<const llvm::Function *>\n    getCalledFunctions(const llvm::CallInst *C) {\n        auto *f = C->getCalledFunction();\n        if (f) {\n            if (f->isDeclaration()) {\n                return {};\n            }\n            return {f};\n        }\n\n        // function pointer call\n        std::vector<const llvm::Function *> funs;\n        if (_pta) {\n            auto pts = _pta->getLLVMPointsTo(_getCalledValue(C));\n            for (const auto &ptr : pts) {\n                if (auto *fun = llvm::dyn_cast<llvm::Function>(ptr.value)) {\n                    if (!fun->isDeclaration()) {\n                        funs.push_back(fun);\n                    }\n                }\n            }\n        }\n        if (_cg) {\n            // return _cg->getCalledFunctions(C);\n            abort();\n            return {};\n        }\n\n        return funs;\n    }\n\n    static const llvm::Value *_getEntryNode(const llvm::Function *f) {\n        assert(f && \"Got no function\");\n        const auto &B = f->getEntryBlock();\n        return &*(B.begin());\n    }\n\n    CDGraph buildInstructions(const llvm::Module *M) {\n        DBG_SECTION_BEGIN(\n                cda, \"Building ICFG (of instructions) for the whole module\");\n        CDGraph graph(\"ICFG\");\n\n        for (const auto &F : *M) {\n            buildInstructions(graph, F);\n        }\n\n        // add interprocedural edges\n        for (auto &it : calls) {\n            const auto *C = it.first;\n            // call edge\n            for (const auto *f : it.second.funs) {\n                auto *cnode = getNode(C);\n                assert(cnode && \"Do not have the node for a call\");\n                auto *entrynode = getNode(_getEntryNode(f));\n                assert(entrynode);\n                graph.addNodeSuccessor(*cnode, *entrynode);\n\n                // return edges\n                const auto *retsite = getNextNonDebugInstruction(C);\n                assert(retsite);\n                auto *retsitenode = getNode(retsite);\n                assert(retsitenode);\n                for (const auto &B : *f) {\n                    if (const auto *R = llvm::dyn_cast<llvm::ReturnInst>(\n                                B.getTerminator())) {\n                        auto *rnode = getNode(R);\n                        graph.addNodeSuccessor(*rnode, *retsitenode);\n                    }\n                }\n            }\n        }\n\n        DBG_SECTION_END(cda, \"Done building interprocedural CD graph\");\n\n        return graph;\n    }\n\n    void buildInstructions(CDGraph &graph, const llvm::Function &F) {\n        struct BBlock {\n            std::vector<CDNode *> nodes;\n        };\n\n        std::unordered_map<const llvm::BasicBlock *, BBlock> _mapping;\n        //_mapping.reserve(F->size());\n\n        // create nodes for instructions\n        for (const auto &BB : F) {\n            auto it = _mapping.emplace(&BB, BBlock());\n            BBlock &block = it.first->second;\n            block.nodes.reserve(BB.size());\n            for (const auto &I : BB) {\n                if (const auto *C = llvm::dyn_cast<llvm::CallInst>(&I)) {\n                    auto funs = getCalledFunctions(C);\n                    if (!funs.empty())\n                        calls.emplace(C, CallInfo(std::move(funs)));\n                }\n\n                auto &nd = graph.createNode();\n                _rev_mapping[&nd] = &I;\n                _nodes[&I] = &nd;\n                block.nodes.push_back(&nd);\n            }\n        }\n\n        // add intraprocedural successor edges\n        for (const auto &BB : F) {\n            auto &bblock = _mapping[&BB];\n            CDNode *last = nullptr;\n            // successors inside the block\n            for (auto *nd : bblock.nodes) {\n                if (last)\n                    graph.addNodeSuccessor(*last, *nd);\n                const auto *C = llvm::dyn_cast<llvm::CallInst>(getValue(nd));\n                if (C && (calls.find(C) != calls.end())) {\n                    // if the node is a call that calls some defined functions\n                    // (we store only such in calls), its successor\n                    // is going to be the entry to the procedure\n                    last = nullptr;\n                } else {\n                    last = nd;\n                }\n            }\n            // every block has at least one (terminator) instruction\n            assert(last && \"Empty block\");\n\n            // successors between blocks\n            for (const auto *bbsucc : successors(&BB)) {\n                auto &succblk = _mapping[bbsucc];\n                if (succblk.nodes.empty()) {\n                    assert(bbsucc->empty());\n                    continue;\n                }\n\n                graph.addNodeSuccessor(*last, *succblk.nodes.front());\n            }\n        }\n    }\n\n    CDGraph buildBlocks(const llvm::Module *M) {\n        DBG_SECTION_BEGIN(cda,\n                          \"Building ICFG (of blocks) for the whole module\");\n        CDGraph graph(\"ICFG\");\n\n        for (const auto &F : *M) {\n            buildBlocks(graph, F);\n        }\n\n        // add successor edges\n        for (const auto &F : *M) {\n            for (const auto &BB : F) {\n                auto *nd = getNode(&BB);\n                assert(nd && \"BUG: creating nodes for bblocks\");\n                auto *blknd = nd;\n\n                // add interprocedural edges\n                for (const auto &I : BB) {\n                    const auto *C = llvm::dyn_cast<llvm::CallInst>(&I);\n                    if (!C) {\n                        continue;\n                    }\n\n                    // create a block that represents the rest of the block\n                    // and add an edge from the returns of f\n                    const auto &funs = getCalledFunctions(C);\n                    if (funs.empty())\n                        continue;\n\n                    auto &retsite = graph.createNode();\n\n                    // call inst\n                    for (const auto *f : getCalledFunctions(C)) {\n                        auto *entrynode = getNode(&f->getEntryBlock());\n                        assert(entrynode);\n                        graph.addNodeSuccessor(*blknd, *entrynode);\n\n                        // return edges\n                        for (const auto &B : *f) {\n                            if (llvm::isa<llvm::ReturnInst>(\n                                        B.getTerminator())) {\n                                // the block returns\n                                auto *rnode = getNode(&B);\n                                assert(rnode);\n                                graph.addNodeSuccessor(*rnode, retsite);\n                            }\n                        }\n                    }\n                    blknd = &retsite;\n                }\n\n                assert(blknd);\n                // add intraprocedural edges\n                for (const auto *bbsucc : successors(&BB)) {\n                    auto *succ = getNode(bbsucc);\n                    assert(succ && \"BUG: do not have a bblock created\");\n                    graph.addNodeSuccessor(*blknd, *succ);\n                }\n            }\n        }\n\n        return graph;\n    }\n\n    void buildBlocks(CDGraph &graph, const llvm::Function &F) {\n        DBG_SECTION_BEGIN(cda, \"Building ICFG (of blocks) for \"\n                                       << F.getName().str());\n\n        // create nodes for blocks\n        for (const auto &BB : F) {\n            auto &nd = graph.createNode();\n            _nodes[&BB] = &nd;\n            _rev_mapping[&nd] = &BB;\n        }\n\n        DBG_SECTION_END(cda, \"Done building graph for function \"\n                                     << F.getName().str());\n    }\n\n  public:\n    ICDGraphBuilder(LLVMPointerAnalysis *pta = nullptr, CallGraph *cg = nullptr)\n            : _pta(pta), _cg(cg) {}\n\n    // \\param instructions  true if we should build nodes for the instructions\n    //                      instead of for basic blocks?\n    CDGraph build(const llvm::Module *M, bool instructions = false) {\n        if (instructions) {\n            return buildInstructions(M);\n        }\n\n        return buildBlocks(M);\n    }\n\n    CDNode *getNode(const llvm::Value *v) {\n        auto it = _nodes.find(v);\n        return it == _nodes.end() ? nullptr : it->second;\n    }\n\n    const CDNode *getNode(const llvm::Value *v) const {\n        auto it = _nodes.find(v);\n        return it == _nodes.end() ? nullptr : it->second;\n    }\n\n    const llvm::Value *getValue(const CDNode *n) const {\n        auto it = _rev_mapping.find(n);\n        return it == _rev_mapping.end() ? nullptr : it->second;\n    }\n};\n\n} // namespace llvmdg\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/llvm/ControlDependence/InterproceduralCD.cpp",
    "content": "#include <llvm/IR/CFG.h>\n#include <llvm/IR/Function.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/Module.h>\n\n#include \"dg/ADT/Queue.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n#include \"dg/util/debug.h\"\n#include \"llvm/ControlDependence/InterproceduralCD.h\"\n\nusing namespace std;\n\nnamespace dg {\nnamespace llvmdg {\n\nstd::vector<const llvm::Function *>\nLLVMInterprocCD::getCalledFunctions(const llvm::Value *v) {\n    if (const auto *F = llvm::dyn_cast<llvm::Function>(v)) {\n        return {F};\n    }\n\n    if (!PTA)\n        return {};\n\n    return dg::getCalledFunctions(v, PTA);\n}\n\nstatic inline bool hasNoSuccessors(const llvm::BasicBlock *bb) {\n    return succ_begin(bb) == succ_end(bb);\n}\n\nvoid LLVMInterprocCD::computeFuncInfo(const llvm::Function *fun,\n                                      std::set<const llvm::Function *> stack) {\n    using namespace llvm;\n\n    if (fun->isDeclaration() || hasFuncInfo(fun))\n        return;\n\n    DBG_SECTION_BEGIN(cda, \"Computing no-return points for function \"\n                                   << fun->getName().str());\n\n    auto &info = _funcInfos[fun];\n    assert(hasFuncInfo(fun) && \"Bug in hasFuncInfo\");\n\n    stack.insert(fun);\n\n    //  compute nonreturning blocks (without successors\n    //  and terminated with non-ret instruction\n    //  and find calls (and other noret points) inside blocks\n    for (const auto &B : *fun) {\n        // no successors and does not return to caller\n        // -- this is a point of no return :)\n        if (hasNoSuccessors(&B) && !isa<ReturnInst>(B.getTerminator())) {\n            info.noret.insert(B.getTerminator());\n        }\n\n        // process the calls in basic blocks\n        for (const auto &I : B) {\n            const auto *C = dyn_cast<CallInst>(&I);\n            if (!C) {\n                continue;\n            }\n\n#if LLVM_VERSION_MAJOR >= 8\n            auto *val = C->getCalledOperand();\n#else\n            auto *val = C->getCalledValue();\n#endif\n            for (const auto *calledFun : getCalledFunctions(val)) {\n                if (calledFun->isDeclaration())\n                    continue;\n\n                if (stack.count(calledFun) > 0) {\n                    // recursive call\n                    info.noret.insert(C);\n                } else {\n                    computeFuncInfo(calledFun, stack);\n                    auto *fi = getFuncInfo(calledFun);\n                    assert(fi && \"Did not compute func info\");\n                    if (!fi->noret.empty()) {\n                        info.noret.insert(C);\n                    }\n                }\n            }\n        }\n    }\n\n    // llvm::errs() << \"Noret points of \" << fun->getName() << \"\\n\";\n    // for (auto *nr : info.noret) {\n    //    llvm::errs() << \"  -> \" << *nr << \"\\n\";\n    //}\n\n    DBG_SECTION_END(cda, \"Done computing no-return points for function \"\n                                 << fun->getName().str());\n}\n\nstruct BlkInfo {\n    // noret points in a block\n    std::vector<llvm::Value *> noret;\n};\n\nvoid LLVMInterprocCD::computeCD(const llvm::Function *fun) {\n    using namespace llvm;\n    DBG_SECTION_BEGIN(cda, \"Computing interprocedural CD for function \"\n                                   << fun->getName().str());\n\n    // (1) initialize information about blocks\n    // FIXME: we could do that in computeFuncInfo (add this mapping to FuncInfo)\n    std::unordered_map<const llvm::BasicBlock *, BlkInfo> blkInfos;\n    blkInfos.reserve(fun->size());\n\n    for (const auto &B : *fun) {\n        for (const auto &I : B) {\n            const auto *C = dyn_cast<CallInst>(&I);\n            if (!C) {\n                continue;\n            }\n\n            bool maynoret = false;\n#if LLVM_VERSION_MAJOR >= 8\n            auto *val = C->getCalledOperand();\n#else\n            auto *val = C->getCalledValue();\n#endif\n            for (const auto *calledFun : getCalledFunctions(val)) {\n                if (calledFun->isDeclaration())\n                    continue;\n\n                auto *fi = getFuncInfo(calledFun);\n                assert(fi && \"Do not have func info for a defined function\");\n                if (!fi->noret.empty()) {\n                    maynoret = true;\n                    break;\n                }\n            }\n            if (maynoret)\n                blkInfos[&B].noret.push_back(const_cast<Instruction *>(&I));\n        }\n    }\n\n    // (2) compute control dependencies generated by calls\n    // compute set of reachable nonret points untill fixpoint\n    std::unordered_map<const llvm::BasicBlock *, std::set<llvm::Value *>> cds;\n    cds.reserve(fun->size());\n\n    ADT::QueueLIFO<const llvm::BasicBlock *> queue;\n    for (auto &it : blkInfos) {\n        for (const auto *succ : successors(it.first)) {\n            queue.push(succ);\n        }\n    }\n\n    // run until fixpoint\n    while (!queue.empty()) {\n        const auto *block = queue.pop();\n        bool changed = false;\n        for (const auto *pred : predecessors(block)) {\n            // merge previously computed info\n            auto cit = cds.find(pred);\n            if (cit != cds.end()) {\n                for (auto *nr : cit->second) {\n                    changed |= cds[block].insert(nr).second;\n                }\n            }\n            // merge info from blkInfos\n            auto bit = blkInfos.find(pred);\n            if (bit != blkInfos.end()) {\n                for (auto *nr : bit->second.noret) {\n                    changed |= cds[block].insert(nr).second;\n                }\n            }\n        }\n\n        if (changed) {\n            for (const auto *succ : successors(block)) {\n                queue.push(succ);\n            }\n        }\n    }\n\n    // (3) compute control dependencies\n    for (auto &it : cds) {\n        _blockCD[it.first] = std::move(it.second);\n    }\n    for (auto &it : blkInfos) {\n        unsigned noretsidx = 0;\n        auto &norets = it.second.noret;\n\n        for (const auto &I : *it.first) {\n            for (unsigned i = 0; i < noretsidx; ++i) {\n                _instrCD[&I].insert(norets[i]);\n            }\n            if (noretsidx < norets.size() && &I == norets[noretsidx]) {\n                ++noretsidx;\n            }\n        }\n    }\n\n    auto *fi = getFuncInfo(fun);\n    assert(fi && \"Whata?!\");\n    fi->hasCD = true;\n\n    DBG_SECTION_END(cda, \"Done computing interprocedural CD for function \"\n                                 << fun->getName().str());\n}\n\n} // namespace llvmdg\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ControlDependence/InterproceduralCD.h",
    "content": "#ifndef DG_LLVM_INTERPROC_CD_H_\n#define DG_LLVM_INTERPROC_CD_H_\n\n#include <llvm/IR/Module.h>\n\n#include \"dg/llvm/ControlDependence/LLVMControlDependenceAnalysisImpl.h\"\n\n#include <map>\n#include <set>\n#include <unordered_map>\n\nnamespace llvm {\nclass Function;\n}\n\nnamespace dg {\n\nclass LLVMPointerAnalysis;\n\nnamespace llvmdg {\n\nclass CallGraph;\n\nclass LLVMInterprocCD : public LLVMControlDependenceAnalysisImpl {\n    LLVMPointerAnalysis *PTA{nullptr};\n    // CallGraph *_cg{nullptr};\n\n    struct FuncInfo {\n        // points that may abort the program\n        // (or cause infinite looping). That is,\n        // points due to which the function may not return\n        // to its caller\n        std::set<const llvm::Value *> noret;\n        bool hasCD = false;\n    };\n\n    std::unordered_map<const llvm::Instruction *, std::set<llvm::Value *>>\n            _instrCD;\n    std::unordered_map<const llvm::BasicBlock *, std::set<llvm::Value *>>\n            _blockCD;\n    std::unordered_map<const llvm::Function *, FuncInfo> _funcInfos;\n\n    FuncInfo *getFuncInfo(const llvm::Function *F) {\n        auto it = _funcInfos.find(F);\n        return it == _funcInfos.end() ? nullptr : &it->second;\n    }\n\n    const FuncInfo *getFuncInfo(const llvm::Function *F) const {\n        auto it = _funcInfos.find(F);\n        return it == _funcInfos.end() ? nullptr : &it->second;\n    }\n\n    bool hasFuncInfo(const llvm::Function *fun) const {\n        return _funcInfos.find(fun) != _funcInfos.end();\n    }\n\n    // recursively compute function info, 'stack' is there to detect recursive\n    // calls\n    void computeFuncInfo(const llvm::Function *fun,\n                         std::set<const llvm::Function *> stack = {});\n    void computeCD(const llvm::Function *fun);\n\n    std::vector<const llvm::Function *>\n    getCalledFunctions(const llvm::Value *v);\n\n  public:\n    using ValVec = LLVMControlDependenceAnalysisImpl::ValVec;\n\n    LLVMInterprocCD(const llvm::Module *module,\n                    const LLVMControlDependenceAnalysisOptions &opts = {},\n                    LLVMPointerAnalysis *pta = nullptr,\n                    CallGraph * /* cg */ = nullptr)\n            : LLVMControlDependenceAnalysisImpl(module, opts), PTA(pta)\n    /*, _cg(cg) */ {}\n\n    ValVec getNoReturns(const llvm::Function *fun) override {\n        ValVec ret;\n        auto *fi = getFuncInfo(fun);\n        if (!fi) {\n            computeFuncInfo(fun);\n        }\n        fi = getFuncInfo(fun);\n        assert(fi && \"BUG in computeFuncInfo\");\n\n        for (const auto *val : fi->noret)\n            ret.push_back(const_cast<llvm::Value *>(val));\n        return ret;\n    }\n\n    /// Getters of dependencies for a value\n    ValVec getDependencies(const llvm::Instruction *I) override {\n        const auto *fun = I->getParent()->getParent();\n        auto *fi = getFuncInfo(fun);\n        if (!fi) {\n            computeFuncInfo(fun);\n        }\n\n        fi = getFuncInfo(fun);\n        assert(fi && \"BUG in computeFuncInfo\");\n        if (!fi->hasCD) {\n            computeCD(fun);\n            assert(fi->hasCD && \"BUG in computeCD\");\n        }\n\n        ValVec ret;\n        auto instrIt = _instrCD.find(I);\n        if (instrIt != _instrCD.end()) {\n            ret.insert(ret.end(), instrIt->second.begin(),\n                       instrIt->second.end());\n        }\n\n        auto blkIt = _blockCD.find(I->getParent());\n        if (blkIt != _blockCD.end()) {\n            ret.insert(ret.end(), blkIt->second.begin(), blkIt->second.end());\n        }\n\n        return ret;\n    }\n\n    ValVec getDependent(const llvm::Instruction * /*unused*/) override {\n        return {};\n    }\n\n    /// Getters of dependencies for a basic block\n    ValVec getDependencies(const llvm::BasicBlock * /*unused*/) override {\n        return {};\n    }\n    ValVec getDependent(const llvm::BasicBlock * /*unused*/) override {\n        return {};\n    }\n\n    void compute(const llvm::Function *F = nullptr) override {\n        if (F && !F->isDeclaration()) {\n            if (!hasFuncInfo(F)) {\n                computeFuncInfo(F);\n            }\n        } else {\n            for (const auto &f : *getModule()) {\n                if (!f.isDeclaration() && !hasFuncInfo(&f)) {\n                    computeFuncInfo(&f);\n                }\n            }\n        }\n    }\n};\n\n} // namespace llvmdg\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/llvm/ControlDependence/NTSCD.h",
    "content": "#ifndef DG_LLVM_NTSCD_H_\n#define DG_LLVM_NTSCD_H_\n\n#include <llvm/IR/Module.h>\n\n#include \"GraphBuilder.h\"\n#include \"IGraphBuilder.h\"\n#include \"dg/llvm/ControlDependence/ControlDependence.h\"\n\n#include \"ControlDependence/NTSCD.h\"\n\n#include <map>\n#include <set>\n#include <unordered_map>\n\nnamespace llvm {\nclass Function;\n}\n\nnamespace dg {\nnamespace llvmdg {\n\nclass NTSCD : public LLVMControlDependenceAnalysisImpl {\n    CDGraphBuilder graphBuilder{};\n\n    using CDResultT = std::map<CDNode *, std::set<CDNode *>>;\n\n    struct Info {\n        CDGraph graph;\n\n        // forward edges (from branchings to dependent blocks)\n        CDResultT controlDependence{};\n        // reverse edges (from dependent blocks to branchings)\n        CDResultT revControlDependence{};\n\n        Info(CDGraph &&graph) : graph(std::move(graph)) {}\n    };\n\n    std::unordered_map<const llvm::Function *, Info> _graphs;\n\n  public:\n    using ValVec = LLVMControlDependenceAnalysis::ValVec;\n\n    NTSCD(const llvm::Module *module,\n          const LLVMControlDependenceAnalysisOptions &opts = {})\n            : LLVMControlDependenceAnalysisImpl(module, opts) {\n        _graphs.reserve(module->size());\n    }\n\n    /// Getters of dependencies for a value\n    ValVec getDependencies(const llvm::Instruction *I) override {\n        if (!getOptions().nodePerInstruction()) {\n            return {};\n        }\n\n        // XXX: this could be computed on-demand per one node (block)\n        // (in contrary to getDependent())\n        const auto *f = I->getParent()->getParent();\n        if (_getGraph(f) == nullptr) {\n            /// FIXME: get rid of the const cast\n            computeOnDemand(const_cast<llvm::Function *>(f));\n        }\n\n        assert(_getGraph(f) != nullptr);\n\n        auto *node = graphBuilder.getNode(I);\n        if (!node) {\n            return {};\n        }\n        auto *info = _getFunInfo(f);\n        assert(info && \"Did not compute CD\");\n\n        auto dit = info->controlDependence.find(node);\n        if (dit == info->controlDependence.end())\n            return {};\n\n        std::set<llvm::Value *> ret;\n        for (auto *dep : dit->second) {\n            const auto *val = graphBuilder.getValue(dep);\n            assert(val && \"Invalid value\");\n            ret.insert(const_cast<llvm::Value *>(val));\n        }\n\n        return ValVec{ret.begin(), ret.end()};\n    }\n\n    ValVec getDependent(const llvm::Instruction * /*unused*/) override {\n        return {};\n    }\n\n    /// Getters of dependencies for a basic block\n    ValVec getDependencies(const llvm::BasicBlock *b) override {\n        if (getOptions().nodePerInstruction()) {\n            return {};\n        }\n\n        // XXX: this could be computed on-demand per one node (block)\n        // (in contrary to getDependent())\n        if (_getGraph(b->getParent()) == nullptr) {\n            /// FIXME: get rid of the const cast\n            computeOnDemand(const_cast<llvm::Function *>(b->getParent()));\n        }\n        assert(_getGraph(b->getParent()) != nullptr);\n\n        auto *block = graphBuilder.getNode(b);\n        if (!block) {\n            return {};\n        }\n        auto *info = _getFunInfo(b->getParent());\n        assert(info && \"Did not compute CD\");\n\n        auto dit = info->controlDependence.find(block);\n        if (dit == info->controlDependence.end())\n            return {};\n\n        std::set<llvm::Value *> ret;\n        for (auto *dep : dit->second) {\n            const auto *val = graphBuilder.getValue(dep);\n            assert(val && \"Invalid value\");\n            ret.insert(const_cast<llvm::Value *>(val));\n        }\n\n        return ValVec{ret.begin(), ret.end()};\n    }\n\n    ValVec getDependent(const llvm::BasicBlock * /*unused*/) override {\n        assert(false && \"Not supported\");\n        abort();\n    }\n\n    // We run on demand but this method can trigger the computation\n    void compute(const llvm::Function *F = nullptr) override {\n        DBG(cda, \"Triggering computation of all dependencies\");\n        if (F && !F->isDeclaration() && (_getGraph(F) == nullptr)) {\n            computeOnDemand(const_cast<llvm::Function *>(F));\n        } else {\n            for (const auto &f : *getModule()) {\n                if (!f.isDeclaration() && (_getGraph(&f) == nullptr)) {\n                    computeOnDemand(const_cast<llvm::Function *>(&f));\n                }\n            }\n        }\n    }\n\n    CDGraph *getGraph(const llvm::Function *f) override { return _getGraph(f); }\n    const CDGraph *getGraph(const llvm::Function *f) const override {\n        return _getGraph(f);\n    }\n\n    // make this one public so that we can dump it in llvm-cda-dump\n    // (keep the _ prefix so that we can see that it should not be normally\n    // used...)\n    const Info *_getFunInfo(const llvm::Function *f) const {\n        auto it = _graphs.find(f);\n        return it == _graphs.end() ? nullptr : &it->second;\n    }\n\n    Info *_getFunInfo(const llvm::Function *f) {\n        auto it = _graphs.find(f);\n        return it == _graphs.end() ? nullptr : &it->second;\n    }\n\n  private:\n    const CDGraph *_getGraph(const llvm::Function *f) const {\n        auto it = _graphs.find(f);\n        return it == _graphs.end() ? nullptr : &it->second.graph;\n    }\n\n    CDGraph *_getGraph(const llvm::Function *f) {\n        auto it = _graphs.find(f);\n        return it == _graphs.end() ? nullptr : &it->second.graph;\n    }\n\n    void computeOnDemand(llvm::Function *F) {\n        DBG(cda, \"Triggering on-demand computation for \" << F->getName().str());\n        assert(_getGraph(F) == nullptr && \"Already have the graph\");\n\n        auto tmpgraph =\n                graphBuilder.build(F, getOptions().nodePerInstruction());\n        // FIXME: we can actually just forget the graph if we do not want to\n        // dump it to the user\n        auto it = _graphs.emplace(F, std::move(tmpgraph));\n\n        auto &info = it.first->second;\n\n        const auto &opts = getOptions();\n        if (opts.ntscd2CD()) {\n            DBG(cda, \"Using the NTSCD 2 algorithm\");\n            dg::NTSCD2 ntscd;\n            auto result = ntscd.compute(info.graph);\n            info.controlDependence = std::move(result.first);\n            info.revControlDependence = std::move(result.second);\n        } else if (opts.ntscdRanganathCD() || opts.ntscdRanganathOrigCD()) {\n            DBG(cda, \"Using the NTSCD Ranganath algorithm\");\n            dg::NTSCDRanganath ntscd;\n            if (opts.ntscdRanganathOrigCD()) {\n                auto result =\n                        ntscd.compute(info.graph, /* doFixpoint= */ false);\n                info.controlDependence = std::move(result.first);\n                info.revControlDependence = std::move(result.second);\n            } else {\n                auto result = ntscd.compute(info.graph);\n                info.controlDependence = std::move(result.first);\n                info.revControlDependence = std::move(result.second);\n            }\n        } else {\n            assert(opts.ntscdCD() && \"Wrong analysis type\");\n            dg::NTSCD ntscd;\n            auto result = ntscd.compute(info.graph);\n            info.controlDependence = std::move(result.first);\n            info.revControlDependence = std::move(result.second);\n        }\n    }\n};\n\nclass InterproceduralNTSCD : public LLVMControlDependenceAnalysisImpl {\n    ICDGraphBuilder igraphBuilder{};\n    CDGraph graph;\n\n    using CDResultT = std::map<CDNode *, std::set<CDNode *>>;\n    // forward edges (from branchings to dependent blocks)\n    CDResultT controlDependence{};\n    // reverse edges (from dependent blocks to branchings)\n    CDResultT revControlDependence{};\n    bool _computed{false};\n\n  public:\n    using ValVec = LLVMControlDependenceAnalysis::ValVec;\n\n    ///\n    // Note: use this only when you know what you want.\n    // Computing intraprocedural CD + interprocedural CD\n    // separately is more efficient.\n    InterproceduralNTSCD(const llvm::Module *module,\n                         const LLVMControlDependenceAnalysisOptions &opts = {},\n                         LLVMPointerAnalysis *pta = nullptr,\n                         CallGraph *cg = nullptr)\n            : LLVMControlDependenceAnalysisImpl(module, opts),\n              igraphBuilder(pta, cg) {}\n\n    /// Getters of dependencies for a value\n    ValVec getDependencies(const llvm::Instruction *I) override {\n        if (!getOptions().nodePerInstruction()) {\n            return {};\n        }\n\n        _compute();\n\n        auto *node = igraphBuilder.getNode(I);\n        if (!node) {\n            return {};\n        }\n\n        assert(_computed && \"CD is not computed\");\n        auto dit = controlDependence.find(node);\n        if (dit == controlDependence.end())\n            return {};\n\n        std::set<llvm::Value *> ret;\n        for (auto *dep : dit->second) {\n            const auto *val = igraphBuilder.getValue(dep);\n            assert(val && \"Invalid value\");\n            ret.insert(const_cast<llvm::Value *>(val));\n        }\n\n        return ValVec{ret.begin(), ret.end()};\n    }\n\n    ValVec getDependent(const llvm::Instruction * /*unused*/) override {\n        return {};\n    }\n\n    /// Getters of dependencies for a basic block\n    ValVec getDependencies(const llvm::BasicBlock *b) override {\n        if (getOptions().nodePerInstruction()) {\n            return {};\n        }\n\n        _compute();\n\n        auto *block = igraphBuilder.getNode(b);\n        if (!block) {\n            return {};\n        }\n\n        assert(_computed && \"Did not compute CD\");\n        auto dit = controlDependence.find(block);\n        if (dit == controlDependence.end())\n            return {};\n\n        std::set<llvm::Value *> ret;\n        for (auto *dep : dit->second) {\n            const auto *val = igraphBuilder.getValue(dep);\n            assert(val && \"Invalid value\");\n            ret.insert(const_cast<llvm::Value *>(val));\n        }\n\n        return ValVec{ret.begin(), ret.end()};\n    }\n\n    ValVec getDependent(const llvm::BasicBlock * /*unused*/) override {\n        assert(false && \"Not supported\");\n        abort();\n    }\n\n    // We run on demand but this method can trigger the computation\n    void compute(const llvm::Function * /*F*/) override { _compute(); }\n\n    /// Getter for noreturn nodes in function (for interprocedural analysis)\n    ValVec getNoReturns(const llvm::Function * /*unused*/) override {\n        assert(false && \"Unsupported\");\n        abort();\n    }\n\n    CDGraph *getGraph(const llvm::Function * /*unused*/) override {\n        return &graph;\n    }\n    const CDGraph *getGraph(const llvm::Function * /*unused*/) const override {\n        return &graph;\n    }\n\n  private:\n    void _compute() {\n        if (_computed)\n            return;\n\n        DBG(cda, \"Triggering computation of interprocedural NTSCD\");\n\n        graph = igraphBuilder.build(getModule(),\n                                    getOptions().nodePerInstruction());\n\n        if (getOptions().ntscd2CD()) {\n            DBG(cda, \"Using the NTSCD 2 algorithm\");\n            dg::NTSCD2 ntscd;\n            auto result = ntscd.compute(graph);\n            controlDependence = std::move(result.first);\n            revControlDependence = std::move(result.second);\n        } else if (getOptions().ntscdRanganathCD()) {\n            DBG(cda, \"Using the NTSCD Ranganath algorithm\");\n            dg::NTSCDRanganath ntscd;\n            auto result = ntscd.compute(graph);\n            controlDependence = std::move(result.first);\n            revControlDependence = std::move(result.second);\n        } else {\n            assert(getOptions().ntscdCD() && \"Wrong analysis type\");\n            dg::NTSCD ntscd;\n            auto result = ntscd.compute(graph);\n            controlDependence = std::move(result.first);\n            revControlDependence = std::move(result.second);\n        }\n\n        _computed = true;\n    }\n};\n\n} // namespace llvmdg\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/llvm/ControlDependence/SCD.cpp",
    "content": "#include \"SCD.h\"\n\n#include <llvm/Analysis/DominanceFrontier.h>\n#include <llvm/Analysis/PostDominators.h>\n#include <llvm/IR/Function.h>\n//#include \"llvm/Analysis/IteratedDominanceFrontier.h\"\n\n#include \"dg/ADT/Queue.h\"\n#include \"dg/util/debug.h\"\n\nusing namespace std;\n\nnamespace dg {\nnamespace llvmdg {\n\nclass PostDominanceFrontiers {\n    using BBlockT = llvm::BasicBlock;\n#if (LLVM_VERSION_MAJOR < 5)\n    using DomSetMapType = typename llvm::DominanceFrontierBase<\n            llvm::BasicBlock>::DomSetMapType;\n    using DomSetType =\n            typename llvm::DominanceFrontierBase<llvm::BasicBlock>::DomSetType;\n#else\n    using DomSetMapType =\n            typename llvm::DominanceFrontierBase<llvm::BasicBlock,\n                                                 true>::DomSetMapType;\n    using DomSetType = typename llvm::DominanceFrontierBase<llvm::BasicBlock,\n                                                            true>::DomSetType;\n#endif\n\n    DomSetMapType frontiers;\n\n  public:\n    // based on the code from giri project by @liuml07,\n    // https://github.com/liuml07/giri\n    DomSetType &calculate(const llvm::PostDominatorTree &DT,\n                          const llvm::DomTreeNode *Node) {\n        llvm::BasicBlock *BB = Node->getBlock();\n        auto &S = frontiers[BB];\n\n#if LLVM_VERSION_MAJOR >= 11\n        bool empty_roots = DT.root_size() == 0;\n#else\n        bool empty_roots = DT.getRoots().empty();\n#endif\n        if (empty_roots)\n            return S;\n\n        // calculate DFlocal[Node]\n        if (BB) {\n            for (auto *P : predecessors(BB)) {\n                // Does Node immediately dominate this predecessor?\n                auto *SINode = DT[P];\n                if (SINode && SINode->getIDom() != Node)\n                    S.insert(P);\n            }\n        }\n\n        // At this point, S is DFlocal.  Now we union in DFup's of our children.\n        // Loop through and visit the nodes that Node immediately dominates\n        // (Node's children in the IDomTree)\n        for (auto *IDominee : *Node) {\n            const auto &ChildDF = calculate(DT, IDominee);\n\n            for (auto *cdfi : ChildDF) {\n                if (!DT.properlyDominates(Node, DT[cdfi]))\n                    S.insert(cdfi);\n            }\n        }\n\n        return S;\n    }\n};\n\nvoid SCD::computePostDominators(llvm::Function &F) {\n    DBG_SECTION_BEGIN(cda, \"Computing post dominators for function \"\n                                   << F.getName().str());\n    using namespace llvm;\n\n    PostDominatorTree *pdtree = nullptr;\n\n    DBG(cda, \"Computing post dominator tree\");\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 9))\n\n    auto pdtreeptr =\n            std::unique_ptr<PostDominatorTree>(new PostDominatorTree());\n    pdtree = pdtreeptr.get();\n    pdtree->runOnFunction(F); // compute post-dominator tree for this function\n\n#else // LLVM >= 3.9\n\n    PostDominatorTreeWrapperPass wrapper;\n    wrapper.runOnFunction(F);\n    pdtree = &wrapper.getPostDomTree();\n\n#ifndef NDEBUG\n    wrapper.verifyAnalysis();\n#endif\n\n    DBG(cda, \"Computing post dominator frontiers and adding CD\");\n\n#if 0 // this does not work as expected\n    llvm::ReverseIDFCalculator PDF(*pdtree);\n    for (auto& B : F) {\n        llvm::SmallPtrSet<llvm::BasicBlock *, 1> blocks;\n        blocks.insert(&B);\n        PDF.setDefiningBlocks(blocks);\n\n        SmallVector<BasicBlock *, 8> pdfrontiers;\n        PDF.calculate(pdfrontiers);\n\n        // FIXME: reserve the memory\n        for (auto *pdf : pdfrontiers) {\n            dependencies[&B].insert(pdf);\n            dependentBlocks[pdf].insert(&B);\n        }\n    }\n#endif\n\n    PostDominanceFrontiers PDF;\n\n    for (auto &B : F) {\n        auto *pdtreenode = pdtree->getNode(&B);\n        assert(pdtreenode && \"Do not have a node in post-dom tree\");\n        auto &pdfrontiers = PDF.calculate(*pdtree, pdtreenode);\n        for (auto *pdf : pdfrontiers) {\n            dependencies[&B].insert(pdf);\n            dependentBlocks[pdf].insert(&B);\n        }\n    }\n\n#endif // LLVM < 3.9\n\n    DBG_SECTION_END(cda, \"Done computing post dominators for function \"\n                                 << F.getName().str());\n}\n\n} // namespace llvmdg\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ControlDependence/SCD.h",
    "content": "#ifndef DG_LLVM_SCD_H_\n#define DG_LLVM_SCD_H_\n\n#include <llvm/IR/Module.h>\n\n#include \"dg/llvm/ControlDependence/ControlDependence.h\"\n#include \"dg/util/debug.h\"\n\n#include <map>\n#include <set>\n#include <unordered_map>\n\nnamespace llvm {\nclass Function;\n}\n\nnamespace dg {\n\nclass LLVMPointerAnalysis;\n\nnamespace llvmdg {\n\n// Standard control dependencies based on the computation\n// of post-dominance frontiers.\n// This class uses purely LLVM, no internal representation\n// like the other classes (we use the post-dominance computation from LLVM).\nclass SCD : public LLVMControlDependenceAnalysisImpl {\n    void computePostDominators(llvm::Function &F);\n\n    std::unordered_map<const llvm::BasicBlock *, std::set<llvm::BasicBlock *>>\n            dependentBlocks;\n    std::unordered_map<const llvm::BasicBlock *, std::set<llvm::BasicBlock *>>\n            dependencies;\n    std::set<const llvm::Function *> _computed;\n\n    void computeOnDemand(const llvm::Function *F) {\n        if (_computed.insert(F).second) {\n            computePostDominators(*const_cast<llvm::Function *>(F));\n        }\n    }\n\n  public:\n    using ValVec = LLVMControlDependenceAnalysis::ValVec;\n\n    SCD(const llvm::Module *module,\n        const LLVMControlDependenceAnalysisOptions &opts = {})\n            : LLVMControlDependenceAnalysisImpl(module, opts) {}\n\n    /// Getters of dependencies for a value\n    ValVec getDependencies(const llvm::Instruction * /*unused*/) override {\n        return {};\n    }\n    ValVec getDependent(const llvm::Instruction * /*unused*/) override {\n        return {};\n    }\n\n    /// Getters of dependencies for a basic block\n    ValVec getDependencies(const llvm::BasicBlock *b) override {\n        computeOnDemand(b->getParent());\n\n        auto &S = dependencies[b];\n        return ValVec{S.begin(), S.end()};\n    }\n\n    ValVec getDependent(const llvm::BasicBlock *b) override {\n        computeOnDemand(b->getParent());\n\n        auto &S = dependentBlocks[b];\n        return ValVec{S.begin(), S.end()};\n    }\n\n    void compute(const llvm::Function *F = nullptr) override {\n        DBG(cda, \"Triggering computation of all dependencies\");\n        if (F && !F->isDeclaration()) {\n            computeOnDemand(F);\n        } else {\n            for (const auto &f : *getModule()) {\n                if (f.isDeclaration()) {\n                    continue;\n                }\n                computeOnDemand(&f);\n            }\n        }\n    }\n};\n\n} // namespace llvmdg\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/llvm/ControlDependence/legacy/Block.cpp",
    "content": "#include \"Block.h\"\n#include \"Function.h\"\n\n#include <sstream>\n\n#include <llvm/IR/Function.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/Support/raw_ostream.h>\n\nnamespace dg {\nnamespace llvmdg {\nnamespace legacy {\n\nint Block::traversalCounter = 0;\n\nconst std::set<Block *> &Block::predecessors() const { return predecessors_; }\n\nconst std::set<Block *> &Block::successors() const { return successors_; }\n\nbool Block::addPredecessor(Block *predecessor) {\n    if (!predecessor) {\n        return false;\n    }\n    predecessors_.insert(predecessor);\n    return predecessor->successors_.insert(this).second;\n}\n\nbool Block::removePredecessor(Block *predecessor) {\n    if (!predecessor) {\n        return false;\n    }\n    predecessors_.erase(predecessor);\n    return predecessor->successors_.erase(this);\n}\n\nbool Block::addSuccessor(Block *successor) {\n    if (!successor) {\n        return false;\n    }\n    successors_.insert(successor);\n    return successor->predecessors_.insert(this).second;\n}\n\nbool Block::removeSuccessor(Block *successor) {\n    if (!successor) {\n        return false;\n    }\n    successors_.erase(successor);\n    return successor->predecessors_.erase(this);\n}\n\nconst llvm::Instruction *Block::lastInstruction() const {\n    if (!llvmInstructions_.empty()) {\n        return llvmInstructions_.back();\n    }\n    return nullptr;\n}\n\nbool Block::addInstruction(const llvm::Instruction *instruction) {\n    if (!instruction) {\n        return false;\n    }\n    llvmInstructions_.push_back(instruction);\n    return true;\n}\n\nbool Block::addCallee(const llvm::Function *llvmFunction, Function *function) {\n    if (!llvmFunction || !function) {\n        return false;\n    }\n    return callees_.emplace(llvmFunction, function).second;\n}\n\nbool Block::addFork(const llvm::Function *llvmFunction, Function *function) {\n    if (!llvmFunction || !function) {\n        return false;\n    }\n    return forks_.emplace(llvmFunction, function).second;\n}\n\nbool Block::addJoin(const llvm::Function *llvmFunction, Function *function) {\n    if (!llvmFunction || !function) {\n        return false;\n    }\n    return joins_.emplace(llvmFunction, function).second;\n}\n\nconst std::map<const llvm::Function *, Function *> &Block::callees() const {\n    return callees_;\n}\n\nstd::map<const llvm::Function *, Function *> Block::callees() {\n    return callees_;\n}\n\nconst std::map<const llvm::Function *, Function *> &Block::forks() const {\n    return forks_;\n}\n\nstd::map<const llvm::Function *, Function *> Block::forks() { return forks_; }\n\nconst std::map<const llvm::Function *, Function *> &Block::joins() const {\n    return joins_;\n}\n\nstd::map<const llvm::Function *, Function *> Block::joins() { return joins_; }\n\nbool Block::isCall() const {\n    return !llvmInstructions_.empty() &&\n           llvmInstructions_.back()->getOpcode() == llvm::Instruction::Call;\n}\n\nbool Block::isArtificial() const { return llvmInstructions_.empty(); }\n\nbool Block::isCallReturn() const { return isArtificial() && callReturn; }\n\nbool Block::isExit() const { return isArtificial() && !isCallReturn(); }\n\nstd::string Block::dotName() const {\n    std::stringstream stream;\n    stream << \"NODE\" << this;\n    return stream.str();\n}\n\nstd::string Block::label() const {\n    std::string label_ = \"[label=\\\"\";\n    if (llvmBlock()) {\n        label_ += \"Function: \";\n        label_ += llvmBlock()->getParent()->getName();\n    }\n    label_ += \"\\\\n\\\\nid:\";\n    label_ += std::to_string(traversalId_);\n    if (isCallReturn()) {\n        label_ += \" Call Return Block\\\\n\\\\n\";\n    } else if (isArtificial()) {\n        label_ += \" Unified Exit Block\\\\n\\\\n\";\n    } else {\n        label_ += \" Block\\\\n\\\\n\";\n        std::string llvmTemporaryString;\n        llvm::raw_string_ostream llvmStream(llvmTemporaryString);\n        for (const auto *instruction : llvmInstructions_) {\n            instruction->print(llvmStream);\n            label_ += llvmTemporaryString + \"\\\\n\";\n            llvmTemporaryString.clear();\n        }\n    }\n    label_ += \"\\\", shape=box]\";\n    return label_;\n}\n\nvoid Block::visit() {\n    this->traversalId();\n    for (auto *successor : successors_) {\n        if (successor->bfsId() == 0) {\n            successor->visit();\n        }\n    }\n    this->traversalId();\n}\n\nvoid Block::dumpNode(std::ostream &ostream) const {\n    ostream << dotName() << \" \" << label();\n}\n\nvoid Block::dumpEdges(std::ostream &ostream) const {\n    for (auto *successor : successors_) {\n        ostream << this->dotName() << \" -> \" << successor->dotName() << \"\\n\";\n    }\n\n    for (auto callee : callees_) {\n        ostream << this->dotName() << \" -> \"\n                << callee.second->entry()->dotName()\n                << \" [style=dashed, constraint=false]\\n\";\n        ostream << callee.second->exit()->dotName() << \" -> \" << this->dotName()\n                << \" [style=dashed, constraint=false]\\n\";\n    }\n\n    for (auto fork : forks_) {\n        ostream << this->dotName() << \" -> \" << fork.second->entry()->dotName()\n                << \" [style=dotted, constraint=false]\\n\";\n    }\n\n    for (auto join : joins_) {\n        ostream << join.second->exit()->dotName() << \" -> \" << this->dotName()\n                << \" [style=dotted, constraint=false]\\n\";\n    }\n}\n\n} // namespace legacy\n} // namespace llvmdg\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ControlDependence/legacy/Block.h",
    "content": "#ifndef DG_LEGACY_NTSCD_BLOCK_H\n#define DG_LEGACY_NTSCD_BLOCK_H\n\n#include <iosfwd>\n#include <map>\n#include <set>\n#include <vector>\n\nnamespace llvm {\nclass Instruction;\nclass Function;\nclass BasicBlock;\n} // namespace llvm\n\nnamespace dg {\nnamespace llvmdg {\nnamespace legacy {\n\nclass Function;\n\nclass Block {\n    const llvm::BasicBlock *_llvm_blk;\n\n  public:\n    Block(const llvm::BasicBlock *b, bool callReturn = false)\n            : _llvm_blk(b), callReturn(callReturn) {}\n\n    // FIXME: make vector\n    const std::set<Block *> &predecessors() const;\n    const std::set<Block *> &successors() const;\n\n    bool addPredecessor(Block *predecessor);\n    bool removePredecessor(Block *predecessor);\n\n    bool addSuccessor(Block *successor);\n    bool removeSuccessor(Block *successor);\n\n    const std::vector<const llvm::Instruction *> &llvmInstructions() const {\n        return llvmInstructions_;\n    }\n\n    const llvm::Instruction *lastInstruction() const;\n\n    bool addInstruction(const llvm::Instruction *instruction);\n\n    bool addCallee(const llvm::Function *llvmFunction, Function *function);\n    bool addFork(const llvm::Function *llvmFunction, Function *function);\n    bool addJoin(const llvm::Function *llvmFunction, Function *function);\n\n    const std::map<const llvm::Function *, Function *> &callees() const;\n    std::map<const llvm::Function *, Function *> callees();\n\n    const std::map<const llvm::Function *, Function *> &forks() const;\n    std::map<const llvm::Function *, Function *> forks();\n\n    const std::map<const llvm::Function *, Function *> &joins() const;\n    std::map<const llvm::Function *, Function *> joins();\n\n    bool isCall() const;\n    bool isArtificial() const;\n    bool isCallReturn() const;\n    bool isExit() const;\n\n    void traversalId() { traversalId_ = ++traversalCounter; }\n    int bfsId() const { return traversalId_; }\n\n    const llvm::BasicBlock *llvmBlock() const { return _llvm_blk; }\n\n    std::string dotName() const;\n\n    std::string label() const;\n\n    void visit();\n\n    void dumpNode(std::ostream &ostream) const;\n    void dumpEdges(std::ostream &ostream) const;\n\n  private:\n    static int traversalCounter;\n\n    std::vector<const llvm::Instruction *> llvmInstructions_;\n\n    std::set<Block *> predecessors_;\n    std::set<Block *> successors_;\n\n    bool callReturn = false;\n    int traversalId_ = 0;\n\n    std::map<const llvm::Function *, Function *> callees_;\n    std::map<const llvm::Function *, Function *> forks_;\n    std::map<const llvm::Function *, Function *> joins_;\n};\n\n} // namespace legacy\n} // namespace llvmdg\n} // namespace dg\n\n#endif // DG_LLVM_BLOCK_H\n"
  },
  {
    "path": "lib/llvm/ControlDependence/legacy/Function.cpp",
    "content": "#include \"Function.h\"\n#include \"Block.h\"\n\n#include <algorithm>\n#include <ostream>\n\nnamespace dg {\nnamespace llvmdg {\nnamespace legacy {\n\nFunction::Function() : lastBlock(new Block(nullptr)) {\n    blocks.insert(lastBlock);\n}\n\nFunction::~Function() {\n    for (auto *block : blocks) {\n        delete block;\n    }\n}\n\nBlock *Function::entry() const { return firstBlock; }\n\nBlock *Function::exit() const { return lastBlock; }\n\nbool Function::addBlock(Block *block) {\n    if (!block) {\n        return false;\n    }\n    if (!firstBlock) {\n        firstBlock = block;\n    }\n    return blocks.insert(block).second;\n}\n\nstd::set<Block *> Function::nodes() const { return blocks; }\n\nstd::set<Block *> Function::condNodes() const {\n    std::set<Block *> condNodes_;\n\n    std::copy_if(\n            blocks.begin(), blocks.end(),\n            std::inserter(condNodes_, condNodes_.end()),\n            [](const Block *block) { return block->successors().size() > 1; });\n\n    return condNodes_;\n}\n\nstd::set<Block *> Function::callReturnNodes() const {\n    std::set<Block *> callReturnNodes_;\n\n    std::copy_if(blocks.begin(), blocks.end(),\n                 std::inserter(callReturnNodes_, callReturnNodes_.end()),\n                 [](const Block *block) { return block->isCallReturn(); });\n\n    return callReturnNodes_;\n}\n\nvoid Function::dumpBlocks(std::ostream &ostream) {\n    for (auto *block : blocks) {\n        block->dumpNode(ostream);\n        ostream << \"\\n\";\n    }\n}\n\nvoid Function::dumpEdges(std::ostream &ostream) {\n    for (auto *block : blocks) {\n        block->dumpEdges(ostream);\n    }\n}\n\n} // namespace legacy\n} // namespace llvmdg\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ControlDependence/legacy/Function.h",
    "content": "#ifndef DG_LEGACY_NTSCD_FUNCTION_H\n#define DG_LEGACY_NTSCD_FUNCTION_H\n\n#include <iosfwd>\n#include <set>\n\nnamespace dg {\nnamespace llvmdg {\nnamespace legacy {\n\nclass Block;\n\nclass Function {\n  public:\n    Function();\n    ~Function();\n\n    Block *entry() const;\n    Block *exit() const;\n\n    bool addBlock(Block *block);\n\n    std::set<Block *> nodes() const;\n    std::set<Block *> condNodes() const;\n    std::set<Block *> callReturnNodes() const;\n\n    void dumpBlocks(std::ostream &ostream);\n    void dumpEdges(std::ostream &ostream);\n\n  private:\n    Block *firstBlock = nullptr;\n    Block *lastBlock = nullptr;\n    std::set<Block *> blocks;\n};\n\n} // namespace legacy\n} // namespace llvmdg\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/llvm/ControlDependence/legacy/GraphBuilder.cpp",
    "content": "#include <llvm/Analysis/LoopInfo.h>\n#include <llvm/IR/CFG.h>\n#include <llvm/IR/Function.h>\n#include <llvm/IR/Value.h>\n#include <llvm/Pass.h>\n\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n#include \"llvm/ForkJoin/ForkJoin.h\"\n\n#include \"Block.h\"\n#include \"Function.h\"\n#include \"GraphBuilder.h\"\n#include \"TarjanAnalysis.h\"\n\nusing dg::ForkJoinAnalysis;\n\nnamespace dg {\nnamespace llvmdg {\nnamespace legacy {\n\nGraphBuilder::GraphBuilder(dg::LLVMPointerAnalysis *pointsToAnalysis)\n        : pointsToAnalysis_(pointsToAnalysis),\n          threads(pointsToAnalysis ? pointsToAnalysis->getOptions().threads\n                                   : false) {}\n\nGraphBuilder::~GraphBuilder() {\n    for (auto function : _functions) {\n        delete function.second;\n    }\n}\n\nbool isExit(const TarjanAnalysis<Block>::StronglyConnectedComponent *component,\n            const Function *function) {\n    bool ret = component->nodes().size() == 1;\n    if (!ret) {\n        return false;\n    }\n    return component->nodes().back() == function->exit();\n}\n\nFunction *GraphBuilder::buildFunction(const llvm::Function *llvmFunction,\n                                      bool recursively) {\n    if (!llvmFunction) {\n        return nullptr;\n    }\n    auto iterator = _functions.find(llvmFunction);\n    if (iterator != _functions.end()) {\n        return nullptr;\n    }\n    iterator = _functions.emplace(llvmFunction, new Function()).first;\n    Function *function = iterator->second;\n\n    std::map<const llvm::Instruction *, Block *> instToBlockMap;\n    Block *lastBlock = nullptr;\n    for (const auto &llvmBlock : *llvmFunction) {\n        if (!isReachable(&llvmBlock)) {\n            continue;\n        }\n\n        bool createBlock = true;\n        for (const auto &llvmInst : llvmBlock) {\n            if (createBlock) {\n                auto *tmpBlock = new Block(&llvmBlock);\n                _mapping[&llvmBlock].push_back(tmpBlock);\n                function->addBlock(tmpBlock);\n                if (lastBlock) {\n                    if (lastBlock->llvmBlock() == &llvmBlock) {\n                        lastBlock->addSuccessor(tmpBlock);\n                    }\n                }\n                lastBlock = tmpBlock;\n                createBlock = false;\n            }\n            bool createCallReturn = false;\n            if (recursively &&\n                llvmInst.getOpcode() == llvm::Instruction::Call) {\n                handleCallInstruction(&llvmInst, lastBlock, createBlock,\n                                      createCallReturn);\n            }\n            lastBlock->addInstruction(&llvmInst);\n            instToBlockMap.emplace(&llvmInst, lastBlock);\n\n            if (createCallReturn) {\n                auto *tmpBlock = new Block(&llvmBlock, createCallReturn);\n                _mapping[&llvmBlock].push_back(tmpBlock);\n                function->addBlock(tmpBlock);\n                lastBlock->addSuccessor(tmpBlock);\n                lastBlock = tmpBlock;\n                createBlock = true;\n            }\n        }\n    }\n\n    for (const auto &llvmBlock : *llvmFunction) {\n        if (isReachable(&llvmBlock)) {\n            auto *block = instToBlockMap[&llvmBlock.back()];\n            for (auto succ = llvm::succ_begin(&llvmBlock);\n                 succ != llvm::succ_end(&llvmBlock); ++succ) {\n                auto *succ_block = instToBlockMap[&succ->front()];\n                block->addSuccessor(succ_block);\n            }\n            if (successorsNumber(&llvmBlock) == 0) {\n                block->addSuccessor(function->exit());\n            }\n        }\n    }\n\n    TarjanAnalysis<Block> tarjan(function->nodes().size());\n    tarjan.compute(function->entry());\n    tarjan.computeCondensation();\n    const auto &componentss = tarjan.components();\n    for (auto *const component : componentss) {\n        if (!isExit(component, function) && component->successors().empty()) {\n            component->nodes().back()->addSuccessor(function->exit());\n        }\n    }\n\n    //    auto components =\n    //    tarjan.computeBackWardReachability(function->exit());\n\n    //    for (auto component : components) {\n    //        if (component->nodes().size() > 1 ||\n    //            component->successors().find(component) !=\n    //            component->successors().end()) {\n    //            component->nodes().back()->addSuccessor(function->exit());\n    //        }\n    //    }\n\n    return function;\n}\n\nFunction *GraphBuilder::findFunction(const llvm::Function *llvmFunction) {\n    if (!llvmFunction) {\n        return nullptr;\n    }\n    auto iterator = _functions.find(llvmFunction);\n    if (iterator != _functions.end()) {\n        return iterator->second;\n    }\n    return nullptr;\n}\n\nFunction *\nGraphBuilder::createOrGetFunction(const llvm::Function *llvmFunction) {\n    if (!llvmFunction) {\n        return nullptr;\n    }\n    auto *function = findFunction(llvmFunction);\n    if (!function) {\n        function = buildFunction(llvmFunction);\n    }\n    return function;\n}\n\nvoid GraphBuilder::dumpNodes(std::ostream &ostream) const {\n    for (auto function : _functions) {\n        function.second->dumpBlocks(ostream);\n    }\n}\n\nvoid GraphBuilder::dumpEdges(std::ostream &ostream) const {\n    for (auto function : _functions) {\n        function.second->dumpEdges(ostream);\n    }\n}\n\nvoid GraphBuilder::dump(std::ostream &ostream) const {\n    ostream << \"digraph \\\"BlockGraph\\\" {\\n\";\n    dumpNodes(ostream);\n    dumpEdges(ostream);\n    ostream << \"}\\n\";\n}\n\nstd::vector<const llvm::Function *>\nGraphBuilder::getCalledFunctions(const llvm::Value *v) {\n    if (const auto *F = llvm::dyn_cast<llvm::Function>(v)) {\n        return {F};\n    }\n\n    if (!pointsToAnalysis_)\n        return {};\n\n    return dg::getCalledFunctions(v, pointsToAnalysis_);\n}\n\nvoid GraphBuilder::handleCallInstruction(const llvm::Instruction *instruction,\n                                         Block *lastBlock, bool &createBlock,\n                                         bool &createCallReturn) {\n    const auto *callInst = llvm::cast<llvm::CallInst>(instruction);\n#if LLVM_VERSION_MAJOR >= 8\n    auto *val = callInst->getCalledOperand();\n#else\n    auto *val = callInst->getCalledValue();\n#endif\n    auto llvmFunctions = getCalledFunctions(val);\n\n    for (const auto *llvmFunction : llvmFunctions) {\n        if (!llvmFunction->empty()) {\n            auto *function = createOrGetFunction(llvmFunction);\n            lastBlock->addCallee(llvmFunction, function);\n            createCallReturn |= true;\n        } else if (threads) {\n            if (llvmFunction->getName() == \"pthread_create\") {\n                createBlock |= createPthreadCreate(callInst, lastBlock);\n            } else if (llvmFunction->getName() == \"pthread_join\") {\n                createCallReturn |= createPthreadJoin(callInst, lastBlock);\n            }\n        }\n    }\n}\n\nbool GraphBuilder::createPthreadCreate(const llvm::CallInst *callInst,\n                                       Block *lastBlock) {\n    bool createBlock = false;\n    llvm::Value *calledValue = callInst->getArgOperand(2);\n    auto forkFunctions = getCalledFunctions(calledValue);\n    std::vector<const llvm::Function *> forkFunctionsWithBlock;\n    for (const auto *forkFunction : forkFunctions) {\n        if (!forkFunction->empty()) {\n            forkFunctionsWithBlock.push_back(forkFunction);\n        }\n    }\n    createBlock |= forkFunctionsWithBlock.size();\n    for (const auto *forkFunction : forkFunctionsWithBlock) {\n        auto *function = createOrGetFunction(forkFunction);\n        lastBlock->addFork(forkFunction, function);\n    }\n    return createBlock;\n}\n\nbool GraphBuilder::createPthreadJoin(const llvm::CallInst *callInst,\n                                     Block *lastBlock) {\n    bool createCallReturn = false;\n\n    // FIXME: create this as attibute so that we perform the analysis only once\n    // (now we do not care as we just forward the results of PTA, but in the\n    // future...)\n    ForkJoinAnalysis FJA{pointsToAnalysis_};\n    auto joinFunctions = FJA.joinFunctions(callInst);\n    for (const auto *joinFunction : joinFunctions) {\n        const auto *llvmFunction = llvm::cast<llvm::Function>(joinFunction);\n        if (!llvmFunction->empty()) {\n            auto *func = createOrGetFunction(llvmFunction);\n            lastBlock->addJoin(llvmFunction, func);\n            createCallReturn |= true;\n        }\n    }\n    return createCallReturn;\n}\n\nint predecessorsNumber(const llvm::BasicBlock *basicBlock) {\n    auto number = std::distance(pred_begin(basicBlock), pred_end(basicBlock));\n    return static_cast<int>(number);\n}\n\nint successorsNumber(const llvm::BasicBlock *basicBlock) {\n    auto number = std::distance(succ_begin(basicBlock), succ_end(basicBlock));\n    return static_cast<int>(number);\n}\n\nbool isReachable(const llvm::BasicBlock *basicBlock) {\n    return predecessorsNumber(basicBlock) > 0 ||\n           &basicBlock->getParent()->front() == basicBlock;\n}\n\n} // namespace legacy\n} // namespace llvmdg\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ControlDependence/legacy/GraphBuilder.h",
    "content": "#ifndef DG_LEGACY_NTSCD_GRAPHBUILDER_H\n#define DG_LEGACY_NTSCD_GRAPHBUILDER_H\n\n#include <iosfwd>\n#include <map>\n#include <unordered_map>\n#include <vector>\n\nnamespace llvm {\nclass Value;\nclass Function;\nclass BasicBlock;\nclass Instruction;\nclass CallInst;\n} // namespace llvm\n\nnamespace dg {\n\nclass LLVMPointerAnalysis;\n\nnamespace llvmdg {\nnamespace legacy {\n\nclass Function;\nclass Block;\n\nclass GraphBuilder {\n    LLVMPointerAnalysis *pointsToAnalysis_ = nullptr;\n    bool threads = false;\n    std::map<const llvm::Function *, Function *> _functions;\n    // mapping from llvm block to our blocks (a vector of blocks\n    // since we split them apart)\n    // FIXME: optimize this, most of the vectors will be just a singleton...\n    std::unordered_map<const llvm::BasicBlock *, std::vector<Block *>> _mapping;\n\n    std::vector<const llvm::Function *>\n    getCalledFunctions(const llvm::Value *v);\n\n    void handleCallInstruction(const llvm::Instruction *instruction,\n                               Block *lastBlock, bool &createBlock,\n                               bool &createCallReturn);\n\n    bool createPthreadCreate(const llvm::CallInst *callInst, Block *lastBlock);\n    bool createPthreadJoin(const llvm::CallInst *callInst, Block *lastBlock);\n\n  public:\n    GraphBuilder(LLVMPointerAnalysis *pointsToAnalysis = nullptr);\n    ~GraphBuilder();\n\n    Function *buildFunction(const llvm::Function *llvmFunction,\n                            bool recursively = false);\n    Function *findFunction(const llvm::Function *llvmFunction);\n    Function *createOrGetFunction(const llvm::Function *llvmFunction);\n\n    const std::map<const llvm::Function *, Function *> &functions() const {\n        return _functions;\n    }\n\n    const std::vector<Block *> *mapBlock(const llvm::BasicBlock *b) const {\n        auto it = _mapping.find(b);\n        return it == _mapping.end() ? nullptr : &it->second;\n    }\n\n    void dumpNodes(std::ostream &ostream) const;\n    void dumpEdges(std::ostream &ostream) const;\n    void dump(std::ostream &ostream) const;\n};\n\n// auxiliary functions\nint predecessorsNumber(const llvm::BasicBlock *basicBlock);\nint successorsNumber(const llvm::BasicBlock *basicBlock);\nbool isReachable(const llvm::BasicBlock *basicBlock);\n\n} // namespace legacy\n} // namespace llvmdg\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/llvm/ControlDependence/legacy/NTSCD.cpp",
    "content": "#include \"NTSCD.h\"\n#include \"Block.h\"\n#include \"Function.h\"\n\nnamespace llvm {\nclass Function;\n}\n\n#include <algorithm>\n#include <functional>\n#include <ostream>\n#include <queue>\n#include <unordered_set>\n\n#include \"dg/util/debug.h\"\n\nusing namespace std;\n\nnamespace dg {\nnamespace llvmdg {\nnamespace legacy {\n\nNTSCD::NTSCD(const llvm::Module *module,\n             const LLVMControlDependenceAnalysisOptions &opts,\n             dg::LLVMPointerAnalysis *pointsToAnalysis)\n        : LLVMControlDependenceAnalysisImpl(module, opts),\n          graphBuilder(pointsToAnalysis) {}\n\n// a is CD on b\nvoid NTSCD::addControlDependence(Block *a, Block *b) {\n    controlDependency[b].insert(a);\n    revControlDependency[a].insert(b);\n}\n\n// FIXME: make it working on-demand\nvoid NTSCD::computeInterprocDependencies(Function *function) {\n    DBG_SECTION_BEGIN(cda, \"Computing interprocedural CD\");\n\n    const auto &nodes = function->nodes();\n    for (auto *node : nodes) {\n        if (!node->callees().empty() || !node->joins().empty()) {\n            auto iterator = std::find_if(\n                    node->successors().begin(), node->successors().end(),\n                    [](const Block *block) { return block->isCallReturn(); });\n            if (iterator != node->successors().end()) {\n                for (auto callee : node->callees()) {\n                    addControlDependence(*iterator, callee.second->exit());\n                }\n                for (auto join : node->joins()) {\n                    addControlDependence(*iterator, join.second->exit());\n                }\n            }\n        }\n    }\n\n    for (auto *node : function->callReturnNodes()) {\n        std::queue<Block *> q;\n        std::unordered_set<Block *> visited(nodes.size());\n        visited.insert(node);\n        for (auto *successor : node->successors()) {\n            if (visited.find(successor) == visited.end()) {\n                q.push(successor);\n                visited.insert(successor);\n            }\n        }\n        while (!q.empty()) {\n            addControlDependence(q.front(), node);\n            for (auto *successor : q.front()->successors()) {\n                if (visited.find(successor) == visited.end()) {\n                    q.push(successor);\n                    visited.insert(successor);\n                }\n            }\n            q.pop();\n        }\n    }\n    DBG_SECTION_END(cda, \"Finished computing interprocedural CD\");\n}\n\nvoid NTSCD::computeIntraprocDependencies(Function *function) {\n    const auto &nodes = function->nodes();\n    DBG_SECTION_BEGIN(cda, \"Computing intraprocedural CD\");\n    for (auto *node : nodes) {\n        // (1) initialize\n        nodeInfo.clear();\n        nodeInfo.reserve(nodes.size());\n        for (auto *node1 : nodes) {\n            nodeInfo[node1].outDegreeCounter = node1->successors().size();\n        }\n        // (2) traverse\n        visitInitialNode(node);\n        // (3) find out dependencies\n        for (auto *node1 : nodes) {\n            if (hasRedAndNonRedSuccessor(node1)) {\n                // node is CD on node1\n                addControlDependence(node, node1);\n            }\n        }\n    }\n    DBG_SECTION_END(cda, \"Finished computing intraprocedural CD\");\n}\n\nvoid NTSCD::computeDependencies(Function *function) {\n    DBG_SECTION_BEGIN(cda, \"Computing CD for a function\");\n\n    computeIntraprocDependencies(function);\n\n    if (getOptions().interproceduralCD()) {\n        computeInterprocDependencies(function);\n    }\n\n    DBG_SECTION_END(cda, \"Finished computing CD for a function\");\n}\n\n///\n///  Compute dependencies for all functions including\n/// the interprocedural dependencies (this method builds\n/// interprocedural CFG). This method is still here mainly\n/// for the legacy LLVMDependenceGraph class.\n/// \\see computeOnDemand\n///\nvoid NTSCD::computeDependencies() {\n    DBG_SECTION_BEGIN(cda, \"Computing CD for the whole module\");\n    auto *entryFunction = getModule()->getFunction(getOptions().entryFunction);\n    if (!entryFunction) {\n        llvm::errs() << \"Missing entry function: \" << getOptions().entryFunction\n                     << \"\\n\";\n        return;\n    }\n\n    graphBuilder.buildFunction(entryFunction, /* recursively = */ true);\n    auto *entryFunc = graphBuilder.findFunction(entryFunction);\n\n    entryFunc->entry()->visit();\n\n    for (const auto &it : graphBuilder.functions()) {\n        computeDependencies(it.second);\n    }\n    DBG_SECTION_END(cda, \"Finished computing CD for the whole module\");\n}\n\n/// Compute intraprocedural dependencies in the given function\nvoid NTSCD::computeOnDemand(llvm::Function *F) {\n    DBG_SECTION_BEGIN(cda, \"Computing CD for function \" << F->getName().str());\n    assert(F);\n\n    auto *function = graphBuilder.createOrGetFunction(F);\n    function->entry()->visit();\n\n    computeIntraprocDependencies(function);\n\n    DBG_SECTION_END(cda,\n                    \"Done computing CD for function \" << F->getName().str());\n}\n\nvoid NTSCD::dump(ostream &ostream) const {\n    ostream << \"digraph \\\"BlockGraph\\\" {\\n\";\n    graphBuilder.dumpNodes(ostream);\n    graphBuilder.dumpEdges(ostream);\n    dumpDependencies(ostream);\n    ostream << \"}\\n\";\n}\n\nvoid NTSCD::dumpDependencies(ostream &ostream) const {\n    for (auto keyValue : controlDependency) {\n        for (auto *dependent : keyValue.second) {\n            ostream << keyValue.first->dotName() << \" -> \"\n                    << dependent->dotName()\n                    << \" [color=blue, constraint=false]\\n\";\n        }\n    }\n}\n\nvoid NTSCD::visitInitialNode(Block *node) {\n    nodeInfo[node].red = true;\n    for (auto *predecessor : node->predecessors()) {\n        visit(predecessor);\n    }\n}\n\nvoid NTSCD::visit(Block *node) {\n    if (nodeInfo[node].outDegreeCounter == 0) {\n        return;\n    }\n    nodeInfo[node].outDegreeCounter--;\n    if (nodeInfo[node].outDegreeCounter == 0) {\n        nodeInfo[node].red = true;\n        for (auto *predecessor : node->predecessors()) {\n            visit(predecessor);\n        }\n    }\n}\n\nbool NTSCD::hasRedAndNonRedSuccessor(Block *node) {\n    size_t redCounter = 0;\n    for (auto *successor : node->successors()) {\n        if (nodeInfo[successor].red) {\n            ++redCounter;\n        }\n    }\n    return redCounter > 0 && node->successors().size() > redCounter;\n}\n\n} // namespace legacy\n} // namespace llvmdg\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ControlDependence/legacy/NTSCD.h",
    "content": "#ifndef DG_LEGACY_LLVM_NTSCD_H_\n#define DG_LEGACY_LLVM_NTSCD_H_\n\n#include <llvm/IR/Module.h>\n\n#include \"GraphBuilder.h\"\n#include \"dg/llvm/ControlDependence/ControlDependence.h\"\n#include \"dg/util/debug.h\"\n\n#include <map>\n#include <set>\n#include <unordered_map>\n\n#include \"Block.h\"\n\nnamespace llvm {\nclass Function;\n}\n\nnamespace dg {\n\nclass LLVMPointerAnalysis;\n\nnamespace llvmdg {\nnamespace legacy {\n\nclass NTSCD : public LLVMControlDependenceAnalysisImpl {\n  public:\n    using ValVec = LLVMControlDependenceAnalysis::ValVec;\n\n    struct NodeInfo {\n        bool visited = false;\n        bool red = false;\n        size_t outDegreeCounter = 0;\n    };\n\n    NTSCD(const llvm::Module *module,\n          const LLVMControlDependenceAnalysisOptions &opts = {},\n          LLVMPointerAnalysis *pointsToAnalysis = nullptr);\n\n    void dump(std::ostream &ostream) const;\n    void dumpDependencies(std::ostream &ostream) const;\n\n    const std::map<Block *, std::set<Block *>> &controlDependencies() const {\n        return controlDependency;\n    }\n\n    /// Getters of dependencies for a value\n    ValVec getDependencies(const llvm::Instruction * /*unused*/) override {\n        return {};\n    }\n    ValVec getDependent(const llvm::Instruction * /*unused*/) override {\n        return {};\n    }\n\n    /// Getters of dependencies for a basic block\n    ValVec getDependencies(const llvm::BasicBlock *b) override {\n        if (_computed.insert(b->getParent()).second) {\n            /// FIXME: get rid of the const cast\n            computeOnDemand(const_cast<llvm::Function *>(b->getParent()));\n        }\n\n        const auto *block = graphBuilder.mapBlock(b);\n        if (!block) {\n            return {};\n        }\n        auto it = revControlDependency.find(block->front());\n        if (it == revControlDependency.end())\n            return {};\n\n        std::set<llvm::Value *> ret;\n        for (auto *dep : it->second) {\n            assert(dep->llvmBlock() && \"Do not have LLVM block\");\n            ret.insert(const_cast<llvm::BasicBlock *>(dep->llvmBlock()));\n        }\n\n        return ValVec{ret.begin(), ret.end()};\n    }\n\n    ValVec getDependent(const llvm::BasicBlock * /*unused*/) override {\n        assert(false && \"Not supported\");\n        abort();\n    }\n\n    // We run on demand. However, you may use manually computeDependencies()\n    // to compute all dependencies in the interprocedural CFG.\n    void compute(const llvm::Function *F = nullptr) override {\n        DBG(cda, \"Triggering computation of all dependencies\");\n        if (F && !F->isDeclaration() && _computed.insert(F).second) {\n            computeOnDemand(const_cast<llvm::Function *>(F));\n        } else {\n            for (const auto &f : *getModule()) {\n                if (!f.isDeclaration() && _computed.insert(&f).second) {\n                    computeOnDemand(const_cast<llvm::Function *>(&f));\n                }\n            }\n        }\n    }\n\n    // Compute dependencies for the whole ICFG (used in legacy code)\n    void computeDependencies();\n\n  private:\n    GraphBuilder graphBuilder;\n\n    // forward edges (from branchings to dependent blocks)\n    std::map<Block *, std::set<Block *>> controlDependency;\n    // reverse edges (from dependent blocks to branchings)\n    std::map<Block *, std::set<Block *>> revControlDependency;\n    std::unordered_map<Block *, NodeInfo> nodeInfo;\n    std::set<const llvm::Function *> _computed; // for on-demand\n\n    void computeDependencies(Function * /*function*/);\n    void computeOnDemand(llvm::Function *F);\n\n    void computeInterprocDependencies(Function *function);\n    void computeIntraprocDependencies(Function *function);\n\n    // a is CD on b\n    void addControlDependence(Block *a, Block *b);\n\n    void visitInitialNode(Block *node);\n    void visit(Block *node);\n\n    bool hasRedAndNonRedSuccessor(Block *node);\n};\n\n} // namespace legacy\n} // namespace llvmdg\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/llvm/ControlDependence/legacy/TarjanAnalysis.h",
    "content": "#ifndef DG_LEGACY_NTSCD_TARJANANALYSIS_H\n#define DG_LEGACY_NTSCD_TARJANANALYSIS_H\n\n#include <algorithm>\n#include <queue>\n#include <set>\n#include <stack>\n#include <unordered_map>\n#include <unordered_set>\n#include <vector>\n\nnamespace dg {\nnamespace llvmdg {\nnamespace legacy {\n\n// FIXME: we've got this and SCC, unify it\ntemplate <typename T>\nclass TarjanAnalysis {\n  public:\n    class StronglyConnectedComponent {\n      private:\n        static int idCounter;\n\n      public:\n        StronglyConnectedComponent() : id_(++idCounter) {}\n\n        void addNode(T *node) { nodes_.push_back(node); }\n\n        bool addSuccessor(StronglyConnectedComponent *successor) {\n            if (!successor) {\n                return false;\n            }\n            successors_.insert(successor);\n            return successor->predecessors_.insert(this).second;\n        }\n\n        bool addPredecessor(StronglyConnectedComponent *predecessor) {\n            if (!predecessor) {\n                return false;\n            }\n            predecessors_.insert(predecessor);\n            return predecessor->successors_.insert(this).second;\n        }\n\n        int id() const { return id_; }\n\n        const std::vector<T *> &nodes() const { return nodes_; }\n\n        const std::set<StronglyConnectedComponent *> &predecessors() const {\n            return predecessors_;\n        }\n\n        const std::set<StronglyConnectedComponent *> &successors() const {\n            return successors_;\n        }\n\n      private:\n        int id_;\n        std::vector<T *> nodes_;\n        std::set<StronglyConnectedComponent *> successors_;\n        std::set<StronglyConnectedComponent *> predecessors_;\n    };\n\n    // this we have to remember for each node\n    struct Node {\n        int dfsId{0};\n        int lowLink{0};\n        bool onStack{false};\n        StronglyConnectedComponent *component{nullptr};\n    };\n\n    TarjanAnalysis(std::size_t size = 0) : nodeInfo(size) {}\n\n    ~TarjanAnalysis() {\n        for (auto component : components_) {\n            delete component;\n        }\n    }\n\n    void compute(T *currentNode) {\n        ++index;\n        nodeInfo[currentNode].dfsId = index;\n        nodeInfo[currentNode].lowLink = index;\n\n        stack.push(currentNode);\n        nodeInfo[currentNode].onStack = true;\n\n        for (auto *successor : currentNode->successors()) {\n            if (!visited(successor)) {\n                compute(successor);\n                nodeInfo[currentNode].lowLink =\n                        std::min(nodeInfo[currentNode].lowLink,\n                                 nodeInfo[successor].lowLink);\n            } else if (nodeInfo[successor].onStack) {\n                nodeInfo[currentNode].lowLink =\n                        std::min(nodeInfo[currentNode].lowLink,\n                                 nodeInfo[successor].dfsId);\n            }\n        }\n\n        if (nodeInfo[currentNode].lowLink == nodeInfo[currentNode].dfsId) {\n            auto component = new StronglyConnectedComponent();\n            components_.insert(component);\n\n            T *node;\n            while (nodeInfo[stack.top()].dfsId >= nodeInfo[currentNode].dfsId) {\n                node = stack.top();\n                stack.pop();\n                nodeInfo[node].onStack = false;\n                component->addNode(node);\n                nodeInfo[node].component = component;\n\n                if (stack.empty()) {\n                    break;\n                }\n            }\n        }\n    }\n\n    void computeCondensation() {\n        for (auto component : components_) {\n            for (auto *node : component->nodes()) {\n                for (auto *successor : node->successors()) {\n                    if (nodeInfo[node].component !=\n                        nodeInfo[successor].component) {\n                        nodeInfo[node].component->addSuccessor(\n                                nodeInfo[successor].component);\n                    }\n                }\n            }\n        }\n    }\n\n    std::set<StronglyConnectedComponent *>\n    computeBackWardReachability(T *node) {\n        std::set<StronglyConnectedComponent *> visitedComponents;\n        std::queue<StronglyConnectedComponent *> queue;\n\n        auto iterator = nodeInfo.find(node);\n        if (iterator == nodeInfo.end()) {\n            return visitedComponents;\n        }\n        auto initialComponent = iterator.second;\n        visitedComponents.insert(initialComponent);\n        queue.push(initialComponent);\n\n        while (!queue.empty()) {\n            auto component = queue.front();\n            queue.pop();\n            for (auto predecessor : component->predecessors()) {\n                if (visitedComponents.find(predecessor) ==\n                    visitedComponents.end()) {\n                    visitedComponents.insert(predecessor);\n                    queue.push(predecessor);\n                }\n            }\n        }\n        return visitedComponents;\n    }\n\n    const std::set<StronglyConnectedComponent *> &components() const {\n        return components_;\n    }\n\n  private:\n    int index{0};\n\n    std::stack<T *> stack;\n\n    std::unordered_map<T *, Node> nodeInfo;\n\n    std::set<StronglyConnectedComponent *> components_;\n\n    bool visited(T *node) { return nodeInfo[node].dfsId > 0; }\n};\n\ntemplate <typename T>\nint TarjanAnalysis<T>::StronglyConnectedComponent::idCounter = 0;\n\n} // namespace legacy\n} // namespace llvmdg\n} // namespace dg\n\n#endif // DG_LLVM_TARJANANALYSIS_H\n"
  },
  {
    "path": "lib/llvm/DataDependenceAnalysis/LLVMDataDependenceAnalysis.cpp",
    "content": "#include <llvm/IR/GlobalVariable.h>\n\n#include \"dg/llvm/DataDependence/DataDependence.h\"\n#include \"llvm/ReadWriteGraph/LLVMReadWriteGraphBuilder.h\"\n\nnamespace dg {\nnamespace dda {\n\nLLVMDataDependenceAnalysis::~LLVMDataDependenceAnalysis() { delete builder; }\n\nLLVMReadWriteGraphBuilder *LLVMDataDependenceAnalysis::createBuilder() {\n    assert(m && pta);\n    return new LLVMReadWriteGraphBuilder(m, pta, _options);\n}\n\nDataDependenceAnalysis *LLVMDataDependenceAnalysis::createDDA() {\n    assert(builder);\n\n    // let the compiler do copy-ellision\n    auto graph = builder->build();\n    return new DataDependenceAnalysis(std::move(graph), _options);\n}\n\nRWNode *LLVMDataDependenceAnalysis::getNode(const llvm::Value *val) {\n    return builder->getNode(val);\n}\n\nconst RWNode *\nLLVMDataDependenceAnalysis::getNode(const llvm::Value *val) const {\n    return builder->getNode(val);\n}\n\nconst llvm::Value *\nLLVMDataDependenceAnalysis::getValue(const RWNode *node) const {\n    return builder->getValue(node);\n}\n\nstd::vector<llvm::Value *> LLVMDataDependenceAnalysis::getLLVMDefinitions(\n        llvm::Instruction *where, llvm::Value *mem, const Offset &off,\n        const Offset &len) {\n    std::vector<llvm::Value *> defs;\n\n    auto *whereN = getNode(where);\n    if (!whereN) {\n        llvm::errs() << \"[DDA] error: no node for: \" << *where << \"\\n\";\n        return defs;\n    }\n\n    auto *memN = getNode(mem);\n    if (!memN) {\n        llvm::errs() << \"[DDA] error: no node for: \" << *mem << \"\\n\";\n        return defs;\n    }\n\n    auto rdDefs = getDefinitions(whereN, memN, off, len);\n#ifndef NDEBUG\n    if (rdDefs.empty()) {\n        auto *GV = llvm::dyn_cast<llvm::GlobalVariable>(mem);\n        if (!GV || GV->isExternallyInitialized()) {\n            // the memory is global and initialised, no need to worry\n            static std::set<std::pair<const llvm::Value *, const llvm::Value *>>\n                    reported;\n            if (reported.insert({where, mem}).second) {\n                llvm::errs() << \"[DDA] warn: no definition for: \" << *mem\n                             << \"at \" << *where << \"\\n\";\n            }\n        }\n    }\n#endif // NDEBUG\n\n    // map the values\n    for (RWNode *nd : rdDefs) {\n        assert(nd->getType() != RWNodeType::PHI);\n        auto *llvmvalue = nd->getUserData<llvm::Value>();\n        assert(llvmvalue && \"RWG node has no value\");\n        defs.push_back(llvmvalue);\n    }\n\n    return defs;\n}\n\n// the value 'use' must be an instruction that reads from memory\nstd::vector<llvm::Value *>\nLLVMDataDependenceAnalysis::getLLVMDefinitions(llvm::Value *use) {\n    std::vector<llvm::Value *> defs;\n\n    auto *loc = getNode(use);\n    if (!loc) {\n        llvm::errs() << \"[DDA] error: no node for: \" << *use << \"\\n\";\n        return defs;\n    }\n\n    if (loc->getUses().empty()) {\n        llvm::errs() << \"[DDA] error: the queried value has empty uses: \"\n                     << *use << \"\\n\";\n        return defs;\n    }\n\n    if (!llvm::isa<llvm::LoadInst>(use) && !llvm::isa<llvm::CallInst>(use)) {\n        llvm::errs() << \"[DDA] error: the queried value is not a use: \" << *use\n                     << \"\\n\";\n    }\n\n    auto rdDefs = getDefinitions(loc);\n#ifndef NDEBUG\n    if (rdDefs.empty()) {\n        if (!loc->usesOnlyGlobals()) {\n            static std::set<const llvm::Value *> reported;\n            if (reported.insert(use).second) {\n                llvm::errs()\n                        << \"[DDA] warn: no definitions for: \" << *use << \"\\n\";\n            }\n        }\n    }\n#endif // NDEBUG\n\n    // map the values\n    for (RWNode *nd : rdDefs) {\n        assert(nd->getType() != RWNodeType::PHI);\n        const auto *llvmvalue = getValue(nd);\n        assert(llvmvalue && \"Have no value for a node\");\n        defs.push_back(const_cast<llvm::Value *>(llvmvalue));\n    }\n\n    return defs;\n}\n\n} // namespace dda\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/DefUse/DefUse.cpp",
    "content": "#include <map>\n\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/DataLayout.h>\n#include <llvm/IR/GlobalVariable.h>\n#include <llvm/IR/Instruction.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/IntrinsicInst.h>\n#include <llvm/IR/Module.h>\n#include <llvm/IR/Value.h>\n#include <llvm/Support/raw_ostream.h>\n\n#include \"dg/DFS.h\"\n\n#include \"dg/llvm/DataDependence/DataDependence.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n\n#include \"dg/llvm/LLVMDependenceGraph.h\"\n#include \"dg/llvm/LLVMNode.h\"\n\n#include \"llvm/llvm-utils.h\"\n\n#include \"DefUse.h\"\n\nusing namespace llvm;\n\n/// --------------------------------------------------\n//   Add def-use edges\n/// --------------------------------------------------\nnamespace dg {\n\n/// Add def-use edges between instruction and its operands\nstatic void handleOperands(const Instruction *Inst, LLVMNode *node) {\n    LLVMDependenceGraph *dg = node->getDG();\n    assert(Inst == node->getKey());\n\n    for (auto I = Inst->op_begin(), E = Inst->op_end(); I != E; ++I) {\n        auto *op = dg->getNode(*I);\n        if (!op)\n            continue;\n        const auto &subs = op->getSubgraphs();\n        if (!subs.empty() && !op->isVoidTy()) {\n            for (auto *s : subs) {\n                s->getExit()->addDataDependence(node);\n            }\n        }\n        // 'node' uses 'op', so we want to add edge 'op'-->'node',\n        // that is, 'op' is used in 'node' ('node' is a user of 'op')\n        op->addUseDependence(node);\n    }\n}\n\nLLVMDefUseAnalysis::LLVMDefUseAnalysis(LLVMDependenceGraph *dg,\n                                       LLVMDataDependenceAnalysis *rd,\n                                       LLVMPointerAnalysis *pta)\n        : legacy::DataFlowAnalysis<LLVMNode>(dg->getEntryBB(),\n                                             legacy::DATAFLOW_INTERPROCEDURAL),\n          dg(dg), RD(rd), PTA(pta), DL(new DataLayout(dg->getModule())) {\n    assert(PTA && \"Need points-to information\");\n    assert(RD && \"Need reaching definitions\");\n}\n\nvoid LLVMDefUseAnalysis::addDataDependencies(LLVMNode *node) {\n    static std::set<const llvm::Value *> reported_mappings;\n\n    auto *val = node->getValue();\n    auto defs = RD->getLLVMDefinitions(val);\n\n    // add data dependence\n    for (auto *def : defs) {\n        LLVMNode *rdnode = dg->getNode(def);\n        if (!rdnode) {\n            // that means that the value is not from this graph.\n            // We need to add interprocedural edge\n            llvm::Function *F = llvm::cast<llvm::Instruction>(def)\n                                        ->getParent()\n                                        ->getParent();\n            LLVMNode *entryNode = dg->getGlobalNode(F);\n            assert(entryNode && \"Don't have built function\");\n\n            // get the graph where the node lives\n            LLVMDependenceGraph *graph = entryNode->getDG();\n            assert(graph != dg && \"Cannot find a node\");\n            rdnode = graph->getNode(def);\n            if (!rdnode) {\n                llvmutils::printerr(\"[DU] error: DG doesn't have val: \", def);\n                abort();\n                return;\n            }\n        }\n\n        assert(rdnode);\n        rdnode->addDataDependence(node);\n    }\n}\n\nbool LLVMDefUseAnalysis::runOnNode(LLVMNode *node, LLVMNode * /*prev*/) {\n    Value *val = node->getKey();\n\n    // just add direct def-use edges to every instruction\n    if (auto *I = dyn_cast<Instruction>(val))\n        handleOperands(I, node);\n\n    if (RD->isUse(val)) {\n        addDataDependencies(node);\n    }\n\n    // we will run only once\n    return false;\n}\n\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/DefUse/DefUse.h",
    "content": "#ifndef LLVM_DEF_USE_ANALYSIS_H_\n#define LLVM_DEF_USE_ANALYSIS_H_\n\n#include <vector>\n\n#include <llvm/IR/DataLayout.h>\n#include <llvm/IR/Instruction.h>\n#include <llvm/IR/Instructions.h>\n\n#include \"dg/legacy/DataFlowAnalysis.h\"\n#include \"dg/llvm/DataDependence/DataDependence.h\"\n\nusing dg::dda::LLVMDataDependenceAnalysis;\n\nnamespace llvm {\nclass DataLayout;\nclass ConstantExpr;\n}; // namespace llvm\n\nnamespace dg {\n\nclass LLVMDependenceGraph;\nclass LLVMNode;\n\nclass LLVMDefUseAnalysis : public legacy::DataFlowAnalysis<LLVMNode> {\n    LLVMDependenceGraph *dg;\n    LLVMDataDependenceAnalysis *RD;\n    LLVMPointerAnalysis *PTA;\n    const llvm::DataLayout *DL;\n\n  public:\n    LLVMDefUseAnalysis(LLVMDependenceGraph *dg, LLVMDataDependenceAnalysis *rd,\n                       LLVMPointerAnalysis *pta);\n\n    ~LLVMDefUseAnalysis() { delete DL; }\n\n    /* virtual */\n    bool runOnNode(LLVMNode *node, LLVMNode *prev) override;\n\n  private:\n    void addDataDependencies(LLVMNode *node);\n\n    void handleLoadInst(llvm::LoadInst *, LLVMNode *);\n    void handleCallInst(LLVMNode *);\n    void handleInlineAsm(LLVMNode *callNode);\n    void handleIntrinsicCall(LLVMNode *callNode, llvm::CallInst *CI);\n    void handleUndefinedCall(LLVMNode *callNode, llvm::CallInst *CI);\n};\n\n} // namespace dg\n\n#endif //  LLVM_DEF_USE_ANALYSIS_H_\n"
  },
  {
    "path": "lib/llvm/Dominators/PostDominators.cpp",
    "content": "#include <llvm/Analysis/PostDominators.h>\n#include <llvm/IR/Function.h>\n\n#include \"dg/BFS.h\"\n#include \"dg/Dominators/PostDominanceFrontiers.h\"\n\n#include \"dg/llvm/LLVMDependenceGraph.h\"\n#include \"dg/util/debug.h\"\n\nnamespace dg {\n\nvoid LLVMDependenceGraph::computePostDominators(bool addPostDomFrontiers) {\n    DBG_SECTION_BEGIN(llvmdg,\n                      \"Computing post-dominator frontiers (control deps.)\");\n    using namespace llvm;\n    // iterate over all functions\n    for (const auto &F : getConstructedFunctions()) {\n        legacy::PostDominanceFrontiers<LLVMNode, LLVMBBlock> pdfrontiers;\n\n        // root of post-dominator tree\n        LLVMBBlock *root = nullptr;\n        Value *val = const_cast<Value *>(F.first);\n        Function &f = *cast<Function>(val);\n        PostDominatorTree *pdtree;\n\n        DBG_SECTION_BEGIN(llvmdg,\n                          \"Computing control deps. for \" << f.getName().str());\n\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 9))\n        pdtree = new PostDominatorTree();\n        // compute post-dominator tree for this function\n        pdtree->runOnFunction(f);\n#else\n        PostDominatorTreeWrapperPass wrapper;\n        wrapper.runOnFunction(f);\n        pdtree = &wrapper.getPostDomTree();\n#ifndef NDEBUG\n        wrapper.verifyAnalysis();\n#endif\n#endif\n\n        // add immediate post-dominator edges\n        auto &our_blocks = F.second->getBlocks();\n        bool built = false;\n        for (auto &it : our_blocks) {\n            LLVMBBlock *BB = it.second;\n            BasicBlock *B = cast<BasicBlock>(const_cast<Value *>(it.first));\n            DomTreeNode *N = pdtree->getNode(B);\n            // when function contains infinite loop, we're screwed\n            // and we don't have anything\n            // FIXME: just check for the root,\n            // don't iterate over all blocks, stupid...\n            if (!N)\n                continue;\n\n            DomTreeNode *idom = N->getIDom();\n            BasicBlock *idomBB = idom ? idom->getBlock() : nullptr;\n            built = true;\n\n            if (idomBB) {\n                LLVMBBlock *pb = our_blocks[idomBB];\n                assert(pb && \"Do not have constructed BB\");\n                BB->setIPostDom(pb);\n                assert(cast<BasicBlock>(BB->getKey())->getParent() ==\n                               cast<BasicBlock>(pb->getKey())->getParent() &&\n                       \"BBs are from diferent functions\");\n                // if we do not have idomBB, then the idomBB is a root BB\n            } else {\n                // PostDominatorTree may has special root without BB set\n                // or it is the node without immediate post-dominator\n                if (!root) {\n                    root = new LLVMBBlock();\n                    root->setKey(nullptr);\n                    F.second->setPostDominatorTreeRoot(root);\n                }\n\n                BB->setIPostDom(root);\n            }\n        }\n\n        // well, if we haven't built the pdtree, this is probably infinite loop\n        // that has no pdtree. Until we have anything better, just add sound\n        // control edges that are not so precise - to predecessors.\n        if (!built && addPostDomFrontiers) {\n            for (auto &it : our_blocks) {\n                LLVMBBlock *BB = it.second;\n                for (const LLVMBBlock::BBlockEdge &succ : BB->successors()) {\n                    // in this case we add only the control dependencies,\n                    // since we have no pd frontiers\n                    BB->addControlDependence(succ.target);\n                }\n            }\n        }\n\n        if (addPostDomFrontiers) {\n            // assert(root && \"BUG: must have root\");\n            if (root)\n                pdfrontiers.compute(root,\n                                    true /* store also control depend. */);\n        }\n\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 9))\n        delete pdtree;\n#endif\n        DBG_SECTION_END(llvmdg, \"Done computing control deps. for \"\n                                        << f.getName().str());\n    }\n    DBG_SECTION_END(llvmdg,\n                    \"Done computing post-dominator frontiers (control deps.)\");\n}\n\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ForkJoin/ForkJoin.cpp",
    "content": "#include <cassert>\n\n#include \"ForkJoin.h\"\n\nnamespace dg {\n\nstd::vector<const llvm::Value *>\nForkJoinAnalysis::matchJoin(const llvm::Value *joinVal) {\n    using namespace llvm;\n\n    if (_PTA->getOptions().isSVF()) {\n        errs() << \"ForkJoin analysis does not support SVF yet\\n\";\n        abort();\n    }\n\n    auto *dgPTA = static_cast<DGLLVMPointerAnalysis *>(_PTA);\n    std::vector<const llvm::Value *> threads;\n\n    auto *const builder = dgPTA->getBuilder();\n    const auto *const joinCall = cast<CallInst>(joinVal);\n    auto *const joinNode = builder->findJoin(joinCall);\n    for (auto *const forkNode : joinNode->forks()) {\n        auto *const llvmcall = forkNode->callInst()->getUserData<llvm::Value>();\n        assert(isa<CallInst>(llvmcall));\n        threads.push_back(llvmcall);\n    }\n\n    return threads;\n\n    // const auto calledVal = joinCall->getCalledValue();\n    // if (const auto joinF = dyn_cast<Function>(calledVal)) {\n    //    assert(joinF->getName().equals(\"pthread_join\")\n    //            && \"Invalid function taken as pthread join\");\n\n    //} else {\n    //    errs() << \"Join via function call not implemented yet\\n\";\n    //    abort();\n    //}\n}\n\nstd::vector<const llvm::Value *>\nForkJoinAnalysis::joinFunctions(const llvm::Value *joinVal) {\n    using namespace llvm;\n\n    if (_PTA->getOptions().isSVF()) {\n        errs() << \"ForkJoin analysis does not support SVF yet\\n\";\n        abort();\n    }\n\n    auto *dgPTA = static_cast<DGLLVMPointerAnalysis *>(_PTA);\n    std::vector<const llvm::Value *> threads;\n\n    auto *const builder = dgPTA->getBuilder();\n    const auto *const joinCall = cast<CallInst>(joinVal);\n    auto *const joinNode = builder->findJoin(joinCall);\n    for (auto *const function : joinNode->functions()) {\n        auto *const llvmFunction = function->getUserData<llvm::Value>();\n        assert(isa<Function>(llvmFunction));\n        threads.push_back(llvmFunction);\n    }\n\n    return threads;\n}\n\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ForkJoin/ForkJoin.h",
    "content": "#ifndef DG_FORK_JOIN_ANALYSIS_H_\n#define DG_FORK_JOIN_ANALYSIS_H_\n\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n\nnamespace dg {\n\n///\n// Analyse which functions are spawned by threads\n// and which threads are joined by joins.\nclass ForkJoinAnalysis {\n    LLVMPointerAnalysis *_PTA{nullptr};\n    // const llvm::Module *_M{nullptr};\n\n  public:\n    ForkJoinAnalysis( // const llvm::Module *M,\n            LLVMPointerAnalysis *PTA)\n            : _PTA(PTA) /*, _M(M)*/ {};\n\n    /// Take llvm::Value which is a call to pthread_join\n    //  and return a vector of values that (may) spawn a thread\n    //  that may be joined by this join.\n    std::vector<const llvm::Value *> matchJoin(const llvm::Value * /*joinVal*/);\n\n    /// Take llvm::Value which is a call to pthread_join\n    //  and return a vector of functions that may have been joined\n    //  by this join.\n    std::vector<const llvm::Value *>\n    joinFunctions(const llvm::Value * /*joinVal*/);\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/llvm/GraphBuilder.h",
    "content": "#ifndef DG_GRAPHBUILDER_H_\n#define DG_GRAPHBUILDER_H_\n\n#include <llvm/IR/CFG.h>\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#include \"dg/ADT/SetQueue.h\"\n#include \"dg/llvm/CallGraph/CallGraph.h\"\n\nnamespace dg {\n\ntemplate <typename NodeT>\nclass NodesSeq {\n    // we can optimize this later...\n    std::vector<NodeT *> nodes;\n    NodeT *representant{nullptr};\n\n  public:\n    NodesSeq(const std::initializer_list<NodeT *> &lst) {\n        if (lst.size() > 0) {\n            nodes.insert(nodes.end(), lst.begin(), lst.end());\n            representant = *lst.begin();\n        }\n    }\n\n    NodesSeq(NodesSeq &&) = default;\n    NodesSeq(const NodesSeq &) = default;\n\n    NodeT *setRepresentant(NodeT *r) { representant = r; }\n\n    NodeT *getRepresentant() const { return representant; }\n\n    bool empty() const { return nodes.empty(); }\n\n    auto begin() -> decltype(nodes.begin()) { return nodes.begin(); }\n    auto end() -> decltype(nodes.end()) { return nodes.end(); }\n    auto begin() const -> decltype(nodes.begin()) { return nodes.begin(); }\n    auto end() const -> decltype(nodes.end()) { return nodes.end(); }\n};\n\ntemplate <typename NodeT, typename BBlockT, typename SubgraphT>\nclass GraphBuilder {\n    struct SubgraphInfo {\n        using BlocksMappingT =\n                std::unordered_map<const llvm::BasicBlock *, BBlockT *>;\n\n        SubgraphT &subgraph;\n        BlocksMappingT blocks{};\n\n        SubgraphInfo(SubgraphT &s) : subgraph(s) {}\n        SubgraphInfo(SubgraphInfo &&) = default;\n        SubgraphInfo(const SubgraphInfo &) = delete;\n    };\n\n    using GlobalsT = std::vector<NodeT *>;\n    using NodesMappingT =\n            std::unordered_map<const llvm::Value *, NodesSeq<NodeT>>;\n    using ValuesMappingT =\n            std::unordered_map<const NodeT *, const llvm::Value *>;\n    using SubgraphsMappingT =\n            std::unordered_map<const llvm::Function *, SubgraphInfo>;\n\n    const llvm::Module *_module;\n\n    SubgraphsMappingT _subgraphs;\n    NodesMappingT _nodes;\n    ValuesMappingT _nodeToValue;\n    GlobalsT _globals;\n\n    void buildCFG(SubgraphInfo &subginfo) {\n        for (auto &it : subginfo.blocks) {\n            auto llvmblk = it.first;\n            auto *bblock = it.second;\n\n            for (auto *succ : successors(llvmblk)) {\n                auto succit = subginfo.blocks.find(succ);\n                assert((succit != subginfo.blocks.end()) &&\n                       \"Do not have the block built\");\n\n                bblock->addSuccessor(succit->second);\n            }\n        }\n    }\n\n    void buildGlobals() {\n        DBG_SECTION_BEGIN(dg, \"Building globals\");\n\n        for (const auto &G : _module->globals()) {\n            // every global node is like memory allocation\n            auto cur = buildNode(&G);\n            _globals.insert(_globals.end(), cur.begin(), cur.end());\n        }\n\n        DBG_SECTION_END(dg, \"Building globals done\");\n    }\n\n  protected:\n    NodesSeq<NodeT> buildNode(const llvm::Value *val) {\n        auto it = _nodes.find(val);\n        if (it != _nodes.end()) {\n            return it->second;\n        }\n\n        const auto &nds = createNode(val);\n        assert((nds.getRepresentant() || nds.empty()) &&\n               \"Built node sequence has no representant\");\n\n        if (auto *repr = nds.getRepresentant()) {\n            _nodes.emplace(val, nds);\n\n            assert((_nodeToValue.find(repr) == _nodeToValue.end()) &&\n                   \"Mapping a node that we already have\");\n            _nodeToValue[repr] = val;\n        }\n\n        return nds;\n    }\n\n    BBlockT &buildBBlock(const llvm::BasicBlock &B, SubgraphInfo &subginfo) {\n        auto &bblock = createBBlock(&B, subginfo.subgraph);\n        assert(subginfo.blocks.find(&B) == subginfo.blocks.end() &&\n               \"Already have this basic block\");\n        subginfo.blocks[&B] = &bblock;\n\n        for (const auto &I : B) {\n            for (auto *node : buildNode(&I)) {\n                bblock.append(node);\n            }\n        }\n\n        return bblock;\n    }\n\n    void buildSubgraph(const llvm::Function &F) {\n        using namespace llvm;\n\n        DBG_SECTION_BEGIN(dg,\n                          \"Building the subgraph for \" << F.getName().str());\n        auto subgit = _subgraphs.find(&F);\n        assert(subgit != _subgraphs.end() && \"Do not have that subgraph\");\n\n        auto &subginfo = subgit->second;\n\n        DBG(dg, \"Building basic blocks of \" << F.getName().str());\n        // do a walk through basic blocks such that all predecessors of\n        // a block are searched before the block itself\n        // (operands must be created before their use)\n        ADT::SetQueue<ADT::QueueFIFO<const llvm::BasicBlock *>> queue;\n        const auto &entry = F.getEntryBlock();\n        queue.push(&entry);\n\n        while (!queue.empty()) {\n            const auto *cur = queue.pop();\n\n            buildBBlock(*cur, subginfo);\n\n            for (const auto *succ : successors(cur)) {\n                queue.push(succ);\n            }\n        }\n\n        DBG(dg, \"Building CFG\");\n        buildCFG(subginfo);\n\n        DBG_SECTION_END(dg, \"Building the subgraph done\");\n    }\n\n    void buildAllFuns() {\n        DBG(dg, \"Building all functions from LLVM module\");\n        for (const auto &F : *_module) {\n            if (F.isDeclaration()) {\n                continue;\n            }\n            assert(_subgraphs.find(&F) == _subgraphs.end() &&\n                   \"Already have that subgraph\");\n            auto &subg = createSubgraph(&F);\n            _subgraphs.emplace(&F, subg);\n        }\n\n        // now do the real thing\n        for (const auto &F : *_module) {\n            if (!F.isDeclaration()) {\n                buildSubgraph(F);\n            }\n        }\n    }\n\n    void buildFunsFromCG(llvmdg::CallGraph *cg) {\n        const auto &funs = cg->functions();\n        // we should have at least the entry fun\n        assert(!funs.empty() && \"No function in call graph\");\n\n        for (const auto *F : funs) {\n            DBG(dg, \"Building functions based on call graph information\");\n            assert(_subgraphs.find(F) == _subgraphs.end() &&\n                   \"Already have that subgraph\");\n            auto &subg = createSubgraph(F);\n            _subgraphs.emplace(F, subg);\n        }\n\n        // now do the real thing\n        for (const auto *F : funs) {\n            if (!F->isDeclaration()) {\n                buildSubgraph(*F);\n            }\n        }\n    }\n\n  public:\n    GraphBuilder(const llvm::Module *m) : _module(m) {}\n    virtual ~GraphBuilder() = default;\n\n    const llvm::Module *getModule() const { return _module; }\n    const llvm::DataLayout *getDataLayout() const {\n        return &_module->getDataLayout();\n    }\n\n    const GlobalsT &getGlobals() const { return _globals; }\n\n    const NodesMappingT &getNodesMapping() const { return _nodes; }\n\n    const ValuesMappingT &getValuesMapping() const { return _nodeToValue; }\n\n    const SubgraphsMappingT &getSubgraphsMapping() const { return _subgraphs; }\n\n    NodeT *getNode(const llvm::Value *v) {\n        auto it = _nodes.find(v);\n        return it == _nodes.end() ? nullptr : it->second.getRepresentant();\n    }\n\n    const NodeT *getNode(const llvm::Value *v) const {\n        auto it = _nodes.find(v);\n        return it == _nodes.end() ? nullptr : it->second.getRepresentant();\n    }\n\n    const llvm::Value *getValue(const NodeT *n) const {\n        auto it = _nodeToValue.find(n);\n        return it == _nodeToValue.end() ? nullptr : it->second;\n    }\n\n    SubgraphT *getSubgraph(const llvm::Function *f) {\n        auto it = _subgraphs.find(f);\n        return it == _subgraphs.end() ? nullptr : &it->second.subgraph;\n    }\n\n    const SubgraphT *getSubgraph(const llvm::Function *f) const {\n        auto it = _subgraphs.find(f);\n        return it == _subgraphs.end() ? nullptr : &it->second.subgraph;\n    }\n\n    virtual NodesSeq<NodeT> createNode(const llvm::Value *) = 0;\n    virtual BBlockT &createBBlock(const llvm::BasicBlock *, SubgraphT &) = 0;\n    virtual SubgraphT &createSubgraph(const llvm::Function *) = 0;\n\n    void buildFromLLVM(llvmdg::CallGraph *cg = nullptr) {\n        assert(_module && \"Do not have the LLVM module\");\n\n        buildGlobals();\n\n        // create emtpy subgraphs for each procedure,\n        // so that calls can use them as operands\n\n        if (cg) {\n            buildFunsFromCG(cg);\n        } else {\n            buildAllFuns();\n        }\n    }\n};\n\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/llvm/LLVMDGVerifier.cpp",
    "content": "#include <cstdarg>\n#include <cstdio>\n\n#include <llvm/IR/Function.h>\n#include <llvm/IR/Value.h>\n#include <llvm/Support/raw_ostream.h>\n\n#include \"dg/llvm/LLVMDependenceGraph.h\"\n#include \"dg/llvm/LLVMNode.h\"\n#include \"llvm/LLVMDGVerifier.h\"\n\nnamespace dg {\n\nvoid LLVMDGVerifier::fault(const char *fmt, ...) {\n    va_list args;\n    va_start(args, fmt);\n    fprintf(stderr, \"ERR dg-verify: \");\n    vfprintf(stderr, fmt, args);\n    fputc('\\n', stderr);\n    va_end(args);\n\n    fflush(stderr);\n\n    ++faults;\n}\n\nbool LLVMDGVerifier::verify() {\n    checkMainProc();\n\n    extern std::map<llvm::Value *, LLVMDependenceGraph *> constructedFunctions;\n    for (auto &it : constructedFunctions)\n        checkGraph(llvm::cast<llvm::Function>(it.first), it.second);\n\n    fflush(stderr);\n    return faults == 0;\n}\n\nvoid LLVMDGVerifier::checkMainProc() {\n    if (!dg->module)\n        fault(\"has no module set\");\n\n    // all the subgraphs must have the same global nodes\n\n    for (const auto &it : getConstructedFunctions()) {\n        if (it.second->global_nodes != dg->global_nodes)\n            fault(\"subgraph has different global nodes than main proc\");\n    }\n}\n\nvoid LLVMDGVerifier::checkNode(const llvm::Value *val, LLVMNode *node) {\n    if (!node->getBBlock()) {\n        fault(\"node has no value set\");\n        llvm::errs() << \"  -> \" << *val << \"\\n\";\n    }\n\n    // FIXME if this is a call-size, check that the parameters match\n}\n\nvoid LLVMDGVerifier::checkBBlock(const llvm::BasicBlock *llvmBB,\n                                 LLVMBBlock *BB) {\n    using namespace llvm;\n    auto BBIT = BB->getNodes().begin();\n\n    for (const Instruction &I : *llvmBB) {\n        LLVMNode *node = *BBIT;\n\n        // check if we have the CFG edges set\n        if (node->getKey() != &I)\n            fault(\"wrong node in BB\");\n\n        checkNode(&I, node);\n        ++BBIT;\n    }\n\n    // FIXME: check successors and predecessors\n}\n\nvoid LLVMDGVerifier::checkGraph(llvm::Function *F, LLVMDependenceGraph *g) {\n    using namespace llvm;\n\n    LLVMNode *entry = g->getEntry();\n    if (!entry) {\n        fault(\"has no entry for %s\", F->getName().data());\n        return;\n    }\n\n    const llvm::Function *func = dyn_cast<Function>(entry->getKey());\n    if (!func) {\n        fault(\"key in entry node is not a llvm::Function\");\n        return;\n    }\n\n    size_t a, b;\n    a = g->getBlocks().size();\n    b = func->size();\n    if (a != b)\n        fault(\"have constructed %lu BBlocks but function has %lu basic blocks\",\n              a, b);\n\n    for (BasicBlock &llvmBB : *F) {\n        LLVMBBlock *BB = g->getBlocks()[&llvmBB];\n        if (!BB) {\n            fault(\"missing BasicBlock\");\n            errs() << llvmBB << \"\\n\";\n        } else\n            checkBBlock(&llvmBB, BB);\n    }\n}\n\n}; // namespace dg\n"
  },
  {
    "path": "lib/llvm/LLVMDGVerifier.h",
    "content": "#ifndef LLVM_DG_VERIFIER_H_\n#define LLVM_DG_VERIFIER_H_\n\n#include \"dg/llvm/LLVMDependenceGraph.h\"\n\nnamespace llvm {\nclass Function;\nclass BasicBlock;\n} // namespace llvm\n\nnamespace dg {\n\n// verify if the built dg is ok\n// this is friend class of LLVMDependenceGraph,\n// so we can do everything!\nclass LLVMDGVerifier {\n    const LLVMDependenceGraph *dg;\n    unsigned int faults;\n\n    void fault(const char *fmt, ...);\n    void checkMainProc();\n    void checkGraph(llvm::Function * /*F*/, LLVMDependenceGraph * /*g*/);\n    void checkBBlock(const llvm::BasicBlock * /*llvmBB*/, LLVMBBlock * /*BB*/);\n    void checkNode(const llvm::Value * /*val*/, LLVMNode * /*node*/);\n\n  public:\n    LLVMDGVerifier(const LLVMDependenceGraph *g) : dg(g), faults(0) {}\n    bool verify();\n};\n\n} // namespace dg\n\n#endif // LLVM_DG_VERIFIER_H_\n"
  },
  {
    "path": "lib/llvm/LLVMDependenceGraph.cpp",
    "content": "#include <set>\n#include <unordered_map>\n#include <utility>\n\n#include <llvm/Config/llvm-config.h>\n\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n#include <llvm/Support/CFG.h>\n#else\n#include <llvm/IR/CFG.h>\n#endif\n\n#include <llvm/IR/DataLayout.h>\n#include <llvm/IR/Function.h>\n#include <llvm/IR/InstIterator.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/Module.h>\n#include <llvm/IR/Value.h>\n#include <llvm/Support/raw_ostream.h>\n\n#include \"dg/llvm/LLVMDependenceGraph.h\"\n#include \"dg/llvm/LLVMNode.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n#include \"dg/llvm/ThreadRegions/ControlFlowGraph.h\"\n#include \"dg/llvm/ThreadRegions/MayHappenInParallel.h\"\n\n#include \"llvm/ControlDependence/InterproceduralCD.h\"\n#include \"llvm/ControlDependence/NTSCD.h\"\n#include \"llvm/ControlDependence/legacy/NTSCD.h\"\n\n#include \"dg/util/debug.h\"\n#include \"llvm-utils.h\"\n#include \"llvm/LLVMDGVerifier.h\"\n\n#include \"dg/ADT/Queue.h\"\n\n#include \"DefUse/DefUse.h\"\n\nusing llvm::errs;\nusing std::make_pair;\n\nnamespace dg {\n\n/// ------------------------------------------------------------------\n//  -- LLVMDependenceGraph\n/// ------------------------------------------------------------------\n\n// map of all constructed functions\nstd::map<llvm::Value *, LLVMDependenceGraph *> constructedFunctions;\n\nconst std::map<llvm::Value *, LLVMDependenceGraph *> &\ngetConstructedFunctions() {\n    return constructedFunctions;\n}\n\nLLVMDependenceGraph::~LLVMDependenceGraph() {\n    // delete nodes\n    for (auto &I : *this) {\n        LLVMNode *node = I.second;\n\n        if (node) {\n            for (LLVMDependenceGraph *subgraph : node->getSubgraphs()) {\n                // graphs are referenced, once the refcount is 0\n                // the graph will be deleted\n                // Because of recursive calls, graph can be its\n                // own subgraph. In that case we're in the destructor\n                // already, so do not delete it\n                subgraph->unref(subgraph != this);\n            }\n\n            // delete parameters (on null it is no op)\n            delete node->getParameters();\n\n#ifdef DEBUG_ENABLED\n            if (!node->getBBlock() && !llvm::isa<llvm::Function>(*I.first))\n                llvmutils::printerr(\"Had no BB assigned\", I.first);\n#endif\n\n            delete node;\n        } else {\n#ifdef DEBUG_ENABLED\n            llvmutils::printerr(\"Had no node assigned\", I.first);\n#endif //\n        }\n    }\n\n    // delete global nodes if this is the last graph holding them\n    if (global_nodes && global_nodes.use_count() == 1) {\n        for (auto &it : *global_nodes)\n            delete it.second;\n    }\n\n    // delete formal parameters\n    delete getParameters();\n\n    // delete post-dominator tree root\n    delete getPostDominatorTreeRoot();\n}\n\nstatic void addGlobals(llvm::Module *m, LLVMDependenceGraph *dg) {\n    DBG_SECTION_BEGIN(llvmdg, \"Building globals\");\n    // create a container for globals,\n    // it will be inherited to subgraphs\n    dg->allocateGlobalNodes();\n\n    for (auto I = m->global_begin(), E = m->global_end(); I != E; ++I)\n        dg->addGlobalNode(new LLVMNode(&*I));\n    DBG_SECTION_END(llvmdg, \"Done building globals\");\n}\n\nbool LLVMDependenceGraph::verify() const {\n    LLVMDGVerifier verifier(this);\n    return verifier.verify();\n}\n\nvoid LLVMDependenceGraph::setThreads(bool threads) { this->threads = threads; }\n\nLLVMNode *LLVMDependenceGraph::findNode(llvm::Value *value) const {\n    auto iterator = nodes.find(value);\n    if (iterator != nodes.end()) {\n        return iterator->second;\n    }\n    return nullptr;\n}\n\nbool LLVMDependenceGraph::build(llvm::Module *m, llvm::Function *entry) {\n    DBG_SECTION_BEGIN(llvmdg, \"Building dependence graphs for the module\");\n    // get entry function if not given\n    if (entry)\n        entryFunction = entry;\n    else\n        entryFunction = m->getFunction(\"main\");\n\n    if (!entryFunction) {\n        errs() << \"No entry function found/given\\n\";\n        return false;\n    }\n\n    module = m;\n\n    // add global nodes. These will be shared across subgraphs\n    addGlobals(m, this);\n\n    // build recursively DG from entry point\n    build(entryFunction);\n\n    DBG_SECTION_END(llvmdg, \"Done building dependence graphs for the module\");\n    return true;\n};\n\nLLVMDependenceGraph *LLVMDependenceGraph::buildSubgraph(LLVMNode *node) {\n    using namespace llvm;\n\n    Value *val = node->getValue();\n    CallInst *CInst = dyn_cast<CallInst>(val);\n    assert(CInst && \"buildSubgraph called on non-CallInst\");\n    Function *callFunc = CInst->getCalledFunction();\n\n    return buildSubgraph(node, callFunc);\n}\n\n// FIXME don't duplicate the code\nbool LLVMDependenceGraph::addFormalGlobal(llvm::Value *val) {\n    // add the same formal parameters\n    LLVMDGParameters *params = getOrCreateParameters();\n    assert(params);\n\n    // if we have this value, just return\n    if (params->find(val))\n        return false;\n\n    LLVMNode *fpin, *fpout;\n    std::tie(fpin, fpout) = params->constructGlobal(val, val, this);\n    assert(fpin && fpout);\n    assert(fpin->getDG() == this && fpout->getDG() == this);\n\n    LLVMNode *entry = getEntry();\n    entry->addControlDependence(fpin);\n    entry->addControlDependence(fpout);\n\n    // if these are the formal parameters of the main\n    // function, add control dependence also between the\n    // global as the formal input parameter representing this global\n    if (llvm::Function *F = llvm::dyn_cast<llvm::Function>(entry->getValue())) {\n        if (F == entryFunction) {\n            auto *gnode = getGlobalNode(val);\n            assert(gnode);\n            gnode->addControlDependence(fpin);\n        }\n    }\n\n    return true;\n}\n\nstatic bool addSubgraphGlobParams(LLVMDependenceGraph *parentdg,\n                                  LLVMDGParameters *params) {\n    bool changed = false;\n    for (auto it = params->global_begin(), et = params->global_end(); it != et;\n         ++it)\n        changed |= parentdg->addFormalGlobal(it->first);\n\n    // and add heap-allocated variables\n    for (const auto &it : *params) {\n        if (llvm::isa<llvm::CallInst>(it.first))\n            changed |= parentdg->addFormalParameter(it.first);\n    }\n\n    return changed;\n}\n\nvoid LLVMDependenceGraph::addSubgraphGlobalParameters(\n        LLVMDependenceGraph *subgraph) {\n    LLVMDGParameters *params = subgraph->getParameters();\n    if (!params)\n        return;\n\n    // if we do not change anything, it means that the graph\n    // has these params already, and so must the callers of the graph\n    if (!addSubgraphGlobParams(this, params))\n        return;\n\n    // recursively add the formal parameters to all callers\n    for (LLVMNode *callsite : this->getCallers()) {\n        LLVMDependenceGraph *graph = callsite->getDG();\n        graph->addSubgraphGlobalParameters(this);\n\n        // update the actual parameters of the call-site\n        callsite->addActualParameters(this);\n    }\n}\n\nLLVMDependenceGraph *\nLLVMDependenceGraph::buildSubgraph(LLVMNode *node, llvm::Function *callFunc,\n                                   bool fork) {\n    using namespace llvm;\n\n    LLVMBBlock *BB;\n\n    // if we don't have this subgraph constructed, construct it\n    // else just add call edge\n    LLVMDependenceGraph *&subgraph = constructedFunctions[callFunc];\n    if (!subgraph) {\n        // since we have reference the the pointer in\n        // constructedFunctions, we can assing to it\n        subgraph = new LLVMDependenceGraph();\n        // set global nodes to this one, so that\n        // we'll share them\n        subgraph->setGlobalNodes(getGlobalNodes());\n        subgraph->module = module;\n        subgraph->PTA = PTA;\n        subgraph->threads = this->threads;\n        // make subgraphs gather the call-sites too\n        subgraph->gatherCallsites(gather_callsites, gatheredCallsites);\n\n        // make the real work\n#ifndef NDEBUG\n        bool ret =\n#endif\n                subgraph->build(callFunc);\n\n#ifndef NDEBUG\n        // at least for now use just assert, if we'll\n        // have a reason to handle such failures at some\n        // point, we can change it\n        assert(ret && \"Building subgraph failed\");\n#endif\n\n        // we built the subgraph, so it has refcount = 1,\n        // later in the code we call addSubgraph, which\n        // increases the refcount to 2, but we need this\n        // subgraph to has refcount 1, so unref it\n        subgraph->unref(false /* deleteOnZero */);\n    }\n\n    BB = node->getBBlock();\n    assert(BB && \"do not have BB; this is a bug, sir\");\n    BB->addCallsite(node);\n\n    // add control dependence from call node\n    // to entry node\n    node->addControlDependence(subgraph->getEntry());\n\n    // add globals that are used in subgraphs\n    // it is necessary if this subgraph was creating due to function\n    // pointer call\n    addSubgraphGlobalParameters(subgraph);\n    node->addActualParameters(subgraph, callFunc, fork);\n\n    if (auto *noret = subgraph->getNoReturn()) {\n        assert(node->getParameters()); // we created them a while ago\n        auto *actnoret = getOrCreateNoReturn(node);\n        noret->addControlDependence(actnoret);\n    }\n\n    return subgraph;\n}\n\nstatic bool is_func_defined(const llvm::Function *func) {\n    return !(!func || func->empty());\n}\n\nLLVMNode *LLVMDependenceGraph::getOrCreateNoReturn() {\n    // add the same formal parameters\n    LLVMDGParameters *params = getOrCreateParameters();\n    LLVMNode *noret = params->getNoReturn();\n    if (!noret) {\n        auto *UI = new llvm::UnreachableInst(getModule()->getContext());\n        noret = new LLVMNode(UI, true);\n        params->addNoReturn(noret);\n        auto *entry = getEntry();\n        assert(entry);\n        entry->addControlDependence(noret);\n    }\n    return noret;\n}\n\nLLVMNode *LLVMDependenceGraph::getOrCreateNoReturn(LLVMNode *call) {\n    LLVMDGParameters *params = call->getOrCreateParameters();\n    assert(params);\n\n    LLVMNode *noret = params->getNoReturn();\n    if (!noret) {\n        auto *UI = new llvm::UnreachableInst(getModule()->getContext());\n        noret = new LLVMNode(UI, true);\n        params->addNoReturn(noret);\n        // this edge is redundant...\n        call->addControlDependence(noret);\n    }\n    return noret;\n}\n\nLLVMDGParameters *LLVMDependenceGraph::getOrCreateParameters() {\n    LLVMDGParameters *params = getParameters();\n    if (!params) {\n        params = new LLVMDGParameters();\n        setParameters(params);\n    }\n\n    return params;\n}\n\nbool LLVMDependenceGraph::addFormalParameter(llvm::Value *val) {\n    // add the same formal parameters\n    LLVMDGParameters *params = getOrCreateParameters();\n\n    // if we have this value, just return\n    if (params->find(val))\n        return false;\n\n    LLVMNode *fpin, *fpout;\n    std::tie(fpin, fpout) = params->construct(val, val, this);\n    assert(fpin && fpout);\n    assert(fpin->getDG() == this && fpout->getDG() == this);\n\n    LLVMNode *entry = getEntry();\n    entry->addControlDependence(fpin);\n    entry->addControlDependence(fpout);\n\n    // if these are the formal parameters of the main\n    // function and val is a global variable,\n    // add control dependence also between the global\n    // and the formal input parameter representing this global\n    if (llvm::isa<llvm::GlobalVariable>(val)) {\n        if (llvm::Function *F =\n                    llvm::dyn_cast<llvm::Function>(entry->getValue())) {\n            if (F == entryFunction) {\n                auto *gnode = getGlobalNode(val);\n                assert(gnode);\n                gnode->addControlDependence(fpin);\n            }\n        }\n    }\n\n    return true;\n}\n\n// FIXME copied from PointsTo.cpp, don't duplicate,\n// add it to analysis generic\nstatic bool isMemAllocationFunc(const llvm::Function *func) {\n    if (!func || !func->hasName())\n        return false;\n\n    const llvm::StringRef &name = func->getName();\n    return name.equals(\"malloc\") || name.equals(\"calloc\") ||\n           name.equals(\"realloc\");\n}\n\nvoid LLVMDependenceGraph::handleInstruction(llvm::Value *val, LLVMNode *node,\n                                            LLVMNode *prevNode) {\n    using namespace llvm;\n\n    if (CallInst *CInst = dyn_cast<CallInst>(val)) {\n#if LLVM_VERSION_MAJOR >= 8\n        Value *strippedValue = CInst->getCalledOperand()->stripPointerCasts();\n#else\n        Value *strippedValue = CInst->getCalledValue()->stripPointerCasts();\n#endif\n        Function *func = dyn_cast<Function>(strippedValue);\n        // if func is nullptr, then this is indirect call\n        // via function pointer. If we have the points-to information,\n        // create the subgraph\n        if (!func && !CInst->isInlineAsm() && PTA) {\n            using namespace dg::pta;\n            auto pts = PTA->getLLVMPointsTo(strippedValue);\n            if (pts.empty()) {\n                llvmutils::printerr(\"Had no PTA node\", strippedValue);\n            }\n            for (const LLVMPointer &ptr : pts) {\n                // vararg may introduce imprecision here, so we\n                // must check that it is really pointer to a function\n                Function *F = dyn_cast<Function>(ptr.value);\n                if (!F)\n                    continue;\n\n                if (F->empty() || !llvmutils::callIsCompatible(F, CInst)) {\n                    if (threads && F && F->getName() == \"pthread_create\") {\n                        auto possibleFunctions = getCalledFunctions(\n                                CInst->getArgOperand(2), PTA);\n                        for (auto &function : possibleFunctions) {\n                            if (!function->empty()) {\n                                LLVMDependenceGraph *subg = buildSubgraph(\n                                        node,\n                                        const_cast<llvm::Function *>(function),\n                                        true /*this is fork*/);\n                                node->addSubgraph(subg);\n                            }\n                        }\n                    } else {\n                        // incompatible prototypes or the function\n                        // is only declaration\n                        continue;\n                    }\n                } else {\n                    LLVMDependenceGraph *subg = buildSubgraph(node, F);\n                    node->addSubgraph(subg);\n                }\n            }\n        }\n\n        if (func && gather_callsites &&\n            func->getName().equals(gather_callsites)) {\n            gatheredCallsites->insert(node);\n        }\n\n        if (is_func_defined(func)) {\n            LLVMDependenceGraph *subg = buildSubgraph(node, func);\n            node->addSubgraph(subg);\n        }\n\n        // if we allocate a memory in a function, we can pass\n        // it to other functions, so it is like global.\n        // We need it as parameter, so that if we define it,\n        // we can add def-use edges from parent, through the parameter\n        // to the definition\n        if (isMemAllocationFunc(CInst->getCalledFunction()))\n            addFormalParameter(val);\n\n        if (threads && func && func->getName() == \"pthread_create\") {\n            auto possibleFunctions =\n                    getCalledFunctions(CInst->getArgOperand(2), PTA);\n            for (auto &function : possibleFunctions) {\n                auto *subg = buildSubgraph(\n                        node, const_cast<llvm::Function *>(function),\n                        true /*this is fork*/);\n                node->addSubgraph(subg);\n            }\n        }\n\n        // no matter what is the function, this is a CallInst,\n        // so create call-graph\n        addCallNode(node);\n    } else if (isa<UnreachableInst>(val)) {\n        auto *noret = getOrCreateNoReturn();\n        node->addControlDependence(noret);\n        // unreachable is being inserted because of the previous instr\n        // aborts the program. This means that whether it is executed\n        // depends on the previous instr\n        if (prevNode)\n            prevNode->addControlDependence(noret);\n    } else if (Instruction *Inst = dyn_cast<Instruction>(val)) {\n        if (isa<LoadInst>(val) || isa<GetElementPtrInst>(val)) {\n            Value *op = Inst->getOperand(0)->stripInBoundsOffsets();\n            if (isa<GlobalVariable>(op))\n                addFormalGlobal(op);\n        } else if (isa<StoreInst>(val)) {\n            Value *op = Inst->getOperand(0)->stripInBoundsOffsets();\n            if (isa<GlobalVariable>(op))\n                addFormalGlobal(op);\n\n            op = Inst->getOperand(1)->stripInBoundsOffsets();\n            if (isa<GlobalVariable>(op))\n                addFormalGlobal(op);\n        }\n    }\n}\n\nLLVMBBlock *LLVMDependenceGraph::build(llvm::BasicBlock &llvmBB) {\n    DBG(llvmdg, \"Building basic block\");\n    using namespace llvm;\n\n    LLVMBBlock *BB = new LLVMBBlock();\n    LLVMNode *node = nullptr;\n    LLVMNode *prevNode = nullptr;\n\n    BB->setKey(&llvmBB);\n\n    // iterate over the instruction and create node for every single one of them\n    for (Instruction &Inst : llvmBB) {\n        prevNode = node;\n\n        Value *val = &Inst;\n        node = new LLVMNode(val);\n\n        // add new node to this dependence graph\n        addNode(node);\n\n        // add the node to our basic block\n        BB->append(node);\n\n        // take instruction specific actions\n        handleInstruction(val, node, prevNode);\n    }\n\n    // did we created at least one node?\n    if (!node) {\n        assert(llvmBB.empty());\n        return BB;\n    }\n\n    // check if this is the exit node of function\n    // (node is now the last instruction in this BB)\n    // if it is, connect it to one artificial return node\n    Value *termval = node->getValue();\n    if (isa<ReturnInst>(termval)) {\n        // create one unified exit node from function and add control dependence\n        // to it from every return instruction. We could use llvm pass that\n        // would do it for us, but then we would lost the advantage of working\n        // on dep. graph that is not for whole llvm\n        LLVMNode *ext = getExit();\n        if (!ext) {\n            // we need new llvm value, so that the nodes won't collide\n            ReturnInst *phonyRet = ReturnInst::Create(termval->getContext());\n            if (!phonyRet) {\n                errs() << \"ERR: Failed creating phony return value \"\n                       << \"for exit node\\n\";\n                // XXX later we could return somehow more mercifully\n                abort();\n            }\n\n            ext = new LLVMNode(phonyRet, true /* node owns the value -\n                                                 it will delete it */);\n            setExit(ext);\n\n            LLVMBBlock *retBB = new LLVMBBlock(ext);\n            retBB->deleteNodesOnDestruction();\n            setExitBB(retBB);\n            assert(!unifiedExitBB &&\n                   \"We should not have it assinged yet (or again) here\");\n            unifiedExitBB = std::unique_ptr<LLVMBBlock>(retBB);\n        }\n\n        // add control dependence from this (return) node to EXIT node\n        assert(node && \"BUG, no node after we went through basic block\");\n        node->addControlDependence(ext);\n        BB->addSuccessor(getExitBB(), LLVMBBlock::ARTIFICIAL_BBLOCK_LABEL);\n    }\n\n    // sanity check if we have the first and the last node set\n    assert(BB->getFirstNode() && \"No first node in BB\");\n    assert(BB->getLastNode() && \"No last node in BB\");\n\n    return BB;\n}\n\nstatic LLVMBBlock *createSingleExitBB(LLVMDependenceGraph *graph) {\n    llvm::UnreachableInst *ui =\n            new llvm::UnreachableInst(graph->getModule()->getContext());\n    LLVMNode *exit = new LLVMNode(ui, true);\n    graph->addNode(exit);\n    graph->setExit(exit);\n    LLVMBBlock *exitBB = new LLVMBBlock(exit);\n    graph->setExitBB(exitBB);\n\n    // XXX should we add predecessors? If the function does not\n    // return anything, we don't need propagate anything outside...\n    return exitBB;\n}\n\nstatic void addControlDepsToPHI(LLVMDependenceGraph *graph, LLVMNode *node,\n                                const llvm::PHINode *phi) {\n    using namespace llvm;\n\n    const BasicBlock *this_block = phi->getParent();\n    auto &CB = graph->getBlocks();\n\n    for (auto I = phi->block_begin(), E = phi->block_end(); I != E; ++I) {\n        BasicBlock *B = *I;\n\n        if (B == this_block)\n            continue;\n\n        LLVMBBlock *our = CB[B];\n        assert(our && \"Don't have block constructed for PHI node\");\n        our->getLastNode()->addControlDependence(node);\n    }\n}\n\nstatic void addControlDepsToPHIs(LLVMDependenceGraph *graph) {\n    // some phi nodes just work like this\n    //\n    //  ; <label>:0\n    //  %1 = load i32, i32* %a, align 4\n    //  %2 = load i32, i32* %b, align 4\n    //  %3 = icmp sgt i32 %1, %2\n    //  br i1 %3, label %4, label %5\n    //\n    //  ; <label>:4                                       ; preds = %0\n    //  br label %6\n    //\n    //  ; <label>:5                                       ; preds = %0\n    //  br label %6\n    //\n    //  ; <label>:6                                       ; preds = %5, %4\n    //  %p.0 = phi i32* [ %a, %4 ], [ %b, %5 ]\n    //\n    //  so we need to keep the blocks %5 and %6 even though it is empty\n\n    // add control dependence to each block going to this phi\n    // XXX: it is over-approximation, but we don't have nothing better now\n    for (auto I = graph->begin(), E = graph->end(); I != E; ++I) {\n        llvm::Value *val = I->first;\n        if (llvm::PHINode *phi = llvm::dyn_cast<llvm::PHINode>(val)) {\n            addControlDepsToPHI(graph, I->second, phi);\n        }\n    }\n}\n\nbool LLVMDependenceGraph::build(llvm::Function *func) {\n    using namespace llvm;\n\n    assert(func && \"Passed no func\");\n\n    DBG_SECTION_BEGIN(llvmdg, \"Building function \" << func->getName().str());\n\n    // do we have anything to process?\n    if (func->empty())\n        return false;\n\n    constructedFunctions.insert(make_pair(func, this));\n\n    // create entry node\n    LLVMNode *entry = new LLVMNode(func);\n    addGlobalNode(entry);\n    // we want the entry node to have this DG set\n    entry->setDG(this);\n    setEntry(entry);\n\n    // add formal parameters to this graph\n    addFormalParameters();\n\n    // iterate over basic blocks\n    BBlocksMapT &blocks = getBlocks();\n    for (llvm::BasicBlock &llvmBB : *func) {\n        LLVMBBlock *BB = build(llvmBB);\n        blocks[&llvmBB] = BB;\n\n        // first basic block is the entry BB\n        if (!getEntryBB())\n            setEntryBB(BB);\n    }\n\n    assert(blocks.size() == func->size() && \"Did not created all blocks\");\n\n    DBG(llvmdg, \"Adding CFG structure to function \" << func->getName().str());\n    // add CFG edges\n    for (auto &it : blocks) {\n        BasicBlock *llvmBB = cast<BasicBlock>(it.first);\n        LLVMBBlock *BB = it.second;\n        BB->setDG(this);\n\n        int idx = 0;\n        for (succ_iterator S = succ_begin(llvmBB), SE = succ_end(llvmBB);\n             S != SE; ++S) {\n            LLVMBBlock *succ = blocks[*S];\n            assert(succ && \"Missing basic block\");\n\n            // don't let overflow the labels silently\n            // if this ever happens, we need to change bit-size\n            if (idx >= LLVMBBlock::MAX_BBLOCK_LABEL) {\n                errs() << \"Too much of successors\";\n                abort();\n            }\n\n            BB->addSuccessor(succ, idx++);\n        }\n    }\n\n    // if graph has no return inst, just create artificial exit node\n    // and point there\n    if (!getExit()) {\n        assert(!unifiedExitBB && \"We should not have exit BB\");\n        unifiedExitBB = std::unique_ptr<LLVMBBlock>(createSingleExitBB(this));\n    }\n\n    // check if we have everything\n    assert(getEntry() && \"Missing entry node\");\n    assert(getExit() && \"Missing exit node\");\n    assert(getEntryBB() && \"Missing entry BB\");\n    assert(getExitBB() && \"Missing exit BB\");\n\n    addControlDepsToPHIs(this);\n\n    // add CFG edge from entry point to the first instruction\n    entry->addControlDependence(getEntryBB()->getFirstNode());\n\n    DBG_SECTION_END(llvmdg, \"Done building function \" << func->getName().str());\n\n    return true;\n}\n\nbool LLVMDependenceGraph::build(llvm::Module *m, LLVMPointerAnalysis *pts,\n                                LLVMDataDependenceAnalysis *rda,\n                                llvm::Function *entry) {\n    this->PTA = pts;\n    this->DDA = rda;\n    return build(m, entry);\n}\n\nvoid LLVMDependenceGraph::addFormalParameters() {\n    using namespace llvm;\n\n    LLVMNode *entryNode = getEntry();\n    assert(entryNode && \"No entry node when adding formal parameters\");\n\n    Function *func = dyn_cast<Function>(entryNode->getValue());\n    assert(func && \"entry node value is not a function\");\n    // assert(func->arg_size() != 0 && \"This function is undefined?\");\n    if (func->arg_size() == 0)\n        return;\n\n    LLVMDGParameters *params = getOrCreateParameters();\n\n    LLVMNode *in, *out;\n    for (auto I = func->arg_begin(), E = func->arg_end(); I != E; ++I) {\n        Value *val = (&*I);\n\n        std::tie(in, out) = params->construct(val, val, this);\n        assert(in && out);\n\n        // add control edges\n        entryNode->addControlDependence(in);\n        entryNode->addControlDependence(out);\n    }\n\n    if (func->isVarArg()) {\n        Value *val = ConstantPointerNull::get(func->getType());\n        val->setName(\"vararg\");\n        in = new LLVMNode(val, true);\n        out = new LLVMNode(val, true);\n        in->setDG(this);\n        out->setDG(this);\n\n        params->setVarArg(in, out);\n        entryNode->addControlDependence(in);\n        entryNode->addControlDependence(out);\n        in->addDataDependence(out);\n    }\n}\n\nstatic bool array_match(llvm::StringRef name, const char *names[]) {\n    unsigned idx = 0;\n    while (names[idx]) {\n        if (name.equals(names[idx]))\n            return true;\n        ++idx;\n    }\n\n    return false;\n}\n\nstatic bool array_match(llvm::StringRef name,\n                        const std::vector<std::string> &names) {\n    for (const auto &nm : names) {\n        if (name == nm)\n            return true;\n    }\n\n    return false;\n}\n\nstatic bool match_callsite_name(LLVMNode *callNode, const char *names[]) {\n    using namespace llvm;\n\n    // if the function is undefined, it has no subgraphs,\n    // but is not called via function pointer\n    if (!callNode->hasSubgraphs()) {\n        const CallInst *callInst = cast<CallInst>(callNode->getValue());\n#if LLVM_VERSION_MAJOR >= 8\n        const Value *calledValue = callInst->getCalledOperand();\n#else\n        const Value *calledValue = callInst->getCalledValue();\n#endif\n        const Function *func =\n                dyn_cast<Function>(calledValue->stripPointerCasts());\n        // in the case we haven't run points-to analysis\n        if (!func)\n            return false;\n\n        // otherwise we would have a subgraph\n        assert(func->size() == 0);\n        return array_match(func->getName(), names);\n    } // simply iterate over the subgraphs, get the entry node\n    // and check it\n    for (LLVMDependenceGraph *dg : callNode->getSubgraphs()) {\n        LLVMNode *entry = dg->getEntry();\n        assert(entry && \"No entry node in graph\");\n\n        const Function *func =\n                cast<Function>(entry->getValue()->stripPointerCasts());\n        if (array_match(func->getName(), names)) {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nstatic bool match_callsite_name(LLVMNode *callNode,\n                                const std::vector<std::string> &names) {\n    using namespace llvm;\n\n    // if the function is undefined, it has no subgraphs,\n    // but is not called via function pointer\n    if (!callNode->hasSubgraphs()) {\n        const CallInst *callInst = cast<CallInst>(callNode->getValue());\n#if LLVM_VERSION_MAJOR >= 8\n        const Value *calledValue = callInst->getCalledOperand();\n#else\n        const Value *calledValue = callInst->getCalledValue();\n#endif\n        const Function *func =\n                dyn_cast<Function>(calledValue->stripPointerCasts());\n        // in the case we haven't run points-to analysis\n        if (!func)\n            return false;\n\n        return array_match(func->getName(), names);\n    } // simply iterate over the subgraphs, get the entry node\n    // and check it\n    for (LLVMDependenceGraph *dg : callNode->getSubgraphs()) {\n        LLVMNode *entry = dg->getEntry();\n        assert(entry && \"No entry node in graph\");\n\n        const Function *func =\n                cast<Function>(entry->getValue()->stripPointerCasts());\n        if (array_match(func->getName(), names)) {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool LLVMDependenceGraph::getCallSites(const char *name,\n                                       std::set<LLVMNode *> *callsites) {\n    const char *names[] = {name, nullptr};\n    return getCallSites(names, callsites);\n}\n\nbool LLVMDependenceGraph::getCallSites(const char *names[],\n                                       std::set<LLVMNode *> *callsites) {\n    for (auto &F : constructedFunctions) {\n        for (auto &I : F.second->getBlocks()) {\n            LLVMBBlock *BB = I.second;\n            for (LLVMNode *n : BB->getNodes()) {\n                if (llvm::isa<llvm::CallInst>(n->getValue())) {\n                    if (match_callsite_name(n, names))\n                        callsites->insert(n);\n                }\n            }\n        }\n    }\n\n    return !callsites->empty();\n}\n\nbool LLVMDependenceGraph::getCallSites(const std::vector<std::string> &names,\n                                       std::set<LLVMNode *> *callsites) {\n    for (const auto &F : constructedFunctions) {\n        for (const auto &I : F.second->getBlocks()) {\n            LLVMBBlock *BB = I.second;\n            for (LLVMNode *n : BB->getNodes()) {\n                if (llvm::isa<llvm::CallInst>(n->getValue())) {\n                    if (match_callsite_name(n, names))\n                        callsites->insert(n);\n                }\n            }\n        }\n    }\n\n    return !callsites->empty();\n}\n\nvoid LLVMDependenceGraph::computeNTSCD(\n        const LLVMControlDependenceAnalysisOptions &opts) {\n    DBG_SECTION_BEGIN(llvmdg, \"Filling in CDA edges (NTSCD)\");\n    dg::LLVMControlDependenceAnalysis ntscd(this->module, opts);\n    assert(opts.ntscdCD() || opts.ntscd2CD());\n\n    for (const auto &it : getConstructedFunctions()) {\n        auto &blocks = it.second->getBlocks();\n        for (auto &BB : *llvm::cast<llvm::Function>(it.first)) {\n            auto *bb = blocks[&BB];\n            assert(bb);\n            for (auto *dep : ntscd.getDependencies(&BB)) {\n                auto *depbb = blocks[dep];\n                assert(depbb);\n                depbb->addControlDependence(bb);\n            }\n\n            for (auto &I : BB) {\n                for (auto *dep : ntscd.getDependencies(&I)) {\n                    auto *depnd = it.second->getNode(dep);\n                    assert(depnd);\n                    auto *ind = it.second->getNode(&I);\n                    assert(ind);\n                    depnd->addControlDependence(ind);\n                }\n            }\n        }\n    }\n\n    DBG_SECTION_END(llvmdg, \"Done computing CDA edges\");\n}\n\nvoid LLVMDependenceGraph::computeNonTerminationControlDependencies() {\n    DBG_SECTION_BEGIN(llvmdg, \"Computing NTSCD\");\n    llvmdg::legacy::NTSCD ntscdAnalysis(this->module, {}, PTA);\n    ntscdAnalysis.computeDependencies();\n    const auto &dependencies = ntscdAnalysis.controlDependencies();\n\n    for (const auto &dep : dependencies) {\n        if (dep.first->isArtificial()) {\n            continue;\n        }\n\n        auto *lastInstruction = findInstruction(\n                castToLLVMInstruction(dep.first->lastInstruction()),\n                getConstructedFunctions());\n        for (auto *const dependant : dep.second) {\n            for (const auto *const instruction :\n                 dependant->llvmInstructions()) {\n                auto *dgInstruction =\n                        findInstruction(castToLLVMInstruction(instruction),\n                                        getConstructedFunctions());\n                if (lastInstruction && dgInstruction) {\n                    lastInstruction->addControlDependence(dgInstruction);\n                } else {\n                    static std::set<std::pair<LLVMNode *, LLVMNode *>> reported;\n                    if (reported.insert({lastInstruction, dgInstruction})\n                                .second) {\n                        llvm::errs() << \"[CD] error: CD could not be set up, \"\n                                        \"some instruction was not found:\\n\";\n                        if (lastInstruction)\n                            llvm::errs()\n                                    << \"[CD] last instruction: \"\n                                    << *lastInstruction->getValue() << \"\\n\";\n                        else\n                            llvm::errs() << \"[CD] No last instruction\\n\";\n                        if (dgInstruction)\n                            llvm::errs() << \"[CD] current instruction: \"\n                                         << *dgInstruction->getValue() << \"\\n\";\n                        else\n                            llvm::errs() << \"[CD] No current instruction\\n\";\n                    }\n                }\n            }\n            if (dependant->isExit() && lastInstruction) {\n                auto *dg = lastInstruction->getDG();\n                auto *noret = dg->getOrCreateNoReturn();\n                lastInstruction->addControlDependence(noret);\n\n                // we added the formal noreturn, now add the noreturn to every\n                // callnode\n                for (auto *caller : dg->getCallers()) {\n                    caller->getOrCreateParameters(); // create params if not\n                                                     // created\n                    auto *actnoret = dg->getOrCreateNoReturn(caller);\n                    noret->addControlDependence(actnoret);\n                }\n            }\n        }\n    }\n    DBG_SECTION_END(llvmdg, \"Done computing NTSCD\");\n}\n\nvoid LLVMDependenceGraph::computeInterferenceDependentEdges(\n        ControlFlowGraph *controlFlowGraph) {\n    auto regions = controlFlowGraph->threadRegions();\n    MayHappenInParallel mayHappenInParallel(regions);\n\n    for (const auto &currentRegion : regions) {\n        auto llvmValuesForCurrentRegion = currentRegion->llvmInstructions();\n        auto currentRegionLoads =\n                getLoadInstructions(llvmValuesForCurrentRegion);\n        auto currentRegionStores =\n                getStoreInstructions(llvmValuesForCurrentRegion);\n        auto parallelRegions =\n                mayHappenInParallel.parallelRegions(currentRegion);\n        for (const auto &parallelRegion : parallelRegions) {\n            auto llvmInstructionsForParallelRegion =\n                    parallelRegion->llvmInstructions();\n            auto parallelRegionLoads =\n                    getLoadInstructions(llvmInstructionsForParallelRegion);\n            auto parallelRegionStores =\n                    getStoreInstructions(llvmInstructionsForParallelRegion);\n            computeInterferenceDependentEdges(currentRegionLoads,\n                                              parallelRegionStores);\n            computeInterferenceDependentEdges(parallelRegionLoads,\n                                              currentRegionStores);\n        }\n    }\n}\n\nvoid LLVMDependenceGraph::computeForkJoinDependencies(\n        ControlFlowGraph *controlFlowGraph) {\n    auto joins = controlFlowGraph->getJoins();\n    for (const auto &join : joins) {\n        auto *joinNode = findInstruction(castToLLVMInstruction(join),\n                                         constructedFunctions);\n        for (const auto &fork : controlFlowGraph->getCorrespondingForks(join)) {\n            auto *forkNode = findInstruction(castToLLVMInstruction(fork),\n                                             constructedFunctions);\n            joinNode->addControlDependence(forkNode);\n        }\n    }\n}\n\nvoid LLVMDependenceGraph::computeCriticalSections(\n        ControlFlowGraph *controlFlowGraph) {\n    auto locks = controlFlowGraph->getLocks();\n    for (const auto *lock : locks) {\n        auto *callLockInst = castToLLVMInstruction(lock);\n        auto *lockNode = findInstruction(callLockInst, constructedFunctions);\n        auto correspondingNodes =\n                controlFlowGraph->getCorrespondingCriticalSection(lock);\n        for (const auto *correspondingNode : correspondingNodes) {\n            auto *node = castToLLVMInstruction(correspondingNode);\n            auto *dependentNode = findInstruction(node, constructedFunctions);\n            if (dependentNode) {\n                lockNode->addControlDependence(dependentNode);\n            } else {\n                llvm::errs()\n                        << \"An instruction \" << *node\n                        << \" was not found, cannot setup\"\n                        << \" control depency on lock \" << *callLockInst << \"\\n\";\n            }\n        }\n\n        auto correspondingUnlocks =\n                controlFlowGraph->getCorrespongingUnlocks(lock);\n        for (const auto *unlock : correspondingUnlocks) {\n            auto *node = castToLLVMInstruction(unlock);\n            auto *unlockNode = findInstruction(node, constructedFunctions);\n            if (unlockNode) {\n                unlockNode->addControlDependence(lockNode);\n            }\n        }\n    }\n}\n\nvoid LLVMDependenceGraph::computeInterferenceDependentEdges(\n        const std::set<const llvm::Instruction *> &loads,\n        const std::set<const llvm::Instruction *> &stores) {\n    for (const auto &load : loads) {\n        auto *loadInst = const_cast<llvm::Instruction *>(load);\n        auto loadFunction = constructedFunctions.find(\n                const_cast<llvm::Function *>(load->getParent()->getParent()));\n        if (loadFunction == constructedFunctions.end())\n            continue;\n        auto *loadNode = loadFunction->second->findNode(loadInst);\n        if (!loadNode)\n            continue;\n\n        for (const auto &store : stores) {\n            auto *storeInst = const_cast<llvm::Instruction *>(store);\n            auto storeFunction =\n                    constructedFunctions.find(const_cast<llvm::Function *>(\n                            store->getParent()->getParent()));\n            if (storeFunction == constructedFunctions.end())\n                continue;\n            auto *storeNode = storeFunction->second->findNode(storeInst);\n            if (!storeNode)\n                continue;\n\n            auto loadPts = PTA->getLLVMPointsTo(load->getOperand(0));\n            auto storePts = PTA->getLLVMPointsTo(store->getOperand(1));\n            for (const auto &pointerLoad : loadPts) {\n                for (const auto &pointerStore : storePts) {\n                    if (pointerLoad.value == pointerStore.value &&\n                        (pointerLoad.offset.isUnknown() ||\n                         pointerStore.offset.isUnknown() ||\n                         pointerLoad.offset == pointerStore.offset)) {\n                        storeNode->addInterferenceDependence(loadNode);\n                    }\n                }\n            }\n\n            // handle the unknown pointer\n            if (loadPts.hasUnknown() || storePts.hasUnknown())\n                storeNode->addInterferenceDependence(loadNode);\n        }\n    }\n}\n\nstd::set<const llvm::Instruction *> LLVMDependenceGraph::getLoadInstructions(\n        const std::set<const llvm::Instruction *> &llvmInstructions) const {\n    return getInstructionsOfType(llvm::Instruction::Load, llvmInstructions);\n}\n\nstd::set<const llvm::Instruction *> LLVMDependenceGraph::getStoreInstructions(\n        const std::set<const llvm::Instruction *> &llvmInstructions) const {\n    return getInstructionsOfType(llvm::Instruction::Store, llvmInstructions);\n}\n\nstd::set<const llvm::Instruction *> LLVMDependenceGraph::getInstructionsOfType(\n        const unsigned opCode,\n        const std::set<const llvm::Instruction *> &llvmInstructions) {\n    std::set<const llvm::Instruction *> instructions;\n    for (const auto &llvmValue : llvmInstructions) {\n        if (llvm::isa<llvm::Instruction>(llvmValue)) {\n            const llvm::Instruction *instruction =\n                    static_cast<const llvm::Instruction *>(llvmValue);\n            if (instruction->getOpcode() == opCode) {\n                instructions.insert(instruction);\n            }\n        }\n    }\n    return instructions;\n}\nvoid LLVMDependenceGraph::computeControlDependencies(\n        const LLVMControlDependenceAnalysisOptions &opts) {\n    if (opts.standardCD()) {\n        computePostDominators(true);\n    } else if (opts.ntscdLegacyCD()) {\n        computeNonTerminationControlDependencies();\n        // the legacy implementation contains a bug, we workaroudn it by running\n        // also the intraprocedural version of new NTSCD\n        auto tmpopts = opts;\n        tmpopts.interprocedural = false;\n        tmpopts.algorithm =\n                ControlDependenceAnalysisOptions::CDAlgorithm::NTSCD2;\n        computeNTSCD(tmpopts);\n    } else if (opts.ntscdCD() || opts.ntscd2CD() || opts.ntscdRanganathCD()) {\n        computeNTSCD(opts);\n    } else\n        abort();\n\n    if (opts.interproceduralCD())\n        addNoreturnDependencies(opts);\n}\n\nvoid LLVMDependenceGraph::addNoreturnDependencies(LLVMNode *noret,\n                                                  LLVMBBlock *from) {\n    std::set<LLVMBBlock *> visited;\n    ADT::QueueLIFO<LLVMBBlock *> queue;\n\n    for (const auto &succ : from->successors()) {\n        if (visited.insert(succ.target).second)\n            queue.push(succ.target);\n    }\n\n    while (!queue.empty()) {\n        auto *cur = queue.pop();\n\n        // do the stuff\n        for (auto *node : cur->getNodes())\n            noret->addControlDependence(node);\n\n        // queue successors\n        for (const auto &succ : cur->successors()) {\n            if (visited.insert(succ.target).second)\n                queue.push(succ.target);\n        }\n    }\n}\n\nvoid LLVMDependenceGraph::addNoreturnDependencies(\n        const LLVMControlDependenceAnalysisOptions &opts) {\n    if (opts.ntscdCD() || opts.ntscd2CD() || opts.ntscdLegacyCD()) {\n        llvmdg::LLVMInterprocCD interprocCD(this->module);\n        for (const auto &F : getConstructedFunctions()) {\n            auto *dg = F.second;\n            auto *fun = llvm::cast<llvm::Function>(F.first);\n            for (auto *noreti : interprocCD.getNoReturns(fun)) {\n                // create noret params if not yet\n                auto *fnoret = dg->getOrCreateNoReturn();\n                for (auto *caller : dg->getCallers()) {\n                    caller->getOrCreateParameters(); // create params if not\n                                                     // created\n                    auto *actnoret = dg->getOrCreateNoReturn(caller);\n                    fnoret->addControlDependence(actnoret);\n                }\n\n                // add edge from function's noret to instruction's nodes\n                auto *nd = dg->getNode(noreti);\n                assert(nd);\n                // if this is a call, add the dependence to noret param\n                if (llvm::isa<llvm::CallInst>(nd->getValue())) {\n                    nd = getOrCreateNoReturn(nd);\n                }\n                nd->addControlDependence(fnoret);\n            }\n        }\n    }\n\n    // in theory, we should not need this one, but it does not work right now\n    for (const auto &F : getConstructedFunctions()) {\n        auto &blocks = F.second->getBlocks();\n\n        for (auto &it : blocks) {\n            LLVMBBlock *B = it.second;\n            std::set<LLVMNode *> noreturns;\n            for (auto *node : B->getNodes()) {\n                // add dependencies for the found no returns\n                for (auto *nrt : noreturns) {\n                    nrt->addControlDependence(node);\n                }\n\n                // is this a call with a noreturn parameter?\n                if (auto *params = node->getParameters()) {\n                    if (auto *noret = params->getNoReturn()) {\n                        // process the rest of the block\n                        noreturns.insert(noret);\n\n                        // process reachable nodes\n                        addNoreturnDependencies(noret, B);\n                    }\n                }\n            }\n        }\n    }\n}\n\nvoid LLVMDependenceGraph::addDefUseEdges(bool preserveDbg) {\n    LLVMDefUseAnalysis DUA(this, DDA, PTA);\n    DUA.run();\n\n    if (preserveDbg) {\n        using namespace llvm;\n\n        for (const auto &it : getConstructedFunctions()) {\n            LLVMDependenceGraph *dg = it.second;\n            for (auto &I : instructions(cast<Function>(it.first))) {\n                Value *val = nullptr;\n                if (auto *DI = dyn_cast<DbgDeclareInst>(&I))\n                    val = DI->getAddress();\n                else if (auto *DI = dyn_cast<DbgValueInst>(&I))\n                    val = DI->getValue();\n#if LLVM_VERSION_MAJOR > 5\n                else if (auto *DI = dyn_cast<DbgAddrIntrinsic>(&I))\n                    val = DI->getAddress();\n#endif\n\n                if (val) {\n                    auto *nd = dg->getNode(&I);\n                    auto *ndop = dg->getNode(val);\n                    assert(nd && \"Do not have a node for a dbg intrinsic\");\n                    assert(ndop && \"Do not have a node for an operand of a dbg \"\n                                   \"intrinsic\");\n                    // add a use edge such that we preserve\n                    // the debugging intrinsic when we preserve\n                    // the value it is talking about\n                    nd->addUseDependence(ndop);\n                }\n            }\n        }\n    }\n}\n\nLLVMNode *findInstruction(llvm::Instruction *instruction,\n                          const std::map<llvm::Value *, LLVMDependenceGraph *>\n                                  &constructedFunctions) {\n    auto valueKey =\n            constructedFunctions.find(instruction->getParent()->getParent());\n    if (valueKey != constructedFunctions.end()) {\n        return valueKey->second->findNode(instruction);\n    }\n    return nullptr;\n}\n\nllvm::Instruction *castToLLVMInstruction(const llvm::Value *value) {\n    return const_cast<llvm::Instruction *>(\n            static_cast<const llvm::Instruction *>(value));\n}\n\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/LLVMNode.cpp",
    "content": "#include <llvm/IR/Constants.h>\n#include <llvm/IR/Function.h>\n#include <llvm/IR/GlobalVariable.h>\n#include <llvm/IR/Instruction.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/Value.h>\n#include <llvm/Support/raw_ostream.h>\n\n#include \"dg/llvm/LLVMDependenceGraph.h\"\n#include \"dg/llvm/LLVMNode.h\"\n\nusing llvm::errs;\n\nnamespace dg {\n\nstatic void addGlobalsParams(LLVMDGParameters *params, LLVMNode *callNode,\n                             LLVMDependenceGraph *funcGraph) {\n    LLVMDGParameters *formal = funcGraph->getParameters();\n    if (!formal)\n        return;\n\n    LLVMNode *pin, *pout;\n    for (auto I = formal->global_begin(), E = formal->global_end(); I != E;\n         ++I) {\n        LLVMDGParameter &p = I->second;\n        llvm::Value *val = I->first;\n        LLVMDGParameter *act = params->findGlobal(val);\n        // reuse or create the parameter\n        if (!act) {\n            std::tie(pin, pout) =\n                    params->constructGlobal(val, val, callNode->getDG());\n        } else {\n            pin = act->in;\n            pout = act->out;\n        }\n        assert(pin && pout);\n\n        // connect the globals with edges\n        pin->addDataDependence(p.in);\n        p.out->addDataDependence(pout);\n\n        // add control dependence from call node\n        callNode->addControlDependence(pin);\n        callNode->addControlDependence(pout);\n    }\n}\n\nstatic void addDynMemoryParams(LLVMDGParameters *params, LLVMNode *callNode,\n                               LLVMDependenceGraph *funcGraph) {\n    LLVMDGParameters *formal = funcGraph->getParameters();\n    if (!formal)\n        return;\n\n    LLVMNode *pin, *pout;\n    for (auto &it : *formal) {\n        // dyn. memory params are only callinsts\n        if (!llvm::isa<llvm::CallInst>(it.first))\n            continue;\n\n        LLVMDGParameter &p = it.second;\n        llvm::Value *val = it.first;\n        LLVMDGParameter *act = params->find(val);\n\n        // reuse or create the parameter\n        if (!act) {\n            std::tie(pin, pout) =\n                    params->construct(val, val, callNode->getDG());\n        } else {\n            pin = act->in;\n            pout = act->out;\n        }\n        assert(pin && pout);\n\n        // connect the params with edges\n        pin->addDataDependence(p.in);\n        p.out->addDataDependence(pout);\n\n        // add control dependence from call node\n        callNode->addControlDependence(pin);\n        callNode->addControlDependence(pout);\n    }\n}\n\nstatic void addOperandsParams(LLVMDGParameters *params,\n                              LLVMDGParameters *formal, LLVMNode *callNode,\n                              llvm::Function *func, bool fork = false) {\n    llvm::CallInst *CInst =\n            llvm::dyn_cast<llvm::CallInst>(callNode->getValue());\n    assert(CInst && \"addActualParameters called on non-CallInst\");\n\n    LLVMNode *in, *out;\n    int idx;\n    if (fork) {\n        idx = 3;\n    } else {\n        idx = 0;\n    }\n    for (auto A = func->arg_begin(), E = func->arg_end(); A != E; ++A, ++idx) {\n        llvm::Value *opval = CInst->getArgOperand(idx);\n        LLVMDGParameter *fp = formal->find(&*A);\n        if (!fp) {\n            errs() << \"ERR: no formal param for value: \" << *opval << \"\\n\";\n            continue;\n        }\n\n        LLVMDGParameter *ap = params->find(opval);\n        if (!ap) {\n            std::tie(in, out) =\n                    params->construct(opval, opval, callNode->getDG());\n        } else {\n            in = ap->in;\n            out = ap->out;\n        }\n        assert(in && out);\n\n        // add control edges from the call-site node\n        // to the parameters\n        callNode->addControlDependence(in);\n        callNode->addControlDependence(out);\n\n        // from actual in to formal in\n        in->addDataDependence(fp->in);\n        // from formal out to actual out\n        fp->out->addDataDependence(out);\n    }\n}\n\nvoid LLVMNode::addActualParameters(LLVMDependenceGraph *funcGraph) {\n    using namespace llvm;\n\n    CallInst *CInst = dyn_cast<CallInst>(key);\n    assert(CInst && \"addActualParameters called on non-CallInst\");\n\n#if LLVM_VERSION_MAJOR >= 8\n    Value *val = CInst->getCalledOperand();\n#else\n    Value *val = CInst->getCalledValue();\n#endif\n    // do not add redundant nodes\n    Function *func = dyn_cast<Function>(val->stripPointerCasts());\n    if (!func || func->empty())\n        return;\n\n    addActualParameters(funcGraph, func);\n}\n\nvoid LLVMNode::addActualParameters(LLVMDependenceGraph *funcGraph,\n                                   llvm::Function *func, bool fork) {\n    using namespace llvm;\n\n    LLVMDGParameters *formal = funcGraph->getParameters();\n    if (!formal)\n        return;\n\n    // if we have parameters, then use them and just\n    // add edges to formal parameters (a call-site can\n    // have more destinations if it is via function pointer)\n    LLVMDGParameters *params = getParameters();\n    if (!params) {\n        params = new LLVMDGParameters(this);\n#ifndef NDEBUG\n        LLVMDGParameters *old =\n#endif\n                setParameters(params);\n        assert(old == nullptr && \"Replaced parameters\");\n    }\n\n    if (func->arg_size() != 0)\n        addOperandsParams(params, formal, this, func, fork);\n\n    // hopefully we matched all the operands, so let's\n    // add the global variables the function uses\n    addGlobalsParams(params, this, funcGraph);\n    addDynMemoryParams(params, this, funcGraph);\n}\n\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/PointerAnalysis/Block.cpp",
    "content": "#include <llvm/Config/llvm-config.h>\n\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n#include <llvm/Support/CFG.h>\n#else\n#include <llvm/IR/CFG.h>\n#endif\n\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/Module.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#include \"dg/llvm/PointerAnalysis/PointerGraph.h\"\n\nnamespace dg {\nnamespace pta {\n\nvoid LLVMPointerGraphBuilder::addPHIOperands(const llvm::Function &F) {\n    for (const llvm::BasicBlock &B : F) {\n        for (const llvm::Instruction &I : B) {\n            if (const llvm::PHINode *PHI = llvm::dyn_cast<llvm::PHINode>(&I)) {\n                if (PSNode *node = getNodes(PHI)->getSingleNode())\n                    addPHIOperands(node, PHI);\n            }\n        }\n    }\n}\n\n// return first and last nodes of the block\nLLVMPointerGraphBuilder::PSNodesBlock\nLLVMPointerGraphBuilder::buildPointerGraphBlock(const llvm::BasicBlock &block,\n                                                PointerSubgraph *parent) {\n    PSNodesBlock blk;\n\n    for (const llvm::Instruction &Inst : block) {\n        if (!isRelevantInstruction(Inst)) {\n            // check if it is a zeroing of memory,\n            // if so, set the corresponding memory to zeroed\n            if (llvm::isa<llvm::MemSetInst>(&Inst))\n                checkMemSet(&Inst);\n\n            continue;\n        }\n\n        assert(nodes_map.count(&Inst) == 0 && \"Already built this instruction\");\n        auto &seq = buildInstruction(Inst);\n\n        // set parent to the new nodes\n        for (auto *nd : seq) {\n            nd->setParent(parent);\n        }\n\n        blk.append(&seq);\n    }\n\n    return blk;\n}\n\n} // namespace pta\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/PointerAnalysis/Calls.cpp",
    "content": "#include \"dg/llvm/PointerAnalysis/PointerGraph.h\"\n#include \"llvm/llvm-utils.h\"\n\nnamespace dg {\nnamespace pta {\n\n// create subgraph or add edges to already existing subgraph,\n// return the CALL node (the first) and the RETURN node (the second),\n// so that we can connect them into the PointerGraph\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createCall(const llvm::Instruction *Inst) {\n    using namespace llvm;\n\n    const CallInst *CInst = cast<CallInst>(Inst);\n\n#if LLVM_VERSION_MAJOR >= 8\n    const Value *calledVal = CInst->getCalledOperand()->stripPointerCasts();\n#else\n    const Value *calledVal = CInst->getCalledValue()->stripPointerCasts();\n#endif\n\n    if (CInst->isInlineAsm()) {\n        return createAsm(Inst);\n    }\n\n    if (const Function *func = dyn_cast<Function>(calledVal)) {\n        if (func->isDeclaration()) {\n            return addNode(CInst, createUndefFunctionCall(CInst, func));\n        }\n        return createCallToFunction(CInst, func);\n    } // this is a function pointer call\n    return createFuncptrCall(CInst, calledVal);\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq\nLLVMPointerGraphBuilder::createUndefFunctionCall(const llvm::CallInst *CInst,\n                                                 const llvm::Function *func) {\n    assert(func->empty());\n    // is it a call to free? If so, create invalidate node instead.\n    if (invalidate_nodes && func->getName().equals(\"free\")) {\n        return {createFree(CInst)};\n    }\n    if (threads_) {\n        if (func->getName().equals(\"pthread_create\")) {\n            return createPthreadCreate(CInst);\n        }\n        if (func->getName().equals(\"pthread_join\")) {\n            return createPthreadJoin(CInst);\n        }\n        if (func->getName().equals(\"pthread_exit\")) {\n            return createPthreadExit(CInst);\n        }\n    }\n    /// memory allocation (malloc, calloc, etc.)\n    auto type = _options.getAllocationFunction(func->getName().str());\n    if (type != AllocationFunction::NONE) {\n        return createDynamicMemAlloc(CInst, type);\n    }\n    if (func->isIntrinsic()) {\n        return createIntrinsic(CInst);\n    }\n\n    // mempy/memmove\n    const auto &funname = func->getName();\n    if (funname.equals(\"memcpy\") || funname.equals(\"__memcpy_chk\") ||\n        funname.equals(\"memove\")) {\n        auto *dest = CInst->getOperand(0);\n        auto *src = CInst->getOperand(1);\n        auto lenVal = llvmutils::getConstantValue(CInst->getOperand(2));\n        return PS.create<PSNodeType::MEMCPY>(getOperand(src), getOperand(dest),\n                                             lenVal);\n    }\n\n    return {createUnknownCall()};\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createFuncptrCall(const llvm::CallInst *CInst,\n                                           const llvm::Value *calledVal) {\n    // just the call_funcptr and call_return nodes are created and\n    // when the pointers are resolved during analysis, the graph\n    // will be dynamically created and it will replace these nodes\n    PSNode *op = getOperand(calledVal);\n    PSNode *call_funcptr = PS.create<PSNodeType::CALL_FUNCPTR>(op);\n    PSNode *ret_call = PS.create<PSNodeType::CALL_RETURN>();\n\n    ret_call->setPairedNode(call_funcptr);\n    call_funcptr->setPairedNode(ret_call);\n\n    call_funcptr->setUserData(const_cast<llvm::CallInst *>(CInst));\n\n    return addNode(CInst, {call_funcptr, ret_call});\n}\n\nPSNode *LLVMPointerGraphBuilder::createUnknownCall() {\n    // This assertion must not hold if the call is wrapped\n    // inside bitcast - it defaults to int, but is bitcased\n    // to pointer\n    // assert(CInst->getType()->isPointerTy());\n    PSNode *call = PS.create<PSNodeType::CALL>();\n    call->setPairedNode(call);\n\n    // the only thing that the node will point at\n    call->addPointsTo(UnknownPointer);\n\n    return call;\n}\n\nPSNode *\nLLVMPointerGraphBuilder::createMemTransfer(const llvm::IntrinsicInst *I) {\n    using namespace llvm;\n    const Value *dest, *src; //, *lenVal;\n    uint64_t lenVal = Offset::UNKNOWN;\n\n    switch (I->getIntrinsicID()) {\n    case Intrinsic::memmove:\n    case Intrinsic::memcpy:\n        dest = I->getOperand(0);\n        src = I->getOperand(1);\n        lenVal = llvmutils::getConstantValue(I->getOperand(2));\n        break;\n    default:\n        errs() << \"ERR: unhandled mem transfer intrinsic\" << *I << \"\\n\";\n        abort();\n    }\n\n    PSNode *destNode = getOperand(dest);\n    PSNode *srcNode = getOperand(src);\n    PSNode *node = PS.create<PSNodeType::MEMCPY>(srcNode, destNode, lenVal);\n\n    return node;\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq\nLLVMPointerGraphBuilder::createMemSet(const llvm::Instruction *Inst) {\n    PSNode *val;\n    if (llvmutils::memsetIsZeroInitialization(\n                llvm::cast<llvm::IntrinsicInst>(Inst)))\n        val = NULLPTR;\n    else\n        // if the memset is not 0-initialized, it does some\n        // garbage into the pointer\n        val = UNKNOWN_MEMORY;\n\n    PSNode *op = getOperand(Inst->getOperand(0)->stripInBoundsOffsets());\n    // we need to make unknown offsets\n    PSNode *G = PS.create<PSNodeType::GEP>(op, Offset::UNKNOWN);\n    PSNode *S = PS.create<PSNodeType::STORE>(val, G);\n\n    PSNodesSeq ret(G);\n    ret.append(S);\n    // no representant here...\n\n    return ret;\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq\nLLVMPointerGraphBuilder::createVarArg(const llvm::IntrinsicInst *Inst) {\n    // just store all the pointers from vararg argument\n    // to the memory given in vastart() on Offset::UNKNOWN.\n    // It is the easiest thing we can do without any further\n    // analysis\n    PSNodesSeq ret;\n\n    // first we need to get the vararg argument phi\n    const llvm::Function *F = Inst->getParent()->getParent();\n    PointerSubgraph *subg = subgraphs_map[F];\n    assert(subg);\n    PSNode *arg = subg->vararg;\n    assert(F->isVarArg() && \"vastart in a non-variadic function\");\n    assert(arg && \"Don't have variadic argument in a variadic function\");\n\n    // vastart will be node that will keep the memory\n    // with pointers, its argument is the alloca, that\n    // alloca will keep pointer to vastart\n    PSNode *vastart = PS.create<PSNodeType::ALLOC>();\n\n    // vastart has only one operand which is the struct\n    // it uses for storing the va arguments. Strip it so that we'll\n    // get the underlying alloca inst\n    PSNode *op = getOperand(Inst->getOperand(0)->stripInBoundsOffsets());\n    // the argument is usually an alloca, but it may be a load\n    // in the case the code was transformed by -reg2mem\n    assert((op->getType() == PSNodeType::ALLOC ||\n            op->getType() == PSNodeType::LOAD) &&\n           \"Argument of vastart is invalid\");\n    // get node with the same pointer, but with Offset::UNKNOWN\n    // FIXME: we're leaking it\n    // make the memory in alloca point to our memory in vastart\n    PSNode *ptr = PS.create<PSNodeType::GEP>(op, Offset::UNKNOWN);\n    PSNode *S1 = PS.create<PSNodeType::STORE>(vastart, ptr);\n    // and also make vastart point to the vararg args\n    PSNode *S2 = PS.create<PSNodeType::STORE>(arg, vastart);\n\n    ret.append(vastart);\n    ret.append(ptr);\n    ret.append(S1);\n    ret.append(S2);\n\n    ret.setRepresentant(vastart);\n\n    return ret;\n}\n\nPSNode *\nLLVMPointerGraphBuilder::createLifetimeEnd(const llvm::Instruction *Inst) {\n    PSNode *op1 = getOperand(Inst->getOperand(1));\n    return PS.create<PSNodeType::INVALIDATE_OBJECT>(op1);\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq\nLLVMPointerGraphBuilder::createIntrinsic(const llvm::Instruction *Inst) {\n    using namespace llvm;\n\n    const IntrinsicInst *I = cast<IntrinsicInst>(Inst);\n    if (isa<MemTransferInst>(I)) {\n        return createMemTransfer(I);\n    }\n    if (isa<MemSetInst>(I)) {\n        return createMemSet(I);\n    }\n\n    switch (I->getIntrinsicID()) {\n    case Intrinsic::vastart:\n        return createVarArg(I);\n    case Intrinsic::stacksave:\n        errs() << \"WARNING: Saving stack may yield unsound results!: \" << *Inst\n               << \"\\n\";\n        return {PSNodeAlloc::get(PS.create<PSNodeType::ALLOC>())};\n    case Intrinsic::stackrestore:\n        return {createInternalLoad(Inst)};\n    case Intrinsic::lifetime_end:\n        return {createLifetimeEnd(Inst)};\n    default:\n        errs() << *Inst << \"\\n\";\n        errs() << \"Unhandled intrinsic ^^\\n\";\n        abort();\n    }\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createAsm(const llvm::Instruction *Inst) {\n    // we filter irrelevant calls in isRelevantCall()\n    // and we don't have assembler there at all. If\n    // we are here, then we got here because this\n    // is undefined call that returns pointer.\n    // In this case return an unknown pointer\n    static bool warned = false;\n    if (!warned) {\n        llvm::errs()\n                << \"PTA: Inline assembly found, analysis  may be unsound\\n\";\n        warned = true;\n    }\n\n    PSNode *n =\n            PS.create<PSNodeType::CONSTANT>(UNKNOWN_MEMORY, Offset::UNKNOWN);\n    // it is call that returns pointer, so we'd like to have\n    // a 'return' node that contains that pointer\n    n->setPairedNode(n);\n    return addNode(Inst, n);\n}\n\nPSNode *LLVMPointerGraphBuilder::createFree(const llvm::Instruction *Inst) {\n    PSNode *op1 = getOperand(Inst->getOperand(0));\n    PSNode *node = PS.create<PSNodeType::FREE>(op1);\n\n    return node;\n}\n\nPSNode *LLVMPointerGraphBuilder::createDynamicAlloc(const llvm::CallInst *CInst,\n                                                    AllocationFunction type) {\n    using namespace llvm;\n\n    const Value *op;\n    uint64_t size = 0, size2 = 0;\n    PSNodeAlloc *node = PSNodeAlloc::get(PS.create<PSNodeType::ALLOC>());\n    node->setIsHeap();\n\n    switch (type) {\n    case AllocationFunction::MALLOC:\n        node->setIsHeap();\n        /* fallthrough */\n    case AllocationFunction::ALLOCA:\n        op = CInst->getOperand(0);\n        break;\n    case AllocationFunction::CALLOC:\n        node->setIsHeap();\n        node->setZeroInitialized();\n        op = CInst->getOperand(1);\n        break;\n    default:\n        errs() << *CInst << \"\\n\";\n        assert(0 && \"unknown memory allocation type\");\n        // for NDEBUG\n        abort();\n    };\n\n    // infer allocated size\n    size = llvmutils::getConstantSizeValue(op);\n    if (size != 0 && type == AllocationFunction::CALLOC) {\n        // if this is call to calloc, the size is given\n        // in the first argument too\n        size2 = llvmutils::getConstantSizeValue(CInst->getOperand(0));\n        // if both ops are constants, multiply them to get\n        // the correct size, otherwise return 0 (unknown)\n        size = size2 != 0 ? size * size2 : 0;\n    }\n\n    node->setSize(size);\n    return node;\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq\nLLVMPointerGraphBuilder::createRealloc(const llvm::CallInst *CInst) {\n    using namespace llvm;\n\n    PSNodesSeq ret;\n\n    // we create new allocation node and memcpy old pointers there\n    PSNode *orig_mem = getOperand(CInst->getOperand(0));\n    PSNodeAlloc *reall = PSNodeAlloc::get(PS.create<PSNodeType::ALLOC>());\n    reall->setIsHeap();\n    reall->setUserData(const_cast<llvm::CallInst *>(CInst));\n\n    // copy everything that is in orig_mem to reall\n    PSNode *mcp =\n            PS.create<PSNodeType::MEMCPY>(orig_mem, reall, Offset::UNKNOWN);\n    // we need the pointer in the last node that we return\n    PSNode *ptr = PS.create<PSNodeType::CONSTANT>(reall, 0);\n\n    reall->setIsHeap();\n    reall->setSize(llvmutils::getConstantSizeValue(CInst->getOperand(1)));\n\n    ret.append(reall);\n    ret.append(mcp);\n    ret.append(ptr);\n    ret.setRepresentant(ptr);\n\n    return ret;\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq\nLLVMPointerGraphBuilder::createDynamicMemAlloc(const llvm::CallInst *CInst,\n                                               AllocationFunction type) {\n    assert(type != AllocationFunction::NONE &&\n           \"BUG: creating dyn. memory node for NONMEM\");\n\n    PSNodesSeq seq;\n    if (type == AllocationFunction::REALLOC) {\n        seq = createRealloc(CInst);\n    } else {\n        seq = {createDynamicAlloc(CInst, type)};\n    }\n    return seq;\n}\n\n} // namespace pta\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/PointerAnalysis/Constants.cpp",
    "content": "#include \"dg/llvm/PointerAnalysis/PointerGraph.h\"\n#include \"llvm/llvm-utils.h\"\n\nnamespace dg {\nnamespace pta {\n\nPointer\nLLVMPointerGraphBuilder::handleConstantPtrToInt(const llvm::PtrToIntInst *P2I) {\n    using namespace llvm;\n\n    const Value *llvmOp = P2I->getOperand(0);\n    // (possibly recursively) get the operand of this bit-cast\n    PSNode *op = getOperand(llvmOp);\n    assert(op->pointsTo.size() == 1 &&\n           \"Constant PtrToInt with not only one pointer\");\n\n    return *op->pointsTo.begin();\n}\n\nPointer\nLLVMPointerGraphBuilder::handleConstantIntToPtr(const llvm::IntToPtrInst *I2P) {\n    using namespace llvm;\n\n    const Value *llvmOp = I2P->getOperand(0);\n    if (isa<ConstantInt>(llvmOp)) {\n        llvm::errs() << \"IntToPtr with constant: \" << *I2P << \"\\n\";\n        return UnknownPointer;\n    }\n\n    // (possibly recursively) get the operand of this bit-cast\n    PSNode *op = getOperand(llvmOp);\n    assert(op->pointsTo.size() == 1 &&\n           \"Constant PtrToInt with not only one pointer\");\n\n    return *op->pointsTo.begin();\n}\n\nPointer\nLLVMPointerGraphBuilder::handleConstantAdd(const llvm::Instruction *Inst) {\n    using namespace llvm;\n\n    PSNode *op;\n    const Value *val = nullptr;\n    Offset off = Offset::UNKNOWN;\n\n    // see createAdd() for details\n    if (isa<ConstantInt>(Inst->getOperand(0))) {\n        op = getOperand(Inst->getOperand(1));\n        val = Inst->getOperand(0);\n    } else if (isa<ConstantInt>(Inst->getOperand(1))) {\n        op = getOperand(Inst->getOperand(0));\n        val = Inst->getOperand(1);\n    } else {\n        op = tryGetOperand(Inst->getOperand(0));\n        if (!op)\n            op = tryGetOperand(Inst->getOperand(1));\n\n        if (!op) {\n            auto &unk = createUnknown(Inst);\n            return Pointer{unk.getSingleNode(), Offset::UNKNOWN};\n        }\n    }\n\n    assert(op && \"Don't have operand for add\");\n    if (val)\n        off = llvmutils::getConstantValue(val);\n\n    assert(op->pointsTo.size() == 1 &&\n           \"Constant add with not only one pointer\");\n\n    Pointer ptr = *op->pointsTo.begin();\n    if (off.isUnknown())\n        return {ptr.target, Offset::UNKNOWN};\n    return {ptr.target, ptr.offset + off};\n}\n\nPointer LLVMPointerGraphBuilder::handleConstantArithmetic(\n        const llvm::Instruction *Inst) {\n    using namespace llvm;\n\n    PSNode *op;\n\n    if (isa<ConstantInt>(Inst->getOperand(0))) {\n        op = getOperand(Inst->getOperand(1));\n    } else if (isa<ConstantInt>(Inst->getOperand(1))) {\n        op = getOperand(Inst->getOperand(0));\n    } else {\n        op = tryGetOperand(Inst->getOperand(0));\n        if (!op)\n            op = tryGetOperand(Inst->getOperand(1));\n\n        if (!op)\n            return Pointer{createUnknown(Inst).getSingleNode(),\n                           Offset::UNKNOWN};\n    }\n\n    assert(op && \"Don't have operand for add\");\n    assert(op->pointsTo.size() == 1 &&\n           \"Constant add with not only one pointer\");\n\n    Pointer ptr = *op->pointsTo.begin();\n    return {ptr.target, Offset::UNKNOWN};\n}\n\nPointer\nLLVMPointerGraphBuilder::handleConstantBitCast(const llvm::CastInst *BC) {\n    using namespace llvm;\n\n    if (!BC->isLosslessCast()) {\n        // If this is a cast to a bigger type (if that can ever happen?),\n        // then preserve the pointer. Otherwise, the pointer is cropped,\n        // and there's nothing we can do...\n        if (!llvmutils::typeCanBePointer(&M->getDataLayout(), BC->getType()))\n            return UnknownPointer;\n        // fall-through\n    }\n\n    const Value *llvmOp = BC->stripPointerCasts();\n    // (possibly recursively) get the operand of this bit-cast\n    PSNode *op = getOperand(llvmOp);\n    assert(op->pointsTo.size() == 1 &&\n           \"Constant BitCast with not only one pointer\");\n\n    return *op->pointsTo.begin();\n}\n\nPointer\nLLVMPointerGraphBuilder::handleConstantGep(const llvm::GetElementPtrInst *GEP) {\n    using namespace llvm;\n\n    const Value *op = GEP->getPointerOperand();\n    Pointer pointer(UNKNOWN_MEMORY, Offset::UNKNOWN);\n\n    // get operand PSNode (this may result in recursive call,\n    // if this gep is recursively defined)\n    PSNode *opNode = getOperand(op);\n    assert(opNode->pointsTo.size() == 1 &&\n           \"Constant node has more that 1 pointer\");\n    pointer = *(opNode->pointsTo.begin());\n\n    unsigned bitwidth = llvmutils::getPointerBitwidth(&M->getDataLayout(), op);\n    APInt offset(bitwidth, 0);\n\n    // get offset of this GEP\n    if (GEP->accumulateConstantOffset(M->getDataLayout(), offset)) {\n        if (offset.isIntN(bitwidth) && !pointer.offset.isUnknown())\n            pointer.offset = offset.getZExtValue();\n        else\n            errs() << \"WARN: Offset greater than \" << bitwidth << \"-bit\" << *GEP\n                   << \"\\n\";\n    }\n\n    return pointer;\n}\n\nPointer\nLLVMPointerGraphBuilder::getConstantExprPointer(const llvm::ConstantExpr *CE) {\n    using namespace llvm;\n\n    Pointer pointer(UNKNOWN_MEMORY, Offset::UNKNOWN);\n    Instruction *Inst = const_cast<ConstantExpr *>(CE)->getAsInstruction();\n\n    switch (Inst->getOpcode()) {\n    case Instruction::GetElementPtr:\n        pointer = handleConstantGep(cast<GetElementPtrInst>(Inst));\n        break;\n        // case Instruction::ExtractValue:\n        // case Instruction::Select:\n        break;\n    case Instruction::BitCast:\n    case Instruction::SExt:\n    case Instruction::ZExt:\n        pointer = handleConstantBitCast(cast<CastInst>(Inst));\n        break;\n    case Instruction::PtrToInt:\n        pointer = handleConstantPtrToInt(cast<PtrToIntInst>(Inst));\n        break;\n    case Instruction::IntToPtr:\n        pointer = handleConstantIntToPtr(cast<IntToPtrInst>(Inst));\n        break;\n    case Instruction::Add:\n        pointer = handleConstantAdd(Inst);\n        break;\n    case Instruction::And:\n    case Instruction::Or:\n    case Instruction::Trunc:\n    case Instruction::Shl:\n    case Instruction::LShr:\n    case Instruction::AShr:\n        pointer = UnknownPointer;\n        break;\n    case Instruction::Sub:\n    case Instruction::Mul:\n    case Instruction::SDiv:\n        pointer = handleConstantArithmetic(Inst);\n        break;\n    default:\n        errs() << \"ERR: Unsupported ConstantExpr \" << *CE << \"\\n\";\n        abort();\n    }\n\n#if LLVM_VERSION_MAJOR < 5\n    delete Inst;\n#else\n    Inst->deleteValue();\n#endif\n    return pointer;\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createConstantExpr(const llvm::ConstantExpr *CE) {\n    Pointer ptr = getConstantExprPointer(CE);\n    PSNode *node = PS.create<PSNodeType::CONSTANT>(ptr.target, ptr.offset);\n\n    return addNode(CE, node);\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createUnknown(const llvm::Value *val) {\n    // nothing better we can do, these operations\n    // completely change the value of pointer...\n\n    // FIXME: or there's enough unknown offset? Check it out!\n    PSNode *node =\n            PS.create<PSNodeType::CONSTANT>(UNKNOWN_MEMORY, Offset::UNKNOWN);\n    assert(node);\n\n    return addNode(val, node);\n}\n\n} // namespace pta\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/PointerAnalysis/Globals.cpp",
    "content": "#include <cassert>\n#include <set>\n\n#include <llvm/Config/llvm-config.h>\n\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n#include <llvm/Support/CFG.h>\n#else\n#include <llvm/IR/CFG.h>\n#endif\n\n#include <llvm/IR/Constant.h>\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/DataLayout.h>\n#include <llvm/IR/Function.h>\n#include <llvm/IR/Instruction.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/IntrinsicInst.h>\n#include <llvm/IR/Module.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#include \"dg/llvm/PointerAnalysis/PointerGraph.h\"\n\nnamespace dg {\nnamespace pta {\n\nvoid LLVMPointerGraphBuilder::handleGlobalVariableInitializer(\n        const llvm::Constant *C, PSNodeAlloc *node, uint64_t offset) {\n    using namespace llvm;\n\n    // if the global is zero initialized, just set the zeroInitialized flag\n    if (C->isNullValue()) {\n        node->setZeroInitialized();\n    } else if (C->getType()->isStructTy()) {\n        uint64_t off = 0;\n        auto *STy = cast<StructType>(C->getType());\n        const StructLayout *SL = M->getDataLayout().getStructLayout(STy);\n        int i = 0;\n        for (auto I = C->op_begin(), E = C->op_end(); I != E; ++I, ++i) {\n            const Constant *op = cast<Constant>(*I);\n            // recursively dive into the aggregate type\n            off = SL->getElementOffset(i);\n            handleGlobalVariableInitializer(op, node, offset + off);\n        }\n    } else if (C->getType()->isArrayTy()) {\n        uint64_t off = 0;\n        for (auto I = C->op_begin(), E = C->op_end(); I != E; ++I) {\n            const Constant *op = cast<Constant>(*I);\n            Type *Ty = op->getType();\n            // recursively dive into the aggregate type\n            handleGlobalVariableInitializer(op, node, offset + off);\n            off += M->getDataLayout().getTypeAllocSize(Ty);\n        }\n    } else if (C->getType()->isPointerTy()) {\n        PSNode *op = getOperand(C);\n        PSNode *target = PS.createGlobal<PSNodeType::CONSTANT>(node, offset);\n        PS.createGlobal<PSNodeType::STORE>(op, target);\n    } else if (isa<ConstantExpr>(C) || isa<Function>(C) ||\n               C->getType()->isPointerTy()) {\n        if (C->getType()->isPointerTy()) {\n            PSNode *value = getOperand(C);\n            assert(value->pointsTo.size() == 1 &&\n                   \"BUG: We should have constant\");\n            PS.createGlobal<PSNodeType::STORE>(value, node);\n        }\n    } else if (isa<UndefValue>(C)) {\n        // undef value means unknown memory\n        PSNode *target = PS.createGlobal<PSNodeType::CONSTANT>(node, offset);\n        PS.createGlobal<PSNodeType::STORE>(UNKNOWN_MEMORY, target);\n    } else if (!isa<ConstantInt>(C) && !isa<ConstantFP>(C)) {\n        llvm::errs() << *C << \"\\n\";\n        llvm::errs() << \"ERROR: ^^^ global variable initializer not handled\\n\";\n        abort();\n    }\n}\n\nstatic uint64_t getAllocatedSize(const llvm::GlobalVariable *GV,\n                                 const llvm::DataLayout *DL) {\n    llvm::Type *Ty = GV->getType()->getContainedType(0);\n    if (!Ty->isSized())\n        return 0;\n\n    return DL->getTypeAllocSize(Ty);\n}\n\nvoid LLVMPointerGraphBuilder::buildGlobals() {\n    // create PointerGraph nodes\n    for (auto I = M->global_begin(), E = M->global_end(); I != E; ++I) {\n        // every global node is like memory allocation\n        PSNodeAlloc *nd =\n                PSNodeAlloc::get(PS.createGlobal<PSNodeType::ALLOC>());\n        nd->setIsGlobal();\n        addNode(&*I, nd);\n    }\n\n    // only now handle the initializers - we need to have then\n    // built, because they can point to each other\n    for (auto I = M->global_begin(), E = M->global_end(); I != E; ++I) {\n        PSNodeAlloc *node = PSNodeAlloc::get(getNodes(&*I)->getSingleNode());\n        assert(node && \"BUG: Do not have global variable\"\n                       \" or it is not an allocation\");\n\n        // handle globals initialization\n        if (const auto *const GV = llvm::dyn_cast<llvm::GlobalVariable>(&*I)) {\n            node->setSize(getAllocatedSize(GV, &M->getDataLayout()));\n\n            if (GV->hasInitializer() && !GV->isExternallyInitialized()) {\n                const llvm::Constant *C = GV->getInitializer();\n                handleGlobalVariableInitializer(C, node);\n            }\n        } else {\n            // without initializer we can not do anything else than\n            // assume that it can point everywhere\n            PS.createGlobal<PSNodeType::STORE>(UNKNOWN_MEMORY, node);\n        }\n    }\n}\n\n} // namespace pta\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/PointerAnalysis/Instructions.cpp",
    "content": "#include \"dg/llvm/PointerAnalysis/PointerGraph.h\"\n#include \"llvm/llvm-utils.h\"\n\nnamespace dg {\nnamespace pta {\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createAlloc(const llvm::Instruction *Inst) {\n    PSNodeAlloc *node = PSNodeAlloc::get(PS.create<PSNodeType::ALLOC>());\n\n    const llvm::AllocaInst *AI = llvm::dyn_cast<llvm::AllocaInst>(Inst);\n    if (AI)\n        node->setSize(llvmutils::getAllocatedSize(AI, &M->getDataLayout()));\n\n    return addNode(Inst, node);\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createStore(const llvm::Instruction *Inst) {\n    using namespace llvm;\n    const Value *valOp = Inst->getOperand(0);\n\n    PSNode *op1;\n    if (isa<AtomicRMWInst>(valOp)) {\n        // we store the old value of AtomicRMW\n        auto it = nodes_map.find(valOp);\n        if (it == nodes_map.end()) {\n            op1 = UNKNOWN_MEMORY;\n        } else {\n            op1 = it->second.getFirst();\n            assert(op1->getType() == PSNodeType::LOAD &&\n                   \"Invalid AtomicRMW nodes seq\");\n        }\n    } else {\n        op1 = getOperand(valOp);\n    }\n\n    PSNode *op2 = getOperand(Inst->getOperand(1));\n    PSNode *node = PS.create<PSNodeType::STORE>(op1, op2);\n\n    assert(node);\n    return addNode(Inst, node);\n}\n\nPSNode *\nLLVMPointerGraphBuilder::createInternalLoad(const llvm::Instruction *Inst) {\n    const llvm::Value *op = Inst->getOperand(0);\n\n    PSNode *op1 = getOperand(op);\n    PSNode *node = PS.create<PSNodeType::LOAD>(op1);\n    assert(node);\n\n    return node;\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createLoad(const llvm::Instruction *Inst) {\n    return addNode(Inst, createInternalLoad(Inst));\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createGEP(const llvm::Instruction *Inst) {\n    using namespace llvm;\n\n    const GetElementPtrInst *GEP = cast<GetElementPtrInst>(Inst);\n    const Value *ptrOp = GEP->getPointerOperand();\n    unsigned bitwidth =\n            llvmutils::getPointerBitwidth(&M->getDataLayout(), ptrOp);\n    APInt offset(bitwidth, 0);\n\n    PSNode *node = nullptr;\n    PSNode *op = getOperand(ptrOp);\n\n    if (*_options.fieldSensitivity > 0 &&\n        GEP->accumulateConstantOffset(M->getDataLayout(), offset)) {\n        // is offset in given bitwidth?\n        if (offset.isIntN(bitwidth)) {\n            // is 0 < offset < field_sensitivity ?\n            uint64_t off = offset.getLimitedValue(*_options.fieldSensitivity);\n            if (off == 0 || off < *_options.fieldSensitivity)\n                node = PS.create<PSNodeType::GEP>(op, offset.getZExtValue());\n        } else\n            errs() << \"WARN: GEP offset greater than \" << bitwidth << \"-bit\";\n        // fall-through to Offset::UNKNOWN in this case\n    }\n\n    // we didn't create the node with concrete offset,\n    // in which case we are supposed to create a node\n    // with Offset::UNKNOWN\n    if (!node)\n        node = PS.create<PSNodeType::GEP>(op, Offset::UNKNOWN);\n\n    assert(node);\n\n    return addNode(Inst, node);\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createSelect(const llvm::Instruction *Inst) {\n    // with ptrtoint/inttoptr it may not be a pointer\n    // assert(Inst->getType()->isPointerTy() && \"BUG: This select is not a\n    // pointer\");\n\n    // select <cond> <op1> <op2>\n    PSNode *op1 = getOperand(Inst->getOperand(1));\n    PSNode *op2 = getOperand(Inst->getOperand(2));\n\n    // select works as a PHI in points-to analysis\n    PSNode *node = PS.create<PSNodeType::PHI>(op1, op2);\n    assert(node);\n\n    return addNode(Inst, node);\n}\n\nOffset accumulateEVOffsets(const llvm::ExtractValueInst *EV,\n                           const llvm::DataLayout &DL) {\n    Offset off{0};\n#if LLVM_VERSION_MAJOR >= 11\n    llvm::Type *type = EV->getAggregateOperand()->getType();\n#else\n    llvm::CompositeType *type = llvm::dyn_cast<llvm::CompositeType>(\n            EV->getAggregateOperand()->getType());\n    assert(type && \"Don't have composite type in extractvalue\");\n#endif\n\n    for (unsigned idx : EV->getIndices()) {\n        if (llvm::StructType *STy = llvm::dyn_cast<llvm::StructType>(type)) {\n            assert(STy->indexValid(idx) && \"Invalid index\");\n            const llvm::StructLayout *SL = DL.getStructLayout(STy);\n            off += SL->getElementOffset(idx);\n        } else {\n            // array or vector, so just move in the array\n            if (auto *arrTy = llvm::dyn_cast<llvm::ArrayType>(type)) {\n                assert(idx < arrTy->getNumElements() && \"Invalid index\");\n                off += idx + DL.getTypeAllocSize(arrTy->getElementType());\n            } else {\n                auto *vecTy = llvm::cast<llvm::VectorType>(type);\n#if LLVM_VERSION_MAJOR >= 12\n                assert(idx < vecTy->getElementCount().getFixedValue() &&\n                       \"Invalid index\");\n#else\n                assert(idx < vecTy->getNumElements() && \"Invalid index\");\n#endif\n                off += idx + DL.getTypeAllocSize(vecTy->getElementType());\n            }\n        }\n\n#if LLVM_VERSION_MAJOR >= 11\n        if (!llvm::GetElementPtrInst::getTypeAtIndex(type, idx))\n#else\n        if (!llvm::dyn_cast<llvm::CompositeType>(type->getTypeAtIndex(idx)))\n#endif\n            break; // we're done\n    }\n\n    return off;\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createExtract(const llvm::Instruction *Inst) {\n    using namespace llvm;\n\n    const ExtractValueInst *EI = cast<ExtractValueInst>(Inst);\n\n    // extract <agg> <idx> {<idx>, ...}\n    PSNode *op1 = getOperand(EI->getAggregateOperand());\n    PSNode *G = PS.create<PSNodeType::GEP>(\n            op1, accumulateEVOffsets(EI, M->getDataLayout()));\n    PSNode *L = PS.create<PSNodeType::LOAD>(G);\n\n    // FIXME: add this later with all edges\n    G->addSuccessor(L);\n\n    PSNodesSeq ret({G, L});\n    return addNode(Inst, ret);\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createPHI(const llvm::Instruction *Inst) {\n    PSNode *node = PS.create<PSNodeType::PHI>();\n    assert(node);\n\n    // NOTE: we didn't add operands to PHI node here, but after building\n    // the whole function, because some blocks may not have been built\n    // when we were creating the phi node\n\n    return addNode(Inst, node);\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createCast(const llvm::Instruction *Inst) {\n    const llvm::Value *op = Inst->getOperand(0);\n    PSNode *op1 = getOperand(op);\n    PSNode *node = PS.create<PSNodeType::CAST>(op1);\n    assert(node);\n    return addNode(Inst, node);\n}\n\n// ptrToInt work just as a bitcast\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createPtrToInt(const llvm::Instruction *Inst) {\n    const llvm::Value *op = Inst->getOperand(0);\n\n    PSNode *op1 = getOperand(op);\n    // NOTE: we don't support arithmetic operations, so instead of\n    // just casting the value do gep with unknown offset -\n    // this way we cover any shift of the pointer due to arithmetic\n    // operations\n    // PSNode *node = PS.create(PSNodeType::CAST, op1);\n    PSNode *node = PS.create<PSNodeType::GEP>(op1, 0);\n    return addNode(Inst, node);\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createIntToPtr(const llvm::Instruction *Inst) {\n    const llvm::Value *op = Inst->getOperand(0);\n    PSNode *op1;\n\n    if (llvm::isa<llvm::Constant>(op)) {\n        llvm::errs() << \"PTA warning: IntToPtr with constant: \" << *Inst\n                     << \"\\n\";\n        // if this is inttoptr with constant, just make the pointer\n        // unknown\n        op1 = UNKNOWN_MEMORY;\n    } else\n        op1 = getOperand(op);\n\n    PSNode *node = PS.create<PSNodeType::CAST>(op1);\n    assert(node);\n\n    return addNode(Inst, node);\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createAdd(const llvm::Instruction *Inst) {\n    using namespace llvm;\n\n    PSNode *node;\n    PSNode *op;\n    const Value *val = nullptr;\n    uint64_t off = Offset::UNKNOWN;\n\n    if (isa<ConstantInt>(Inst->getOperand(0))) {\n        op = getOperand(Inst->getOperand(1));\n        val = Inst->getOperand(0);\n    } else if (isa<ConstantInt>(Inst->getOperand(1))) {\n        op = getOperand(Inst->getOperand(0));\n        val = Inst->getOperand(1);\n    } else {\n        // the operands are both non-constant. Check if we\n        // can get an operand as one of them and if not,\n        // fall-back to unknown memory, because we\n        // would need to track down both operads...\n        op = tryGetOperand(Inst->getOperand(0));\n        if (!op)\n            op = tryGetOperand(Inst->getOperand(1));\n\n        if (!op)\n            return createUnknown(Inst);\n    }\n\n    assert(op && \"Don't have operand for add\");\n    if (val)\n        off = llvmutils::getConstantValue(val);\n\n    node = PS.create<PSNodeType::GEP>(op, off);\n    assert(node);\n\n    return addNode(Inst, node);\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createArithmetic(const llvm::Instruction *Inst) {\n    using namespace llvm;\n\n    PSNode *node;\n    PSNode *op;\n\n    // we don't know if the operand is the first or\n    // the other operand\n    if (isa<ConstantInt>(Inst->getOperand(0))) {\n        op = getOperand(Inst->getOperand(1));\n    } else if (isa<ConstantInt>(Inst->getOperand(0))) {\n        op = getOperand(Inst->getOperand(0));\n    } else {\n        // the operands are both non-constant. Check if we\n        // can get an operand as one of them and if not,\n        // fall-back to unknown memory, because we\n        // would need to track down both operads...\n        op = tryGetOperand(Inst->getOperand(0));\n        if (!op)\n            op = tryGetOperand(Inst->getOperand(1));\n\n        if (!op)\n            return createUnknown(Inst);\n    }\n\n    // we don't know what the operation does,\n    // so set unknown offset\n    node = PS.create<PSNodeType::GEP>(op, Offset::UNKNOWN);\n    assert(node);\n\n    return addNode(Inst, node);\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createReturn(const llvm::Instruction *Inst) {\n    PSNode *op1 = nullptr;\n    // is nullptr if this is 'ret void'\n    llvm::Value *retVal = llvm::cast<llvm::ReturnInst>(Inst)->getReturnValue();\n\n    // we create even void and non-pointer return nodes,\n    // since these modify CFG (they won't bear any\n    // points-to information though)\n    // XXX is that needed?\n\n    if (retVal) {\n        // A struct is being returned. In this case,\n        // return the address of the local variable\n        // that holds the return value, so that\n        // we can then do a load on this object\n        if (retVal->getType()->isAggregateType()) {\n            if (llvm::LoadInst *LI = llvm::dyn_cast<llvm::LoadInst>(retVal)) {\n                op1 = getOperand(LI->getPointerOperand());\n            }\n\n            if (!op1) {\n                llvm::errs()\n                        << \"WARN: Unsupported return of an aggregate type\\n\";\n                llvm::errs() << *Inst << \"\\n\";\n                op1 = UNKNOWN_MEMORY;\n            }\n        } else if (retVal->getType()->isVectorTy()) {\n            op1 = getOperand(retVal);\n            if (auto *alloc = PSNodeAlloc::get(op1)) {\n                assert(alloc->isTemporary());\n                (void) alloc; // c++17 TODO: replace with [[maybe_unused]]\n            } else {\n                llvm::errs() << \"WARN: Unsupported return of a vector\\n\";\n                llvm::errs() << *Inst << \"\\n\";\n                op1 = UNKNOWN_MEMORY;\n            }\n        }\n\n        if (llvm::isa<llvm::ConstantPointerNull>(retVal) ||\n            llvmutils::isConstantZero(retVal))\n            op1 = NULLPTR;\n        else if (llvmutils::typeCanBePointer(&M->getDataLayout(),\n                                             retVal->getType()) &&\n                 (!isInvalid(retVal->stripPointerCasts(), invalidate_nodes) ||\n                  llvm::isa<llvm::ConstantExpr>(retVal) ||\n                  llvm::isa<llvm::UndefValue>(retVal)))\n            op1 = getOperand(retVal);\n    }\n\n    assert((op1 || !retVal || !retVal->getType()->isPointerTy()) &&\n           \"Don't have an operand for ReturnInst with pointer\");\n\n    PSNode *node = op1 ? PS.create<PSNodeType::RETURN>(op1)\n                       : PS.create<PSNodeType::RETURN>();\n    assert(node);\n\n    return addNode(Inst, node);\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createInsertElement(const llvm::Instruction *Inst) {\n    PSNodeAlloc *tempAlloc = nullptr;\n    PSNode *lastNode = nullptr;\n    PSNodesSeq seq;\n\n    auto *Ty = llvm::cast<llvm::InsertElementInst>(Inst)->getType();\n    auto elemSize = llvmutils::getAllocatedSize(Ty->getContainedType(0),\n                                                &M->getDataLayout());\n    auto *vec = Inst->getOperand(0);\n    if (llvm::isa<llvm::UndefValue>(vec) || llvm::isa<llvm::Constant>(vec)) {\n        tempAlloc = PSNodeAlloc::get(PS.create<PSNodeType::ALLOC>());\n        tempAlloc->setIsTemporary();\n        seq.append(tempAlloc);\n        lastNode = tempAlloc;\n        if (llvm::isa<llvm::Constant>(vec) &&\n            !llvm::isa<llvm::UndefValue>(vec)) {\n            // populate the allocation with elements of the constant\n            unsigned idx = 0;\n            for (auto &op : llvm::cast<llvm::ConstantVector>(vec)->operands()) {\n                auto *ptr = getOperand(op);\n                auto *GEP =\n                        PS.create<PSNodeType::GEP>(tempAlloc, elemSize * idx);\n                auto *S = PS.create<PSNodeType::STORE>(ptr, GEP);\n\n                seq.append(GEP);\n                seq.append(S);\n\n                // TODO: do we need adding the successors here??\n                lastNode->addSuccessor(GEP);\n                GEP->addSuccessor(S);\n                lastNode = S;\n                ++idx;\n            }\n        }\n    } else {\n        auto *fromTempAlloc = PSNodeAlloc::get(getOperand(vec));\n        assert(fromTempAlloc && \"Is not an allocation node\");\n        assert(fromTempAlloc->isTemporary());\n\n        tempAlloc = PSNodeAlloc::get(PS.create<PSNodeType::ALLOC>());\n        tempAlloc->setIsTemporary();\n        assert(tempAlloc);\n        seq.append(tempAlloc);\n\n        // copy old temporary allocation to the new temp allocation\n        // (this is how insertelem works)\n        auto *cpy = PS.create<PSNodeType::MEMCPY>(fromTempAlloc, tempAlloc,\n                                                  Offset::UNKNOWN);\n        seq.append(cpy);\n        tempAlloc->addSuccessor(cpy);\n        lastNode = cpy;\n    }\n\n    assert(tempAlloc && \"Do not have the operand 0\");\n    seq.setRepresentant(tempAlloc);\n\n    // write the pointers to the temporary allocation representing\n    // the operand of insertelement\n    auto *ptr = getOperand(Inst->getOperand(1));\n    auto idx = llvmutils::getConstantValue(Inst->getOperand(2));\n    assert(idx != ~((uint64_t) 0) && \"Invalid index\");\n\n    // also, set the size of the temporary allocation\n    tempAlloc->setSize(llvmutils::getAllocatedSize(Ty, &M->getDataLayout()));\n\n    auto *GEP = PS.create<PSNodeType::GEP>(tempAlloc, elemSize * idx);\n    auto *S = PS.create<PSNodeType::STORE>(ptr, GEP);\n\n    seq.append(GEP);\n    seq.append(S);\n\n    lastNode->addSuccessor(GEP);\n    GEP->addSuccessor(S);\n\n    // this is a hack same as for call-inst.\n    // We should really change the design here...\n    tempAlloc->setPairedNode(S);\n\n    return addNode(Inst, seq);\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createExtractElement(const llvm::Instruction *Inst) {\n    auto *op = getOperand(Inst->getOperand(0));\n    assert(op && \"Do not have the operand 0\");\n\n    auto idx = llvmutils::getConstantValue(Inst->getOperand(1));\n    assert(idx != ~((uint64_t) 0) && \"Invalid index\");\n\n    auto *Ty =\n            llvm::cast<llvm::ExtractElementInst>(Inst)->getVectorOperandType();\n    auto elemSize = llvmutils::getAllocatedSize(Ty->getContainedType(0),\n                                                &M->getDataLayout());\n\n    auto *GEP = PS.create<PSNodeType::GEP>(op, elemSize * idx);\n    auto *L = PS.create<PSNodeType::LOAD>(GEP);\n\n    GEP->addSuccessor(L);\n\n    PSNodesSeq ret({GEP, L});\n    return addNode(Inst, ret);\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createAtomicRMW(const llvm::Instruction *Inst) {\n    using namespace llvm;\n\n    const auto *RMW = dyn_cast<AtomicRMWInst>(Inst);\n    assert(RMW && \"Wrong instruction\");\n\n    auto operation = RMW->getOperation();\n    if (operation != AtomicRMWInst::Xchg && operation != AtomicRMWInst::Add &&\n        operation != AtomicRMWInst::Sub) {\n        return createUnknown(Inst);\n    }\n\n    auto *ptr = getOperand(RMW->getPointerOperand());\n    Offset cval = Offset::UNKNOWN;\n\n    auto *R = PS.create<PSNodeType::LOAD>(ptr);\n\n    PSNode *M = nullptr;\n    switch (operation) {\n    case AtomicRMWInst::Xchg:\n        M = getOperand(RMW->getValOperand());\n        break;\n    case AtomicRMWInst::Add:\n        cval = Offset(llvmutils::getConstantValue(RMW->getValOperand()));\n        M = PS.create<PSNodeType::GEP>(ptr, cval);\n        R->addSuccessor(M);\n        break;\n    case AtomicRMWInst::Sub:\n        cval = Offset(0) -\n               Offset(llvmutils::getConstantValue(RMW->getValOperand()));\n        M = PS.create<PSNodeType::GEP>(ptr, cval);\n        R->addSuccessor(M);\n        break;\n    default:\n        assert(false && \"Invalid operation\");\n        abort();\n    }\n    assert(M);\n\n    auto *W = PS.create<PSNodeType::STORE>(M, ptr);\n    if (operation == AtomicRMWInst::Add || operation == AtomicRMWInst::Sub) {\n        M->addSuccessor(W);\n    }\n\n    PSNodesSeq ret({R, W});\n    return addNode(Inst, ret);\n}\n\n} // namespace pta\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/PointerAnalysis/Interprocedural.cpp",
    "content": "#include <llvm/Config/llvm-config.h>\n\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n#include <llvm/Support/CFG.h>\n#else\n#include <llvm/IR/CFG.h>\n#endif\n\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/Module.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#include \"dg/llvm/PointerAnalysis/PointerGraph.h\"\n\n#include \"llvm/llvm-utils.h\"\n\nnamespace dg {\nnamespace pta {\n\nvoid LLVMPointerGraphBuilder::addArgumentOperands(const llvm::CallInst *CI,\n                                                  PSNode *arg, unsigned idx) {\n    assert(idx < llvmutils::getNumArgOperands(CI));\n    PSNode *op = tryGetOperand(CI->getArgOperand(idx));\n    if (op && !arg->hasOperand(op)) {\n        // NOTE: do not add an operand multiple-times\n        // (when a function is called multiple-times with\n        // the same actual parameters)\n        arg->addOperand(op);\n    }\n}\n\nvoid LLVMPointerGraphBuilder::addArgumentOperands(const llvm::CallInst &CI,\n                                                  PSNode &node) {\n    for (const auto &arg : llvmutils::args(CI)) {\n        PSNode *operand = tryGetOperand(arg);\n        if (operand && !node.hasOperand(operand)) {\n            node.addOperand(operand);\n        }\n    }\n}\n\nvoid LLVMPointerGraphBuilder::addArgumentOperands(const llvm::Function *F,\n                                                  PSNode *arg, unsigned idx) {\n    using namespace llvm;\n\n    for (auto I = F->use_begin(), E = F->use_end(); I != E; ++I) {\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n        const Value *use = *I;\n#else\n        const Value *use = I->getUser();\n#endif\n        const CallInst *CI = dyn_cast<CallInst>(use);\n        if (CI && CI->getCalledFunction() == F)\n            addArgumentOperands(CI, arg, idx);\n    }\n}\n\nvoid LLVMPointerGraphBuilder::addArgumentsOperands(const llvm::Function *F,\n                                                   const llvm::CallInst *CI,\n                                                   unsigned index) {\n    for (auto A = F->arg_begin(), E = F->arg_end(); A != E; ++A, ++index) {\n        auto it = nodes_map.find(&*A);\n        assert(it != nodes_map.end());\n        PSNodesSeq &cur = it->second;\n\n        if (CI) {\n            // with func ptr call we know from which\n            // call we should take the values\n            addArgumentOperands(CI, cur.getSingleNode(), index);\n        } else {\n            // with regular call just use all calls\n            addArgumentOperands(F, cur.getSingleNode(), index);\n        }\n    }\n}\n\nvoid LLVMPointerGraphBuilder::addVariadicArgumentOperands(\n        const llvm::Function *F, const llvm::CallInst *CI, PSNode *arg) {\n    for (unsigned idx = F->arg_size() - 1;\n         idx < llvmutils::getNumArgOperands(CI); ++idx)\n        addArgumentOperands(CI, arg, idx);\n}\n\nvoid LLVMPointerGraphBuilder::addVariadicArgumentOperands(\n        const llvm::Function *F, PSNode *arg) {\n    using namespace llvm;\n\n    for (auto I = F->use_begin(), E = F->use_end(); I != E; ++I) {\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n        const Value *use = *I;\n#else\n        const Value *use = I->getUser();\n#endif\n        const CallInst *CI = dyn_cast<CallInst>(use);\n        if (CI && CI->getCalledFunction() == F)\n            addVariadicArgumentOperands(F, CI, arg);\n        // if this is funcptr, we handle it in the other\n        // version of addVariadicArgumentOperands\n    }\n}\n\nvoid LLVMPointerGraphBuilder::addReturnNodesOperands(const llvm::Function *F,\n                                                     PointerSubgraph &subg,\n                                                     PSNode *callNode) {\n    using namespace llvm;\n\n    for (PSNode *r : subg.returnNodes) {\n        // call-return node is like a PHI node\n        // But we're interested only in the nodes that return some value\n        // from subprocedure, not for all nodes that have no successor.\n        if (callNode) {\n            addReturnNodeOperand(callNode, r);\n        } else {\n            addReturnNodeOperand(F, r);\n        }\n    }\n}\n\nvoid LLVMPointerGraphBuilder::addReturnNodeOperand(PSNode *callNode,\n                                                   PSNode *ret) {\n    assert(PSNodeRet::get(ret));\n    auto *callReturn = PSNodeCallRet::cast(callNode->getPairedNode());\n    // the function must be defined, since we have the return node,\n    // so there must be associated the return node\n    assert(callReturn);\n    assert(callReturn != callNode);\n    assert(callReturn->getType() == PSNodeType::CALL_RETURN);\n\n    if (!callReturn->hasOperand(ret))\n        callReturn->addOperand(ret);\n\n    // setup return edges (do it here, since recursive calls\n    // may not have build return nodes earlier)\n    PSNodeRet::get(ret)->addReturnSite(callReturn);\n    callReturn->addReturn(ret);\n}\n\nvoid LLVMPointerGraphBuilder::addReturnNodeOperand(const llvm::Function *F,\n                                                   PSNode *op) {\n    using namespace llvm;\n\n    for (auto I = F->use_begin(), E = F->use_end(); I != E; ++I) {\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n        const Value *use = *I;\n#else\n        const Value *use = I->getUser();\n#endif\n        // get every call and its assocciated return and add the operand\n        const CallInst *CI = dyn_cast<CallInst>(use);\n        if (CI && CI->getCalledFunction() == F) {\n            auto *nodes = getNodes(CI);\n            // since we're building the graph only for the reachable nodes from\n            // the entry, we may not have all call-sites of this function\n            if (!nodes)\n                continue;\n            PSNode *callNode = nodes->getFirst();\n            assert(PSNodeCall::cast(callNode) && \"Got wrong node\");\n            addReturnNodeOperand(callNode, op);\n        }\n    }\n}\n\nvoid LLVMPointerGraphBuilder::addInterproceduralPthreadOperands(\n        const llvm::Function *F, const llvm::CallInst *CI) {\n    // last argument (with index 3) is argument to function pthread_create will\n    // call\n    addArgumentsOperands(F, CI, 3);\n}\n\nvoid LLVMPointerGraphBuilder::addInterproceduralOperands(\n        const llvm::Function *F, PointerSubgraph &subg,\n        const llvm::CallInst *CI, PSNode *callNode) {\n    assert((!CI || callNode) && (!callNode || CI));\n\n    // add operands to arguments' PHI nodes\n    addArgumentsOperands(F, CI);\n\n    if (F->isVarArg()) {\n        assert(subg.vararg);\n        if (CI)\n            // funcptr call\n            addVariadicArgumentOperands(F, CI, subg.vararg);\n        else\n            addVariadicArgumentOperands(F, subg.vararg);\n    }\n\n    if (!subg.returnNodes.empty()) {\n        addReturnNodesOperands(F, subg, callNode);\n    } else if (callNode) {\n        // disconnect call-return nodes\n        auto *callReturnNode = PSNodeCallRet::cast(callNode->getPairedNode());\n        assert(callReturnNode && callNode != callReturnNode);\n        (void) callReturnNode; // c++17 TODO: replace with [[maybe_unused]]\n\n        if (callNode->successorsNum() != 0) {\n            assert(callNode->getSingleSuccessor() == callReturnNode);\n            callNode->removeSingleSuccessor();\n        } else {\n            // the call does not return\n            assert(callNode->successorsNum() == 0);\n        }\n    }\n}\n\n} // namespace pta\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/PointerAnalysis/PointerAnalysis.cpp",
    "content": "#include <llvm/IR/Instruction.h>\n\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n#include \"llvm/llvm-utils.h\"\n\nnamespace dg {\n\nstd::pair<bool, LLVMMemoryRegionSet>\nLLVMPointerAnalysis::getAccessedMemory(const llvm::Instruction *I) {\n    using namespace llvm;\n\n    LLVMPointsToSet PTSet;\n    LLVMPointsToSet PTSet2; // memmove and such use two ptsets\n    LLVMMemoryRegionSet regions;\n    Offset len;\n\n    const Module *M = I->getParent()->getParent()->getParent();\n    const auto &DL = M->getDataLayout();\n\n    if (isa<StoreInst>(I)) {\n        PTSet = getLLVMPointsTo(I->getOperand(1));\n        len = llvmutils::getAllocatedSize(I->getOperand(0)->getType(), &DL);\n    } else if (isa<LoadInst>(I)) {\n        PTSet = getLLVMPointsTo(I->getOperand(0));\n        len = llvmutils::getAllocatedSize(I->getType(), &DL);\n    } else if (isa<VAArgInst>(I)) {\n        PTSet = getLLVMPointsTo(I->getOperand(0));\n        len = Offset::UNKNOWN;\n    } else if (isa<AtomicCmpXchgInst>(I)) {\n        PTSet = getLLVMPointsTo(I->getOperand(0));\n        len = llvmutils::getAllocatedSize(I->getOperand(2)->getType(), &DL);\n    } else if (isa<AtomicRMWInst>(I)) {\n        PTSet = getLLVMPointsTo(I->getOperand(0));\n        len = llvmutils::getAllocatedSize(I->getOperand(1)->getType(), &DL);\n    } else if (const auto *II = dyn_cast<IntrinsicInst>(I)) {\n        switch (II->getIntrinsicID()) {\n        // lifetime start/end do not access the memory,\n        // but the user may want to find out information\n        // also about these\n        case Intrinsic::lifetime_start:\n        case Intrinsic::lifetime_end:\n            PTSet = getLLVMPointsTo(I->getOperand(1));\n            len = llvmutils::getConstantValue(II->getOperand(0));\n            break;\n        case Intrinsic::memset:\n            PTSet = getLLVMPointsTo(I->getOperand(0));\n            len = llvmutils::getConstantValue(II->getOperand(2));\n            break;\n        case Intrinsic::memmove:\n        case Intrinsic::memcpy:\n            PTSet = getLLVMPointsTo(I->getOperand(0));\n            PTSet2 = getLLVMPointsTo(I->getOperand(1));\n            len = llvmutils::getConstantValue(II->getOperand(2));\n            break;\n        case Intrinsic::vastart:\n        case Intrinsic::vaend:\n            PTSet = getLLVMPointsTo(I->getOperand(0));\n            len = Offset::UNKNOWN;\n            break;\n        case Intrinsic::vacopy:\n            PTSet = getLLVMPointsTo(I->getOperand(0));\n            PTSet2 = getLLVMPointsTo(I->getOperand(1));\n            len = Offset::UNKNOWN;\n            break;\n        default:\n            llvm::errs() << \"ERROR: Unhandled intrinsic\\n\" << *I << \"\\n\";\n            return {true, regions};\n        }\n    } else if (const auto *CI = dyn_cast<CallInst>(I)) {\n        if (CI->doesNotAccessMemory()) {\n            return {false, regions};\n        }\n\n        // check which operands are pointers and get the information for them\n        bool hasUnknown = false;\n        for (const auto &arg : llvmutils::args(CI)) {\n            if (hasPointsTo(arg)) {\n                auto tmp = getLLVMPointsToChecked(arg);\n                hasUnknown |= tmp.first;\n                // translate to regions\n                for (const auto &ptr : tmp.second) {\n                    regions.add(ptr.value, Offset::UNKNOWN, Offset::UNKNOWN);\n                }\n            }\n        }\n        return {hasUnknown, regions};\n    } else {\n        if (I->mayReadOrWriteMemory()) {\n            llvm::errs() << \"[ERROR]: getAccessedMemory: unhandled intruction\\n\"\n                         << *I << \"\\n\";\n        } else {\n            llvm::errs() << \"[ERROR]: getAccessedMemory: queries invalid \"\n                            \"instruction\\n\"\n                         << *I << \"\\n\";\n        }\n        return {true, regions};\n    }\n\n    if (len == 0) // unknown length\n        len = Offset::UNKNOWN;\n\n    // translate to regions\n    for (const auto &ptr : PTSet) {\n        regions.add(ptr.value, ptr.offset, len);\n    }\n    for (const auto &ptr : PTSet2) {\n        regions.add(ptr.value, ptr.offset, len);\n    }\n\n    return {PTSet.hasUnknown(), regions};\n}\n\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/PointerAnalysis/PointerGraph.cpp",
    "content": "#include <cassert>\n#include <set>\n\n#include <llvm/Config/llvm-config.h>\n\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n#include <llvm/Support/CFG.h>\n#else\n#include <llvm/IR/CFG.h>\n#endif\n\n#include <llvm/IR/Constant.h>\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/DataLayout.h>\n#include <llvm/IR/Function.h>\n#include <llvm/IR/Instruction.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/IntrinsicInst.h>\n#include <llvm/IR/Module.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#include <llvm/IR/Dominators.h>\n\n#include \"dg/PointerAnalysis/PointerGraph.h\"\n#include \"dg/PointerAnalysis/PointerGraphOptimizations.h\"\n#include \"dg/llvm/PointerAnalysis/PointerGraph.h\"\n\n#include \"llvm/PointerAnalysis/PointerGraphValidator.h\"\n#include \"llvm/llvm-utils.h\"\n\n#include \"dg/util/debug.h\"\n\nnamespace dg {\nnamespace pta {\n\nPSNode *LLVMPointerGraphBuilder::getConstant(const llvm::Value *val) {\n    using namespace llvm;\n    if (isa<ConstantPointerNull>(val) || llvmutils::isConstantZero(val)) {\n        return NULLPTR;\n    }\n    if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(val)) {\n        return createConstantExpr(CE).getRepresentant();\n    }\n    if (isa<Function>(val)) {\n        PSNode *ret = PS.create<PSNodeType::FUNCTION>();\n        addNode(val, ret);\n        return ret;\n    }\n    if (isa<Constant>(val) || isa<UndefValue>(val)) {\n        // it is just some constant that we can not handle\n        return UNKNOWN_MEMORY;\n    }\n\n    return nullptr;\n}\n\n// try get operand, return null if no such value has been constructed\nPSNode *LLVMPointerGraphBuilder::tryGetOperand(const llvm::Value *val) {\n    auto it = nodes_map.find(val);\n    PSNode *op = nullptr;\n\n    if (it != nodes_map.end())\n        op = it->second.getRepresentant();\n\n    // if we don't have the operand, then it is a ConstantExpr\n    // or some operand of intToPtr instruction (or related to that)\n    if (!op) {\n        if (llvm::isa<llvm::Constant>(val)) {\n            op = getConstant(val);\n            if (!op) {\n                // unknown constant\n                llvm::errs() << \"ERR: unhandled constant: \" << *val << \"\\n\";\n                return nullptr;\n            }\n        } else\n            // unknown operand\n            return nullptr;\n    }\n\n    // we either found the operand, or we bailed out earlier,\n    // so we need to have the operand here\n    assert(op && \"Did not find an operand\");\n\n    // if the operand is a call, use the return node of the call instead\n    // - that is the one that contains returned pointers\n    if (op->isCall()) {\n        op = op->getPairedNode();\n    }\n\n    return op;\n}\n\nPSNode *LLVMPointerGraphBuilder::getOperand(const llvm::Value *val) {\n    PSNode *op = tryGetOperand(val);\n    if (!op) {\n        if (isInvalid(val, invalidate_nodes))\n            return UNKNOWN_MEMORY;\n\n        llvm::errs() << \"ERROR: missing value in graph: \" << *val << \"\\n\";\n        abort();\n    } else\n        return op;\n}\n\nPointerSubgraph &\nLLVMPointerGraphBuilder::getAndConnectSubgraph(const llvm::Function *F,\n                                               const llvm::CallInst *CInst,\n                                               PSNode *callNode) {\n    // find or build the subgraph for the function F\n    PointerSubgraph &subg = createOrGetSubgraph(F);\n    assert(subg.root); // we took the subg by reference, so it should be filled\n                       // now\n\n    // setup call edges\n    PSNodeCall::cast(callNode)->addCallee(&subg);\n    PSNodeEntry *ent = PSNodeEntry::cast(subg.root);\n    ent->addCaller(callNode);\n\n    // update callgraph\n    const auto *callerF = CInst->getParent()->getParent();\n    PS.registerCall(getPointsToNode(callerF), getPointsToNode(F));\n    DBG(pta, \"CallGraph: \" << callerF->getName().str() << \" -> \"\n                           << F->getName().str());\n\n    return subg;\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createCallToFunction(const llvm::CallInst *CInst,\n                                              const llvm::Function *F) {\n    PSNodeCall *callNode = PSNodeCall::get(PS.create<PSNodeType::CALL>());\n    auto &subg = getAndConnectSubgraph(F, CInst, callNode);\n\n    // the operands to the return node (which works as a phi node)\n    // are going to be added when the subgraph is built\n    PSNodeCallRet *returnNode =\n            PSNodeCallRet::get(PS.create<PSNodeType::CALL_RETURN>());\n\n    returnNode->setPairedNode(callNode);\n    callNode->setPairedNode(returnNode);\n\n    // this must be after we created the CALL_RETURN node\n    if (ad_hoc_building) {\n        // add operands to arguments and return nodes\n        addInterproceduralOperands(F, subg, CInst, callNode);\n    }\n\n    PSNodesSeq seq({callNode, returnNode});\n    seq.setRepresentant(returnNode);\n\n    return addNode(CInst, seq);\n}\n\nbool LLVMPointerGraphBuilder::callIsCompatible(PSNode *call, PSNode *func) {\n    const llvm::CallInst *CI = call->getUserData<llvm::CallInst>();\n    const llvm::Function *F = func->getUserData<llvm::Function>();\n    assert(CI && \"No user data in call node\");\n    assert(F && \"No user data in function node\");\n    // incompatible prototypes, skip it...\n    return llvmutils::callIsCompatible(F, CI);\n}\n\nvoid LLVMPointerGraphBuilder::insertFunctionCall(PSNode *callsite,\n                                                 PSNode *called) {\n    const llvm::CallInst *CI = callsite->getUserData<llvm::CallInst>();\n    const llvm::Function *F = called->getUserData<llvm::Function>();\n\n    if (F->isDeclaration()) {\n        /// memory allocation (malloc, calloc, etc.)\n        auto seq = createUndefFunctionCall(CI, F);\n        // we must manually set the data of representant,\n        // as we didn't call addNode\n        auto *repr = seq.getRepresentant();\n        repr->setUserData(const_cast<llvm::CallInst *>(CI));\n        // add internal successors\n        PSNodesSequenceAddSuccessors(seq);\n\n        callsite->addSuccessor(seq.getFirst());\n        auto *retval = callsite->getPairedNode();\n        seq.getLast()->addSuccessor(retval);\n\n        retval->addOperand(seq.getRepresentant());\n        return;\n    }\n\n    PointerSubgraph &subg = getAndConnectSubgraph(F, CI, callsite);\n\n    // remove the CFG edge and keep only the call edge\n    if (callsite->successorsNum() == 1 &&\n        callsite->getSingleSuccessor() == callsite->getPairedNode()) {\n        callsite->removeSingleSuccessor();\n    }\n\n    assert(ad_hoc_building && \"This should be called with ad_hoc_building\");\n    // add operands to arguments and return nodes\n    addInterproceduralOperands(F, subg, CI, callsite);\n}\n\nstd::vector<PSNode *>\nLLVMPointerGraphBuilder::getPointsToFunctions(const llvm::Value *calledValue) {\n    using namespace llvm;\n    std::vector<PSNode *> functions;\n    if (isa<Function>(calledValue)) {\n        PSNode *node;\n        auto iterator = nodes_map.find(calledValue);\n        if (iterator == nodes_map.end()) {\n            node = PS.create<PSNodeType::FUNCTION>();\n            addNode(calledValue, node);\n            functions.push_back(node);\n        } else {\n            functions.push_back(iterator->second.getFirst());\n        }\n        return functions;\n    }\n\n    PSNode *operand = getPointsToNode(calledValue);\n    if (operand == nullptr) {\n        return functions;\n    }\n\n    for (const auto &pointer : operand->pointsTo) {\n        if (pointer.isValid() && !pointer.isInvalidated() &&\n            isa<Function>(pointer.target->getUserData<Value>())) {\n            functions.push_back(pointer.target);\n        }\n    }\n    return functions;\n}\n\nPointerSubgraph &\nLLVMPointerGraphBuilder::createOrGetSubgraph(const llvm::Function *F) {\n    auto it = subgraphs_map.find(F);\n    if (it == subgraphs_map.end()) {\n        // create a new subgraph\n        PointerSubgraph &subg = buildFunction(*F);\n        assert(subg.root != nullptr);\n\n        if (ad_hoc_building) {\n            addProgramStructure(F, subg);\n        }\n\n        return subg;\n    }\n\n    assert(it->second != nullptr && \"Subgraph is nullptr\");\n    return *it->second;\n}\n\nPointerSubgraph *LLVMPointerGraphBuilder::getSubgraph(const llvm::Function *F) {\n    auto it = subgraphs_map.find(F);\n    if (it == subgraphs_map.end()) {\n        return nullptr;\n    }\n\n    assert(it->second != nullptr && \"Subgraph is nullptr\");\n    return it->second;\n}\n\nvoid LLVMPointerGraphBuilder::addPHIOperands(PSNode *node,\n                                             const llvm::PHINode *PHI) {\n    for (unsigned i = 0, e = PHI->getNumIncomingValues(); i < e; ++i) {\n        if (PSNode *op = tryGetOperand(PHI->getIncomingValue(i))) {\n            // do not add duplicate operands\n            if (!node->hasOperand(op))\n                node->addOperand(op);\n        }\n    }\n}\n\ntemplate <typename OptsT>\nstatic bool isRelevantCall(const llvm::Instruction *Inst, bool invalidate_nodes,\n                           const OptsT &opts) {\n    using namespace llvm;\n\n    // we don't care about debugging stuff\n    if (isa<DbgValueInst>(Inst))\n        return false;\n\n    const CallInst *CInst = cast<CallInst>(Inst);\n#if LLVM_VERSION_MAJOR >= 8\n    const Value *calledVal = CInst->getCalledOperand()->stripPointerCasts();\n#else\n    const Value *calledVal = CInst->getCalledValue()->stripPointerCasts();\n#endif\n    const Function *func = dyn_cast<Function>(calledVal);\n\n    if (!func)\n        // function pointer call - we need that in PointerGraph\n        return true;\n\n    if (func->empty()) {\n        if (opts.getAllocationFunction(func->getName().str()) !=\n            AllocationFunction::NONE)\n            // we need memory allocations\n            return true;\n\n        if (func->getName().equals(\"free\"))\n            // we need calls of free\n            return true;\n\n        if (func->getName().equals(\"pthread_exit\"))\n            return true;\n\n        if (func->isIntrinsic())\n            return isRelevantIntrinsic(func, invalidate_nodes);\n\n        // it returns something? We want that!\n        return !func->getReturnType()->isVoidTy();\n    } // we want defined function, since those can contain\n    // pointer's manipulation and modify CFG\n    return true;\n\n    assert(0 && \"We should not reach this\");\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::buildInstruction(const llvm::Instruction &Inst) {\n    using namespace llvm;\n\n    PSNodesSeq *seq{nullptr};\n\n    switch (Inst.getOpcode()) {\n    case Instruction::Alloca:\n        seq = &createAlloc(&Inst);\n        break;\n    case Instruction::Store:\n        seq = &createStore(&Inst);\n        break;\n    case Instruction::Load:\n        seq = &createLoad(&Inst);\n        break;\n    case Instruction::GetElementPtr:\n        seq = &createGEP(&Inst);\n        break;\n    case Instruction::ExtractValue:\n        return createExtract(&Inst);\n    case Instruction::Select:\n        seq = &createSelect(&Inst);\n        break;\n    case Instruction::PHI:\n        seq = &createPHI(&Inst);\n        break;\n    case Instruction::BitCast:\n    case Instruction::SExt:\n    case Instruction::ZExt:\n        seq = &createCast(&Inst);\n        break;\n    case Instruction::PtrToInt:\n        seq = &createPtrToInt(&Inst);\n        break;\n    case Instruction::IntToPtr:\n        seq = &createIntToPtr(&Inst);\n        break;\n    case Instruction::Ret:\n        seq = &createReturn(&Inst);\n        break;\n    case Instruction::Call:\n        return createCall(&Inst);\n    case Instruction::And:\n    case Instruction::Or:\n    case Instruction::Trunc:\n    case Instruction::Shl:\n    case Instruction::LShr:\n    case Instruction::AShr:\n    case Instruction::Xor:\n    case Instruction::FSub:\n    case Instruction::FAdd:\n    case Instruction::FDiv:\n    case Instruction::FMul:\n    case Instruction::UDiv:\n    case Instruction::SDiv:\n    case Instruction::URem:\n    case Instruction::SRem:\n    case Instruction::FRem:\n    case Instruction::FPTrunc:\n    case Instruction::FPExt:\n#if LLVM_VERSION_MAJOR >= 8\n    case Instruction::FNeg:\n#endif\n        // these instructions reinterpert the pointer,\n        // nothing better we can do here (I think?)\n        seq = &createUnknown(&Inst);\n        break;\n    case Instruction::Add:\n        seq = &createAdd(&Inst);\n        break;\n    case Instruction::Sub:\n    case Instruction::Mul:\n        seq = &createArithmetic(&Inst);\n        break;\n    case Instruction::UIToFP:\n    case Instruction::SIToFP:\n        seq = &createCast(&Inst);\n        break;\n    case Instruction::FPToUI:\n    case Instruction::FPToSI:\n        if (llvmutils::typeCanBePointer(&M->getDataLayout(), Inst.getType()))\n            seq = &createCast(&Inst);\n        else\n            seq = &createUnknown(&Inst);\n        break;\n    case Instruction::InsertElement:\n        return createInsertElement(&Inst);\n    case Instruction::ExtractElement:\n        return createExtractElement(&Inst);\n    case Instruction::AtomicRMW:\n        return createAtomicRMW(&Inst);\n    case Instruction::ShuffleVector:\n        llvm::errs() << \"ShuffleVector instruction is not supported, loosing \"\n                        \"precision\\n\";\n        seq = &createUnknown(&Inst);\n        break;\n    default:\n        llvm::errs() << \"[pta] UNHANDLED: \" << Inst << \"\\n\";\n        assert(0 && \"Unhandled instruction\");\n        seq = &createUnknown(&Inst);\n    }\n\n    assert(seq && \"Did not create instruction\");\n    return *seq;\n}\n\n// is the instruction relevant to points-to analysis?\nbool LLVMPointerGraphBuilder::isRelevantInstruction(\n        const llvm::Instruction &Inst) {\n    using namespace llvm;\n\n    switch (Inst.getOpcode()) {\n    case Instruction::ICmp:\n    case Instruction::FCmp:\n    case Instruction::Br:\n    case Instruction::Switch:\n    case Instruction::Unreachable:\n        return false;\n    case Instruction::Fence:\n        // this one is relevant only if we analyze threads\n        return _options.threads;\n    case Instruction::Call:\n        return isRelevantCall(&Inst, invalidate_nodes, _options);\n    default:\n        return true;\n    }\n\n    assert(0 && \"Not to be reached\");\n}\n\n// create a formal argument\nLLVMPointerGraphBuilder::PSNodesSeq &\nLLVMPointerGraphBuilder::createArgument(const llvm::Argument *farg) {\n    PSNode *arg = PS.create<PSNodeType::PHI>();\n    return addNode(farg, arg);\n}\n\nvoid LLVMPointerGraphBuilder::checkMemSet(const llvm::Instruction *Inst) {\n    using namespace llvm;\n\n    if (!llvmutils::memsetIsZeroInitialization(cast<IntrinsicInst>(Inst))) {\n        llvm::errs() << \"WARNING: Non-0 memset: \" << *Inst << \"\\n\";\n        return;\n    }\n\n    const Value *src = Inst->getOperand(0)->stripInBoundsOffsets();\n    PSNode *op = getOperand(src);\n\n    if (const AllocaInst *AI = dyn_cast<AllocaInst>(src)) {\n        // if there cannot be stored a pointer, we can bail out here\n        // XXX: what if it is alloca of generic mem (e. g. [100 x i8])\n        // and we then store there a pointer? Or zero it and load from it?\n        // like:\n        // char mem[100];\n        // void *ptr = (void *) mem;\n        // void *p = *ptr;\n        if (llvmutils::tyContainsPointer(AI->getAllocatedType()))\n            PSNodeAlloc::cast(op)->setZeroInitialized();\n    } else {\n        // fallback: create a store that represents memset\n        // the store will save null to ptr + Offset::UNKNOWN,\n        // so we need to do:\n        // G = GEP(op, Offset::UNKNOWN)\n        // STORE(null, G)\n        buildInstruction(*Inst);\n    }\n}\n\n// Get llvm BasicBlock's in levels of Dominator Tree (BFS order through the\n// dominator tree)\nstd::vector<const llvm::BasicBlock *>\ngetBasicBlocksInDominatorOrder(llvm::Function &F) {\n    std::vector<const llvm::BasicBlock *> blocks;\n    blocks.reserve(F.size());\n\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 9))\n    llvm::DominatorTree DTree;\n    DTree.recalculate(F);\n#else\n    llvm::DominatorTreeWrapperPass wrapper;\n    wrapper.runOnFunction(F);\n    auto &DTree = wrapper.getDomTree();\n#ifndef NDEBUG\n    wrapper.verifyAnalysis();\n#endif\n#endif\n\n    auto *root_node = DTree.getRootNode();\n    blocks.push_back(root_node->getBlock());\n\n    std::vector<llvm::DomTreeNode *> to_process;\n    to_process.reserve(4);\n    to_process.push_back(root_node);\n\n    while (!to_process.empty()) {\n        std::vector<llvm::DomTreeNode *> new_to_process;\n        new_to_process.reserve(to_process.size());\n\n        for (auto *cur_node : to_process) {\n            for (auto *child : *cur_node) {\n                new_to_process.push_back(child);\n                blocks.push_back(child->getBlock());\n            }\n        }\n\n        to_process.swap(new_to_process);\n    }\n\n    return blocks;\n}\n\nvoid LLVMPointerGraphBuilder::buildArguments(const llvm::Function &F,\n                                             PointerSubgraph *parent) {\n    for (auto A = F.arg_begin(), E = F.arg_end(); A != E; ++A) {\n#ifndef NDEBUG\n        PSNode *a = tryGetOperand(&*A);\n        // we must not have built this argument before\n        // (or it is a number or irelevant value)\n        assert(a == nullptr || a == UNKNOWN_MEMORY);\n#endif\n        auto &arg = createArgument(&*A);\n        arg.getSingleNode()->setParent(parent);\n    }\n}\n\nPointerSubgraph &\nLLVMPointerGraphBuilder::buildFunction(const llvm::Function &F) {\n    DBG_SECTION_BEGIN(pta, \"building function '\" << F.getName().str() << \"'\");\n\n    assert(!getSubgraph(&F) && \"We already built this function\");\n    assert(!F.isDeclaration() && \"Cannot build an undefined function\");\n\n    // create root and later (an unified) return nodes of this subgraph.\n    // These are just for our convenience when building the graph,\n    // they can be optimized away later since they are noops\n    PSNodeEntry *root = PSNodeEntry::get(PS.create<PSNodeType::ENTRY>());\n    assert(root);\n    root->setFunctionName(F.getName().str());\n\n    // if the function has variable arguments,\n    // then create the node for it\n    PSNode *vararg = nullptr;\n    if (F.isVarArg()) {\n        vararg = PS.create<PSNodeType::PHI>();\n    }\n\n    // add record to built graphs here, so that subsequent call of this function\n    // from buildPointerGraphBlock won't get stuck in infinite recursive call\n    // when this function is recursive\n    PointerSubgraph *subg = PS.createSubgraph(root, vararg);\n    subgraphs_map[&F] = subg;\n\n    assert(subg->root == root && subg->vararg == vararg);\n\n    // create the arguments\n    buildArguments(F, subg);\n\n    root->setParent(subg);\n    if (vararg)\n        vararg->setParent(subg);\n\n    assert(_funcInfo.find(&F) == _funcInfo.end());\n    auto &finfo = _funcInfo[&F];\n    auto llvmBlocks =\n            getBasicBlocksInDominatorOrder(const_cast<llvm::Function &>(F));\n\n    // build the instructions from blocks\n    for (const llvm::BasicBlock *block : llvmBlocks) {\n        auto blk = buildPointerGraphBlock(*block, subg);\n\n        if (blk.empty()) {\n            continue;\n        }\n\n        assert(finfo.llvmBlocks.find(block) == finfo.llvmBlocks.end() &&\n               \"Already have this block\");\n\n        // gather all return nodes\n        if ((blk.getLastNode()->getType() == PSNodeType::RETURN)) {\n            subg->returnNodes.insert(blk.getLastNode());\n        }\n\n        finfo.llvmBlocks.emplace(block, std::move(blk));\n    }\n\n    // add operands to PHI nodes. It must be done after all blocks are\n    // built, since the PHI gathers values from different blocks\n    addPHIOperands(F);\n\n    assert(getSubgraph(&F)->root != nullptr);\n    DBG_SECTION_END(pta,\n                    \"building function '\" << F.getName().str() << \"' done\");\n    return *subg;\n}\n\nvoid LLVMPointerGraphBuilder::addProgramStructure() {\n    // form intraprocedural program structure (CFG edges)\n    for (auto &it : subgraphs_map) {\n        const llvm::Function *F = it.first;\n        PointerSubgraph *subg = it.second;\n        assert(subg && \"Subgraph was nullptr\");\n\n        // add the CFG edges\n        addProgramStructure(F, *subg);\n\n        // add the missing operands (to arguments and return nodes)\n        addInterproceduralOperands(F, *subg);\n    }\n}\n\nPointerGraph *LLVMPointerGraphBuilder::buildLLVMPointerGraph() {\n    DBG_SECTION_BEGIN(pta, \"building pointer graph\");\n\n    // get entry function\n    llvm::Function *F = M->getFunction(_options.entryFunction);\n    if (!F) {\n        llvm::errs() << \"Did not find \" << _options.entryFunction\n                     << \" function in module\\n\";\n        abort();\n    }\n\n    // first we must build globals, because nodes can use them as operands\n    buildGlobals();\n\n    // now we can build rest of the graph\n    PointerSubgraph &subg = buildFunction(*F);\n    PSNode *root = subg.root;\n    assert(root != nullptr);\n    (void) root; // c++17 TODO: replace with [[maybe_unused]]\n\n    // fill in the CFG edges\n    addProgramStructure();\n\n    // FIXME: set entry procedure, not an entry node\n    auto *mainsg = getSubgraph(F);\n    assert(mainsg);\n    PS.setEntry(mainsg);\n\n    // add root to the call graph\n    PS.getCallGraph().createNode(getPointsToNode(F));\n\n#ifndef NDEBUG\n    for (const auto &subg : PS.getSubgraphs()) {\n        assert(subg->root && \"No root in a subgraph\");\n    }\n\n    LLVMPointerGraphValidator validator(&PS);\n    if (validator.validate()) {\n        llvm::errs() << validator.getWarnings();\n\n        llvm::errs() << \"Pointer Subgraph is broken (right after building)!\\n\";\n        assert(!validator.getErrors().empty());\n        llvm::errs() << validator.getErrors();\n        // return nullptr;\n    } else {\n        llvm::errs() << validator.getWarnings();\n    }\n#endif // NDEBUG\n\n    // set this flag to true, so that createCallToFunction\n    // (and all recursive calls to this function)\n    // will also add the program structure instead of only\n    // building the nodes. This is needed as we have the\n    // graph already built and we are now only building\n    // newly created subgraphs ad hoc.\n    ad_hoc_building = true;\n\n    DBG_SECTION_END(pta, \"building pointer graph done\");\n\n    return &PS;\n}\n\nbool LLVMPointerGraphBuilder::validateSubgraph(bool no_connectivity) const {\n    LLVMPointerGraphValidator validator(getPS(), no_connectivity);\n    if (validator.validate()) {\n        assert(!validator.getErrors().empty());\n        llvm::errs() << validator.getErrors();\n        return false;\n    }\n    return true;\n}\n\nstd::vector<PSNode *>\nLLVMPointerGraphBuilder::getFunctionNodes(const llvm::Function *F) const {\n    auto it = subgraphs_map.find(F);\n    if (it == subgraphs_map.end())\n        return {};\n\n    auto nodes =\n            getReachableNodes(it->second->root, nullptr, false /* interproc */);\n    std::vector<PSNode *> ret;\n    ret.reserve(nodes.size());\n    std::copy(nodes.begin(), nodes.end(), std::back_inserter(ret));\n\n    return ret;\n}\n\n} // namespace pta\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/PointerAnalysis/PointerGraphValidator.cpp",
    "content": "#include <llvm/IR/Type.h>\n#include <llvm/IR/Value.h>\n\n#include \"llvm/PointerAnalysis/PointerGraphValidator.h\"\n\nnamespace dg {\nnamespace pta {\n\nstatic const llvm::Value *getValue(const PSNode *nd) {\n    return nd->getUserData<llvm::Value>();\n}\n\nbool LLVMPointerGraphValidator::reportInvalOperands(\n        const PSNode *nd, const std::string &user_err) {\n    // just check whether the PHI is a pointer type. If it is a number,\n    // we do not know whether it is an error.\n    if (nd->getType() == PSNodeType::PHI) {\n        const llvm::Value *val = getValue(nd);\n        assert(val);\n\n        if (val->getType()->isPointerTy()) {\n            // this is the PHI node that corresponds to argv, we're fine here\n            if (isa<llvm::Argument>(val) && nd->getParent() &&\n                nd->getParent()->root->getParent() == nullptr)\n                return false;\n\n            return PointerGraphValidator::reportInvalOperands(nd, user_err);\n        } // else issue a warning?\n        return false;\n    }\n\n    return PointerGraphValidator::reportInvalOperands(nd, user_err);\n}\n\n} // namespace pta\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/PointerAnalysis/PointerGraphValidator.h",
    "content": "#ifndef LLVM_DG_POINTER_SUBGRAPH_VALIDATOR_H_\n#define LLVM_DG_POINTER_SUBGRAPH_VALIDATOR_H_\n\n#include \"dg/PointerAnalysis/PointerGraph.h\"\n#include \"dg/PointerAnalysis/PointerGraphValidator.h\"\n\nnamespace dg {\nnamespace pta {\n\n/**\n * Take PointerGraph instance and check whether it is not broken\n */\nclass LLVMPointerGraphValidator : public PointerGraphValidator {\n    bool reportInvalOperands(const PSNode *n,\n                             const std::string &user_err) override;\n\n  public:\n    LLVMPointerGraphValidator(const PointerGraph *ps,\n                              bool no_connectivity = false)\n            : PointerGraphValidator(ps, no_connectivity) {}\n\n    ~LLVMPointerGraphValidator() override = default;\n};\n\n} // namespace pta\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/llvm/PointerAnalysis/Structure.cpp",
    "content": "#include <cassert>\n#include <set>\n\n#include <llvm/Config/llvm-config.h>\n\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n#include <llvm/Support/CFG.h>\n#else\n#include <llvm/IR/CFG.h>\n#endif\n\n#include <llvm/IR/Constant.h>\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/DataLayout.h>\n#include <llvm/IR/Function.h>\n#include <llvm/IR/Instruction.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/IntrinsicInst.h>\n#include <llvm/IR/Module.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#include \"dg/llvm/PointerAnalysis/PointerGraph.h\"\n#include \"dg/util/debug.h\"\n\nnamespace dg {\nnamespace pta {\n\nvoid LLVMPointerGraphBuilder::FuncGraph::blockAddSuccessors(\n        std::set<const llvm::BasicBlock *> &found_blocks,\n        LLVMPointerGraphBuilder::PSNodesBlock &blk,\n        const llvm::BasicBlock &block) {\n    for (auto S = llvm::succ_begin(&block), SE = llvm::succ_end(&block);\n         S != SE; ++S) {\n        // we already processed this block? Then don't try to add the edges\n        // again\n        if (!found_blocks.insert(*S).second)\n            continue;\n\n        auto it = llvmBlocks.find(*S);\n        if (it == llvmBlocks.end()) {\n            // if we don't have this block built (there was no points-to\n            // relevant instruction), we must pretend to be there for\n            // control flow information. Thus instead of adding it as\n            // successor, add its successors as successors\n            blockAddSuccessors(found_blocks, blk, *(*S));\n        } else {\n            // add successor to the last nodes\n            blk.getLastNode()->addSuccessor(it->second.getFirstNode());\n        }\n    }\n}\n\nLLVMPointerGraphBuilder::PSNodesBlock\nLLVMPointerGraphBuilder::buildArgumentsStructure(const llvm::Function &F) {\n    PSNodesBlock blk;\n\n    int idx = 0;\n    for (auto A = F.arg_begin(), E = F.arg_end(); A != E; ++A, ++idx) {\n        auto it = nodes_map.find(&*A);\n        if (it == nodes_map.end())\n            continue;\n\n        PSNodesSeq &cur = it->second;\n        assert(cur.getFirst() == cur.getLast());\n\n        blk.append(&cur);\n    }\n\n    // add CFG edges between the arguments\n    PSNodesBlockAddSuccessors(blk);\n\n    return blk;\n}\n\nvoid LLVMPointerGraphBuilder::addProgramStructure(const llvm::Function *F,\n                                                  PointerSubgraph &subg) {\n    assert(subg.root && \"Subgraph has no root\");\n\n    assert(_funcInfo.find(F) != _funcInfo.end());\n    auto &finfo = _funcInfo[F];\n\n    // with function pointer calls it may happen that we try\n    // to add structure more times, so bail out in that case\n    if (finfo.has_structure) {\n        DBG(pta, \"Already got structure for function '\" << F->getName().str()\n                                                        << \"', bailing out\");\n        return;\n    }\n\n    PSNodesBlock argsBlk = buildArgumentsStructure(*F);\n    PSNode *lastNode = connectArguments(F, argsBlk, subg);\n    assert(lastNode && \"Did not connect arguments of a function correctly\");\n\n    // add successors in each one basic block\n    for (auto &it : finfo.llvmBlocks) {\n        PSNodesBlockAddSuccessors(it.second, true);\n    }\n\n    addCFGEdges(F, finfo, lastNode);\n\n    DBG(pta, \"Added CFG structure to function '\" << F->getName().str() << \"'\");\n\n    finfo.has_structure = true;\n}\n\nPSNode *LLVMPointerGraphBuilder::connectArguments(const llvm::Function *F,\n                                                  PSNodesBlock &argsBlk,\n                                                  PointerSubgraph &subg) {\n    PSNode *lastNode = nullptr;\n\n    // make arguments the entry block of the subgraphs (if there\n    // are any arguments)\n    if (!argsBlk.empty()) {\n        subg.root->addSuccessor(argsBlk.getFirstNode());\n\n        // insert the variadic arg node into the graph if needed\n        if (F->isVarArg()) {\n            assert(subg.vararg);\n            argsBlk.getLastNode()->addSuccessor(subg.vararg);\n            lastNode = subg.vararg;\n        } else {\n            lastNode = argsBlk.getLastNode();\n        }\n    } else if (subg.vararg) {\n        // this function has only ... argument\n        assert(F->isVarArg());\n        subg.root->addSuccessor(subg.vararg);\n        lastNode = subg.vararg;\n    } else {\n        lastNode = subg.root;\n    }\n\n    return lastNode;\n}\n\nvoid LLVMPointerGraphBuilder::addCFGEdges(\n        const llvm::Function *F, LLVMPointerGraphBuilder::FuncGraph &finfo,\n        PSNode *lastNode) {\n    // check whether we created the entry block. If not, we would\n    // have a problem while adding successors, so fake that\n    // the entry block is the root or the last argument\n    const llvm::BasicBlock *entry = &F->getBasicBlockList().front();\n    auto it = finfo.llvmBlocks.find(entry);\n    if (it != finfo.llvmBlocks.end()) {\n        // if we have the entry block, just make it the successor\n        // of the root or the last argument\n        lastNode->addSuccessor(it->second.getFirstNode());\n    } else {\n        // Create a temporary PSNodesSeq with lastNode\n        // and use it during adding successors for the\n        // non-existing entry block\n        PSNodesSeq seq(lastNode);\n        PSNodesBlock blk(&seq);\n\n        std::set<const llvm::BasicBlock *> found_blocks;\n        finfo.blockAddSuccessors(found_blocks, blk, *entry);\n    }\n\n    for (auto &it : finfo.llvmBlocks) {\n        auto &blk = it.second;\n        assert(!blk.empty() && \"Has empty block between built blocks\");\n\n        // add successors to this block (skipping the empty blocks).\n        // To avoid infinite loops we use found_blocks container that will\n        // serve as a marker in BFS/DFS - the program should not contain\n        // so many blocks that this could have some big overhead. If proven\n        // otherwise later, we'll change this.\n        std::set<const llvm::BasicBlock *> found_blocks;\n        finfo.blockAddSuccessors(found_blocks, blk, *it.first);\n    }\n}\n\n} // namespace pta\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/PointerAnalysis/Threads.cpp",
    "content": "#include <cassert>\n#include <set>\n\n#include <llvm/Config/llvm-config.h>\n\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n#include <llvm/Support/CFG.h>\n#else\n#include <llvm/IR/CFG.h>\n#endif\n\n#include <llvm/IR/Constant.h>\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/DataLayout.h>\n#include <llvm/IR/Function.h>\n#include <llvm/IR/Instruction.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/IntrinsicInst.h>\n#include <llvm/IR/Module.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#include <llvm/IR/Dominators.h>\n\n#include \"dg/PointerAnalysis/PointerGraph.h\"\n#include \"dg/PointerAnalysis/PointerGraphOptimizations.h\"\n#include \"dg/llvm/PointerAnalysis/PointerGraph.h\"\n\n#include \"llvm/PointerAnalysis/PointerGraphValidator.h\"\n#include \"llvm/llvm-utils.h\"\n\n#include \"dg/util/debug.h\"\n\nnamespace dg {\nnamespace pta {\n\nvoid LLVMPointerGraphBuilder::insertPthreadCreateByPtrCall(PSNode *callsite) {\n    auto *fork =\n            createForkNode(callsite->getUserData<llvm::CallInst>(), callsite);\n    fork->setCallInst(callsite);\n    callsite->addSuccessor(fork);\n}\n\nvoid LLVMPointerGraphBuilder::insertPthreadJoinByPtrCall(PSNode *callsite) {\n    auto *join =\n            createJoinNode(callsite->getUserData<llvm::CallInst>(), callsite);\n    join->setCallInst(callsite);\n    join->insertAfter(callsite);\n}\n\nPSNodeJoin *\nLLVMPointerGraphBuilder::findJoin(const llvm::CallInst *callInst) const {\n    for (auto *join : joinNodes) {\n        if (join->getUserData<llvm::CallInst>() == callInst)\n            return join;\n    }\n    return nullptr;\n}\n\nbool LLVMPointerGraphBuilder::addFunctionToFork(PSNode *function,\n                                                PSNodeFork *forkNode) {\n    const llvm::CallInst *CInst =\n            forkNode->callInst()->getUserData<llvm::CallInst>();\n    const llvm::Function *F = function->getUserData<llvm::Function>();\n\n    DBG(pta,\n        \"Function '\" << F->getName().str() << \"' can be spawned via thread\");\n\n    PointerSubgraph &subgraph = createOrGetSubgraph(F);\n    addInterproceduralPthreadOperands(F, CInst);\n    // FIXME: create fork and join edges\n    forkNode->addSuccessor(subgraph.root);\n    forkNode->addFunction(function);\n\n    return true;\n}\n\nbool LLVMPointerGraphBuilder::addFunctionToJoin(PSNode *function,\n                                                PSNodeJoin *joinNode) {\n    PSNode *CInst = joinNode->getPairedNode();\n    joinNode->addFunction(function);\n    const llvm::Function *F = function->getUserData<llvm::Function>();\n\n    if (!F->empty()) {\n        PointerSubgraph *subgraph = getSubgraph(F);\n        assert(subgraph && \"Did not build the subgraph for thread\");\n\n        DBG(pta, \"Found a new join point for function '\" << F->getName().str()\n                                                         << \"'\");\n        if (!CInst->getOperand(1)->isNull()) {\n            PSNode *phi = PS.create<PSNodeType::PHI>();\n            PSNode *store =\n                    PS.create<PSNodeType::STORE>(phi, CInst->getOperand(1));\n            phi->addSuccessor(store);\n            store->addSuccessor(joinNode);\n            for (PSNode *ret : subgraph->returnNodes) {\n                ret->addSuccessor(phi);\n                phi->addOperand(ret);\n            }\n        } else {\n            for (PSNode *ret : subgraph->returnNodes) {\n                ret->addSuccessor(joinNode);\n            }\n        }\n    }\n    return true;\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq\nLLVMPointerGraphBuilder::createPthreadCreate(const llvm::CallInst *CInst) {\n    PSNodeCall *callNode = PSNodeCall::get(PS.create<PSNodeType::CALL>());\n    PSNodeFork *forkNode = createForkNode(CInst, callNode);\n\n    callNode->addSuccessor(forkNode);\n\n    // do not add the fork node into the sequence,\n    // it is going to branch from the call\n    return {callNode};\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq\nLLVMPointerGraphBuilder::createPthreadJoin(const llvm::CallInst *CInst) {\n    PSNodeCall *callNode = PSNodeCall::get(PS.create<PSNodeType::CALL>());\n    PSNodeJoin *joinNode = createJoinNode(CInst, callNode);\n\n    // FIXME: create only the join node, not call node and join node\n    return {callNode, joinNode};\n}\n\nPSNodeFork *LLVMPointerGraphBuilder::createForkNode(const llvm::CallInst *CInst,\n                                                    PSNode *callNode) {\n    using namespace llvm;\n    PSNodeFork *forkNode = PSNodeFork::get(\n            PS.create<PSNodeType::FORK>(getOperand(CInst->getArgOperand(2))));\n    callNode->setPairedNode(forkNode);\n    forkNode->setPairedNode(callNode);\n\n    forkNode->setCallInst(callNode);\n\n    forkNodes.push_back(forkNode);\n    addArgumentOperands(*CInst, *callNode);\n\n    const Value *spawnedFunc = CInst->getArgOperand(2)->stripPointerCasts();\n    if (const Function *func = dyn_cast<Function>(spawnedFunc)) {\n        addFunctionToFork(getNodes(func)->getSingleNode(), forkNode);\n    }\n\n    return forkNode;\n}\n\nPSNodeJoin *LLVMPointerGraphBuilder::createJoinNode(const llvm::CallInst *CInst,\n                                                    PSNode *callNode) {\n    using namespace llvm;\n\n    PSNodeJoin *joinNode = PSNodeJoin::get(PS.create<PSNodeType::JOIN>());\n    callNode->setPairedNode(joinNode);\n    joinNode->setPairedNode(callNode);\n\n    joinNode->setCallInst(callNode);\n\n    joinNodes.push_back(joinNode);\n    addArgumentOperands(*CInst, *callNode);\n\n    return joinNode;\n}\n\nLLVMPointerGraphBuilder::PSNodesSeq\nLLVMPointerGraphBuilder::createPthreadExit(const llvm::CallInst *CInst) {\n    using namespace llvm;\n\n    PSNodeCall *callNode = PSNodeCall::get(PS.create<PSNodeType::CALL>());\n    addArgumentOperands(*CInst, *callNode);\n    auto *pthread_exit_operand = callNode->getOperand(0);\n\n    PSNodeRet *returnNode =\n            PSNodeRet::get(PS.create<PSNodeType::RETURN>(pthread_exit_operand));\n    callNode->setPairedNode(returnNode);\n    returnNode->setPairedNode(callNode);\n    callNode->addSuccessor(returnNode);\n\n    return {callNode, returnNode};\n}\n\nbool LLVMPointerGraphBuilder::matchJoinToRightCreate(PSNode *joinNode) {\n    using namespace llvm;\n    using namespace dg::pta;\n    PSNodeJoin *join = PSNodeJoin::get(joinNode);\n    PSNode *pthreadJoinCall = join->getPairedNode();\n\n    PSNode *loadNode = pthreadJoinCall->getOperand(0);\n    PSNode *joinThreadHandlePtr = loadNode->getOperand(0);\n    bool changed = false;\n    for (auto *fork : getForks()) {\n        auto *pthreadCreateCall = fork->getPairedNode();\n        auto *createThreadHandlePtr = pthreadCreateCall->getOperand(0);\n\n        std::set<PSNode *> threadHandleIntersection;\n        for (const auto &createPointsTo : createThreadHandlePtr->pointsTo) {\n            for (const auto &joinPointsTo : joinThreadHandlePtr->pointsTo) {\n                if (createPointsTo.target == joinPointsTo.target) {\n                    threadHandleIntersection.insert(createPointsTo.target);\n                }\n            }\n        }\n\n        if (!threadHandleIntersection\n                     .empty()) { // TODO refactor this into method for finding\n                                 // new functions\n            PSNode *func = pthreadCreateCall->getOperand(2);\n            const llvm::Value *V = func->getUserData<llvm::Value>();\n            auto pointsToFunctions = getPointsToFunctions(V);\n\n            auto oldFunctions = join->functions();\n            for (auto *function : pointsToFunctions) {\n                if (join->functions().count(function) == 0) {\n                    changed |= addFunctionToJoin(function, join);\n                }\n            }\n            if (changed) {\n                join->addFork(fork);\n            }\n        }\n    }\n    return changed;\n}\n\n} // namespace pta\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ReadWriteGraph/Calls.cpp",
    "content": "#include <cassert>\n#include <vector>\n\n#include <llvm/IR/Constant.h>\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/DataLayout.h>\n#include <llvm/IR/Function.h>\n#include <llvm/IR/Instruction.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/IntrinsicInst.h>\n#include <llvm/IR/Module.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#include \"dg/llvm/PointerAnalysis/PointerGraph.h\"\n\n#include \"llvm/ReadWriteGraph/LLVMReadWriteGraphBuilder.h\"\n#include \"llvm/llvm-utils.h\"\n\nnamespace dg {\nnamespace dda {\n\nstatic void reportIncompatibleCalls(\n        const std::set<const llvm::Function *> &incompatibleCalls,\n        const llvm::CallInst *CInst, size_t tried_num) {\n    if (incompatibleCalls.empty()) {\n        return;\n    }\n\n#ifndef NDEBUG\n    llvm::errs() << \"[RWG] warning: incompatible function pointers for \"\n                 << ValInfo(CInst) << \"\\n\";\n\n    for (auto *F : incompatibleCalls) {\n        llvm::errs() << \"   Tried: \" << F->getName() << \" of type \"\n                     << *F->getType() << \"\\n\";\n    }\n#endif\n    if (incompatibleCalls.size() == tried_num) {\n        llvm::errs() << \"[RWG] error: did not find any compatible function \"\n                        \"pointer for \"\n                     << ValInfo(CInst) << \"\\n\";\n    }\n}\n\nNodesSeq<RWNode> LLVMReadWriteGraphBuilder::createCallToFunctions(\n        const std::vector<const llvm::Function *> &functions,\n        const llvm::CallInst *CInst) {\n    assert(!functions.empty() && \"No functions to call\");\n\n    std::set<const llvm::Function *> incompatibleCalls;\n    std::vector<RWNode *> called_values;\n    std::vector<RWSubgraph *> called_subgraphs;\n    for (const auto *F : functions) {\n        if (!llvmutils::callIsCompatible(F, CInst)) {\n            incompatibleCalls.insert(F);\n            continue;\n        }\n\n        if (const auto *model = _options.getFunctionModel(F->getName().str())) {\n            called_values.push_back(funcFromModel(model, CInst));\n        } else if (F->isDeclaration()) {\n            called_values.push_back(createCallToUndefinedFunction(F, CInst));\n        } else {\n            auto *s = getSubgraph(F);\n            assert(s && \"Do not have a subgraph for a function\");\n            called_subgraphs.push_back(s);\n        }\n    }\n\n    reportIncompatibleCalls(incompatibleCalls, CInst, functions.size());\n\n    // if we call just one undefined function, simplify the graph and\n    // do not create a CALL node -- just put the already created node there\n    if (called_subgraphs.empty() && called_values.size() == 1) {\n        return {called_values[0]};\n    }\n    RWNodeCall *callNode = RWNodeCall::get(&create(RWNodeType::CALL));\n    for (auto *item : called_subgraphs)\n        callNode->addCallee(item);\n    for (auto *item : called_values)\n        callNode->addCallee(item);\n    return {callNode};\n}\n\nRWNode *\nLLVMReadWriteGraphBuilder::createUnknownCall(const llvm::CallInst *CInst) {\n    using namespace llvm;\n\n    RWNode *node = &create(RWNodeType::GENERIC);\n\n    // if we assume that undefined functions are pure\n    // (have no side effects), we can bail out here\n    if (_options.undefinedArePure())\n        return node;\n\n    bool args = false;\n    if (_options.undefinedFunsReadAny()) {\n        node->addUse(UNKNOWN_MEMORY);\n    } else {\n        args |= _options.undefinedFunsReadArgs();\n    }\n\n    if (_options.undefinedFunsWriteAny()) {\n        node->addDef(UNKNOWN_MEMORY);\n    } else {\n        args |= _options.undefinedFunsWriteArgs();\n    }\n\n    if (!args)\n        return node;\n\n    // every pointer we pass into the undefined call may be defined\n    // in the function\n    for (const auto &arg : llvmutils::args(CInst)) {\n        // constants cannot be redefined except for global variables\n        // (that are constant, but may point to non constant memory\n        const Value *strippedValue = arg->stripPointerCasts();\n        if (isa<Constant>(strippedValue)) {\n            const GlobalVariable *GV = dyn_cast<GlobalVariable>(strippedValue);\n            // if the constant is not global variable,\n            // or the global variable points to constant memory\n            if (!GV || GV->isConstant())\n                continue;\n        }\n\n        auto pts = PTA->getLLVMPointsToChecked(arg);\n        // if we do not have a pts, this is not pointer\n        // relevant instruction. We must do it this way\n        // instead of type checking, due to the inttoptr.\n        if (!pts.first)\n            continue;\n\n        for (const auto &ptr : pts.second) {\n            if (llvm::isa<llvm::Function>(ptr.value))\n                // function may not be redefined\n                continue;\n\n            RWNode *target = getOperand(ptr.value);\n            assert(target && \"Don't have pointer target for call argument\");\n\n            // this call may use and define this memory\n            if (_options.undefinedFunsWriteArgs() &&\n                !_options.undefinedFunsWriteAny())\n                node->addDef(target, Offset::UNKNOWN, Offset::UNKNOWN);\n            if (_options.undefinedFunsReadArgs() &&\n                !_options.undefinedFunsReadAny())\n                node->addUse(target, Offset::UNKNOWN, Offset::UNKNOWN);\n        }\n    }\n\n    return node;\n}\n\n/*\nvoid LLVMReadWriteGraphBuilder::matchForksAndJoins()\n{\n    using namespace llvm;\n    using namespace pta;\n\n    ForkJoinAnalysis FJA{PTA};\n\n    for (auto& it : threadJoinCalls) {\n        // it.first -> llvm::CallInst, it.second -> RWNode *\n        auto functions = FJA.joinFunctions(it.first);\n        for (auto llvmFunction : functions) {\n            auto graphIterator = subgraphs_map.find(llvmFunction);\n            for (auto returnNode : graphIterator->second.returns) {\n                makeEdge(returnNode, it.second);\n            }\n        }\n    }\n}\n*/\n\nRWNode *\nLLVMReadWriteGraphBuilder::createIntrinsicCall(const llvm::CallInst *CInst) {\n    using namespace llvm;\n\n    const IntrinsicInst *I = cast<IntrinsicInst>(CInst);\n    const Value *dest;\n    const Value *lenVal;\n\n    RWNode *ret;\n    switch (I->getIntrinsicID()) {\n    case Intrinsic::memmove:\n    case Intrinsic::memcpy:\n    case Intrinsic::memset:\n        // memcpy/set <dest>, <src/val>, <len>\n        dest = I->getOperand(0);\n        lenVal = I->getOperand(2);\n        break;\n    case Intrinsic::vastart:\n        // we create this node because this nodes works\n        // as ALLOC in points-to, so we can have\n        // reaching definitions to that\n        ret = &create(RWNodeType::ALLOC);\n        ret->addDef(ret, 0, Offset::UNKNOWN);\n        return ret;\n    default:\n        return createUnknownCall(CInst);\n    }\n\n    ret = &create(RWNodeType::GENERIC);\n\n    auto pts = PTA->getLLVMPointsToChecked(dest);\n    if (!pts.first) {\n        llvm::errs()\n                << \"[RWG] Error: No points-to information for destination in\\n\";\n        llvm::errs() << ValInfo(I) << \"\\n\";\n        // continue, the points-to set is {unknown}\n    }\n\n    uint64_t len = Offset::UNKNOWN;\n    if (const ConstantInt *C = dyn_cast<ConstantInt>(lenVal))\n        len = C->getLimitedValue();\n\n    for (const auto &ptr : pts.second) {\n        if (llvm::isa<llvm::Function>(ptr.value))\n            continue;\n\n        Offset from, to;\n        if (ptr.offset.isUnknown()) {\n            // if the offset is UNKNOWN, use whole memory\n            from = Offset::UNKNOWN;\n            len = Offset::UNKNOWN;\n        } else {\n            from = *ptr.offset;\n        }\n\n        // do not allow overflow\n        if (Offset::UNKNOWN - *from > len)\n            to = from + len;\n        else\n            to = Offset::UNKNOWN;\n\n        RWNode *target = getOperand(ptr.value);\n        // assert(target && \"Don't have pointer target for intrinsic call\");\n        if (!target) {\n            // keeping such set is faster then printing it all to terminal\n            // ... and we don't flood the terminal that way\n            static std::set<const llvm::Value *> warned;\n            if (warned.insert(ptr.value).second) {\n                llvm::errs() << \"[RWG] error at \" << ValInfo(CInst) << \"\\n\"\n                             << \"[RWG] error: Haven't created node for: \"\n                             << ValInfo(ptr.value) << \"\\n\";\n            }\n            target = UNKNOWN_MEMORY;\n        }\n\n        // add the definition\n        ret->addDef(target, from, to,\n                    !from.isUnknown() && !to.isUnknown() /* strong update */);\n    }\n\n    return ret;\n}\n\ntemplate <typename T>\nstd::pair<Offset, Offset> getFromTo(const llvm::CallInst *CInst, T what) {\n    auto from = what->from.isOperand()\n                        ? llvmutils::getConstantValue(\n                                  CInst->getArgOperand(what->from.getOperand()))\n                        : what->from.getOffset();\n    auto to = what->to.isOperand()\n                      ? llvmutils::getConstantValue(\n                                CInst->getArgOperand(what->to.getOperand()))\n                      : what->to.getOffset();\n\n    return {from, to};\n}\n\nRWNode *LLVMReadWriteGraphBuilder::funcFromModel(const FunctionModel *model,\n                                                 const llvm::CallInst *CInst) {\n    RWNode *node = &create(RWNodeType::GENERIC);\n\n    for (unsigned int i = 0; i < llvmutils::getNumArgOperands(CInst); ++i) {\n        if (!model->handles(i))\n            continue;\n\n        auto *const llvmOp = CInst->getArgOperand(i);\n        auto pts = PTA->getLLVMPointsToChecked(llvmOp);\n        // if we do not have a pts, this is not pointer\n        // relevant instruction. We must do it this way\n        // instead of type checking, due to the inttoptr.\n        if (!pts.first) {\n            llvm::errs()\n                    << \"[Warning]: did not find pt-set for modeled function\\n\";\n            llvm::errs() << \"           Func: \" << model->name << \", operand \"\n                         << i << \"\\n\";\n            continue;\n        }\n\n        for (const auto &ptr : pts.second) {\n            if (llvm::isa<llvm::Function>(ptr.value))\n                // functions may not be redefined\n                continue;\n\n            RWNode *target = getOperand(ptr.value);\n            assert(target && \"Don't have pointer target for call argument\");\n\n            Offset from, to;\n            if (const auto *defines = model->defines(i)) {\n                std::tie(from, to) = getFromTo(CInst, defines);\n                // this call may define this memory\n                bool strong_updt = pts.second.size() == 1 &&\n                                   !ptr.offset.isUnknown() &&\n                                   !(ptr.offset + from).isUnknown() &&\n                                   !(ptr.offset + to).isUnknown() &&\n                                   !llvm::isa<llvm::CallInst>(ptr.value);\n                // FIXME: what about vars in recursive functions?\n                node->addDef(target, ptr.offset + from, ptr.offset + to,\n                             strong_updt);\n            }\n            if (const auto *uses = model->uses(i)) {\n                std::tie(from, to) = getFromTo(CInst, uses);\n                // this call uses this memory\n                node->addUse(target, ptr.offset + from, ptr.offset + to);\n            }\n        }\n    }\n\n    return node;\n}\nRWNode *LLVMReadWriteGraphBuilder::createCallToUndefinedFunction(\n        const llvm::Function *function, const llvm::CallInst *CInst) {\n    if (function->isIntrinsic()) {\n        return createIntrinsicCall(CInst);\n    }\n    if (_options.threads) {\n        // assert(false && \"Threads unsupported yet\");\n        if (function->getName() == \"pthread_create\") {\n            return createPthreadCreateCalls(CInst);\n        } else if (function->getName() == \"pthread_join\") {\n            return createPthreadJoinCall(CInst);\n        } else if (function->getName() == \"pthread_exit\") {\n            return createPthreadExitCall(CInst);\n        }\n    }\n\n    auto type = _options.getAllocationFunction(function->getName().str());\n    if (type != AllocationFunction::NONE) {\n        if (type == AllocationFunction::REALLOC)\n            return createRealloc(CInst);\n        return createDynAlloc(CInst, type);\n    }\n    return createUnknownCall(CInst);\n\n    assert(false && \"Unreachable\");\n    abort();\n}\n\nRWNode *LLVMReadWriteGraphBuilder::createPthreadCreateCalls(\n        const llvm::CallInst *CInst) {\n    using namespace llvm;\n\n    RWNode *rootNode = &create(RWNodeType::FORK);\n    threadCreateCalls.emplace(CInst, rootNode);\n\n    Value *calledValue = CInst->getArgOperand(2);\n    const auto &functions = getCalledFunctions(calledValue, PTA);\n\n    for (const Function *function : functions) {\n        if (function->isDeclaration()) {\n            llvm::errs()\n                    << \"[RWG] error: phtread_create spawns undefined function: \"\n                    << function->getName() << \"\\n\";\n            continue;\n        }\n    }\n    return rootNode;\n}\n\nRWNode *\nLLVMReadWriteGraphBuilder::createPthreadJoinCall(const llvm::CallInst *CInst) {\n    // TODO later change this to create join node and set data correctly\n    // we need just to create one node;\n    // undefined call is overapproximation, so its ok\n    RWNode *node = createUnknownCall(CInst);\n    threadJoinCalls.emplace(CInst, node);\n    return node;\n}\n\nRWNode *\nLLVMReadWriteGraphBuilder::createPthreadExitCall(const llvm::CallInst *CInst) {\n    return createReturn(CInst);\n}\n\n} // namespace dda\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ReadWriteGraph/Instructions.cpp",
    "content": "#include <cassert>\n#include <vector>\n\n#include <llvm/IR/Constant.h>\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/DataLayout.h>\n#include <llvm/IR/Function.h>\n#include <llvm/IR/Instruction.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/IntrinsicInst.h>\n#include <llvm/IR/Module.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n//#include \"dg/llvm/PointerAnalysis/PointerGraph.h\"\n//#include \"llvm/ForkJoin/ForkJoin.h\"\n#include \"dg/ReadWriteGraph/RWNode.h\"\n#include \"llvm/ReadWriteGraph/LLVMReadWriteGraphBuilder.h\"\n#include \"llvm/llvm-utils.h\"\n\nnamespace dg {\nnamespace dda {\n\nstatic inline llvm::Value *getMemIntrinsicValueOp(llvm::MemIntrinsic *MI) {\n    switch (MI->getIntrinsicID()) {\n    case llvm::Intrinsic::memmove:\n    case llvm::Intrinsic::memcpy:\n    case llvm::Intrinsic::memset:\n        return MI->getOperand(1);\n        break;\n    default:\n        assert(false && \"Unsupported intrinsic\");\n    }\n    return nullptr;\n}\n\nRWNode *LLVMReadWriteGraphBuilder::createAlloc(const llvm::Instruction *Inst) {\n    using namespace llvm;\n\n    RWNode &node = create(RWNodeType::ALLOC);\n\n    // check if the address of this alloca is taken\n    for (auto I = Inst->use_begin(), E = Inst->use_end(); I != E; ++I) {\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n        auto *use = *I;\n#else\n        auto *use = I->getUser();\n#endif\n        if (auto *S = dyn_cast<StoreInst>(use)) {\n            if (S->getValueOperand() == Inst) {\n                node.setAddressTaken();\n                break;\n            }\n        } else if (auto *MI = dyn_cast<MemIntrinsic>(use)) {\n            if (getMemIntrinsicValueOp(MI) == Inst) {\n                node.setAddressTaken();\n                break;\n            }\n        } else if (const auto *I = dyn_cast<Instruction>(Inst)) {\n            assert(!I->mayWriteToMemory() &&\n                   \"Unhandled memory-writing instruction\");\n            (void) I; // c++17 TODO: replace with [[maybe_unused]]\n        }\n    }\n\n    if (const AllocaInst *AI = dyn_cast<AllocaInst>(Inst)) {\n        auto size = llvmutils::getAllocatedSize(AI, getDataLayout());\n        node.setSize(size);\n        // this is a alloca that does not have the address taken,\n        // therefore we must always access the last instance in loads\n        // (even in recursive functions) and may terminate the search\n        // for definitions of this alloca at this alloca\n        if (!node.hasAddressTaken()) {\n            node.addOverwrites(&node, 0, size > 0 ? size : Offset::UNKNOWN);\n        }\n    }\n    return &node;\n}\n\nRWNode *LLVMReadWriteGraphBuilder::createDynAlloc(const llvm::Instruction *Inst,\n                                                  AllocationFunction type) {\n    using namespace llvm;\n\n    RWNode &node = create(RWNodeType::DYN_ALLOC);\n    const CallInst *CInst = cast<CallInst>(Inst);\n    const Value *op;\n    uint64_t size = 0, size2 = 0;\n\n    switch (type) {\n    case AllocationFunction::MALLOC:\n    case AllocationFunction::ALLOCA:\n        op = CInst->getOperand(0);\n        break;\n    case AllocationFunction::CALLOC:\n        op = CInst->getOperand(1);\n        break;\n    default:\n        errs() << *CInst << \"\\n\";\n        assert(0 && \"unknown memory allocation type\");\n        // for NDEBUG\n        abort();\n    };\n\n    // infer allocated size\n    size = llvmutils::getConstantValue(op);\n    if (size != 0 && type == AllocationFunction::CALLOC) {\n        // if this is call to calloc, the size is given\n        // in the first argument too\n        size2 = llvmutils::getConstantValue(CInst->getOperand(0));\n        if (size2 != 0)\n            size *= size2;\n    }\n\n    node.setSize(size);\n    return &node;\n}\n\nRWNode *\nLLVMReadWriteGraphBuilder::createRealloc(const llvm::Instruction *Inst) {\n    RWNode &node = create(RWNodeType::DYN_ALLOC);\n\n    uint64_t size = llvmutils::getConstantValue(Inst->getOperand(1));\n    if (size == 0)\n        size = Offset::UNKNOWN;\n    else\n        node.setSize(size);\n\n    // realloc defines itself, since it copies the values\n    // from previous memory\n    node.addDef(&node, 0, size, false /* strong update */);\n\n    if (buildUses) {\n        // realloc copies the memory\n        // NOTE: do not use mapPointers, it could lead to infinite\n        // recursion as realloc may use itself and the 'node' is not\n        // in the map yet\n        addReallocUses(Inst, node, size);\n    }\n    return &node;\n}\n\nvoid LLVMReadWriteGraphBuilder::addReallocUses(const llvm::Instruction *Inst,\n                                               RWNode &node, uint64_t size) {\n    auto psn = PTA->getLLVMPointsToChecked(Inst->getOperand(0));\n    if (!psn.first) {\n#ifndef NDEBUG\n        llvm::errs() << \"[RWG] warning at: \" << ValInfo(Inst) << \"\\n\";\n        llvm::errs() << \"No points-to set for: \" << ValInfo(Inst->getOperand(0))\n                     << \"\\n\";\n#endif\n        node.addUse(UNKNOWN_MEMORY);\n        return;\n    }\n\n    if (psn.second.empty()) {\n#ifndef NDEBUG\n        llvm::errs() << \"[RWG] warning at: \" << ValInfo(Inst) << \"\\n\";\n        llvm::errs() << \"Empty points-to set for: \"\n                     << ValInfo(Inst->getOperand(0)) << \"\\n\";\n#endif\n        node.addUse(UNKNOWN_MEMORY);\n        return;\n    }\n\n    if (psn.second.hasUnknown()) {\n        node.addUse(UNKNOWN_MEMORY);\n    }\n\n    for (const auto &ptr : psn.second) {\n        // realloc may be only from other dynamic allocation\n        if (!llvm::isa<llvm::CallInst>(ptr.value))\n            continue;\n\n        // llvm::errs() << \"Realloc ptr: \" << *ptr.value << \"\\n\";\n        RWNode *ptrNode = nullptr;\n        if (ptr.value == Inst) {\n            // the realloc reallocates itself\n            ptrNode = &node;\n        } else {\n            ptrNode = getOperand(ptr.value);\n        }\n        if (!ptrNode) {\n            static std::set<const llvm::Value *> warned;\n            if (warned.insert(ptr.value).second) {\n                llvm::errs() << \"[RWG] error at \" << ValInfo(Inst) << \"\\n\";\n                llvm::errs() << \"[RWG] error for \"\n                             << ValInfo(Inst->getOperand(0)) << \"\\n\";\n                llvm::errs() << \"[RWG] error: Cannot find node for \"\n                             << ValInfo(ptr.value) << \"\\n\";\n            }\n            continue;\n        }\n\n        node.addUse(ptrNode, ptr.offset,\n                    ptr.offset.isUnknown() ? Offset::UNKNOWN : size);\n    }\n}\n\nRWNode *\nLLVMReadWriteGraphBuilder::createReturn(const llvm::Instruction * /*unused*/) {\n    return &create(RWNodeType::RETURN);\n}\n\nRWNode *LLVMReadWriteGraphBuilder::createStore(const llvm::Instruction *Inst) {\n    RWNode &node = create(RWNodeType::STORE);\n\n    uint64_t size = llvmutils::getAllocatedSize(Inst->getOperand(0)->getType(),\n                                                getDataLayout());\n    if (size == 0)\n        size = Offset::UNKNOWN;\n\n    auto defSites = mapPointers(Inst, Inst->getOperand(1), size);\n\n    // strong update is possible only with must aliases that point\n    // to the last instance of the memory object. Since detecting that\n    // is not that easy, do strong updates only on must aliases\n    // of local and global variables (and, of course, we must know the offsets)\n    // FIXME: ALLOCAs in recursive procedures can also yield only weak update\n    bool strong_update = false;\n    if (defSites.size() == 1) {\n        const auto &ds = *(defSites.begin());\n        strong_update = (ds.target->isAlloc() || ds.target->isGlobal()) &&\n                        !ds.offset.isUnknown() && !ds.len.isUnknown();\n    }\n\n    for (const auto &ds : defSites) {\n        node.addDef(ds, strong_update);\n    }\n\n    return &node;\n}\n\nRWNode *LLVMReadWriteGraphBuilder::createLoad(const llvm::Instruction *Inst) {\n    RWNode &node = create(RWNodeType::LOAD);\n\n    uint64_t size =\n            llvmutils::getAllocatedSize(Inst->getType(), getDataLayout());\n    if (size == 0)\n        size = Offset::UNKNOWN;\n\n    auto defSites = mapPointers(Inst, Inst->getOperand(0), size);\n    for (const auto &ds : defSites) {\n        node.addUse(ds);\n    }\n\n    return &node;\n}\n\nRWNode *\nLLVMReadWriteGraphBuilder::createAtomicRMW(const llvm::Instruction *Inst) {\n    const auto *RMW = llvm::cast<llvm::AtomicRMWInst>(Inst);\n    RWNode &node = create(RWNodeType::STORE);\n\n    uint64_t size = llvmutils::getAllocatedSize(RMW->getValOperand()->getType(),\n                                                getDataLayout());\n    if (size == 0)\n        size = Offset::UNKNOWN;\n\n    auto defSites = mapPointers(RMW, RMW->getPointerOperand(), size);\n\n    // strong update is possible only with must aliases that point\n    // to the last instance of the memory object. Since detecting that\n    // is not that easy, do strong updates only on must aliases\n    // of local and global variables (and, of course, we must know the offsets)\n    // FIXME: ALLOCAs in recursive procedures can also yield only weak update\n    bool strong_update = false;\n    if (defSites.size() == 1) {\n        const auto &ds = *(defSites.begin());\n        strong_update = (ds.target->isAlloc() || ds.target->isGlobal()) &&\n                        !ds.offset.isUnknown() && !ds.len.isUnknown();\n    }\n\n    for (const auto &ds : defSites) {\n        node.addDef(ds, strong_update);\n    }\n\n    // RMW is also use\n    for (const auto &ds : defSites) {\n        node.addUse(ds);\n    }\n\n    return &node;\n}\n\nNodesSeq<RWNode>\nLLVMReadWriteGraphBuilder::createCall(const llvm::Instruction *Inst) {\n    using namespace llvm;\n    const CallInst *CInst = cast<CallInst>(Inst);\n#if LLVM_VERSION_MAJOR >= 8\n    const Value *calledVal = CInst->getCalledOperand()->stripPointerCasts();\n#else\n    const Value *calledVal = CInst->getCalledValue()->stripPointerCasts();\n#endif\n    static bool warned_inline_assembly = false;\n\n    if (CInst->isInlineAsm()) {\n        if (!warned_inline_assembly) {\n            llvm::errs() << \"[RWG] WARNING: Inline assembler found\\n\";\n            warned_inline_assembly = true;\n        }\n        return {createUnknownCall(CInst)};\n    }\n\n    if (const Function *function = dyn_cast<Function>(calledVal)) {\n        return createCallToFunctions({function}, CInst);\n    }\n\n    const auto &functions = getCalledFunctions(calledVal, PTA);\n    if (functions.empty()) {\n        llvm::errs() << \"[RWG] error: could not determine the called function \"\n                        \"in a call via pointer: \\n\"\n                     << ValInfo(CInst) << \"\\n\";\n        return {createUnknownCall(CInst)};\n    }\n    return createCallToFunctions(functions, CInst);\n}\n\ntemplate <typename OptsT>\nstatic bool isRelevantCall(const llvm::Instruction *Inst, OptsT &opts) {\n    using namespace llvm;\n\n    // we don't care about debugging stuff\n    if (isa<DbgValueInst>(Inst))\n        return false;\n\n    const CallInst *CInst = cast<CallInst>(Inst);\n#if LLVM_VERSION_MAJOR >= 8\n    const Value *calledVal = CInst->getCalledOperand()->stripPointerCasts();\n#else\n    const Value *calledVal = CInst->getCalledValue()->stripPointerCasts();\n#endif\n    const Function *func = dyn_cast<Function>(calledVal);\n\n    if (!func)\n        // function pointer call - we need that\n        return true;\n\n    if (func->empty()) {\n        // we have a model for this function\n        if (opts.getFunctionModel(func->getName().str()))\n            return true;\n        // memory allocation\n        if (opts.isAllocationFunction(func->getName().str()))\n            return true;\n\n        if (func->isIntrinsic()) {\n            switch (func->getIntrinsicID()) {\n            case Intrinsic::memmove:\n            case Intrinsic::memcpy:\n            case Intrinsic::memset:\n            case Intrinsic::vastart:\n                return true;\n            default:\n                return false;\n            }\n        }\n\n        // undefined function\n        return true;\n    } // we want defined function, since those can contain\n    // pointer's manipulation and modify CFG\n    return true;\n\n    assert(0 && \"We should not reach this\");\n}\n\nNodesSeq<RWNode> LLVMReadWriteGraphBuilder::createNode(const llvm::Value *v) {\n    using namespace llvm;\n    if (isa<GlobalVariable>(v)) {\n        // global variables are like allocations\n        return {&create(RWNodeType::GLOBAL)};\n    }\n\n    const auto *I = dyn_cast<Instruction>(v);\n    if (!I)\n        return {};\n\n    // we may created this node when searching for an operand\n    switch (I->getOpcode()) {\n    case Instruction::Alloca:\n        // we need alloca's as target to DefSites\n        return {createAlloc(I)};\n    case Instruction::Store:\n        return {createStore(I)};\n    case Instruction::AtomicRMW:\n        return {createAtomicRMW(I)};\n    case Instruction::Load:\n        if (buildUses) {\n            return {createLoad(I)};\n        }\n        break;\n    case Instruction::Ret:\n        // we need create returns, since\n        // these modify CFG and thus data-flow\n        return {createReturn(I)};\n    case Instruction::Call:\n        if (!isRelevantCall(I, _options))\n            break;\n\n        return createCall(I);\n    }\n\n    return {};\n}\n\n} // namespace dda\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ReadWriteGraph/LLVMReadWriteGraphBuilder.cpp",
    "content": "#include <cassert>\n#include <set>\n\n#include <llvm/Config/llvm-config.h>\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n#include <llvm/Support/CFG.h>\n#else\n#include <llvm/IR/CFG.h>\n#endif\n\n#include <llvm/IR/Constant.h>\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/DataLayout.h>\n#include <llvm/IR/Function.h>\n#include <llvm/IR/Instruction.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/IntrinsicInst.h>\n#include <llvm/IR/Module.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#include <llvm/IR/Dominators.h>\n\n#include \"dg/ADT/Queue.h\"\n#include \"dg/llvm/PointerAnalysis/PointerGraph.h\"\n\n#include \"llvm/ForkJoin/ForkJoin.h\"\n#include \"llvm/ReadWriteGraph/LLVMReadWriteGraphBuilder.h\"\n#include \"llvm/llvm-utils.h\"\n\nnamespace dg {\nnamespace dda {\n\nllvm::raw_ostream &operator<<(llvm::raw_ostream &os, const ValInfo &vi) {\n    using namespace llvm;\n\n    if (const auto *I = dyn_cast<Instruction>(vi.v)) {\n        os << I->getParent()->getParent()->getName();\n        if (auto &DL = I->getDebugLoc()) {\n            os << \" (line \" << DL.getLine() << \", col \" << DL.getCol() << \")\";\n        }\n        os << \" :: \" << *I;\n    } else if (const auto *A = dyn_cast<Argument>(vi.v)) {\n        os << A->getParent()->getParent()->getName() << \":: (arg) \" << *A;\n    } else if (const auto *F = dyn_cast<Function>(vi.v)) {\n        os << \"(func) \" << F->getName();\n    } else {\n        os << *vi.v;\n    }\n\n    return os;\n}\n\n///\n// Map pointers of 'val' to def-sites.\n// \\param where  location in the program, for debugging\n// \\param size is the number of bytes used from the memory\nstd::vector<DefSite>\nLLVMReadWriteGraphBuilder::mapPointers(const llvm::Value *where,\n                                       const llvm::Value *val, Offset size) {\n    std::vector<DefSite> result;\n\n    auto psn = PTA->getLLVMPointsToChecked(val);\n    if (!psn.first) {\n        result.emplace_back(UNKNOWN_MEMORY);\n#ifndef NDEBUG\n        llvm::errs() << \"[RWG] warning at: \" << ValInfo(where) << \"\\n\";\n        llvm::errs() << \"No points-to set for: \" << ValInfo(val) << \"\\n\";\n#endif\n        // don't have points-to information for used pointer\n        return result;\n    }\n\n    if (psn.second.empty()) {\n#ifndef NDEBUG\n        llvm::errs() << \"[RWG] warning at: \" << ValInfo(where) << \"\\n\";\n        llvm::errs() << \"Empty points-to set for: \" << ValInfo(val) << \"\\n\";\n#endif\n        // this may happen on invalid reads and writes to memory,\n        // like when you try for example this:\n        //\n        //   int p, q;\n        //   memcpy(p, q, sizeof p);\n        //\n        // (there should be &p and &q)\n        // NOTE: maybe this is a bit strong to say unknown memory,\n        // but better be sound then incorrect\n        result.emplace_back(UNKNOWN_MEMORY);\n        return result;\n    }\n\n    result.reserve(psn.second.size());\n\n    if (psn.second.hasUnknown()) {\n        result.emplace_back(UNKNOWN_MEMORY);\n    }\n\n    for (const auto &ptr : psn.second) {\n        if (llvm::isa<llvm::Function>(ptr.value))\n            continue;\n\n        RWNode *ptrNode = getOperand(ptr.value);\n        if (!ptrNode) {\n            // keeping such set is faster then printing it all to terminal\n            // ... and we don't flood the terminal that way\n            static std::set<const llvm::Value *> warned;\n            if (warned.insert(ptr.value).second) {\n                llvm::errs() << \"[RWG] error at \" << ValInfo(where) << \"\\n\";\n                llvm::errs() << \"[RWG] error for \" << ValInfo(val) << \"\\n\";\n                llvm::errs() << \"[RWG] error: Cannot find node for \"\n                             << ValInfo(ptr.value) << \"\\n\";\n            }\n            continue;\n        }\n\n        // FIXME: we should pass just size to the DefSite ctor, but the old code\n        // relies on the behavior that when offset is unknown, the length is\n        // also unknown. So for now, mimic the old code. Remove it once we fix\n        // the old code.\n        result.emplace_back(ptrNode, ptr.offset,\n                            ptr.offset.isUnknown() ? Offset::UNKNOWN : size);\n    }\n\n    return result;\n}\n\nRWNode *LLVMReadWriteGraphBuilder::getOperand(const llvm::Value *val) {\n    auto *op = getNode(val);\n    if (!op) {\n        // lazily create allocations as these are targets in defsites\n        // and may not have been created yet\n        if (llvm::isa<llvm::AllocaInst>(val) ||\n            // FIXME: check that it is allocation\n            llvm::isa<llvm::CallInst>(val)) {\n            op = buildNode(val).getRepresentant();\n        }\n\n        if (!op) {\n            llvm::errs() << \"[RWG] error: cannot find an operand: \" << *val\n                         << \"\\n\";\n            abort();\n        }\n    }\n    assert(op && \"Do not have an operand\");\n    return op;\n}\n\n} // namespace dda\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ReadWriteGraph/LLVMReadWriteGraphBuilder.h",
    "content": "#ifndef LLVM_DG_RWG_BUILDER_H\n#define LLVM_DG_RWG_BUILDER_H\n\n#include <memory>\n#include <set>\n#include <unordered_map>\n\n#include <llvm/IR/CFG.h>\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#include \"dg/ReadWriteGraph/ReadWriteGraph.h\"\n#include \"dg/llvm/CallGraph/CallGraph.h\"\n#include \"dg/llvm/DataDependence/LLVMDataDependenceAnalysisOptions.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n\n#include \"llvm/GraphBuilder.h\"\n\n#ifndef NDEBUG\n#include \"dg/util/debug.h\"\n#endif // NDEBUG\n\nnamespace dg {\nnamespace dda {\n\nclass LLVMReadWriteGraphBuilder\n        : public GraphBuilder<RWNode, RWBBlock, RWSubgraph> {\n    const LLVMDataDependenceAnalysisOptions &_options;\n    // points-to information\n    dg::LLVMPointerAnalysis *PTA;\n    // even the data-flow analysis needs uses to have the mapping of llvm values\n    bool buildUses{true};\n    // optimization for reaching-definitions analysis\n    // TODO: do not do this while building graph, but let the analysis\n    // modify the graph itself (or forget it some other way as we'll\n    // have the interprocedural graph)\n    // bool forgetLocalsAtReturn{false};\n\n    ReadWriteGraph graph;\n\n    // RWNode& getOperand(const llvm::Value *) override;\n    NodesSeq<RWNode> createNode(const llvm::Value * /*unused*/) override;\n    RWBBlock &createBBlock(const llvm::BasicBlock * /*unused*/,\n                           RWSubgraph &subg) override {\n        return subg.createBBlock();\n    }\n\n    RWSubgraph &createSubgraph(const llvm::Function *F) override {\n        auto &subg = graph.createSubgraph();\n        subg.setName(F->getName().str());\n        return subg;\n    }\n\n    std::map<const llvm::CallInst *, RWNode *> threadCreateCalls;\n    std::map<const llvm::CallInst *, RWNode *> threadJoinCalls;\n\n    /*\n    // mapping of call nodes to called subgraphs\n    std::map<std::pair<RWNode *, RWNode *>, std::set<Subgraph *>> calls;\n    */\n\n    RWNode &create(RWNodeType t) { return graph.create(t); }\n\n  public:\n    LLVMReadWriteGraphBuilder(const llvm::Module *m, dg::LLVMPointerAnalysis *p,\n                              const LLVMDataDependenceAnalysisOptions &opts)\n            : GraphBuilder(m), _options(opts), PTA(p) {}\n\n    ReadWriteGraph &&build() {\n        // FIXME: this is a bit of a hack\n        if (!PTA->getOptions().isSVF()) {\n            auto *dgpta = static_cast<DGLLVMPointerAnalysis *>(PTA);\n            llvmdg::CallGraph CG(dgpta->getPTA()->getPG()->getCallGraph());\n            buildFromLLVM(&CG);\n        } else {\n            buildFromLLVM();\n        }\n\n        auto *entry = getModule()->getFunction(_options.entryFunction);\n        assert(entry && \"Did not find the entry function\");\n        graph.setEntry(getSubgraph(entry));\n\n        return std::move(graph);\n    }\n\n    RWNode *getOperand(const llvm::Value *val);\n\n    std::vector<DefSite> mapPointers(const llvm::Value *where,\n                                     const llvm::Value *val, Offset size);\n\n    RWNode *createStore(const llvm::Instruction *Inst);\n    RWNode *createLoad(const llvm::Instruction *Inst);\n    RWNode *createAtomicRMW(const llvm::Instruction *Inst);\n    RWNode *createAlloc(const llvm::Instruction *Inst);\n    RWNode *createDynAlloc(const llvm::Instruction *Inst,\n                           AllocationFunction type);\n    RWNode *createRealloc(const llvm::Instruction *Inst);\n    RWNode *createReturn(const llvm::Instruction *Inst);\n\n    void addReallocUses(const llvm::Instruction *Inst, RWNode &node,\n                        uint64_t size);\n\n    RWNode *funcFromModel(const FunctionModel *model,\n                          const llvm::CallInst * /*CInst*/);\n\n    NodesSeq<RWNode> createCall(const llvm::Instruction *Inst);\n\n    RWNode *createCallToUndefinedFunction(const llvm::Function *function,\n                                          const llvm::CallInst *CInst);\n\n    NodesSeq<RWNode>\n    createCallToFunctions(const std::vector<const llvm::Function *> &functions,\n                          const llvm::CallInst *CInst);\n\n    RWNode *createPthreadCreateCalls(const llvm::CallInst *CInst);\n    RWNode *createPthreadJoinCall(const llvm::CallInst *CInst);\n    RWNode *createPthreadExitCall(const llvm::CallInst *CInst);\n\n    RWNode *createIntrinsicCall(const llvm::CallInst *CInst);\n    RWNode *createUnknownCall(const llvm::CallInst *CInst);\n\n    // void matchForksAndJoins();\n};\n\nstruct ValInfo {\n    const llvm::Value *v;\n    ValInfo(const llvm::Value *val) : v(val) {}\n};\n\nllvm::raw_ostream &operator<<(llvm::raw_ostream &os, const ValInfo &vi);\n\n} // namespace dda\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "lib/llvm/SummaryEdges.cpp",
    "content": "#include <set>\n#include <unordered_map>\n#include <utility>\n\n#include \"dg/llvm/LLVMDependenceGraph.h\"\n#include \"dg/llvm/LLVMNode.h\"\n//#include \"llvm-utils.h\"\n\n#include \"dg/ADT/Queue.h\"\n\nnamespace dg {\n\n/// ------------------------------------------------------------------\n//  -- LLVMDependenceGraph -- summary edges\n/// ------------------------------------------------------------------\n\nextern std::map<llvm::Value *, LLVMDependenceGraph *> constructedFunctions;\nclass SummaryEdgesComputation {\n    using NodeT = LLVMNode;\n    using Edge = std::pair<NodeT *, NodeT *>;\n    ADT::QueueLIFO<Edge> workList;\n    // FIXME: optimize this: we can store only a subset of these edges\n    // and we can store only a set of nodes (beginnings of the paths)\n    std::set<Edge> pathEdge;\n\n    // collected vertices for fast checks\n    std::set<NodeT *> actualOutVertices;\n    std::set<NodeT *> formalInVertices;\n\n    void propagate(const Edge &e) {\n        if (pathEdge.insert(e).second) {\n            workList.push(e);\n        }\n    }\n\n    void propagate(NodeT *n1, NodeT *n2) { propagate({n1, n2}); }\n\n    void initialize() {\n        // collect all actual out and formal in vertices,\n        // as we need to check whether a node is of this type\n        for (auto &it : getConstructedFunctions()) {\n            LLVMDependenceGraph *dg = it.second;\n            assert(dg && \"null as dg\");\n\n            // formal parameters of this dg\n            if (auto params = dg->getParameters()) {\n                for (auto &paramIt : *params) {\n                    // Initialize the worklist (using formal out params).\n                    propagate({paramIt.second.out, paramIt.second.out});\n                    // Gather formal in params.\n                    formalInVertices.insert(paramIt.second.in);\n                }\n\n                // XXX: what about params for globals?\n            }\n\n            for (auto callNode : dg->getCallNodes()) {\n                // gather actual-out vertices\n                if (auto params = callNode->getParameters()) {\n                    for (auto &paramIt : *params) {\n                        actualOutVertices.insert(paramIt.second.out);\n                    }\n\n                    // XXX: what about params for globals?\n                }\n            }\n        }\n    }\n\n    bool isActualOut(NodeT *n) const { return actualOutVertices.count(n) > 0; }\n    bool isFormalIn(NodeT *n) const { return formalInVertices.count(n) > 0; }\n\n    void handleActualOut(const Edge &e) {\n        for (auto I = e.first->rev_control_begin(),\n                  E = e.first->rev_control_end();\n             I != E; ++I) {\n            propagate(*I, e.second);\n        }\n        for (auto I = e.first->rev_summary_begin(),\n                  E = e.first->rev_summary_end();\n             I != E; ++I) {\n            propagate(*I, e.second);\n        }\n    }\n\n    void handleGenericEdge(const Edge &e) {\n        for (auto I = e.first->rev_control_begin(),\n                  E = e.first->rev_control_end();\n             I != E; ++I) {\n            propagate(*I, e.second);\n        }\n        for (auto I = e.first->rev_data_begin(), E = e.first->rev_data_end();\n             I != E; ++I) {\n            propagate(*I, e.second);\n        }\n        for (auto I = e.first->user_begin(), E = e.first->user_end(); I != E;\n             ++I) {\n            propagate(*I, e.second);\n        }\n    }\n\n    void handleFormalIn(const Edge &e) {\n        using namespace llvm;\n\n        // the edge 'e' is a summary edge between formal parameters,\n        // we want to map it to actual parameters\n        assert(e.first->getDG());\n        assert(e.second->getDG());\n\n        auto params =\n                LLVMDGFormalParameters::get(e.second->getDG()->getParameters());\n        assert(params);\n        assert(params->formalToActual.find(e.second) !=\n                       params->formalToActual.end() &&\n               \"Cannot find formal -> actual parameter mapping\");\n        for (auto &it : params->formalToActual[e.second]) {\n            // it = pair of (call-site, actual (out) param)\n            // get the actual in param too }\n            assert(params->formalToActual.find(e.first) !=\n                   params->formalToActual.end());\n            auto actIn = params->formalToActual[e.first][it.first];\n            assert(actIn && \"Do not have actual in param\");\n\n            // add summary edge\n            actIn->addSummaryEdge(it.second);\n\n            // XXX: very inefficient\n            for (auto &pe : pathEdge) {\n                if (pe.first == it.second) {\n                    propagate(actIn, pe.second);\n                }\n            }\n        }\n    }\n\n  public:\n    void computeSummaryEdges() {\n        initialize();\n\n        while (!workList.empty()) {\n            Edge e = workList.pop();\n\n            if (isActualOut(e.first)) {\n                handleActualOut(e);\n            } else if (isFormalIn(e.first)) {\n                handleFormalIn(e);\n            } else {\n                handleGenericEdge(e);\n            }\n        }\n    }\n};\n\nvoid LLVMDependenceGraph::computeSummaryEdges() {\n    SummaryEdgesComputation C;\n    C.computeSummaryEdges();\n}\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/SystemDependenceGraph/Dependencies.cpp",
    "content": "#include \"dg/llvm/ControlDependence/ControlDependence.h\"\n#include \"dg/llvm/DataDependence/DataDependence.h\"\n#include \"dg/llvm/SystemDependenceGraph/SystemDependenceGraph.h\"\n#include \"dg/util/debug.h\"\n\nnamespace dg {\nnamespace llvmdg {\n\n///\n// Fill in dependence edges into SDG\nstruct SDGDependenciesBuilder {\n    llvmdg::SystemDependenceGraph &_sdg;\n    dda::LLVMDataDependenceAnalysis *DDA;\n    LLVMControlDependenceAnalysis *CDA;\n\n    SDGDependenciesBuilder(llvmdg::SystemDependenceGraph &g,\n                           dda::LLVMDataDependenceAnalysis *dda,\n                           LLVMControlDependenceAnalysis *cda)\n            : _sdg(g), DDA(dda), CDA(cda) {}\n\n    void addUseDependencies(sdg::DGElement *nd, llvm::Instruction &I) {\n        for (auto &op : I.operands()) {\n            auto *val = &*op;\n            if (llvm::isa<llvm::ConstantExpr>(val)) {\n                val = val->stripPointerCasts();\n            } else if (llvm::isa<llvm::BasicBlock>(val) ||\n                       llvm::isa<llvm::ConstantInt>(val)) {\n                // we do not add use edges to basic blocks\n                // FIXME: but maybe we could? The implementation could be then\n                // clearer...\n                continue;\n            }\n\n            auto *opnd = _sdg.getNode(val);\n            if (!opnd) {\n                if (auto *fun = llvm::dyn_cast<llvm::Function>(val)) {\n                    llvm::errs() << \"[SDG error] Do not have fun as operand: \"\n                                 << fun->getName() << \"\\n\";\n                    continue;\n                }\n\n                llvm::errs() << \"[SDG error] Do not have operand node:\\n\";\n                llvm::errs() << *val << \"\\n\";\n                abort();\n            }\n\n            assert(opnd && \"Do not have operand node\");\n            assert(sdg::DGNode::get(nd) && \"Wrong type of node\");\n\n            if (auto *arg = sdg::DGArgumentPair::get(opnd)) {\n                sdg::DGNode::get(nd)->addUses(arg->getInputArgument());\n            } else {\n                auto *opnode = sdg::DGNode::get(opnd);\n                assert(opnode && \"Wrong type of node\");\n                sdg::DGNode::get(nd)->addUses(*opnode);\n            }\n        }\n    }\n\n    // elem is CD on 'on'\n    void addControlDep(sdg::DepDGElement *elem, const llvm::Value *on) {\n        if (const auto *depB = llvm::dyn_cast<llvm::BasicBlock>(on)) {\n            auto *depblock = _sdg.getBBlock(depB);\n            assert(depblock && \"Do not have the block\");\n            elem->addControlDep(*depblock);\n        } else {\n            auto *depnd = sdg::DepDGElement::get(_sdg.getNode(on));\n            assert(depnd && \"Do not have the node\");\n\n            if (auto *C = sdg::DGNodeCall::get(depnd)) {\n                // this is 'noret' dependence (we have no other control deps for\n                // calls)\n                auto *noret = C->getParameters().getNoReturn();\n                if (!noret)\n                    noret = &C->getParameters().createNoReturn();\n                elem->addControlDep(*noret);\n\n                // add CD to all formal norets\n                for (auto *calledF : C->getCallees()) {\n                    auto *fnoret = calledF->getParameters().getNoReturn();\n                    if (!fnoret)\n                        fnoret = &calledF->getParameters().createNoReturn();\n                    noret->addControlDep(*fnoret);\n                }\n            } else {\n                elem->addControlDep(*depnd);\n            }\n        }\n    }\n\n    void addControlDependencies(sdg::DepDGElement *elem, llvm::Instruction &I) {\n        assert(elem);\n        for (auto *dep : CDA->getDependencies(&I)) {\n            addControlDep(elem, dep);\n        }\n    }\n\n    void addControlDependencies(sdg::DGBBlock *block, llvm::BasicBlock &B) {\n        assert(block);\n        for (auto *dep : CDA->getDependencies(&B)) {\n            addControlDep(block, dep);\n        }\n    }\n\n    void addDataDependencies(sdg::DGElement *nd, llvm::Instruction &I) {\n        addInterprocDataDependencies(nd, I);\n    }\n\n    void addInterprocDataDependencies(sdg::DGElement *nd,\n                                      llvm::Instruction &I) {\n        if (!DDA->isUse(&I))\n            return;\n\n        for (auto &op : DDA->getLLVMDefinitions(&I)) {\n            auto *val = &*op;\n            auto *opnd = _sdg.getNode(val);\n            if (!opnd) {\n                llvm::errs() << \"[SDG error] Do not have operand node:\\n\";\n                llvm::errs() << *val << \"\\n\";\n                abort();\n            }\n\n            assert(opnd && \"Do not have operand node\");\n            assert(sdg::DGNode::get(nd) && \"Wrong type of node\");\n\n            if (auto *arg = sdg::DGArgumentPair::get(opnd)) {\n                sdg::DGNode::get(nd)->addMemoryDep(arg->getInputArgument());\n            } else {\n                auto *opnode = sdg::DGNode::get(opnd);\n                assert(opnode && \"Wrong type of node\");\n                sdg::DGNode::get(nd)->addMemoryDep(*opnode);\n            }\n        }\n    }\n\n    void processInstr(llvm::Instruction &I) {\n        auto *nd = sdg::DepDGElement::get(_sdg.getNode(&I));\n        assert(nd && \"Do not have node\");\n\n        if (llvm::isa<llvm::DbgInfoIntrinsic>(&I)) {\n            // FIXME\n            llvm::errs() << \"sdg: Skipping \" << I << \"\\n\";\n            return;\n        }\n\n        // add dependencies\n        addUseDependencies(nd, I);\n        addDataDependencies(nd, I);\n        addControlDependencies(nd, I);\n    }\n\n    void processDG(llvm::Function &F) {\n        auto *dg = _sdg.getDG(&F);\n        assert(dg && \"Do not have dg\");\n\n        for (auto &B : F) {\n            for (auto &I : B) {\n                processInstr(I);\n            }\n\n            // block-based control dependencies\n            addControlDependencies(_sdg.getBBlock(&B), B);\n        }\n\n        // add noreturn dependencies\n\n        DBG(sdg, \"Adding noreturn dependencies to \" << F.getName().str());\n        auto *noret = dg->getParameters().getNoReturn();\n        if (!noret)\n            noret = &dg->getParameters().createNoReturn();\n        for (auto *dep : CDA->getNoReturns(&F)) {\n            llvm::errs() << \"NORET: \" << *dep << \"\\n\";\n            auto *nd = sdg::DepDGElement::get(_sdg.getNode(dep));\n            assert(nd && \"Do not have the node\");\n            if (auto *C = sdg::DGNodeCall::get(nd)) {\n                // if this is call, add it again to noret node\n                auto *cnoret = C->getParameters().getNoReturn();\n                assert(cnoret && \"Did not create a noret for a call\");\n                noret->addControlDep(*cnoret);\n            } else {\n                noret->addControlDep(*nd);\n            }\n        }\n    }\n\n    void processFuns() {\n        for (auto &F : *_sdg.getModule()) {\n            if (F.isDeclaration()) {\n                continue;\n            }\n\n            processDG(F);\n        }\n    }\n};\n\nvoid SystemDependenceGraph::buildEdges() {\n    DBG_SECTION_BEGIN(sdg, \"Adding edges into SDG\");\n\n    SDGDependenciesBuilder builder(*this, _dda, _cda);\n    builder.processFuns();\n\n    DBG_SECTION_END(sdg, \"Adding edges into SDG finished\");\n}\n\n} // namespace llvmdg\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/SystemDependenceGraph/SDG2Dot.cpp",
    "content": "#include \"dg/llvm/SystemDependenceGraph/SDG2Dot.h\"\n#include \"dg/llvm/SystemDependenceGraph/SystemDependenceGraph.h\"\n\nstd::ostream &operator<<(std::ostream &os, const llvm::Value *val) {\n    if (!val) {\n        os << \"(null)\";\n        return os;\n    }\n\n    std::ostringstream ostr;\n    llvm::raw_os_ostream ro(ostr);\n\n    if (llvm::isa<llvm::Function>(val)) {\n        ro << \"FUNC \" << val->getName();\n    } else if (const auto *B = llvm::dyn_cast<llvm::BasicBlock>(val)) {\n        ro << B->getParent()->getName() << \"::\\n\";\n        ro << \"label \" << val->getName();\n    } else if (const auto *I = llvm::dyn_cast<llvm::Instruction>(val)) {\n        const auto *const B = I->getParent();\n        if (B) {\n            ro << B->getParent()->getName() << \"::\\n\";\n        } else {\n            ro << \"<null>::\\n\";\n        }\n        ro << *val;\n    } else {\n        ro << *val;\n    }\n\n    ro.flush();\n\n    // break the string if it is too long\n    std::string str = ostr.str();\n    if (str.length() > 100) {\n        str.resize(40);\n    }\n\n    // escape the \"\n    size_t pos = 0;\n    while ((pos = str.find('\"', pos)) != std::string::npos) {\n        str.replace(pos, 1, \"\\\\\\\"\");\n        // we replaced one char with two, so we must shift after the new \"\n        pos += 2;\n    }\n\n    os << str;\n\n    return os;\n}\n"
  },
  {
    "path": "lib/llvm/SystemDependenceGraph/SystemDependenceGraph.cpp",
    "content": "#include \"dg/llvm/SystemDependenceGraph/SystemDependenceGraph.h\"\n#include \"dg/util/debug.h\"\n\n#include \"llvm/llvm-utils.h\"\n\nnamespace dg {\nnamespace llvmdg {\n\nstruct SDGBuilder {\n    SystemDependenceGraph *_llvmsdg;\n    llvm::Module *_module;\n\n    SDGBuilder(SystemDependenceGraph *llvmsdg, llvm::Module *m)\n            : _llvmsdg(llvmsdg), _module(m) {}\n\n    sdg::DependenceGraph &getOrCreateDG(llvm::Function *F) {\n        auto *dg = _llvmsdg->getDG(F);\n        if (!dg) {\n            auto &g = _llvmsdg->getSDG().createGraph(F->getName().str());\n            _llvmsdg->addFunMapping(F, &g);\n            return g;\n        }\n\n        return *dg;\n    }\n\n    sdg::DGNode &buildCallNode(sdg::DependenceGraph &dg, llvm::CallInst *CI) {\n#if LLVM_VERSION_MAJOR >= 8\n        auto *CV = CI->getCalledOperand()->stripPointerCasts();\n#else\n        auto *CV = CI->getCalledValue()->stripPointerCasts();\n#endif\n        if (!CV) {\n            assert(false && \"funcptr not implemnted yet\");\n            abort();\n        }\n\n        auto *F = llvm::dyn_cast<llvm::Function>(CV);\n        if (!F) {\n            assert(false && \"funcptr not implemnted yet\");\n            abort();\n        }\n\n        if (F->isDeclaration()) {\n            return dg.createInstruction();\n        }\n\n        // create the node call and and the call edge\n        auto &node = dg.createCall();\n        node.addCallee(getOrCreateDG(F));\n\n        // create actual parameters\n        auto &params = node.getParameters();\n        for (const auto &arg : llvmutils::args(CI)) {\n            llvm::errs() << \"Act: \" << *arg << \"\\n\";\n            params.createParameter();\n        }\n        return node;\n    }\n\n    void buildBBlock(sdg::DependenceGraph &dg, llvm::BasicBlock &B) {\n        auto &block = dg.createBBlock();\n        _llvmsdg->addBlkMapping(&B, &block);\n\n        for (auto &I : B) {\n            sdg::DGNode *node = nullptr;\n            if (auto *CI = llvm::dyn_cast<llvm::CallInst>(&I)) {\n                node = &buildCallNode(dg, CI);\n            } else {\n                node = &dg.createInstruction();\n                if (llvm::isa<llvm::ReturnInst>(I)) {\n                    // add formal 'ret' parameter\n                    auto &params = dg.getParameters();\n                    auto *ret = params.getReturn();\n                    if (!ret)\n                        ret = &params.createReturn();\n                    // XXX: do we want the 'use' edge here?\n                    node->addUser(*ret);\n                }\n            }\n            assert(node && \"Failed creating a node\");\n\n            block.append(node);\n            _llvmsdg->addMapping(&I, node);\n        }\n    }\n\n    void buildFormalParameters(sdg::DependenceGraph &dg, llvm::Function &F) {\n        DBG(sdg, \"Building parameters for '\" << F.getName().str() << \"'\");\n        auto &params = dg.getParameters();\n\n        if (F.isVarArg()) {\n            params.createVarArg();\n        }\n\n        for (auto &arg : F.args()) {\n            llvm::errs() << \"Form: \" << arg << \"\\n\";\n            auto &param = params.createParameter();\n            _llvmsdg->addMapping(&arg, &param);\n        }\n    }\n\n    void buildDG(sdg::DependenceGraph &dg, llvm::Function &F) {\n        DBG_SECTION_BEGIN(sdg, \"Building '\" << F.getName().str() << \"'\");\n\n        buildFormalParameters(dg, F);\n\n        for (auto &B : F) {\n            buildBBlock(dg, B);\n        }\n\n        DBG_SECTION_END(sdg, \"Building '\" << F.getName().str() << \"' finished\");\n    }\n\n    void buildGlobals(sdg::DependenceGraph &entry) {\n        DBG_SECTION_BEGIN(sdg, \"Building globals\");\n\n        // globals are formal parameters of the entry function\n        auto &params = entry.getParameters();\n        for (auto &GV : _module->globals()) {\n            auto &g = params.createParameter();\n            _llvmsdg->addMapping(&GV, &g);\n            llvm::errs() << \"GV: \" << GV << \"\\n\";\n        }\n        DBG_SECTION_END(sdg, \"Finished building globals\");\n    }\n\n    void buildFuns() {\n        DBG_SECTION_BEGIN(sdg, \"Building functions\");\n        // build dependence graph for each procedure\n        for (auto &F : *_module) {\n            if (F.isDeclaration()) {\n                continue;\n            }\n\n            auto &g = getOrCreateDG(&F);\n            buildDG(g, F);\n        }\n        DBG_SECTION_END(sdg, \"Done building functions\");\n    }\n};\n\nvoid SystemDependenceGraph::buildNodes() {\n    DBG_SECTION_BEGIN(sdg, \"Building SDG nodes\");\n    assert(_module);\n    assert(_pta);\n\n    SDGBuilder builder(this, _module);\n\n    builder.buildFuns();\n\n    // set the entry function\n    auto *llvmentry = _module->getFunction(_options.entryFunction);\n    assert(llvmentry && \"Module does not contain the entry function\");\n    auto *entry = getDG(llvmentry);\n    assert(entry && \"Did not build the entry function\");\n    _sdg.setEntry(entry);\n\n    // only after funs, we need the entry fun created\n    builder.buildGlobals(*entry);\n\n    DBG_SECTION_END(sdg, \"Building SDG nodes finished\");\n}\n\nvoid SystemDependenceGraph::buildSDG() {\n    buildNodes();\n    // defined in Dependencies.cpp\n    buildEdges();\n}\n\n} // namespace llvmdg\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Graphs/BlockGraph.cpp",
    "content": "#include \"BlockGraph.h\"\n\nBlockGraph::BlockGraph(const llvm::BasicBlock *llvmBlock, Node *firstNode,\n                       Node *lastNode)\n        : llvmBlock_(llvmBlock), firstNode_(firstNode), lastNode_(lastNode)\n\n{}\n\nNode *BlockGraph::firstNode() const { return firstNode_; }\n\nNode *BlockGraph::lastNode() const { return lastNode_; }\n\nconst llvm::BasicBlock *BlockGraph::llvmBlock() const { return llvmBlock_; }\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Graphs/BlockGraph.h",
    "content": "#ifndef BLOCKGRAPH_H\n#define BLOCKGRAPH_H\n\n#include <map>\n#include <ostream>\n#include <set>\n\nnamespace llvm {\nclass BasicBlock;\n}\n\nclass Node;\n\nclass BlockGraph {\n  private:\n    const llvm::BasicBlock *llvmBlock_ = nullptr;\n\n    Node *firstNode_ = nullptr;\n    Node *lastNode_ = nullptr;\n\n  public:\n    BlockGraph(const llvm::BasicBlock *llvmBlock, Node *firstNode,\n               Node *lastNode);\n\n    BlockGraph(const BlockGraph &) = delete;\n\n    BlockGraph &operator==(const BlockGraph &) = delete;\n\n    const llvm::BasicBlock *llvmBlock() const;\n\n    Node *firstNode() const;\n    Node *lastNode() const;\n};\n\n#endif // BLOCKGRAPH_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Graphs/ControlFlowGraph.cpp",
    "content": "#include \"dg/llvm/ThreadRegions/ControlFlowGraph.h\"\n\n#include \"CriticalSectionsBuilder.h\"\n#include \"GraphBuilder.h\"\n#include \"ThreadRegionsBuilder.h\"\n\nControlFlowGraph::ControlFlowGraph(dg::DGLLVMPointerAnalysis *pointsToAnalysis)\n        : graphBuilder(new GraphBuilder(pointsToAnalysis)),\n          threadRegionsBuilder(new ThreadRegionsBuilder()),\n          criticalSectionsBuilder(new CriticalSectionsBuilder()) {}\n\nstd::set<const llvm::CallInst *> ControlFlowGraph::getJoins() const {\n    return graphBuilder->getJoins();\n}\n\nstd::set<const llvm::CallInst *>\nControlFlowGraph::getCorrespondingForks(const llvm::CallInst *callInst) const {\n    return graphBuilder->getCorrespondingForks(callInst);\n}\n\nstd::set<const llvm::CallInst *> ControlFlowGraph::getLocks() const {\n    return criticalSectionsBuilder->locks();\n}\n\nstd::set<const llvm::CallInst *> ControlFlowGraph::getCorrespongingUnlocks(\n        const llvm::CallInst *callInst) const {\n    return criticalSectionsBuilder->correspondingUnlocks(callInst);\n}\n\nstd::set<const llvm::Instruction *>\nControlFlowGraph::getCorrespondingCriticalSection(\n        const llvm::CallInst *callInst) const {\n    return criticalSectionsBuilder->correspondingNodes(callInst);\n}\n\nControlFlowGraph::~ControlFlowGraph() = default;\n\nvoid ControlFlowGraph::buildFunction(const llvm::Function *function) {\n    auto nodeSeq = graphBuilder->buildFunction(function);\n    graphBuilder->matchForksAndJoins();\n    graphBuilder->matchLocksAndUnlocks();\n\n    auto locks = graphBuilder->getLocks();\n\n    for (auto *lock : locks) {\n        criticalSectionsBuilder->buildCriticalSection(lock);\n    }\n\n    threadRegionsBuilder->reserve(graphBuilder->size());\n    threadRegionsBuilder->build(nodeSeq.first);\n}\n\nvoid ControlFlowGraph::printWithRegions(std::ostream &ostream) const {\n    ostream << \"digraph \\\"Control Flow Graph\\\" {\\n\";\n    ostream << \"compound = true\\n\";\n\n    threadRegionsBuilder->printNodes(ostream);\n    graphBuilder->printEdges(ostream);\n    threadRegionsBuilder->printEdges(ostream);\n\n    ostream << \"}\\n\";\n}\n\nvoid ControlFlowGraph::printWithoutRegions(std::ostream &ostream) const {\n    graphBuilder->print(ostream);\n}\n\nstd::set<ThreadRegion *> ControlFlowGraph::threadRegions() {\n    return threadRegionsBuilder->threadRegions();\n}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Graphs/CriticalSectionsBuilder.cpp",
    "content": "#include \"CriticalSectionsBuilder.h\"\n#include \"llvm/ThreadRegions/Nodes/Nodes.h\"\n\n#include <llvm/IR/Instructions.h>\n\nCriticalSectionsBuilder::CriticalSectionsBuilder() = default;\n\nCriticalSectionsBuilder::~CriticalSectionsBuilder() {\n    for (auto iterator : criticalSections_) {\n        delete iterator.second;\n    }\n}\n\nbool CriticalSectionsBuilder::buildCriticalSection(LockNode *lock) {\n    auto iterator = criticalSections_.find(lock->callInstruction());\n    if (iterator != criticalSections_.end()) {\n        return false;\n    }\n\n    auto *criticalSection = new CriticalSection(lock);\n    criticalSections_.emplace(lock->callInstruction(), criticalSection);\n\n    currentLock = lock;\n    currentUnlocks = lock->correspondingUnlocks();\n    visitNode(lock);\n    bool changed = populateCriticalSection();\n    examined_.clear();\n    return changed;\n}\n\nbool CriticalSectionsBuilder::populateCriticalSection() {\n    return criticalSections_[currentLock->callInstruction()]->insertNodes(\n            examined_);\n}\n\nvoid CriticalSectionsBuilder::visitNode(Node *node) {\n    preVisit(node);\n    visit(node);\n    postVisit(node);\n}\n\nstd::set<const llvm::CallInst *> CriticalSectionsBuilder::locks() const {\n    std::set<const llvm::CallInst *> llvmLocks;\n\n    for (auto lock : criticalSections_) {\n        llvmLocks.insert(lock.first);\n    }\n    return llvmLocks;\n}\n\nstd::set<const llvm::Instruction *>\nCriticalSectionsBuilder::correspondingNodes(const llvm::CallInst *lock) const {\n    if (!lock) {\n        return {};\n    }\n    auto iterator = criticalSections_.find(lock);\n    if (iterator != criticalSections_.end()) {\n        return iterator->second->nodes();\n    }\n    return {};\n}\n\nstd::set<const llvm::CallInst *> CriticalSectionsBuilder::correspondingUnlocks(\n        const llvm::CallInst *lock) const {\n    if (!lock) {\n        return {};\n    }\n    auto iterator = criticalSections_.find(lock);\n    if (iterator != criticalSections_.end()) {\n        return iterator->second->unlocks();\n    }\n    return {};\n}\n\nvoid CriticalSectionsBuilder::preVisit(Node *node) {\n    visited_.insert(node);\n    if (auto *unlockNode = castNode<NodeType::UNLOCK>(node)) {\n        currentUnlocks.erase(unlockNode);\n    }\n}\n\nvoid CriticalSectionsBuilder::visit(Node *node) {\n    if (currentUnlocks.empty()) {\n        return;\n    }\n\n    for (auto *successor : *node) {\n        if (!visited(successor) && !examined(successor)) {\n            visitNode(successor);\n        }\n    }\n}\n\nvoid CriticalSectionsBuilder::postVisit(Node *node) {\n    visited_.erase(node);\n    examined_.insert(node);\n}\n\nbool CriticalSectionsBuilder::visited(Node *node) const {\n    auto iterator = visited_.find(node);\n    return iterator != visited_.end();\n}\n\nbool CriticalSectionsBuilder::examined(Node *node) const {\n    auto iterator = examined_.find(node);\n    return iterator != examined_.end();\n}\n\nCriticalSection::CriticalSection(LockNode *lock) : lock_(lock) {}\n\nconst llvm::CallInst *CriticalSection::lock() const {\n    return this->lock_->callInstruction();\n}\n\nstd::set<const llvm::Instruction *> CriticalSection::nodes() const {\n    std::set<const llvm::Instruction *> llvmNodes;\n    for (auto *node : nodes_) {\n        if (!node->isArtificial()) {\n            llvmNodes.insert(node->llvmInstruction());\n        }\n    }\n    return llvmNodes;\n}\n\nstd::set<const llvm::CallInst *> CriticalSection::unlocks() const {\n    std::set<const llvm::CallInst *> llvmUnlocks;\n    for (auto *unlock : lock_->correspondingUnlocks()) {\n        llvmUnlocks.insert(unlock->callInstruction());\n    }\n    return llvmUnlocks;\n}\n\nbool CriticalSection::insertNodes(const std::set<Node *> &nodes) {\n    auto sizeBefore = this->nodes_.size();\n    this->nodes_.insert(nodes.begin(), nodes.end());\n    this->nodes_.erase(lock_);\n    auto sizeAfter = this->nodes_.size();\n    return sizeBefore < sizeAfter;\n}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Graphs/CriticalSectionsBuilder.h",
    "content": "#ifndef CRITICALSECTIONSBUILDER_H\n#define CRITICALSECTIONSBUILDER_H\n\n#include <map>\n#include <set>\n#include <vector>\n\nclass Node;\nclass LockNode;\nclass UnlockNode;\nclass ExitNode;\nclass ForkNode;\n\nnamespace llvm {\nclass Instruction;\nclass CallInst;\n} // namespace llvm\n\nclass CriticalSection {\n  private:\n    LockNode *lock_;\n    std::set<Node *> nodes_;\n\n  public:\n    CriticalSection(LockNode *lock);\n\n    const llvm::CallInst *lock() const;\n\n    std::set<const llvm::Instruction *> nodes() const;\n\n    std::set<const llvm::CallInst *> unlocks() const;\n\n    bool insertNodes(const std::set<Node *> &nodes_);\n};\n\nclass CriticalSectionsBuilder {\n    std::set<LockNode *> locks_;\n\n    LockNode *currentLock;\n    std::set<UnlockNode *> currentUnlocks;\n\n    std::set<Node *> visited_;\n    std::set<Node *> examined_;\n\n    std::map<const llvm::CallInst *, CriticalSection *> criticalSections_;\n\n  public:\n    CriticalSectionsBuilder();\n\n    ~CriticalSectionsBuilder();\n\n    bool buildCriticalSection(LockNode *lock);\n\n    std::set<const llvm::CallInst *> locks() const;\n\n    std::set<const llvm::Instruction *>\n    correspondingNodes(const llvm::CallInst *lock) const;\n\n    std::set<const llvm::CallInst *>\n    correspondingUnlocks(const llvm::CallInst *lock) const;\n\n  private:\n    bool populateCriticalSection();\n\n    void visitNode(Node *node);\n\n    void preVisit(Node *node);\n\n    void visit(Node *node);\n\n    void postVisit(Node *node);\n\n    bool visited(Node *node) const;\n\n    bool examined(Node *node) const;\n};\n\n#endif // CRITICALSECTIONSBUILDER_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Graphs/FunctionGraph.cpp",
    "content": "#include \"FunctionGraph.h\"\n\nFunctionGraph::FunctionGraph(const llvm::Function *llvmFunction,\n                             EntryNode *entryNode, ExitNode *exitNode)\n        : llvmFunction_(llvmFunction), entryNode_(entryNode),\n          exitNode_(exitNode) {}\n\nEntryNode *FunctionGraph::entryNode() const { return entryNode_; }\n\nExitNode *FunctionGraph::exitNode() const { return exitNode_; }\n\nconst llvm::Function *FunctionGraph::llvmFunction() const {\n    return llvmFunction_;\n}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Graphs/FunctionGraph.h",
    "content": "#ifndef FUNCTIONGRAPH_H\n#define FUNCTIONGRAPH_H\n\nnamespace llvm {\nclass Function;\n}\n\nclass EntryNode;\nclass ExitNode;\n\nclass FunctionGraph {\n  private:\n    const llvm::Function *llvmFunction_ = nullptr;\n\n    EntryNode *entryNode_ = nullptr;\n    ExitNode *exitNode_ = nullptr;\n\n  public:\n    FunctionGraph(const llvm::Function *llvmFunction, EntryNode *entryNode,\n                  ExitNode *exitNode);\n\n    FunctionGraph(const FunctionGraph &) = delete;\n\n    FunctionGraph &operator==(const FunctionGraph &) = delete;\n\n    const llvm::Function *llvmFunction() const;\n\n    EntryNode *entryNode() const;\n    ExitNode *exitNode() const;\n};\n\n#endif // FUNCTIONGRAPH_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Graphs/GraphBuilder.cpp",
    "content": "#include \"GraphBuilder.h\"\n\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n#include \"llvm/ForkJoin/ForkJoin.h\"\n\n#include \"BlockGraph.h\"\n#include \"FunctionGraph.h\"\n#include \"llvm/ThreadRegions/Nodes/Nodes.h\"\n\n#include <llvm/IR/CFG.h>\n#include <llvm/IR/Function.h>\n#include <llvm/IR/Instructions.h>\n\n#include <vector>\n\nusing namespace llvm;\n\nusing dg::ForkJoinAnalysis;\n\nGraphBuilder::GraphBuilder(dg::DGLLVMPointerAnalysis *pointsToAnalysis)\n        : pointsToAnalysis_(pointsToAnalysis) {}\n\nGraphBuilder::~GraphBuilder() {\n    for (auto *node : artificialNodes_) {\n        delete node;\n    }\n\n    for (auto llvmAndNode : llvmToNodeMap_) {\n        delete llvmAndNode.second;\n    }\n\n    for (auto iterator : llvmToBlockMap_) {\n        delete iterator.second;\n    }\n\n    for (auto iterator : llvmToFunctionMap_) {\n        delete iterator.second;\n    }\n}\n\ntemplate <>\nForkNode *GraphBuilder::addNode(ForkNode *node) {\n    llvmToForks_.emplace(node->callInstruction(), node);\n    if (node->isArtificial()) {\n        if (this->artificialNodes_.insert(node).second) {\n            return node;\n        }\n    } else {\n        if (this->llvmToNodeMap_.emplace(node->llvmInstruction(), node)\n                    .second) {\n            return node;\n        }\n    }\n\n    return nullptr;\n}\n\ntemplate <>\nJoinNode *GraphBuilder::addNode(JoinNode *node) {\n    llvmToJoins_.emplace(node->callInstruction(), node);\n    if (node->isArtificial()) {\n        if (this->artificialNodes_.insert(node).second) {\n            return node;\n        }\n    } else {\n        if (this->llvmToNodeMap_.emplace(node->llvmInstruction(), node)\n                    .second) {\n            return node;\n        }\n    }\n\n    return nullptr;\n}\n\ntemplate <>\nLockNode *GraphBuilder::addNode(LockNode *node) {\n    llvmToLocks_.emplace(node->callInstruction(), node);\n    if (node->isArtificial()) {\n        if (this->artificialNodes_.insert(node).second) {\n            return node;\n        }\n    } else {\n        if (this->llvmToNodeMap_.emplace(node->llvmInstruction(), node)\n                    .second) {\n            return node;\n        }\n    }\n\n    return nullptr;\n}\n\ntemplate <>\nUnlockNode *GraphBuilder::addNode(UnlockNode *node) {\n    llvmToUnlocks_.emplace(node->callInstruction(), node);\n    if (node->isArtificial()) {\n        if (this->artificialNodes_.insert(node).second) {\n            return node;\n        }\n    } else {\n        if (this->llvmToNodeMap_.emplace(node->llvmInstruction(), node)\n                    .second) {\n            return node;\n        }\n    }\n\n    return nullptr;\n}\n\nGraphBuilder::NodeSequence\nGraphBuilder::buildInstruction(const llvm::Instruction *instruction) {\n    if (!instruction) {\n        return {nullptr, nullptr};\n    }\n\n    auto *inst = findInstruction(instruction);\n    if (inst) {\n        return {nullptr, nullptr};\n    }\n    NodeSequence sequence;\n    switch (instruction->getOpcode()) {\n    case Instruction::Call:\n        sequence = buildCallInstruction(instruction);\n        break;\n    case Instruction::Ret:\n        sequence = buildReturnInstruction(instruction);\n        break;\n    default:\n        sequence = buildGeneralInstruction(instruction);\n        break;\n    }\n    return sequence;\n}\n\nGraphBuilder::NodeSequence\nGraphBuilder::buildBlock(const llvm::BasicBlock *basicBlock) {\n    if (!basicBlock) {\n        return {nullptr, nullptr};\n    }\n\n    auto *block = findBlock(basicBlock);\n    if (block) {\n        return {nullptr, nullptr};\n    }\n    std::vector<NodeSequence> builtInstructions;\n    for (const auto &instruction : *basicBlock) {\n        auto builtInstruction = buildInstruction(&instruction);\n        builtInstructions.push_back(builtInstruction);\n        if (builtInstruction.second->getType() == NodeType::RETURN)\n            break;\n    }\n\n    if (builtInstructions.size() > 1) {\n        for (auto iterator = builtInstructions.begin() + 1;\n             iterator != builtInstructions.end(); ++iterator) {\n            (iterator - 1)->second->addSuccessor(iterator->first);\n        }\n    }\n\n    Node *firstNode = builtInstructions.front().first;\n    Node *lastNode = builtInstructions.back().second;\n\n    auto *blockGraph = new BlockGraph(basicBlock, firstNode, lastNode);\n    this->llvmToBlockMap_.emplace(basicBlock, blockGraph);\n\n    return {firstNode, lastNode};\n}\n\nGraphBuilder::NodeSequence\nGraphBuilder::buildFunction(const llvm::Function *function) {\n    if (!function) {\n        return {nullptr, nullptr};\n    }\n\n    if (function->empty()) {\n        return {nullptr, nullptr};\n    }\n\n    auto *functionGraph = findFunction(function);\n    if (functionGraph) {\n        return {nullptr, nullptr};\n    }\n\n    // TODO refactor this into createFunctionGraph method\n    auto *entryNode = addNode(createNode<NodeType::ENTRY>());\n    auto *exitNode = addNode(createNode<NodeType::EXIT>());\n    functionGraph = new FunctionGraph(function, entryNode, exitNode);\n    this->llvmToFunctionMap_.emplace(function, functionGraph);\n\n    for (const auto &block : *function) {\n        if (isReachable(&block)) {\n            buildBlock(&block);\n        }\n    }\n\n    for (const auto &block : *function) {\n        if (isReachable(&block)) {\n            auto *blockGraph = findBlock(&block);\n            if (predecessorsNumber(&block) == 0) {\n                functionGraph->entryNode()->addSuccessor(\n                        blockGraph->firstNode());\n            }\n            if (successorsNumber(&block) == 0) {\n                blockGraph->lastNode()->addSuccessor(functionGraph->exitNode());\n            }\n            for (auto it = succ_begin(&block); it != succ_end(&block); ++it) {\n                auto *successorGraph = findBlock(*it);\n                blockGraph->lastNode()->addSuccessor(\n                        successorGraph->firstNode());\n            }\n        }\n    }\n\n    return {functionGraph->entryNode(), functionGraph->exitNode()};\n}\n\nNode *GraphBuilder::findInstruction(const llvm::Instruction *instruction) {\n    auto iterator = this->llvmToNodeMap_.find(instruction);\n    if (iterator == this->llvmToNodeMap_.end()) {\n        return nullptr;\n    }\n    return iterator->second;\n}\n\nBlockGraph *GraphBuilder::findBlock(const llvm::BasicBlock *basicBlock) {\n    if (!basicBlock) {\n        return nullptr;\n    }\n    auto iterator = this->llvmToBlockMap_.find(basicBlock);\n    if (iterator == this->llvmToBlockMap_.end()) {\n        return nullptr;\n    }\n    return iterator->second;\n}\n\nFunctionGraph *GraphBuilder::findFunction(const llvm::Function *function) {\n    auto iterator = this->llvmToFunctionMap_.find(function);\n    if (iterator == this->llvmToFunctionMap_.end()) {\n        return nullptr;\n    }\n    return iterator->second;\n}\n\nstd::set<const CallInst *> GraphBuilder::getJoins() const {\n    std::set<const CallInst *> llvmJoins;\n    for (auto iterator : llvmToJoins_) {\n        llvmJoins.insert(iterator.first);\n    }\n    return llvmJoins;\n}\n\nstd::set<const CallInst *>\nGraphBuilder::getCorrespondingForks(const CallInst *callInst) const {\n    std::set<const CallInst *> llvmForks;\n    auto iterator = llvmToJoins_.find(callInst);\n    if (iterator != llvmToJoins_.end()) {\n        auto forks = iterator->second->correspondingForks();\n        for (auto *fork : forks) {\n            llvmForks.insert(fork->callInstruction());\n        }\n    }\n    return llvmForks;\n}\n\nstd::set<LockNode *> GraphBuilder::getLocks() const {\n    std::set<LockNode *> locks;\n    for (auto iterator : llvmToLocks_) {\n        locks.insert(iterator.second);\n    }\n    return locks;\n}\n\nbool GraphBuilder::matchForksAndJoins() {\n    using namespace llvm;\n    bool changed = false;\n\n    ForkJoinAnalysis FJA{pointsToAnalysis_};\n\n    for (auto &it : llvmToJoins_) {\n        // it.first -> llvm::CallInst, it.second -> RWNode *\n        auto *joinNode = it.second;\n        auto llvmforks = FJA.matchJoin(it.first);\n        for (const auto *forkcall : llvmforks) {\n            auto *foundInstruction =\n                    findInstruction(cast<Instruction>(forkcall));\n            auto *forkNode = castNode<NodeType::FORK>(foundInstruction);\n            if (forkNode) {\n                changed |= true;\n                joinNode->addCorrespondingFork(forkNode);\n            }\n        }\n\n        auto functions = FJA.joinFunctions(it.first);\n        for (const auto *llvmFunction : functions) {\n            auto *functionGraph = findFunction(cast<Function>(llvmFunction));\n            if (functionGraph) {\n                joinNode->addJoinPredecessor(functionGraph->exitNode());\n                changed |= true;\n            }\n        }\n    }\n\n    return changed;\n}\n\nbool GraphBuilder::matchLocksAndUnlocks() {\n    using namespace dg::pta;\n    bool changed = false;\n    for (auto lock : llvmToLocks_) {\n        auto *lockMutexPtr = pointsToAnalysis_->getPointsToNode(lock.first);\n        for (auto unlock : llvmToUnlocks_) {\n            auto *unlockMutexPtr =\n                    pointsToAnalysis_->getPointsToNode(unlock.first);\n\n            std::set<PSNode *> mutexPointerIntersection;\n            for (const auto lockPointsTo : lockMutexPtr->pointsTo) {\n                for (const auto unlockPointsTo : unlockMutexPtr->pointsTo) {\n                    if (lockPointsTo.target == unlockPointsTo.target) {\n                        mutexPointerIntersection.insert(lockPointsTo.target);\n                    }\n                }\n            }\n\n            if (!mutexPointerIntersection.empty()) {\n                changed |= lock.second->addCorrespondingUnlock(unlock.second);\n            }\n        }\n    }\n    return changed;\n}\n\nvoid GraphBuilder::print(std::ostream &ostream) const {\n    ostream << \"digraph \\\"Control Flow Graph\\\" {\\n\";\n    ostream << \"compound = true\\n\";\n    printNodes(ostream);\n    printEdges(ostream);\n    ostream << \"}\\n\";\n}\n\nvoid GraphBuilder::printNodes(std::ostream &ostream) const {\n    for (const auto &iterator : llvmToNodeMap_) {\n        ostream << iterator.second->dump();\n    }\n    for (const auto &iterator : artificialNodes_) {\n        ostream << iterator->dump();\n    }\n}\n\nvoid GraphBuilder::printEdges(std::ostream &ostream) const {\n    for (const auto &iterator : llvmToNodeMap_) {\n        iterator.second->printOutcomingEdges(ostream);\n    }\n    for (const auto &iterator : artificialNodes_) {\n        iterator->printOutcomingEdges(ostream);\n    }\n}\n\nvoid GraphBuilder::clear() {\n    for (auto *node : artificialNodes_) {\n        delete node;\n    }\n\n    for (auto llvmAndNode : llvmToNodeMap_) {\n        delete llvmAndNode.second;\n    }\n\n    for (auto iterator : llvmToBlockMap_) {\n        delete iterator.second;\n    }\n\n    for (auto iterator : llvmToFunctionMap_) {\n        delete iterator.second;\n    }\n\n    artificialNodes_.clear();\n    llvmToNodeMap_.clear();\n    llvmToBlockMap_.clear();\n    llvmToFunctionMap_.clear();\n    llvmToJoins_.clear();\n    llvmToForks_.clear();\n    llvmToLocks_.clear();\n    llvmToUnlocks_.clear();\n}\n\nGraphBuilder::NodeSequence\nGraphBuilder::buildGeneralInstruction(const Instruction *instruction) {\n    auto *currentNode = addNode(createNode<NodeType::GENERAL>(instruction));\n    return {currentNode, currentNode};\n}\n\nGraphBuilder::NodeSequence\nGraphBuilder::buildGeneralCallInstruction(const CallInst *callInstruction) {\n    CallNode *callNode;\n    if (callInstruction->getCalledFunction()) {\n        callNode = addNode(createNode<NodeType::CALL>(callInstruction));\n    } else {\n        callNode =\n                addNode(createNode<NodeType::CALL>(nullptr, callInstruction));\n    }\n    return {callNode, callNode};\n}\n\nGraphBuilder::NodeSequence\nGraphBuilder::insertUndefinedFunction(const Function *function,\n                                      const CallInst *callInstruction) {\n    std::string funcName = function->getName().str();\n\n    if (funcName == \"pthread_create\") {\n        return insertPthreadCreate(callInstruction);\n    }\n    if (funcName == \"pthread_join\") {\n        return insertPthreadJoin(callInstruction);\n    }\n    if (funcName == \"pthread_exit\") {\n        return insertPthreadExit(callInstruction);\n    }\n    if (funcName == \"pthread_mutex_lock\") {\n        return insertPthreadMutexLock(callInstruction);\n    } else if (funcName == \"pthread_mutex_unlock\") {\n        return insertPthreadMutexUnlock(callInstruction);\n    } else {\n        return buildGeneralCallInstruction(callInstruction);\n    }\n}\n\nGraphBuilder::NodeSequence\nGraphBuilder::insertPthreadCreate(const CallInst *callInstruction) {\n    ForkNode *forkNode;\n    if (callInstruction->getCalledFunction()) {\n        forkNode = addNode(createNode<NodeType::FORK>(callInstruction));\n    } else {\n        forkNode =\n                addNode(createNode<NodeType::FORK>(nullptr, callInstruction));\n    }\n    auto *possibleFunction = callInstruction->getArgOperand(2);\n    auto functionsToBeForked =\n            getCalledFunctions(possibleFunction, pointsToAnalysis_);\n    for (const auto *function : functionsToBeForked) {\n        auto graph = createOrGetFunction(function);\n        if (graph.first) {\n            forkNode->addForkSuccessor(static_cast<EntryNode *>(graph.first));\n        }\n    }\n    return {forkNode, forkNode};\n}\n\nGraphBuilder::NodeSequence\nGraphBuilder::insertPthreadMutexLock(const CallInst *callInstruction) {\n    LockNode *lockNode;\n    if (callInstruction->getCalledFunction()) {\n        lockNode = addNode(createNode<NodeType::LOCK>(callInstruction));\n    } else {\n        lockNode =\n                addNode(createNode<NodeType::LOCK>(nullptr, callInstruction));\n    }\n\n    return {lockNode, lockNode};\n}\n\nGraphBuilder::NodeSequence\nGraphBuilder::insertPthreadMutexUnlock(const CallInst *callInstruction) {\n    UnlockNode *unlockNode;\n    if (callInstruction->getCalledFunction()) {\n        unlockNode = addNode(createNode<NodeType::UNLOCK>(callInstruction));\n    } else {\n        unlockNode =\n                addNode(createNode<NodeType::UNLOCK>(nullptr, callInstruction));\n    }\n\n    return {unlockNode, unlockNode};\n}\n\nGraphBuilder::NodeSequence\nGraphBuilder::insertPthreadJoin(const CallInst *callInstruction) {\n    JoinNode *joinNode;\n    if (callInstruction->getCalledFunction()) {\n        joinNode = addNode(createNode<NodeType::JOIN>(callInstruction));\n    } else {\n        joinNode =\n                addNode(createNode<NodeType::JOIN>(nullptr, callInstruction));\n    }\n    return {joinNode, joinNode};\n}\n\nGraphBuilder::NodeSequence\nGraphBuilder::insertPthreadExit(const CallInst *callInstruction) {\n    CallNode *callNode;\n    if (callInstruction->getCalledFunction()) {\n        callNode = addNode(createNode<NodeType::CALL>(callInstruction));\n    } else {\n        callNode =\n                addNode(createNode<NodeType::CALL>(nullptr, callInstruction));\n    }\n    auto *returnNode = addNode(createNode<NodeType::RETURN>());\n    callNode->addSuccessor(returnNode);\n    return {callNode, returnNode};\n}\n\nGraphBuilder::NodeSequence\nGraphBuilder::insertFunction(const Function *function,\n                             const CallInst *callInstruction) {\n    if (function->empty()) {\n        return insertUndefinedFunction(function, callInstruction);\n    }\n    Node *callNode;\n    if (callInstruction->getCalledFunction()) {\n        callNode = createNode<NodeType::CALL>(callInstruction);\n    } else {\n        callNode = createNode<NodeType::CALL>(nullptr, callInstruction);\n    }\n    addNode(callNode);\n    auto nodeSeq = createOrGetFunction(function);\n    callNode->addSuccessor(nodeSeq.first);\n    return {callNode, nodeSeq.second};\n}\n\nGraphBuilder::NodeSequence\nGraphBuilder::insertFunctionPointerCall(const CallInst *callInstruction) {\n#if LLVM_VERSION_MAJOR >= 8\n    auto *calledValue = callInstruction->getCalledOperand();\n#else\n    auto *calledValue = callInstruction->getCalledValue();\n#endif\n    auto functions = getCalledFunctions(calledValue, pointsToAnalysis_);\n\n    auto *callFuncPtrNode =\n            addNode(createNode<NodeType::CALL_FUNCPTR>(callInstruction));\n    Node *returnNode;\n\n    if (functions.size() > 1) {\n        returnNode = addNode(createNode<NodeType::CALL_RETURN>());\n        for (const auto *function : functions) {\n            auto nodeSeq = insertFunction(function, callInstruction);\n            callFuncPtrNode->addSuccessor(nodeSeq.first);\n            nodeSeq.second->addSuccessor(returnNode);\n        }\n    } else if (functions.size() == 1) {\n        auto nodeSeq = insertFunction(functions.front(), callInstruction);\n        callFuncPtrNode->addSuccessor(nodeSeq.first);\n        returnNode = nodeSeq.second;\n    } else {\n        auto nodeSeq = buildGeneralCallInstruction(callInstruction);\n        callFuncPtrNode->addSuccessor(nodeSeq.first);\n        returnNode = nodeSeq.second;\n    }\n    return {callFuncPtrNode, returnNode};\n}\n\nGraphBuilder::NodeSequence\nGraphBuilder::buildCallInstruction(const Instruction *instruction) {\n    const auto *callInst = cast<CallInst>(instruction);\n    if (callInst->isInlineAsm()) {\n        return buildGeneralInstruction(instruction);\n    }\n\n    if (callInst->getCalledFunction()) {\n        return insertFunction(callInst->getCalledFunction(), callInst);\n    }\n    return insertFunctionPointerCall(callInst);\n}\n\nGraphBuilder::NodeSequence\nGraphBuilder::buildReturnInstruction(const Instruction *instruction) {\n    auto *currentNode = addNode(createNode<NodeType::RETURN>(instruction));\n    return {currentNode, currentNode};\n}\n\nGraphBuilder::NodeSequence\nGraphBuilder::createOrGetFunction(const Function *function) {\n    auto *functionGraph = findFunction(function);\n    if (functionGraph) {\n        return {functionGraph->entryNode(), functionGraph->exitNode()};\n    }\n    return buildFunction(function);\n}\n\nint predecessorsNumber(const BasicBlock *basicBlock) {\n    auto number = std::distance(pred_begin(basicBlock), pred_end(basicBlock));\n    return static_cast<int>(number);\n}\n\nint successorsNumber(const BasicBlock *basicBlock) {\n    auto number = std::distance(succ_begin(basicBlock), succ_end(basicBlock));\n    return static_cast<int>(number);\n}\n\nbool isReachable(const BasicBlock *basicBlock) {\n    return predecessorsNumber(basicBlock) > 0 ||\n           &basicBlock->getParent()->front() == basicBlock;\n}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Graphs/GraphBuilder.h",
    "content": "#ifndef GRAPHBUILDER_H\n#define GRAPHBUILDER_H\n\n#include <ostream>\n#include <set>\n#include <unordered_map>\n#include <unordered_set>\n#include <utility>\n\nnamespace dg {\nclass DGLLVMPointerAnalysis;\nnamespace analysis {\nnamespace pta {\nclass PSNodeJoin;\n}\n} // namespace analysis\n} // namespace dg\n\nnamespace llvm {\nclass Instruction;\nclass BasicBlock;\nclass Function;\nclass CallInst;\n} // namespace llvm\n\nclass Node;\nclass ForkNode;\nclass JoinNode;\nclass LockNode;\nclass UnlockNode;\nclass BlockGraph;\nclass FunctionGraph;\n\nclass GraphBuilder {\n  private:\n    dg::DGLLVMPointerAnalysis *pointsToAnalysis_ = nullptr;\n\n    std::unordered_set<Node *> artificialNodes_;\n    std::unordered_map<const llvm::Instruction *, Node *> llvmToNodeMap_;\n\n    std::unordered_map<const llvm::BasicBlock *, BlockGraph *> llvmToBlockMap_;\n    std::unordered_map<const llvm::Function *, FunctionGraph *>\n            llvmToFunctionMap_;\n\n    std::unordered_map<const llvm::CallInst *, JoinNode *> llvmToJoins_;\n    std::unordered_map<const llvm::CallInst *, ForkNode *> llvmToForks_;\n\n    std::unordered_map<const llvm::CallInst *, LockNode *> llvmToLocks_;\n    std::unordered_map<const llvm::CallInst *, UnlockNode *> llvmToUnlocks_;\n\n  public:\n    using NodeSequence = std::pair<Node *, Node *>;\n\n    GraphBuilder(dg::DGLLVMPointerAnalysis *pointsToAnalysis);\n\n    ~GraphBuilder();\n\n    auto size() const\n            -> decltype(llvmToNodeMap_.size() + artificialNodes_.size()) {\n        return llvmToNodeMap_.size() + artificialNodes_.size();\n    }\n\n    NodeSequence buildInstruction(const llvm::Instruction *instruction);\n\n    NodeSequence buildBlock(const llvm::BasicBlock *basicBlock);\n\n    NodeSequence buildFunction(const llvm::Function *function);\n\n    Node *findInstruction(const llvm::Instruction *instruction);\n\n    BlockGraph *findBlock(const llvm::BasicBlock *basicBlock);\n\n    FunctionGraph *findFunction(const llvm::Function *function);\n\n    std::set<const llvm::CallInst *> getJoins() const;\n    std::set<const llvm::CallInst *>\n    getCorrespondingForks(const llvm::CallInst *callInst) const;\n\n    std::set<LockNode *> getLocks() const;\n\n    bool matchForksAndJoins();\n\n    bool matchLocksAndUnlocks();\n\n    void print(std::ostream &ostream) const;\n\n    void printNodes(std::ostream &ostream) const;\n\n    void printEdges(std::ostream &ostream) const;\n\n    void clear();\n\n  private:\n    NodeSequence buildCallInstruction(const llvm::Instruction *instruction);\n\n    NodeSequence buildReturnInstruction(const llvm::Instruction *instruction);\n\n    NodeSequence buildGeneralInstruction(const llvm::Instruction *instruction);\n\n    NodeSequence\n    buildGeneralCallInstruction(const llvm::CallInst *callInstruction);\n\n    NodeSequence insertFunction(const llvm::Function *function,\n                                const llvm::CallInst *callInstruction);\n\n    NodeSequence\n    insertFunctionPointerCall(const llvm::CallInst *callInstruction);\n\n    NodeSequence insertUndefinedFunction(const llvm::Function *function,\n                                         const llvm::CallInst *callInstruction);\n\n    NodeSequence insertPthreadCreate(const llvm::CallInst *callInstruction);\n\n    NodeSequence insertPthreadMutexLock(const llvm::CallInst *callInstruction);\n\n    NodeSequence\n    insertPthreadMutexUnlock(const llvm::CallInst *callInstruction);\n\n    NodeSequence insertPthreadJoin(const llvm::CallInst *callInstruction);\n\n    NodeSequence insertPthreadExit(const llvm::CallInst *callInstruction);\n\n    NodeSequence createOrGetFunction(const llvm::Function *function);\n\n    template <typename T>\n    T *addNode(T *node) {\n        if (node->isArtificial()) {\n            if (this->artificialNodes_.insert(node).second) {\n                return node;\n            }\n        } else {\n            if (this->llvmToNodeMap_.emplace(node->llvmInstruction(), node)\n                        .second) {\n                return node;\n            }\n        }\n        return nullptr;\n    }\n};\n\nint predecessorsNumber(const llvm::BasicBlock *basicBlock);\n\nint successorsNumber(const llvm::BasicBlock *basicBlock);\n\nbool isReachable(const llvm::BasicBlock *basicBlock);\n\ntemplate <typename T>\nconst llvm::CallInst *getCallInst(T *PSNode) {\n    return PSNode->callInst()->template getUserData<llvm::CallInst>();\n}\n\n#endif // GRAPHBUILDER_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Graphs/ThreadRegionsBuilder.cpp",
    "content": "#include \"ThreadRegionsBuilder.h\"\n\n#include \"dg/llvm/ThreadRegions/ThreadRegion.h\"\n#include \"llvm/ThreadRegions/Nodes/Nodes.h\"\n\nThreadRegionsBuilder::ThreadRegionsBuilder(std::size_t size)\n        : visitedNodeToRegionMap(size), examinedNodeToRegionMap(size) {}\n\nThreadRegionsBuilder::~ThreadRegionsBuilder() { clear(); }\n\nvoid ThreadRegionsBuilder::build(Node *node) {\n    auto *threadRegion = new ThreadRegion(node);\n    threadRegions_.insert(threadRegion);\n    this->visitedNodeToRegionMap.emplace(node, threadRegion);\n\n    visit(node);\n    //    visitRightNode(node);\n    populateThreadRegions();\n    clearComputingData();\n}\n\nvoid ThreadRegionsBuilder::populateThreadRegions() {\n    for (auto nodeAngRegion : examinedNodeToRegionMap) {\n        nodeAngRegion.second->insertNode(nodeAngRegion.first);\n    }\n}\n\nbool ThreadRegionsBuilder::unvisited(Node *node) const {\n    return !regionOfVisitedNode(node) && !regionOfExaminedNode(node);\n}\n\nbool ThreadRegionsBuilder::visited(Node *node) const {\n    return regionOfVisitedNode(node);\n}\n\nbool ThreadRegionsBuilder::examined(Node *node) const {\n    return regionOfExaminedNode(node);\n}\n\nvoid ThreadRegionsBuilder::visit(Node *node) {\n    for (auto *successor : *node) {\n        if (visited(successor)) {\n            continue;\n        }\n        if (examined(region(successor))) {\n            region(node)->addSuccessor(region(successor));\n        } else {\n            ThreadRegion *successorRegion = nullptr;\n            if (shouldCreateNewRegion(node, successor)) {\n                successorRegion = new ThreadRegion(successor);\n                threadRegions_.insert(successorRegion);\n                region(node)->addSuccessor(successorRegion);\n            } else {\n                successorRegion = region(node);\n            }\n            this->visitedNodeToRegionMap.emplace(successor, successorRegion);\n            visit(successor);\n        }\n    }\n    this->examinedNodeToRegionMap.emplace(node, region(node));\n    this->visitedNodeToRegionMap.erase(node);\n}\n\nbool ThreadRegionsBuilder::examined(ThreadRegion *region) const {\n    if (!region) {\n        return false;\n    }\n    return examined(region->foundingNode());\n}\n\nThreadRegion *ThreadRegionsBuilder::region(Node *node) const {\n    auto *threadRegion = regionOfExaminedNode(node);\n    if (!threadRegion) {\n        threadRegion = regionOfVisitedNode(node);\n    }\n    return threadRegion;\n}\n\nvoid ThreadRegionsBuilder::printNodes(std::ostream &ostream) const {\n    for (auto *threadRegion : threadRegions_) {\n        threadRegion->printNodes(ostream);\n    }\n}\n\nvoid ThreadRegionsBuilder::printEdges(std::ostream &ostream) const {\n    for (auto *threadRegion : threadRegions_) {\n        threadRegion->printEdges(ostream);\n    }\n}\n\nvoid ThreadRegionsBuilder::reserve(std::size_t size) {\n    visitedNodeToRegionMap.reserve(size);\n    examinedNodeToRegionMap.reserve(size);\n}\n\nvoid ThreadRegionsBuilder::clear() {\n    for (auto iterator : visitedNodeToRegionMap) {\n        delete iterator.second;\n    }\n\n    for (auto iterator : examinedNodeToRegionMap) {\n        delete iterator.second;\n    }\n\n    clearComputingData();\n\n    for (auto *iterator : threadRegions_) {\n        delete iterator;\n    }\n\n    threadRegions_.clear();\n}\n\nstd::set<ThreadRegion *> ThreadRegionsBuilder::threadRegions() {\n    return threadRegions_;\n}\n\nvoid ThreadRegionsBuilder::clearComputingData() {\n    visitedNodeToRegionMap.clear();\n    examinedNodeToRegionMap.clear();\n}\n\nThreadRegion *ThreadRegionsBuilder::regionOfVisitedNode(Node *node) const {\n    auto iterator = visitedNodeToRegionMap.find(node);\n    if (iterator != visitedNodeToRegionMap.end()) {\n        return iterator->second;\n    }\n    return nullptr;\n}\n\nThreadRegion *ThreadRegionsBuilder::regionOfExaminedNode(Node *node) const {\n    auto iterator = examinedNodeToRegionMap.find(node);\n    if (iterator != visitedNodeToRegionMap.end()) {\n        return iterator->second;\n    }\n    return nullptr;\n}\n\nbool ThreadRegionsBuilder::shouldCreateNewRegion(Node *caller,\n                                                 Node *successor) const {\n    return caller->getType() == NodeType::EXIT ||\n           caller->getType() == NodeType::FORK ||\n           successor->getType() == NodeType::ENTRY ||\n           successor->getType() == NodeType::JOIN ||\n           successor->predecessorsNumber() > 1;\n}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Graphs/ThreadRegionsBuilder.h",
    "content": "#ifndef THREADREGIONBUILDER_H\n#define THREADREGIONBUILDER_H\n\n#include <iosfwd>\n#include <set>\n#include <unordered_map>\n\n#include \"dg/llvm/ThreadRegions/ThreadRegion.h\"\n\nclass Node;\nclass ForkNode;\nclass ExitNode;\n\nclass ThreadRegionsBuilder {\n  private:\n    std::unordered_map<Node *, ThreadRegion *> visitedNodeToRegionMap;\n    std::unordered_map<Node *, ThreadRegion *> examinedNodeToRegionMap;\n\n    std::set<ThreadRegion *> threadRegions_;\n\n  public:\n    ThreadRegionsBuilder(std::size_t size = 0);\n\n    ~ThreadRegionsBuilder();\n\n    void build(Node *node);\n\n    ThreadRegion *region(Node *node) const;\n\n    void printNodes(std::ostream &ostream) const;\n\n    void printEdges(std::ostream &ostream) const;\n\n    void reserve(std::size_t size);\n\n    void clear();\n\n    std::set<ThreadRegion *> threadRegions();\n\n  private:\n    void visit(Node *node);\n\n    bool unvisited(Node *node) const;\n\n    bool visited(Node *node) const;\n\n    bool examined(Node *node) const;\n\n    bool examined(ThreadRegion *region) const;\n\n    void populateThreadRegions();\n\n    void clearComputingData();\n\n    ThreadRegion *regionOfVisitedNode(Node *node) const;\n\n    ThreadRegion *regionOfExaminedNode(Node *node) const;\n\n    bool shouldCreateNewRegion(Node *caller, Node *successor) const;\n};\n\n#endif // THREADREGIONBUILDER_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/MayHappenInParallel.cpp",
    "content": "#include \"dg/llvm/ThreadRegions/MayHappenInParallel.h\"\n\nusing namespace std;\n\nMayHappenInParallel::MayHappenInParallel(set<ThreadRegion *> threadRegions)\n        : threadRegions_(move(threadRegions)) {}\n\nset<ThreadRegion *>\nMayHappenInParallel::parallelRegions(ThreadRegion * /*unused*/) {\n    return threadRegions_;\n}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/CallFuncPtrNode.cpp",
    "content": "#include \"CallFuncPtrNode.h\"\n\nCallFuncPtrNode::CallFuncPtrNode(const llvm::Instruction *instruction)\n        : Node(NodeType::CALL_FUNCPTR, instruction) {}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/CallFuncPtrNode.h",
    "content": "#ifndef CALLFUNCPTRNODE_H\n#define CALLFUNCPTRNODE_H\n\n#include \"Node.h\"\n\nclass CallFuncPtrNode : public Node {\n  public:\n    CallFuncPtrNode(const llvm::Instruction *instruction);\n};\n\n#endif // CALLFUNCPTRNODE_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/CallNode.cpp",
    "content": "#include \"CallNode.h\"\n\nCallNode::CallNode(const llvm::Instruction *instruction,\n                   const llvm::CallInst *callInst)\n        : Node(NodeType::CALL, instruction, callInst) {}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/CallNode.h",
    "content": "#ifndef CALLNODE_H\n#define CALLNODE_H\n\n#include \"Node.h\"\n\nclass CallNode : public Node {\n  public:\n    CallNode(const llvm::Instruction *instruction = nullptr,\n             const llvm::CallInst *callInst = nullptr);\n};\n\n#endif // CALLNODE_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/CallReturnNode.cpp",
    "content": "#include \"CallReturnNode.h\"\n\nCallReturnNode::CallReturnNode() : Node(NodeType::CALL_RETURN) {}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/CallReturnNode.h",
    "content": "#ifndef CALLRETURNNODE_H\n#define CALLRETURNNODE_H\n\n#include \"Node.h\"\n\nclass CallReturnNode : public Node {\n  public:\n    CallReturnNode();\n};\n\n#endif // CALLRETURNNODE_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/EntryNode.cpp",
    "content": "#include \"EntryNode.h\"\n#include \"ForkNode.h\"\n\nusing namespace std;\n\nEntryNode::EntryNode() : Node(NodeType::ENTRY) {}\n\nbool EntryNode::addForkPredecessor(ForkNode *forkNode) {\n    if (!forkNode) {\n        return false;\n    }\n    forkPredecessors_.insert(forkNode);\n    return forkNode->forkSuccessors_.insert(this).second;\n}\n\nbool EntryNode::removeForkPredecessor(ForkNode *forkNode) {\n    if (!forkNode) {\n        return false;\n    }\n    forkPredecessors_.erase(forkNode);\n    return forkNode->forkSuccessors_.erase(this);\n}\n\nconst set<ForkNode *> &EntryNode::forkPredecessors() const {\n    return forkPredecessors_;\n}\n\nstd::set<ForkNode *> EntryNode::forkPredecessors() { return forkPredecessors_; }\n\nsize_t EntryNode::predecessorsNumber() const {\n    return predecessors().size() + forkPredecessors_.size();\n}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/EntryNode.h",
    "content": "#ifndef ENTRYNODE_H\n#define ENTRYNODE_H\n\n#include \"Node.h\"\n\n#include <set>\n\nclass ForkNode;\n\nclass EntryNode : public Node {\n  private:\n    std::set<ForkNode *> forkPredecessors_;\n\n  public:\n    EntryNode();\n\n    bool addForkPredecessor(ForkNode *forkNode);\n\n    bool removeForkPredecessor(ForkNode *forkNode);\n\n    const std::set<ForkNode *> &forkPredecessors() const;\n    std::set<ForkNode *> forkPredecessors();\n\n    std::size_t predecessorsNumber() const override;\n\n    friend class ForkNode;\n};\n\n#endif // ENTRYNODE_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/ExitNode.cpp",
    "content": "#include \"ExitNode.h\"\n#include \"JoinNode.h\"\n\n#include <iostream>\n#include <string>\n\nExitNode::ExitNode() : Node(NodeType::EXIT) {}\n\nbool ExitNode::addJoinSuccessor(JoinNode *joinNode) {\n    if (!joinNode) {\n        return false;\n    }\n    joinSuccessors_.insert(joinNode);\n    return joinNode->joinPredecessors_.insert(this).second;\n}\n\nbool ExitNode::removeJoinSuccessor(JoinNode *joinNode) {\n    if (!joinNode) {\n        return false;\n    }\n    joinSuccessors_.erase(joinNode);\n    return joinNode->joinPredecessors_.erase(this);\n}\n\nconst std::set<JoinNode *> &ExitNode::joinSuccessors() const {\n    return joinSuccessors_;\n}\n\nstd::set<JoinNode *> ExitNode::joinSuccessors() { return joinSuccessors_; }\n\nstd::size_t ExitNode::successorsNumber() const {\n    return successors().size() + joinSuccessors_.size();\n}\n\nvoid ExitNode::printOutcomingEdges(std::ostream &ostream) const {\n    Node::printOutcomingEdges(ostream);\n    for (const auto &joinSuccessor : joinSuccessors_) {\n        ostream << this->dotName() << \" -> \" << joinSuccessor->dotName()\n                << \" [style=dashed]\\n\";\n    }\n}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/ExitNode.h",
    "content": "#ifndef EXITNODE_H\n#define EXITNODE_H\n\n#include \"Node.h\"\n\n#include <set>\n\nclass JoinNode;\n\nclass ExitNode : public Node {\n  private:\n    std::set<JoinNode *> joinSuccessors_;\n\n  public:\n    ExitNode();\n\n    bool addJoinSuccessor(JoinNode *joinNode);\n\n    bool removeJoinSuccessor(JoinNode *joinNode);\n\n    const std::set<JoinNode *> &joinSuccessors() const;\n    std::set<JoinNode *> joinSuccessors();\n\n    std::size_t successorsNumber() const override;\n\n    void printOutcomingEdges(std::ostream &ostream) const override;\n\n    friend class JoinNode;\n};\n\n#endif // EXITNODE_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/ForkNode.cpp",
    "content": "#include \"ForkNode.h\"\n#include \"EntryNode.h\"\n#include \"JoinNode.h\"\n\n#include \"dg/llvm/ThreadRegions/ControlFlowGraph.h\"\n\n#include <iostream>\n\nusing namespace std;\n\nForkNode::ForkNode(const llvm::Instruction *instruction,\n                   const llvm::CallInst *callInst)\n        : Node(NodeType::FORK, instruction, callInst) {}\n\nbool ForkNode::addCorrespondingJoin(JoinNode *joinNode) {\n    if (!joinNode) {\n        return false;\n    }\n    correspondingJoins_.insert(joinNode);\n    return joinNode->correspondingForks_.insert(this).second;\n}\n\nbool ForkNode::addForkSuccessor(EntryNode *entryNode) {\n    if (!entryNode) {\n        return false;\n    }\n    forkSuccessors_.insert(entryNode);\n    return entryNode->forkPredecessors_.insert(this).second;\n}\n\nbool ForkNode::removeForkSuccessor(EntryNode *entryNode) {\n    if (!entryNode) {\n        return false;\n    }\n    forkSuccessors_.erase(entryNode);\n    return entryNode->forkPredecessors_.erase(this);\n}\n\nconst std::set<EntryNode *> &ForkNode::forkSuccessors() const {\n    return forkSuccessors_;\n}\n\nstd::set<EntryNode *> ForkNode::forkSuccessors() { return forkSuccessors_; }\n\nsize_t ForkNode::successorsNumber() const {\n    return successors().size() + forkSuccessors_.size();\n}\n\nconst std::set<JoinNode *> &ForkNode::correspondingJoins() const {\n    return correspondingJoins_;\n}\n\nstd::set<JoinNode *> ForkNode::correspondingJoins() {\n    return correspondingJoins_;\n}\n\nvoid ForkNode::printOutcomingEdges(ostream &ostream) const {\n    Node::printOutcomingEdges(ostream);\n    for (const auto &forkSuccessor : forkSuccessors_) {\n        ostream << this->dotName() << \" -> \" << forkSuccessor->dotName()\n                << \" [style=dashed]\\n\";\n    }\n}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/ForkNode.h",
    "content": "#ifndef FORKNODE_H\n#define FORKNODE_H\n\n#include \"Node.h\"\n\nclass EntryNode;\nclass JoinNode;\n\nclass ForkNode : public Node {\n    std::set<EntryNode *> forkSuccessors_;\n    std::set<JoinNode *> correspondingJoins_;\n\n  public:\n    ForkNode(const llvm::Instruction *instruction = nullptr,\n             const llvm::CallInst *callInst = nullptr);\n\n    bool addCorrespondingJoin(JoinNode *joinNode);\n\n    bool addForkSuccessor(EntryNode *entryNode);\n\n    bool removeForkSuccessor(EntryNode *entryNode);\n\n    const std::set<EntryNode *> &forkSuccessors() const;\n    std::set<EntryNode *> forkSuccessors();\n\n    std::size_t successorsNumber() const override;\n\n    const std::set<JoinNode *> &correspondingJoins() const;\n    std::set<JoinNode *> correspondingJoins();\n\n    void printOutcomingEdges(std::ostream &ostream) const override;\n\n    friend class EntryNode;\n    friend class JoinNode;\n};\n\n#endif // FORKNODE_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/GeneralNode.cpp",
    "content": "#include \"GeneralNode.h\"\n\nGeneralNode::GeneralNode(const llvm::Instruction *instruction)\n        : Node(NodeType::GENERAL, instruction) {}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/GeneralNode.h",
    "content": "#ifndef GENERALNODE_H\n#define GENERALNODE_H\n\n#include \"Node.h\"\n\nclass GeneralNode : public Node {\n  public:\n    GeneralNode(const llvm::Instruction *instruction = nullptr);\n};\n\n#endif // GENERALNODE_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/JoinNode.cpp",
    "content": "#include \"JoinNode.h\"\n#include \"ExitNode.h\"\n#include \"ForkNode.h\"\n\n#include <llvm/IR/Instructions.h>\n\nJoinNode::JoinNode(const llvm::Instruction *value,\n                   const llvm::CallInst *callInst)\n        : Node(NodeType::JOIN, value, callInst) {}\n\nbool JoinNode::addCorrespondingFork(ForkNode *forkNode) {\n    if (!forkNode) {\n        return false;\n    }\n    correspondingForks_.insert(forkNode);\n    return forkNode->correspondingJoins_.insert(this).second;\n}\n\nbool JoinNode::addJoinPredecessor(ExitNode *exitNode) {\n    if (!exitNode) {\n        return false;\n    }\n    joinPredecessors_.insert(exitNode);\n    return exitNode->joinSuccessors_.insert(this).second;\n}\n\nbool JoinNode::removeJoinPredecessor(ExitNode *exitNode) {\n    if (!exitNode) {\n        return false;\n    }\n    joinPredecessors_.erase(exitNode);\n    return exitNode->joinSuccessors_.erase(this);\n}\n\nconst std::set<const ExitNode *> &JoinNode::joinPredecessors() const {\n    return joinPredecessors_;\n}\n\nstd::set<const ExitNode *> JoinNode::joinPredecessors() {\n    return joinPredecessors_;\n}\n\nstd::size_t JoinNode::predecessorsNumber() const {\n    return predecessors().size() + joinPredecessors_.size();\n}\n\nconst std::set<ForkNode *> &JoinNode::correspondingForks() const {\n    return correspondingForks_;\n}\n\nstd::set<ForkNode *> JoinNode::correspondingForks() {\n    return correspondingForks_;\n}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/JoinNode.h",
    "content": "#ifndef JOINNODE_H\n#define JOINNODE_H\n\n#include \"Node.h\"\n\n#include <set>\n\nclass ExitNode;\nclass ForkNode;\n\nclass JoinNode : public Node {\n  private:\n    std::set<const ExitNode *> joinPredecessors_;\n    std::set<ForkNode *> correspondingForks_;\n\n  public:\n    JoinNode(const llvm::Instruction *value = nullptr,\n             const llvm::CallInst *callInst = nullptr);\n\n    bool addCorrespondingFork(ForkNode *forkNode);\n\n    bool addJoinPredecessor(ExitNode *exitNode);\n\n    bool removeJoinPredecessor(ExitNode *exitNode);\n\n    const std::set<const ExitNode *> &joinPredecessors() const;\n    std::set<const ExitNode *> joinPredecessors();\n\n    std::size_t predecessorsNumber() const override;\n\n    const std::set<ForkNode *> &correspondingForks() const;\n    std::set<ForkNode *> correspondingForks();\n\n    friend class ExitNode;\n    friend class ForkNode;\n};\n\n#endif // JOINNODE_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/LockNode.cpp",
    "content": "#include \"LockNode.h\"\n\nLockNode::LockNode(const llvm::Instruction *instruction,\n                   const llvm::CallInst *callInst)\n        : Node(NodeType::LOCK, instruction, callInst) {}\n\nbool LockNode::addCorrespondingUnlock(UnlockNode *unlockNode) {\n    if (!unlockNode) {\n        return false;\n    }\n    return correspondingUnlocks_.insert(unlockNode).second;\n}\n\nconst std::set<UnlockNode *> &LockNode::correspondingUnlocks() const {\n    return correspondingUnlocks_;\n}\n\nstd::set<UnlockNode *> LockNode::correspondingUnlocks() {\n    return correspondingUnlocks_;\n}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/LockNode.h",
    "content": "#ifndef LOCKNODE_H\n#define LOCKNODE_H\n\n#include \"Node.h\"\n\nclass UnlockNode;\n\nclass LockNode : public Node {\n    std::set<UnlockNode *> correspondingUnlocks_;\n\n  public:\n    LockNode(const llvm::Instruction *instruction = nullptr,\n             const llvm::CallInst *callInst = nullptr);\n\n    bool addCorrespondingUnlock(UnlockNode *unlockNode);\n\n    const std::set<UnlockNode *> &correspondingUnlocks() const;\n    std::set<UnlockNode *> correspondingUnlocks();\n};\n\n#endif // LOCKNODE_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/Node.cpp",
    "content": "#include <llvm/IR/Instructions.h>\n#include <llvm/Support/raw_ostream.h>\n\n#include <iostream>\n#include <sstream>\n\n#include \"Node.h\"\n\nusing namespace std;\nusing namespace llvm;\n\nint Node::lastId = 0;\n\nNode::Node(NodeType type, const Instruction *instruction,\n           const CallInst *callInst)\n        : id_(lastId++), nodeType_(type), llvmInstruction_(instruction),\n          callInstruction_(callInst) {}\n\nNodeIterator Node::begin() const { return NodeIterator(this, true); }\n\nNodeIterator Node::end() const { return NodeIterator(this, false); }\n\nint Node::id() const { return id_; }\n\nNodeType Node::getType() const { return nodeType_; }\n\nstring Node::dotName() const { return \"NODE\" + to_string(id_); }\n\nbool Node::addPredecessor(Node *node) {\n    if (!node) {\n        return false;\n    }\n    predecessors_.insert(node);\n    return node->successors_.insert(this).second;\n}\n\nbool Node::addSuccessor(Node *node) {\n    if (!node) {\n        return false;\n    }\n    successors_.insert(node);\n    return node->predecessors_.insert(this).second;\n}\n\nbool Node::removePredecessor(Node *node) {\n    if (!node) {\n        return false;\n    }\n    predecessors_.erase(node);\n    return node->successors_.erase(this);\n}\n\nbool Node::removeSuccessor(Node *node) {\n    if (!node) {\n        return false;\n    }\n    successors_.erase(node);\n    return node->predecessors_.erase(this);\n}\n\nconst set<Node *> &Node::predecessors() const { return predecessors_; }\n\nconst set<Node *> &Node::successors() const { return successors_; }\n\nsize_t Node::predecessorsNumber() const { return predecessors_.size(); }\n\nsize_t Node::successorsNumber() const { return predecessors_.size(); }\n\nbool Node::isArtificial() const { return llvmInstruction_ == nullptr; }\n\nconst Instruction *Node::llvmInstruction() const { return llvmInstruction_; }\n\nconst CallInst *Node::callInstruction() const {\n    if (callInstruction_) {\n        return callInstruction_;\n    }\n    if (llvmInstruction_) {\n        return llvm::dyn_cast<llvm::CallInst>(llvmInstruction_);\n    }\n    return nullptr;\n}\n\nstring Node::dump() const {\n    return this->dotName() + \" \" + this->label() + \"\\n\";\n}\n\nstring Node::label() const {\n    std::string label_ = \"[label=\\\"<\" + std::to_string(this->id()) + \"> \" +\n                         nodeTypeToString(this->getType());\n    if (!isArtificial()) {\n        string llvmTemporaryString;\n        raw_string_ostream llvmStream(llvmTemporaryString);\n        llvmInstruction_->print(llvmStream);\n        label_ += \"\\n\" + llvmTemporaryString;\n    }\n    label_ += \" \\\"]\";\n    return label_;\n}\n\nvoid Node::printOutcomingEdges(ostream &ostream) const {\n    for (const auto &successor : successors_) {\n        ostream << this->dotName() << \" -> \" << successor->dotName() << \"\\n\";\n    }\n}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/Node.h",
    "content": "#ifndef NODE_H\n#define NODE_H\n\n#include <iosfwd>\n#include <set>\n#include <string>\n\n#include \"NodeIterator.h\"\n\nnamespace llvm {\nclass CallInst;\nclass Instruction;\n} // namespace llvm\n\nenum class NodeType {\n    GENERAL,\n    FORK,\n    JOIN,\n    LOCK,\n    UNLOCK,\n    ENTRY,\n    EXIT,\n    CALL,\n    CALL_FUNCPTR,\n    CALL_RETURN,\n    RETURN\n};\n\ninline std::string nodeTypeToString(enum NodeType type) {\n#define ELEM(t)                                                                \\\n    case t:                                                                    \\\n        do {                                                                   \\\n            return (#t);                                                       \\\n        } while (0);                                                           \\\n        break;\n    switch (type) {\n        ELEM(NodeType::GENERAL)\n        ELEM(NodeType::FORK)\n        ELEM(NodeType::JOIN)\n        ELEM(NodeType::LOCK)\n        ELEM(NodeType::UNLOCK)\n        ELEM(NodeType::ENTRY)\n        ELEM(NodeType::EXIT)\n        ELEM(NodeType::CALL)\n        ELEM(NodeType::CALL_RETURN)\n        ELEM(NodeType::CALL_FUNCPTR)\n        ELEM(NodeType::RETURN)\n    };\n#undef ELEM\n    return \"undefined\";\n}\n\nclass Node {\n  private:\n    const int id_;\n    const NodeType nodeType_;\n    const llvm::Instruction *llvmInstruction_;\n    const llvm::CallInst *callInstruction_;\n    std::set<Node *> predecessors_;\n    std::set<Node *> successors_;\n\n    static int lastId;\n\n  public:\n    Node(NodeType type, const llvm::Instruction *instruction = nullptr,\n         const llvm::CallInst *callInst = nullptr);\n\n    virtual ~Node() = default;\n\n    NodeIterator begin() const;\n\n    NodeIterator end() const;\n\n    int id() const;\n\n    NodeType getType() const;\n\n    std::string dotName() const;\n\n    bool addPredecessor(Node * /*node*/);\n    bool addSuccessor(Node * /*node*/);\n\n    bool removePredecessor(Node * /*node*/);\n    bool removeSuccessor(Node * /*node*/);\n\n    const std::set<Node *> &predecessors() const;\n    const std::set<Node *> &successors() const;\n\n    virtual std::size_t predecessorsNumber() const;\n    virtual std::size_t successorsNumber() const;\n\n    bool isArtificial() const;\n\n    const llvm::Instruction *llvmInstruction() const;\n\n    const llvm::CallInst *callInstruction() const;\n\n    std::string dump() const;\n\n    std::string label() const;\n\n    virtual void printOutcomingEdges(std::ostream &ostream) const;\n};\n\n#endif // NODE_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/NodeIterator.cpp",
    "content": "#include \"NodeIterator.h\"\n\n#include \"Nodes.h\"\n\nNodeIterator::NodeIterator(const Node *node, bool begin) {\n    if (!node) {\n        return;\n    }\n    if (begin) {\n        if ((forkNode = castNode<NodeType::FORK>(node))) {\n            forkSuccessorsIterator = forkNode->forkSuccessors().begin();\n        } else if ((exitNode = castNode<NodeType::EXIT>(node))) {\n            joinSuccessorsIterator = exitNode->joinSuccessors().begin();\n        }\n        successorsIterator = node->successors().begin();\n    } else {\n        if ((forkNode = castNode<NodeType::FORK>(node))) {\n            forkSuccessorsIterator = forkNode->forkSuccessors().end();\n        } else if ((exitNode = castNode<NodeType::EXIT>(node))) {\n            joinSuccessorsIterator = exitNode->joinSuccessors().end();\n        }\n        successorsIterator = node->successors().end();\n    }\n}\n\nNodeIterator &NodeIterator::operator++() {\n    if (forkNode) {\n        if (forkSuccessorsIterator != forkNode->forkSuccessors().end()) {\n            ++forkSuccessorsIterator;\n            return *this;\n        }\n    } else if (exitNode) {\n        if (joinSuccessorsIterator != exitNode->joinSuccessors().end()) {\n            ++joinSuccessorsIterator;\n            return *this;\n        }\n    }\n    ++successorsIterator;\n    return *this;\n}\n\nNodeIterator NodeIterator::operator++(int) {\n    NodeIterator retval = *this;\n    ++(*this);\n    return retval;\n}\n\nbool NodeIterator::operator==(const NodeIterator &other) const {\n    if (successorsIterator != other.successorsIterator) {\n        return false;\n    }\n\n    if (forkNode) {\n        return forkSuccessorsIterator == other.forkSuccessorsIterator;\n    }\n    if (exitNode) {\n        return joinSuccessorsIterator == other.joinSuccessorsIterator;\n    }\n    return true;\n}\n\nbool NodeIterator::operator!=(const NodeIterator &other) const {\n    return !(*this == other);\n}\n\nNode *NodeIterator::operator*() const {\n    if (forkNode) {\n        if (forkSuccessorsIterator != forkNode->forkSuccessors().end()) {\n            return *forkSuccessorsIterator;\n        }\n    } else if (exitNode) {\n        if (joinSuccessorsIterator != exitNode->joinSuccessors().end()) {\n            return *joinSuccessorsIterator;\n        }\n    }\n    return *successorsIterator;\n}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/NodeIterator.h",
    "content": "#ifndef NODEITERATOR_H\n#define NODEITERATOR_H\n\n#include <set>\n\nclass Node;\nclass ForkNode;\nclass JoinNode;\nclass EntryNode;\nclass ExitNode;\n\nclass NodeIterator {\n  private:\n    const ForkNode *forkNode = nullptr;\n    const ExitNode *exitNode = nullptr;\n    std::set<Node *>::iterator successorsIterator;\n    std::set<EntryNode *>::iterator forkSuccessorsIterator;\n    std::set<JoinNode *>::iterator joinSuccessorsIterator;\n\n  public:\n    explicit NodeIterator(const Node *node = nullptr, bool begin = true);\n\n    NodeIterator &operator++();\n    NodeIterator operator++(int);\n    bool operator==(const NodeIterator &other) const;\n    bool operator!=(const NodeIterator &other) const;\n    Node *operator*() const;\n};\n\n#endif // NODEITERATOR_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/Nodes.h",
    "content": "#ifndef NODES_H\n#define NODES_H\n\n#include \"CallFuncPtrNode.h\"\n#include \"CallNode.h\"\n#include \"CallReturnNode.h\"\n#include \"EntryNode.h\"\n#include \"ExitNode.h\"\n#include \"ForkNode.h\"\n#include \"GeneralNode.h\"\n#include \"JoinNode.h\"\n#include \"LockNode.h\"\n#include \"ReturnNode.h\"\n#include \"UnlockNode.h\"\n\ntemplate <NodeType>\nstruct Map;\n\ntemplate <>\nstruct Map<NodeType::GENERAL> {\n    using type = GeneralNode;\n    using const_type = const GeneralNode;\n};\n\ntemplate <>\nstruct Map<NodeType::FORK> {\n    using type = ForkNode;\n    using const_type = const ForkNode;\n};\n\ntemplate <>\nstruct Map<NodeType::JOIN> {\n    using type = JoinNode;\n    using const_type = const JoinNode;\n};\n\ntemplate <>\nstruct Map<NodeType::LOCK> {\n    using type = LockNode;\n    using const_type = const LockNode;\n};\n\ntemplate <>\nstruct Map<NodeType::UNLOCK> {\n    using type = UnlockNode;\n    using const_type = const UnlockNode;\n};\n\ntemplate <>\nstruct Map<NodeType::ENTRY> {\n    using type = EntryNode;\n    using const_type = const EntryNode;\n};\n\ntemplate <>\nstruct Map<NodeType::EXIT> {\n    using type = ExitNode;\n    using const_type = const ExitNode;\n};\n\ntemplate <>\nstruct Map<NodeType::CALL> {\n    using type = CallNode;\n    using const_type = const CallNode;\n};\n\ntemplate <>\nstruct Map<NodeType::CALL_FUNCPTR> {\n    using type = CallFuncPtrNode;\n    using const_type = const CallFuncPtrNode;\n};\n\ntemplate <>\nstruct Map<NodeType::CALL_RETURN> {\n    using type = CallReturnNode;\n    using const_type = const CallReturnNode;\n};\n\ntemplate <>\nstruct Map<NodeType::RETURN> {\n    using type = ReturnNode;\n    using const_type = const ReturnNode;\n};\n\ntemplate <NodeType nodeType, typename... Args>\ntypename Map<nodeType>::type *createNode(Args... args) {\n    return new typename Map<nodeType>::type(args...);\n}\n\ntemplate <NodeType nodeType, typename T>\ntypename Map<nodeType>::type *castNode(T *node) {\n    if (!node) {\n        return nullptr;\n    }\n    if (node->getType() == nodeType) {\n        return static_cast<typename Map<nodeType>::type *>(node);\n    }\n    return nullptr;\n}\n\ntemplate <NodeType nodeType, typename T>\ntypename Map<nodeType>::const_type *castNode(const T *node) {\n    if (!node) {\n        return nullptr;\n    }\n    if (node->getType() == nodeType) {\n        return static_cast<typename Map<nodeType>::const_type *>(node);\n    }\n    return nullptr;\n}\n\n#endif // NODES_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/ReturnNode.cpp",
    "content": "#include \"ReturnNode.h\"\n\nReturnNode::ReturnNode(const llvm::Instruction *instruction)\n        : Node(NodeType::RETURN, instruction) {}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/ReturnNode.h",
    "content": "#ifndef RETURNNODE_H\n#define RETURNNODE_H\n\n#include \"Node.h\"\n\nclass ReturnNode : public Node {\n  public:\n    ReturnNode(const llvm::Instruction *instruction = nullptr);\n};\n\n#endif // RETURNNODE_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/UnlockNode.cpp",
    "content": "#include \"UnlockNode.h\"\n\nUnlockNode::UnlockNode(const llvm::Instruction *instruction,\n                       const llvm::CallInst *callInst)\n        : Node(NodeType::UNLOCK, instruction, callInst) {}\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/Nodes/UnlockNode.h",
    "content": "#ifndef UNLOCKNODE_H\n#define UNLOCKNODE_H\n\n#include \"Node.h\"\n\nclass UnlockNode : public Node {\n  public:\n    UnlockNode(const llvm::Instruction *instruction = nullptr,\n               const llvm::CallInst *callInst = nullptr);\n};\n\n#endif // UNLOCKNODE_H\n"
  },
  {
    "path": "lib/llvm/ThreadRegions/ThreadRegion.cpp",
    "content": "#include \"dg/llvm/ThreadRegions/ThreadRegion.h\"\n\n#include \"llvm/ThreadRegions/Nodes/Node.h\"\n\n#include <iostream>\n\nint ThreadRegion::lastId = 0;\n\nThreadRegion::ThreadRegion(Node *node) : id_(lastId++), foundingNode_(node) {}\n\nint ThreadRegion::id() const { return id_; }\n\nbool ThreadRegion::addPredecessor(ThreadRegion *predecessor) {\n    predecessors_.insert(predecessor);\n    return predecessor->successors_.insert(this).second;\n}\n\nbool ThreadRegion::addSuccessor(ThreadRegion *threadRegion) {\n    successors_.insert(threadRegion);\n    return threadRegion->predecessors_.insert(this).second;\n}\n\nbool ThreadRegion::removePredecessor(ThreadRegion *predecessor) {\n    if (!predecessor) {\n        return false;\n    }\n    predecessors_.erase(predecessor);\n    return predecessor->successors_.erase(this);\n}\n\nbool ThreadRegion::removeSuccessor(ThreadRegion *successor) {\n    if (!successor) {\n        return false;\n    }\n    successors_.erase(successor);\n    return successor->predecessors_.erase(this);\n}\n\nconst std::set<ThreadRegion *> &ThreadRegion::predecessors() const {\n    return predecessors_;\n}\n\nstd::set<ThreadRegion *> ThreadRegion::predecessors() { return predecessors_; }\n\nconst std::set<ThreadRegion *> &ThreadRegion::successors() const {\n    return successors_;\n}\n\nstd::set<ThreadRegion *> ThreadRegion::successors() { return successors_; }\n\nbool ThreadRegion::insertNode(Node *node) {\n    nodes_.insert(node);\n    return false;\n}\n\nbool ThreadRegion::removeNode(Node *node) {\n    nodes_.erase(node);\n    return false;\n}\n\nNode *ThreadRegion::foundingNode() const { return foundingNode_; }\n\nconst std::set<Node *> &ThreadRegion::nodes() const { return nodes_; }\n\nstd::set<Node *> ThreadRegion::nodes() { return nodes_; }\n\nvoid ThreadRegion::printNodes(std::ostream &ostream) {\n    ostream << \"subgraph \" << dotName() << \" {\\n\";\n    ostream << \"color = blue\\n style = rounded\\n\";\n    for (const auto &node : nodes_) {\n        ostream << node->dump();\n    }\n    ostream << \"}\\n\";\n}\n\nvoid ThreadRegion::printEdges(std::ostream &ostream) {\n    for (const auto &successor : successors_) {\n        ostream << (*this->nodes_.begin())->dotName() << \" -> \"\n                << (*successor->nodes_.begin())->dotName()\n                << \" [ltail = \" << this->dotName()\n                << \" lhead = \" << successor->dotName()\n                << \", color = blue, style = bold]\\n\";\n    }\n}\n\nstd::string ThreadRegion::dotName() { return \"cluster\" + std::to_string(id_); }\n\nstd::set<const llvm::Instruction *> ThreadRegion::llvmInstructions() const {\n    std::set<const llvm::Instruction *> llvmValues;\n    for (const auto &node : nodes_) {\n        if (!node->isArtificial()) {\n            llvmValues.insert(node->llvmInstruction());\n        }\n    }\n    return llvmValues;\n}\n"
  },
  {
    "path": "lib/llvm/ValueRelations/GraphBuilder.cpp",
    "content": "#include \"dg/llvm/ValueRelations/GraphBuilder.h\"\n\n#include <llvm/IR/CFG.h>\n\n#ifndef NDEBUG\n#include \"dg/llvm/ValueRelations/getValName.h\"\n#endif\n\nnamespace dg {\nnamespace vr {\n\nvoid GraphBuilder::build() {\n    for (const llvm::Function &function : module) {\n        if (function.isDeclaration())\n            continue;\n\n        buildBlocks(function);\n        buildTerminators(function);\n    }\n}\n\nvoid GraphBuilder::buildBlocks(const llvm::Function &function) {\n    for (const llvm::BasicBlock &block : function) {\n        assert(!block.empty());\n        buildBlock(block);\n    }\n\n    codeGraph.setEntryLocation(\n            &function,\n            codeGraph.getVRLocation(&function.getEntryBlock().front()));\n}\n\nvoid GraphBuilder::buildTerminators(const llvm::Function &function) {\n    for (const llvm::BasicBlock &block : function) {\n        assert(backs.find(&block) != backs.end());\n        VRLocation &last = *backs[&block];\n\n        const llvm::Instruction *terminator = block.getTerminator();\n        if (const auto *branch = llvm::dyn_cast<llvm::BranchInst>(terminator)) {\n            buildBranch(branch, last);\n\n        } else if (const auto *swtch =\n                           llvm::dyn_cast<llvm::SwitchInst>(terminator)) {\n            buildSwitch(swtch, last);\n\n        } else if (const auto *rturn =\n                           llvm::dyn_cast<llvm::ReturnInst>(terminator)) {\n            buildReturn(rturn, last);\n\n        } else if (llvm::succ_begin(&block) != llvm::succ_end(&block)) {\n#ifndef NDEBUG\n            std::cerr << \"Unhandled  terminator: \"\n                      << dg::debug::getValName(terminator) << \"\\n\";\n            llvm::errs() << \"Unhandled terminator: \" << *terminator << \"\\n\";\n#endif\n            abort();\n        }\n    }\n}\n\nvoid GraphBuilder::buildBranch(const llvm::BranchInst *inst, VRLocation &last) {\n    if (inst->isUnconditional()) {\n        assert(fronts.find(inst->getSuccessor(0)) != fronts.end());\n        VRLocation &first = *fronts[inst->getSuccessor(0)];\n\n        last.connect(first, new VRNoop());\n    } else {\n        VRLocation &truePadding = codeGraph.newVRLocation();\n        VRLocation &falsePadding = codeGraph.newVRLocation();\n\n        auto *condition = inst->getCondition();\n        last.connect(truePadding, new VRAssumeBool(condition, true));\n        last.connect(falsePadding, new VRAssumeBool(condition, false));\n\n        assert(fronts.find(inst->getSuccessor(0)) != fronts.end());\n        assert(fronts.find(inst->getSuccessor(1)) != fronts.end());\n\n        VRLocation &firstTrue = *fronts[inst->getSuccessor(0)];\n        VRLocation &firstFalse = *fronts[inst->getSuccessor(1)];\n\n        truePadding.connect(firstTrue, new VRNoop());\n        falsePadding.connect(firstFalse, new VRNoop());\n    }\n}\n\nvoid GraphBuilder::buildSwitch(const llvm::SwitchInst *swtch,\n                               VRLocation &last) {\n    for (auto &it : swtch->cases()) {\n        VRLocation &padding = codeGraph.newVRLocation();\n\n        last.connect(padding, new VRAssumeEqual(swtch->getCondition(),\n                                                it.getCaseValue()));\n\n        assert(fronts.find(it.getCaseSuccessor()) != fronts.end());\n        VRLocation &first = *fronts[it.getCaseSuccessor()];\n\n        padding.connect(first, new VRNoop());\n    }\n\n    assert(fronts.find(swtch->getDefaultDest()) != fronts.end());\n    VRLocation &first = *fronts[swtch->getDefaultDest()];\n    last.connect(first, new VRNoop());\n}\n\nvoid GraphBuilder::buildReturn(const llvm::ReturnInst *inst, VRLocation &last) {\n    last.connect(nullptr, new VRInstruction(inst));\n}\n\nvoid GraphBuilder::buildBlock(const llvm::BasicBlock &block) {\n    auto it = block.begin();\n    const llvm::Instruction *previousInst = &(*it);\n    VRLocation *previousLoc = &codeGraph.newVRLocation(previousInst);\n    ++it;\n\n    fronts.emplace(&block, previousLoc);\n\n    for (; it != block.end(); ++it) {\n        const llvm::Instruction &inst = *it;\n        VRLocation &newLoc = codeGraph.newVRLocation(&inst);\n\n        previousLoc->connect(newLoc, new VRInstruction(previousInst));\n\n        previousInst = &inst;\n        previousLoc = &newLoc;\n    }\n\n    backs.emplace(&block, previousLoc);\n}\n\n} // namespace vr\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ValueRelations/GraphElements.cpp",
    "content": "#include \"dg/llvm/ValueRelations/GraphElements.h\"\n\n#include <cassert>\n#include <iterator>\n#include <list>\n#include <queue>\n\n#include \"dg/llvm/ValueRelations/UniquePtrVector.h\"\n#include \"dg/llvm/ValueRelations/ValueRelations.h\"\n\n#include <llvm/IR/Instructions.h>\n\n#ifndef NDEBUG\n#include \"dg/llvm/ValueRelations/getValName.h\"\n#endif\n\nnamespace dg {\nnamespace vr {\n\nvoid VRLocation::connect(std::unique_ptr<VREdge> &&edge) {\n    if (edge->target)\n        edge->target->predecessors.push_back(edge.get());\n    successors.emplace_back(std::move(edge));\n}\n\nvoid VRLocation::connect(VRLocation *target, std::unique_ptr<VROp> &&op) {\n    connect(std::unique_ptr<VREdge>(new VREdge(this, target, std::move(op))));\n}\n\nvoid VRLocation::connect(VRLocation *target, VROp *op) {\n    connect(std::unique_ptr<VREdge>(new VREdge(this, target, op)));\n}\n\nvoid VRLocation::connect(VRLocation &target, VROp *op) { connect(&target, op); }\n\nstd::vector<VRLocation *> VRLocation::getPredLocations() {\n    std::vector<VRLocation *> result;\n    for (VREdge *edge : predecessors) {\n        result.push_back(edge->source);\n    }\n    return result;\n}\n\nstd::vector<VRLocation *> VRLocation::getSuccLocations() {\n    std::vector<VRLocation *> result;\n    for (auto &edge : successors) {\n        result.push_back(edge->target);\n    }\n    return result;\n}\n\nbool VRLocation::isJoin() const { return predecessors.size() > 1; }\n\nbool VRLocation::isJustBranchJoin() const {\n    // allows TREE and FORWARD\n    if (!isJoin())\n        return false;\n    for (VREdge *pred : predecessors) {\n        if (pred->type != EdgeType::TREE && pred->type != EdgeType::FORWARD)\n            return false;\n    }\n    return true;\n}\n\nbool VRLocation::isJustLoopJoin() const {\n    // allows TREE and BACK\n    if (!isJoin())\n        return false;\n    for (VREdge *pred : predecessors) {\n        if (pred->type != EdgeType::TREE && pred->type != EdgeType::BACK)\n            return false;\n    }\n    return true;\n}\n\nVRLocation &VRLocation::getTreePredecessor() const {\n    VRLocation *treePred = nullptr;\n    for (VREdge *predEdge : predecessors) {\n        if (predEdge->type == EdgeType::TREE)\n            treePred = predEdge->source;\n    }\n    assert(treePred);\n    return *treePred;\n}\n\nVRLocation &VRCodeGraph::newVRLocation() {\n    locations.emplace_back(locations.size());\n    return locations.back();\n}\n\nVRLocation &VRCodeGraph::newVRLocation(const llvm::Instruction *inst) {\n    assert(locationMapping.find(inst) == locationMapping.end());\n\n    VRLocation &loc = newVRLocation();\n    locationMapping.emplace(inst, &loc);\n    return loc;\n}\n\nvoid VRCodeGraph::setEntryLocation(const llvm::Function *f, VRLocation &loc) {\n    functionMapping.emplace(f, &loc);\n}\n\nVRLocation &VRCodeGraph::getVRLocation(const llvm::Instruction *ptr) const {\n    return *locationMapping.at(ptr);\n}\n\nVRLocation &VRCodeGraph::getEntryLocation(const llvm::Function &f) const {\n    return *functionMapping.at(&f);\n}\n\nvoid VRCodeGraph::hasCategorizedEdges() { categorizedEdges = true; }\n\n/* ************ visits ************ */\n\nvoid VRCodeGraph::SimpleVisit::find(VRLocation *loc) { visited.emplace(loc); }\n\nbool VRCodeGraph::SimpleVisit::wasVisited(VRLocation *loc) const {\n    return visited.find(loc) != visited.end();\n}\n\nunsigned VRCodeGraph::LazyVisit::getPrevEdgesSize(VRLocation *loc) {\n    return loc->predsSize();\n}\n\nvoid VRCodeGraph::LazyVisit::find(VRLocation *loc) {\n    auto &count = visited[loc];\n    if (loc->isJustBranchJoin())\n        ++count;\n    else\n        count = getPrevEdgesSize(loc);\n}\n\nbool VRCodeGraph::LazyVisit::wasVisited(VRLocation *loc) const {\n    auto it = visited.find(loc);\n    return it != visited.end() && it->second >= getPrevEdgesSize(loc);\n}\n\n/* ************ begins and ends ************ */\n\nVRCodeGraph::LazyDFS\nVRCodeGraph::lazy_dfs_begin(const llvm::Function &f) const {\n    assert(categorizedEdges);\n    return LazyDFS(f, &getEntryLocation(f), Dir::FORWARD);\n}\n\nVRCodeGraph::LazyDFS\nVRCodeGraph::lazy_dfs_begin(const llvm::Function &f,\n                            const VRLocation &start) const {\n    assert(categorizedEdges);\n    return LazyDFS(f, &start, Dir::FORWARD);\n}\n\nVRCodeGraph::LazyDFS VRCodeGraph::lazy_dfs_end() { return LazyDFS(); }\n\nVRCodeGraph::SimpleDFS VRCodeGraph::dfs_begin(const llvm::Function &f) const {\n    return SimpleDFS(f, &getEntryLocation(f), Dir::FORWARD);\n}\n\nVRCodeGraph::SimpleDFS VRCodeGraph::dfs_begin(const llvm::Function &f,\n                                              const VRLocation &start) const {\n    return SimpleDFS(f, &start, Dir::FORWARD);\n}\n\nVRCodeGraph::SimpleDFS VRCodeGraph::dfs_end() { return SimpleDFS(); }\n\nVRCodeGraph::SimpleDFS\nVRCodeGraph::backward_dfs_begin(const llvm::Function &f,\n                                const VRLocation &start) {\n    return SimpleDFS(f, &start, Dir::BACKWARD);\n}\n\nVRCodeGraph::SimpleDFS VRCodeGraph::backward_dfs_end() { return SimpleDFS(); }\n\n/* ************ code graph iterator stuff ************ */\n\nVRCodeGraph::VRCodeGraphIterator::VRCodeGraphIterator(MappingIterator end)\n        : intoMapping(end), endMapping(end) {}\n\nVRCodeGraph::VRCodeGraphIterator::VRCodeGraphIterator(MappingIterator begin,\n                                                      MappingIterator end)\n        : intoMapping(begin), endMapping(end),\n          intoFunction(*begin->first, begin->second, Dir::FORWARD) {}\n\nbool operator==(const VRCodeGraph::VRCodeGraphIterator &lt,\n                const VRCodeGraph::VRCodeGraphIterator &rt) {\n    bool ltIsEnd = lt.intoMapping == lt.endMapping;\n    bool rtIsEnd = rt.intoMapping == rt.endMapping;\n    return (ltIsEnd && rtIsEnd) ||\n           (!ltIsEnd && !rtIsEnd && lt.intoFunction == rt.intoFunction);\n}\n\nVRCodeGraph::VRCodeGraphIterator &\nVRCodeGraph::VRCodeGraphIterator::operator++() {\n    ++intoFunction;\n    if (intoFunction == LazyDFS()) {\n        ++intoMapping;\n        if (intoMapping != endMapping)\n            intoFunction = LazyDFS(*intoMapping->first, intoMapping->second,\n                                   Dir::FORWARD);\n    }\n    return *this;\n}\n\nVRCodeGraph::VRCodeGraphIterator\nVRCodeGraph::VRCodeGraphIterator::operator++(int) {\n    auto copy = *this;\n    ++*this;\n    return copy;\n}\n\nVRCodeGraph::VRCodeGraphIterator VRCodeGraph::begin() const {\n    return functionMapping.empty()\n                   ? VRCodeGraphIterator()\n                   : VRCodeGraphIterator(functionMapping.begin(),\n                                         functionMapping.end());\n}\n\nVRCodeGraph::VRCodeGraphIterator VRCodeGraph::end() const {\n    return functionMapping.empty() ? VRCodeGraphIterator()\n                                   : VRCodeGraphIterator(functionMapping.end());\n}\n\n} // namespace vr\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ValueRelations/RelationsAnalyzer.cpp",
    "content": "#include \"dg/llvm/ValueRelations/RelationsAnalyzer.h\"\n\n#include <algorithm>\n\nnamespace dg {\nnamespace vr {\n\nusing V = ValueRelations::V;\n\n// ********************** points to invalidation ********************** //\nbool RelationsAnalyzer::isIgnorableIntrinsic(llvm::Intrinsic::ID id) {\n    switch (id) {\n    case llvm::Intrinsic::lifetime_start:\n    case llvm::Intrinsic::lifetime_end:\n    case llvm::Intrinsic::stacksave:\n    case llvm::Intrinsic::stackrestore:\n    case llvm::Intrinsic::dbg_declare:\n    case llvm::Intrinsic::dbg_value:\n        return true;\n    default:\n        return false;\n    }\n}\n\nbool RelationsAnalyzer::isSafe(I inst) const {\n    if (!inst->mayWriteToMemory() && !inst->mayHaveSideEffects())\n        return true;\n\n    if (const auto *intrinsic = llvm::dyn_cast<llvm::IntrinsicInst>(inst)) {\n        if (isIgnorableIntrinsic(intrinsic->getIntrinsicID())) {\n            return true;\n        }\n    }\n\n    if (const auto *call = llvm::dyn_cast<llvm::CallInst>(inst)) {\n        const auto *function = call->getCalledFunction();\n        if (function && safeFunctions.find(function->getName().str()) !=\n                                safeFunctions.end())\n            return true;\n    }\n    return false;\n}\n\nbool RelationsAnalyzer::isDangerous(I inst) {\n    const auto *store = llvm::dyn_cast<llvm::StoreInst>(inst);\n    if (!store) // most probably CallInst\n        // unable to presume anything about such instruction\n        return true;\n\n    // if store writes to a fix location, it cannot be easily said which\n    // values it affects\n    if (llvm::isa<llvm::Constant>(store->getPointerOperand()))\n        return true;\n\n    return false;\n}\n\nbool RelationsAnalyzer::mayHaveAlias(const ValueRelations &graph, V val) const {\n    for (const auto *eqval : graph.getEqual(val)) {\n        if (!hasKnownOrigin(graph, eqval) || mayHaveAlias(eqval))\n            return true;\n    }\n    return false;\n}\n\nbool RelationsAnalyzer::mayHaveAlias(V val) const {\n    // if value is not pointer, we don't care whether there can be other name\n    // for same value\n    if (!val->getType()->isPointerTy())\n        return false;\n\n    if (llvm::isa<llvm::GetElementPtrInst>(val))\n        return true;\n\n    for (const llvm::User *user : val->users()) {\n        // if value is stored, it can be accessed\n        if (llvm::isa<llvm::StoreInst>(user)) {\n            if (user->getOperand(0) == val)\n                return true;\n\n        } else if (llvm::isa<llvm::CastInst>(user)) {\n            if (mayHaveAlias(user))\n                return true;\n\n        } else if (llvm::isa<llvm::GetElementPtrInst>(user)) {\n            return true; // TODO possible to collect here\n\n        } else if (const auto *intrinsic =\n                           llvm::dyn_cast<llvm::IntrinsicInst>(user)) {\n            if (!isIgnorableIntrinsic(intrinsic->getIntrinsicID()) &&\n                intrinsic->mayWriteToMemory())\n                return true;\n\n        } else if (const auto *inst = llvm::dyn_cast<llvm::Instruction>(user)) {\n            if (inst->mayWriteToMemory())\n                return true;\n        }\n    }\n    return false;\n}\n\nbool RelationsAnalyzer::hasKnownOrigin(const ValueRelations &graph, V from) {\n    for (const auto *val : graph.getEqual(from)) {\n        if (hasKnownOrigin(val))\n            return true;\n    }\n    return false;\n}\n\nbool RelationsAnalyzer::hasKnownOrigin(V from) {\n    return llvm::isa<llvm::AllocaInst>(from);\n}\n\nV getGEPBase(V val) {\n    if (const auto *gep = llvm::dyn_cast<llvm::GetElementPtrInst>(val))\n        return gep->getPointerOperand();\n    return nullptr;\n}\n\nbool sameBase(const ValueRelations &graph, V val1, V val2) {\n    V val2orig = val2;\n    while (val1) {\n        val2 = val2orig;\n        while (val2) {\n            if (graph.are(val1, Relations::EQ,\n                          val2)) // TODO compare whether indices may equal\n                return true;\n            val2 = getGEPBase(val2);\n        }\n        val1 = getGEPBase(val1);\n    }\n    return false;\n}\n\nbool RelationsAnalyzer::mayOverwrite(I inst, V address) const {\n    assert(inst);\n    assert(address);\n\n    const ValueRelations &graph = codeGraph.getVRLocation(inst).relations;\n\n    if (isSafe(inst))\n        return false;\n\n    if (isDangerous(inst))\n        return true;\n\n    const auto *store = llvm::cast<llvm::StoreInst>(inst);\n    V memoryPtr = store->getPointerOperand();\n\n    return sameBase(graph, memoryPtr, address) ||\n           (!hasKnownOrigin(graph, memoryPtr) &&\n            mayHaveAlias(graph, address)) ||\n           (mayHaveAlias(graph, memoryPtr) && !hasKnownOrigin(graph, address));\n}\n\nconst llvm::Argument *getArgument(const ValueRelations &graph,\n                                  ValueRelations::Handle h) {\n    const llvm::Argument *result = nullptr;\n    for (auto handleRel : graph.getRelated(h, Relations().sle().sge())) {\n        const llvm::Argument *arg =\n                graph.getInstance<llvm::Argument>(handleRel.first);\n        if (arg) {\n            assert(!result);\n            result = arg;\n        }\n    }\n    return result;\n}\n\n// ************************ operation helpers ************************* //\nbool RelationsAnalyzer::operandsEqual(\n        ValueRelations &graph, I fst, I snd,\n        bool sameOrder) { // false means checking in reverse order\n    unsigned total = fst->getNumOperands();\n    if (total != snd->getNumOperands())\n        return false;\n\n    for (unsigned i = 0; i < total; ++i) {\n        unsigned otherI = sameOrder ? i : total - i - 1;\n\n        if (!graph.isEqual(fst->getOperand(i), snd->getOperand(otherI)))\n            return false;\n    }\n    return true;\n}\n\nvoid RelationsAnalyzer::solveByOperands(ValueRelations &graph,\n                                        const llvm::BinaryOperator *operation,\n                                        bool sameOrder) {\n    for (const auto *same :\n         structure.getInstructionSetFor(operation->getOpcode())) {\n        assert(llvm::isa<const llvm::BinaryOperator>(same));\n        const auto *sameOperation =\n                llvm::cast<const llvm::BinaryOperator>(same);\n\n        if (operation != sameOperation &&\n            operandsEqual(graph, operation, sameOperation, sameOrder))\n            graph.setEqual(operation, sameOperation);\n    }\n}\n\nvoid RelationsAnalyzer::solveEquality(ValueRelations &graph,\n                                      const llvm::BinaryOperator *operation) {\n    solveByOperands(graph, operation, true);\n}\n\nvoid RelationsAnalyzer::solveCommutativity(\n        ValueRelations &graph, const llvm::BinaryOperator *operation) {\n    solveByOperands(graph, operation, false);\n}\n\n// ******************** gen from instruction ************************** //\nvoid RelationsAnalyzer::storeGen(ValueRelations &graph,\n                                 const llvm::StoreInst *store) {\n    graph.setLoad(store->getPointerOperand()->stripPointerCasts(),\n                  store->getValueOperand());\n}\n\nvoid RelationsAnalyzer::loadGen(ValueRelations &graph,\n                                const llvm::LoadInst *load) {\n    graph.setLoad(load->getPointerOperand()->stripPointerCasts(), load);\n}\n\nint toChange(const llvm::GetElementPtrInst *gep) {\n    if (gep->getNumIndices() != 1)\n        return 0;\n    if (const auto *i = llvm::dyn_cast<llvm::ConstantInt>(gep->getOperand(1))) {\n        if (i->isOne())\n            return 1;\n        if (i->isMinusOne())\n            return -1;\n    }\n    return 0;\n}\n\nvoid RelationsAnalyzer::gepGen(ValueRelations &graph,\n                               const llvm::GetElementPtrInst *gep) {\n    if (gep->hasAllZeroIndices())\n        graph.setEqual(gep, gep->getPointerOperand());\n\n    int thisChange = toChange(gep);\n    if (const auto *origGep = graph.getInstance<llvm::GetElementPtrInst>(\n                gep->getPointerOperand())) {\n        int origChange = toChange(origGep);\n        if (thisChange && origChange && thisChange + origChange == 0)\n            graph.set(gep, Relations::EQ, origGep->getPointerOperand());\n    }\n\n    if (thisChange)\n        graph.set(gep->getPointerOperand(),\n                  thisChange == 1 ? Relations::SLT : Relations::SGT, gep);\n\n    for (auto it = graph.begin_buckets(Relations().pt());\n         it != graph.end_buckets(); ++it) {\n        for (V from : graph.getEqual(it->from())) {\n            if (const auto *otherGep =\n                        llvm::dyn_cast<llvm::GetElementPtrInst>(from)) {\n                if (operandsEqual(graph, gep, otherGep, true)) {\n                    graph.setEqual(gep, otherGep);\n                    return;\n                }\n            }\n        }\n    }\n    // TODO something more?\n    // indices method gives iterator over indices\n}\n\nvoid RelationsAnalyzer::extGen(ValueRelations &graph,\n                               const llvm::CastInst *ext) {\n    graph.setEqual(ext, ext->getOperand(0));\n}\n\nvoid solveNonConstants(ValueRelations &graph,\n                       llvm::Instruction::BinaryOps opcode,\n                       const llvm::BinaryOperator *op) {\n    if (opcode != llvm::Instruction::Sub)\n        return;\n\n    const llvm::Constant *zero = llvm::ConstantInt::getSigned(op->getType(), 0);\n    V fst = op->getOperand(0);\n    V snd = op->getOperand(1);\n\n    if (graph.isLesser(zero, snd) && graph.isLesserEqual(snd, fst))\n        graph.setLesser(op, fst);\n}\n\nstd::pair<llvm::Value *, llvm::ConstantInt *>\ngetParams(const llvm::BinaryOperator *op) {\n    if (llvm::isa<llvm::ConstantInt>(op->getOperand(0))) {\n        assert(!llvm::isa<llvm::ConstantInt>(op->getOperand(1)));\n        if (op->getOpcode() == llvm::Instruction::Sub)\n            return {nullptr, nullptr};\n        return {op->getOperand(1),\n                llvm::cast<llvm::ConstantInt>(op->getOperand(0))};\n    }\n    return {op->getOperand(0),\n            llvm::cast<llvm::ConstantInt>(op->getOperand(1))};\n}\n\nRelationsAnalyzer::Shift\nRelationsAnalyzer::getShift(const llvm::BinaryOperator *op,\n                            const VectorSet<V> &froms) {\n    if (llvm::isa<llvm::ConstantInt>(op->getOperand(0)) ==\n        llvm::isa<llvm::ConstantInt>(op->getOperand(1)))\n        return Shift::UNKNOWN;\n    V param = nullptr;\n    llvm::ConstantInt *c = nullptr;\n    std::tie(param, c) = getParams(op);\n\n    assert(param && c);\n    auto load = llvm::dyn_cast<llvm::LoadInst>(param);\n    if (!load || !froms.contains(load->getPointerOperand()))\n        return Shift::UNKNOWN;\n\n    auto opcode = op->getOpcode();\n    if ((opcode == llvm::Instruction::Add && c->isOne()) ||\n        (opcode == llvm::Instruction::Sub && c->isMinusOne())) {\n        return Shift::INC;\n    }\n    if ((opcode == llvm::Instruction::Add && c->isMinusOne()) ||\n        (opcode == llvm::Instruction::Sub && c->isOne())) {\n        return Shift::DEC;\n    }\n    return Shift::UNKNOWN;\n}\n\nRelationsAnalyzer::Shift\nRelationsAnalyzer::getShift(const llvm::GetElementPtrInst *op,\n                            const VectorSet<V> &froms) {\n    V ptr = op->getPointerOperand();\n    auto load = llvm::dyn_cast<llvm::LoadInst>(ptr);\n    if (!load || !froms.contains(load->getPointerOperand()))\n        return Shift::UNKNOWN;\n    if (const auto *i = llvm::dyn_cast<llvm::ConstantInt>(op->getOperand(1))) {\n        if (i->isOne())\n            return Shift::INC;\n        if (i->isMinusOne())\n            return Shift::DEC;\n    }\n    return Shift::UNKNOWN;\n}\n\nRelationsAnalyzer::Shift\nRelationsAnalyzer::getShift(const llvm::Value *val, const VectorSet<V> &froms) {\n    if (auto op = llvm::dyn_cast<llvm::BinaryOperator>(val))\n        return getShift(op, froms);\n    if (auto op = llvm::dyn_cast<llvm::GetElementPtrInst>(val))\n        return getShift(op, froms);\n    return Shift::UNKNOWN;\n}\n\nRelationsAnalyzer::Shift RelationsAnalyzer::getShift(\n        const std::vector<const VRLocation *> &changeLocations,\n        const VectorSet<V> &froms) const {\n    Shift shift = Shift::EQ;\n    // first location is the tree predecessor\n    for (auto it = std::next(changeLocations.begin());\n         it != changeLocations.end(); ++it) {\n        const VRLocation *loc = *it;\n        assert(loc->predsSize() == 1);\n\n        V inst = static_cast<VRInstruction *>(loc->getPredEdge(0)->op.get())\n                         ->getInstruction();\n        assert(inst);\n        assert(llvm::isa<llvm::StoreInst>(inst));\n        const llvm::StoreInst *store = llvm::cast<llvm::StoreInst>(inst);\n        if (!froms.contains(store->getPointerOperand()))\n            return Shift::UNKNOWN;\n\n        const auto *what = store->getValueOperand();\n\n        Shift current = getShift(what, froms);\n\n        if (shift == Shift::UNKNOWN)\n            return shift;\n        if (shift == Shift::EQ)\n            shift = current;\n        else if (shift != current)\n            return Shift::UNKNOWN;\n    }\n    return shift;\n}\n\nbool RelationsAnalyzer::canShift(const ValueRelations &graph, V param,\n                                 Relations::Type shift) {\n    const auto *paramType = param->getType();\n    assert(Relations::isStrict(shift) && Relations::isSigned(shift));\n    if (!graph.hasAnyRelation(param) || !param->getType()->isIntegerTy())\n        return false;\n\n    // if there is a value lesser/greater with same or smaller range, then param\n    // is also inc/decrementable\n    for (auto pair : graph.getRelated(\n                 param,\n                 Relations().set(shift).set(Relations::getNonStrict(shift)))) {\n        for (const auto &val : graph.getEqual(pair.first)) {\n            const auto *valType = val->getType();\n            if (valType->isIntegerTy() &&\n                valType->getIntegerBitWidth() <=\n                        paramType->getIntegerBitWidth()) {\n                if (pair.second.has(shift))\n                    return true;\n                assert(pair.second.has(Relations::getNonStrict(shift)));\n                if (const auto *c = llvm::dyn_cast<llvm::ConstantInt>(val)) {\n                    if (!(shift == Relations::SGT && c->isMinValue(true)) &&\n                        !(shift == Relations::SLT && c->isMaxValue(true)))\n                        return true;\n                }\n            }\n        }\n    }\n\n    // if the shifted value is a parameter, it depends on the passed value;\n    // check when validating\n    if (const auto *paramInst = llvm::dyn_cast<llvm::Instruction>(param)) {\n        const llvm::Function *thisFun = paramInst->getFunction();\n\n        for (const auto *val : graph.getEqual(paramInst)) {\n            if (const auto *arg = llvm::dyn_cast<llvm::Argument>(val)) {\n                if (arg->getType()->isIntegerTy()) {\n                    const auto *zero =\n                            llvm::ConstantInt::get(arg->getType(), 0);\n                    if (graph.are(arg, Relations::NE, zero))\n                        structure.addPrecondition(\n                                thisFun, arg, Relations::getNonStrict(shift),\n                                zero);\n                    else\n                        structure.addPrecondition(thisFun, arg, shift, zero);\n                    return true;\n                }\n            }\n        }\n    }\n    return false;\n}\n\nvoid RelationsAnalyzer::solveDifferent(ValueRelations &graph,\n                                       const llvm::BinaryOperator *op) {\n    auto opcode = op->getOpcode();\n\n    V param = nullptr;\n    llvm::ConstantInt *c = nullptr;\n    std::tie(param, c) = getParams(op);\n\n    if (!param)\n        return;\n\n    assert(param && c);\n\n    Relations::Type shift;\n    if ((opcode == llvm::Instruction::Add && c->isOne()) ||\n        (opcode == llvm::Instruction::Sub && c->isMinusOne())) {\n        shift = Relations::SLT;\n    } else if ((opcode == llvm::Instruction::Add && c->isMinusOne()) ||\n               (opcode == llvm::Instruction::Sub && c->isOne())) {\n        shift = Relations::SGT;\n    } else\n        return;\n\n    if (canShift(graph, param, shift)) {\n        graph.set(param, shift, op);\n\n        std::vector<V> sample =\n                graph.getDirectlyRelated(param, Relations().set(shift));\n\n        for (V val : sample) {\n            assert(graph.are(param, shift, val));\n            graph.set(op, Relations::getNonStrict(shift), val);\n        }\n\n        auto boundC = graph.getBound(param, Relations::getNonStrict(shift));\n        if (boundC.first && boundC.second.has(Relations::getNonStrict(shift)) &&\n            !graph.are(op, Relations::getNonStrict(shift), boundC.first)) {\n            int64_t intC = boundC.first->getSExtValue();\n            intC += shift == Relations::SLT ? 1 : -1;\n            const auto *newBound =\n                    llvm::ConstantInt::get(boundC.first->getType(), intC, true);\n            graph.set(op, Relations::getNonStrict(shift), newBound);\n        }\n    }\n}\n\nvoid RelationsAnalyzer::opGen(ValueRelations &graph,\n                              const llvm::BinaryOperator *op) {\n    const auto *c1 = llvm::dyn_cast<llvm::ConstantInt>(op->getOperand(0));\n    const auto *c2 = llvm::dyn_cast<llvm::ConstantInt>(op->getOperand(1));\n    auto opcode = op->getOpcode();\n\n    solveEquality(graph, op);\n    if (opcode == llvm::Instruction::Add || opcode == llvm::Instruction::Mul)\n        solveCommutativity(graph, op);\n\n    if (opcode == llvm::Instruction::Mul)\n        return;\n\n    if (c1 && c2)\n        return;\n\n    if (!c1 && !c2)\n        return solveNonConstants(graph, opcode, op);\n\n    solveDifferent(graph, op);\n}\n\nvoid RelationsAnalyzer::remGen(ValueRelations &graph,\n                               const llvm::BinaryOperator *rem) {\n    assert(rem);\n    const llvm::Constant *zero =\n            llvm::ConstantInt::getSigned(rem->getType(), 0);\n\n    if (!graph.isLesserEqual(zero, rem->getOperand(0)))\n        return;\n\n    graph.setLesserEqual(zero, rem);\n    graph.setLesser(rem, rem->getOperand(1));\n}\n\nvoid RelationsAnalyzer::castGen(ValueRelations &graph,\n                                const llvm::CastInst *cast) {\n    if (cast->isLosslessCast() || cast->isNoopCast(module.getDataLayout()))\n        graph.setEqual(cast, cast->getOperand(0));\n}\n\n// ******************** process assumption ************************** //\nRelationsAnalyzer::Relation\nRelationsAnalyzer::ICMPToRel(const llvm::ICmpInst *icmp, bool assumption) {\n    llvm::ICmpInst::Predicate pred = assumption ? icmp->getSignedPredicate()\n                                                : icmp->getInversePredicate();\n\n    switch (pred) {\n    case llvm::ICmpInst::Predicate::ICMP_EQ:\n        return Relation::EQ;\n    case llvm::ICmpInst::Predicate::ICMP_NE:\n        return Relation::NE;\n    case llvm::ICmpInst::Predicate::ICMP_ULE:\n        return Relation::ULE;\n    case llvm::ICmpInst::Predicate::ICMP_SLE:\n        return Relation::SLE;\n    case llvm::ICmpInst::Predicate::ICMP_ULT:\n        return Relation::ULT;\n    case llvm::ICmpInst::Predicate::ICMP_SLT:\n        return Relation::SLT;\n    case llvm::ICmpInst::Predicate::ICMP_UGE:\n        return Relation::UGE;\n    case llvm::ICmpInst::Predicate::ICMP_SGE:\n        return Relation::SGE;\n    case llvm::ICmpInst::Predicate::ICMP_UGT:\n        return Relation::UGT;\n    case llvm::ICmpInst::Predicate::ICMP_SGT:\n        return Relation::SGT;\n    default:\n#ifndef NDEBUG\n        llvm::errs() << \"Unhandled predicate in\" << *icmp << \"\\n\";\n#endif\n        abort();\n    }\n}\n\nsize_t limitingBorder(const ValueRelations &relations, const llvm::Value *val) {\n    for (const auto &handleRel : relations.getRelated(val, Relations().sle())) {\n        auto mId = relations.getBorderId(handleRel.first);\n        if (mId != std::string::npos)\n            return mId;\n    }\n    return std::string::npos;\n}\n\nbool RelationsAnalyzer::findEqualBorderBucket(const ValueRelations &relations,\n                                              const llvm::Value *mBorderV,\n                                              const llvm::Value *comparedV) {\n    if (!llvm::isa<llvm::Instruction>(mBorderV) ||\n        !llvm::isa<llvm::Instruction>(comparedV))\n        return false;\n    if (!relations.contains(mBorderV) || !relations.contains(comparedV))\n        return false;\n\n    const auto &borderFroms = getFroms(relations, mBorderV);\n    const auto &comparedFroms = getFroms(relations, comparedV);\n\n    if (borderFroms.size() != 2 || comparedFroms.size() != 2)\n        return false;\n\n    auto mBorderId = limitingBorder(relations, borderFroms[0]);\n    if (mBorderId == std::string::npos)\n        return false;\n\n    // if (limitingBorder(relations, comparedFroms[0]) != std::string::npos)\n    //     return true;\n\n    const llvm::Argument *arg =\n            getArgument(relations, *relations.getHandle(comparedFroms[0]));\n    if (!arg)\n        return false;\n\n    const auto *comparedFrom = llvm::cast<llvm::Instruction>(comparedFroms[0]);\n    const auto *func = comparedFrom->getFunction();\n    assert(structure.hasBorderValues(func));\n    BorderValue bv = structure.getBorderValueFor(func, mBorderId);\n    for (const auto &borderVal : structure.getBorderValuesFor(func)) {\n        if (borderVal.from == arg && borderVal.stored == bv.stored) {\n            assert(codeGraph.getVRLocation(comparedFrom)\n                           .getSuccLocation(0)\n                           ->join);\n            VRLocation &join = const_cast<VRLocation &>(\n                    *codeGraph.getVRLocation(comparedFrom)\n                             .getSuccLocation(0)\n                             ->join);\n            assert(join.relations.has(comparedFroms[1], Relations::PT));\n            const auto &placeholder =\n                    join.relations.getPointedTo(comparedFroms[1]);\n\n            auto thisBorderPlaceholder =\n                    join.relations.getBorderH(borderVal.id);\n            assert(thisBorderPlaceholder);\n            join.relations.set(placeholder, Relations::SLE,\n                               *thisBorderPlaceholder);\n            return true;\n        }\n    }\n\n    auto id = structure.addBorderValue(func, arg, bv.stored);\n    ValueRelations &entryRels = codeGraph.getEntryLocation(*func).relations;\n    Handle entryBorderPlaceholder = entryRels.newBorderBucket(id);\n    entryRels.set(entryBorderPlaceholder, Relations::PT, bv.stored);\n    entryRels.set(entryBorderPlaceholder, Relations::SGE, arg);\n    return true;\n}\n\nbool RelationsAnalyzer::processICMP(const ValueRelations &oldGraph,\n                                    ValueRelations &newGraph,\n                                    VRAssumeBool *assume) {\n    const llvm::ICmpInst *icmp = llvm::cast<llvm::ICmpInst>(assume->getValue());\n    bool assumption = assume->getAssumption();\n\n    V op1 = icmp->getOperand(0);\n    V op2 = icmp->getOperand(1);\n\n    Relation rel = ICMPToRel(icmp, assumption);\n\n    if (oldGraph.hasConflictingRelation(op1, op2, rel))\n        return false;\n\n    newGraph.set(op1, rel, op2);\n\n    if (rel == Relations::EQ) {\n        if (!findEqualBorderBucket(oldGraph, op1, op2))\n            findEqualBorderBucket(oldGraph, op2, op1);\n    }\n    return true;\n}\n\nstd::pair<const llvm::LoadInst *, const llvm::Value *>\ngetParams(const ValueRelations &graph, const llvm::ICmpInst *icmp) {\n    const llvm::Value *op1 = icmp->getOperand(0);\n    const llvm::Value *op2 = icmp->getOperand(1);\n    if (const auto *load = graph.getInstance<llvm::LoadInst>(op1))\n        return {load, op2};\n    if (const auto *load = graph.getInstance<llvm::LoadInst>(op2))\n        return {load, op1};\n    return {nullptr, nullptr};\n}\n\nvoid RelationsAnalyzer::inferFromNEPointers(ValueRelations &newGraph,\n                                            VRAssumeBool *assume) const {\n    const llvm::ICmpInst *icmp =\n            llvm::dyn_cast<llvm::ICmpInst>(assume->getValue());\n    if (!icmp)\n        return;\n    bool assumption = assume->getAssumption();\n    Relation rel = ICMPToRel(icmp, assumption);\n\n    const llvm::LoadInst *load;\n    const llvm::Value *compared;\n    std::tie(load, compared) = getParams(newGraph, icmp);\n    if (!load || (rel != Relations::EQ && rel != Relations::NE))\n        return;\n\n    for (auto related : newGraph.getRelated(load->getPointerOperand(),\n                                            Relations().sle().sge())) {\n        if (related.second.has(Relations::EQ))\n            continue;\n\n        if (newGraph.are(related.first, Relations::PT, compared)) {\n            size_t id = newGraph.getBorderId(related.first);\n            if (id == std::string::npos)\n                continue;\n            auto arg =\n                    structure.getBorderValueFor(load->getFunction(), id).from;\n            if (newGraph.are(arg, related.second.get(),\n                             load->getPointerOperand())) {\n                Relations::Type toSet =\n                        rel == Relations::EQ\n                                ? Relations::EQ\n                                : Relations::getStrict(related.second.get());\n                newGraph.set(load->getPointerOperand(), toSet, related.first);\n            }\n        }\n    }\n}\n\nbool RelationsAnalyzer::processPhi(ValueRelations &newGraph,\n                                   VRAssumeBool *assume) {\n    const llvm::PHINode *phi = llvm::cast<llvm::PHINode>(assume->getValue());\n    const auto &sources =\n            structure.possibleSources(phi, assume->getAssumption());\n    if (sources.size() != 1)\n        return true;\n\n    VRInstruction *inst = static_cast<VRInstruction *>(sources[0]->op.get());\n    const auto *icmp = llvm::dyn_cast<llvm::ICmpInst>(inst->getInstruction());\n\n    bool result;\n    if (icmp) {\n        VRAssumeBool tmp{inst->getInstruction(), assume->getAssumption()};\n        result = processICMP(codeGraph.getVRLocation(icmp).relations, newGraph,\n                             &tmp);\n        if (!result)\n            return false;\n    }\n\n    VRLocation &source = *sources[0]->target;\n    result = newGraph.merge(source.relations);\n    assert(result);\n    return true;\n}\n\n// *********************** merge helpers **************************** //\nvoid RelationsAnalyzer::inferFromPreds(VRLocation &location, Handle lt,\n                                       Relations known, Handle rt) {\n    const ValueRelations &predGraph = location.getTreePredecessor().relations;\n    ValueRelations &newGraph = location.relations;\n\n    std::set<V> setEqual;\n    for (const auto *ltVal : predGraph.getEqual(lt)) {\n        if (setEqual.find(ltVal) != setEqual.end())\n            continue;\n        for (const auto *rtVal : predGraph.getEqual(rt)) {\n            if (ltVal == rtVal)\n                continue;\n\n            Relations related = getCommon(location, ltVal, known, rtVal);\n            if (!related.any())\n                continue;\n\n            if (related.has(Relations::EQ))\n                setEqual.emplace(rtVal);\n            newGraph.set(ltVal, related, rtVal);\n        }\n\n        size_t rtId = predGraph.getBorderId(rt);\n        if (rtId != std::string::npos) {\n            Relations related = getCommon(location, ltVal, known, rtId);\n            if (!related.any())\n                continue;\n\n            newGraph.set(ltVal, related, rtId);\n        }\n    }\n\n    size_t ltId = predGraph.getBorderId(lt);\n    if (ltId != std::string::npos) {\n        for (const auto *rtVal : predGraph.getEqual(rt)) {\n            Relations related = getCommon(location, ltId, known, rtVal);\n            if (!related.any())\n                continue;\n\n            newGraph.set(ltId, related, rtVal);\n        }\n\n        size_t rtId = predGraph.getBorderId(rt);\n        if (rtId != std::string::npos) {\n            Relations related = getCommon(location, ltId, known, rtId);\n            if (!related.any())\n                return;\n\n            newGraph.set(ltId, related, rtId);\n        }\n    }\n}\n\nstd::vector<const VRLocation *>\nRelationsAnalyzer::getBranchChangeLocations(const VRLocation &join,\n                                            const VectorSet<V> &froms) const {\n    std::vector<const VRLocation *> changeLocations;\n    for (unsigned i = 0; i < join.predsSize(); ++i) {\n        auto loc = join.getPredLocation(i);\n        bool hasLoad = false;\n        for (V from : froms) {\n            if (loc->relations.hasLoad(from)) {\n                hasLoad = true;\n                break;\n            }\n        }\n        if (!hasLoad)\n            return {};\n        changeLocations.emplace_back(loc);\n    }\n    return changeLocations;\n}\n\nstd::vector<const VRLocation *>\nRelationsAnalyzer::getLoopChangeLocations(const VRLocation &join,\n                                          const VectorSet<V> &froms) const {\n    std::vector<const VRLocation *> changeLocations = {\n            &join.getTreePredecessor()};\n\n    for (const auto &inloopInst : structure.getInloopValues(join)) {\n        VRLocation &targetLoc =\n                *codeGraph.getVRLocation(inloopInst).getSuccLocation(0);\n\n        for (V from : froms) {\n            if (mayOverwrite(inloopInst, from)) {\n                if (!targetLoc.relations.hasLoad(from))\n                    return {}; // no merge by load can happen here\n\n                changeLocations.emplace_back(&targetLoc);\n            }\n        }\n    }\n    return changeLocations;\n}\n\nstd::vector<const VRLocation *>\nRelationsAnalyzer::getChangeLocations(const VRLocation &join,\n                                      const VectorSet<V> &froms) {\n    if (!join.isJustLoopJoin() && !join.isJustBranchJoin())\n        return {};\n    if (join.isJustBranchJoin()) {\n        return getBranchChangeLocations(join, froms);\n    }\n    assert(join.isJustLoopJoin());\n    return getLoopChangeLocations(join, froms);\n}\n\nstd::pair<RelationsAnalyzer::C, Relations>\nRelationsAnalyzer::getBoundOnPointedToValue(\n        const std::vector<const VRLocation *> &changeLocations,\n        const VectorSet<V> &froms, Relation rel) {\n    C bound = nullptr;\n    Relations current = allRelations;\n\n    for (const VRLocation *loc : changeLocations) {\n        const ValueRelations &graph = loc->relations;\n        HandlePtr from = getCorrespondingByContent(graph, froms);\n        assert(from);\n        if (!graph.hasLoad(*from))\n            return {nullptr, current};\n\n        Handle pointedTo = graph.getPointedTo(*from);\n        auto valueRels = graph.getBound(pointedTo, rel);\n\n        if (!valueRels.first)\n            return {nullptr, current};\n\n        if (!bound || ValueRelations::compare(bound, Relations::getStrict(rel),\n                                              valueRels.first)) {\n            bound = valueRels.first;\n            current = Relations().set(Relations::getStrict(rel)).addImplied();\n        }\n\n        current &= valueRels.second;\n        assert(current.any());\n    }\n    return {bound, current};\n}\n\nstd::pair<V, bool> getCompared(const ValueRelations &graph,\n                               const llvm::ICmpInst *icmp,\n                               const llvm::Value *from) {\n    const auto *op1 = icmp->getOperand(0);\n    const auto *op2 = icmp->getOperand(1);\n\n    for (const auto *op : {op1, op2}) {\n        const auto &froms = RelationsAnalyzer::getFroms(graph, op);\n        if (std::find(froms.begin(), froms.end(), from) != froms.end()) {\n            if (op == op1)\n                return {op2, froms.size() <= 1};\n            return {op1, froms.size() <= 1};\n        }\n    }\n    return {nullptr, false};\n}\n\nstd::vector<const llvm::ICmpInst *>\nRelationsAnalyzer::getEQICmp(const VRLocation &join) {\n    std::vector<const llvm::ICmpInst *> result;\n    for (const auto *loopEnd : join.loopEnds) {\n        if (!loopEnd->op->isAssumeBool())\n            continue;\n\n        const auto *assume = static_cast<VRAssumeBool *>(loopEnd->op.get());\n        const auto &icmps = structure.getRelevantConditions(assume);\n        if (icmps.empty())\n            return {};\n\n        for (const auto *icmp : icmps) {\n            Relation rel = ICMPToRel(icmp, assume->getAssumption());\n\n            if (rel != Relations::EQ)\n                continue; // TODO check or collect\n\n            result.emplace_back(icmp);\n        }\n    }\n    return result;\n}\n\nvoid RelationsAnalyzer::inferFromNonEquality(VRLocation &join,\n                                             const VectorSet<V> &froms, Shift s,\n                                             Handle placeholder) {\n    const ValueRelations &predGraph = join.getTreePredecessor().relations;\n    for (V from : froms) {\n        Handle initH = predGraph.getPointedTo(from);\n        for (const auto *icmp : getEQICmp(join)) {\n            V compared;\n            bool direct;\n            std::tie(compared, direct) = getCompared(\n                    codeGraph.getVRLocation(icmp).relations, icmp, from);\n            if (!compared ||\n                (!llvm::isa<llvm::Constant>(compared) &&\n                 !codeGraph.getVRLocation(icmp)\n                          .relations.getInstance<llvm::Argument>(compared)))\n                continue;\n\n            const llvm::Argument *arg = getArgument(predGraph, initH);\n            if (!arg)\n                continue;\n\n            const llvm::Function *func = icmp->getFunction();\n\n            ValueRelations &entryRels =\n                    codeGraph.getEntryLocation(*func).relations;\n            if (direct) {\n                if (!join.relations.are(*predGraph.getEqual(initH).begin(),\n                                        s == Shift::INC ? Relations::SLE\n                                                        : Relations::SGE,\n                                        compared)) {\n                    structure.addPrecondition(func, arg,\n                                              s == Shift::INC ? Relations::SLE\n                                                              : Relations::SGE,\n                                              compared);\n                    entryRels.set(arg,\n                                  s == Shift::INC ? Relations::SLE\n                                                  : Relations::SGE,\n                                  compared);\n                }\n\n                if (join.relations.are(arg, Relations::NE, compared))\n                    join.relations.set(placeholder,\n                                       s == Shift::INC ? Relations::SLT\n                                                       : Relations::SGT,\n                                       compared);\n                else\n                    join.relations.set(placeholder,\n                                       s == Shift::INC ? Relations::SLE\n                                                       : Relations::SGE,\n                                       compared);\n            } else {\n                if (structure.hasBorderValues(func)) {\n                    for (const auto &borderVal :\n                         structure.getBorderValuesFor(func)) {\n                        if (borderVal.from == arg &&\n                            borderVal.stored == compared) {\n                            auto thisBorderPlaceholder =\n                                    join.relations.getBorderH(borderVal.id);\n                            assert(thisBorderPlaceholder);\n                            join.relations.set(placeholder,\n                                               s == Shift::INC ? Relations::SLE\n                                                               : Relations::SGE,\n                                               *thisBorderPlaceholder);\n                            return;\n                        }\n                    }\n                }\n\n                auto id = structure.addBorderValue(func, arg, compared);\n                Handle entryBorderPlaceholder = entryRels.newBorderBucket(id);\n                entryRels.set(entryBorderPlaceholder, Relations::PT, compared);\n                entryRels.set(entryBorderPlaceholder,\n                              Relations::inverted(s == Shift::INC\n                                                          ? Relations::SLE\n                                                          : Relations::SGE),\n                              arg);\n            }\n        }\n    }\n}\n\nvoid RelationsAnalyzer::inferShiftInLoop(\n        const std::vector<const VRLocation *> &changeLocations,\n        const VectorSet<V> &froms, ValueRelations &newGraph,\n        Handle placeholder) {\n    const ValueRelations &predGraph = changeLocations[0]->relations;\n    HandlePtr from = getCorrespondingByContent(predGraph, froms);\n    assert(from);\n\n    const auto &initial = predGraph.getEqual(predGraph.getPointedTo(*from));\n    if (initial.empty())\n        return;\n\n    auto shift = getShift(changeLocations, froms);\n    if (shift == Shift::UNKNOWN)\n        return;\n\n    if (shift == Shift::INC || shift == Shift::DEC)\n        inferFromNonEquality(*changeLocations[0]->getSuccLocation(0), froms,\n                             shift, placeholder);\n\n    Relations::Type rel =\n            shift == Shift::EQ\n                    ? Relations::EQ\n                    : (shift == Shift::INC ? Relations::SLE : Relations::SGE);\n\n    // placeholder must be first so that if setting EQ, its bucket is\n    // preserved\n    newGraph.set(placeholder, Relations::inverted(rel), *initial.begin());\n}\n\nvoid RelationsAnalyzer::relateBounds(\n        const std::vector<const VRLocation *> &changeLocations,\n        const VectorSet<V> &froms, ValueRelations &newGraph,\n        Handle placeholder) {\n    auto signedLowerBound =\n            getBoundOnPointedToValue(changeLocations, froms, Relation::SGE);\n    auto unsignedLowerBound = getBoundOnPointedToValue(\n            changeLocations, froms,\n            Relation::UGE); // TODO collect upper bound too\n\n    if (signedLowerBound.first)\n        newGraph.set(placeholder, signedLowerBound.second,\n                     signedLowerBound.first);\n\n    if (unsignedLowerBound.first)\n        newGraph.set(placeholder, unsignedLowerBound.second,\n                     unsignedLowerBound.first);\n}\n\nvoid RelationsAnalyzer::relateValues(\n        const std::vector<const VRLocation *> &changeLocations,\n        const VectorSet<V> &froms, ValueRelations &newGraph,\n        Handle placeholder) {\n    const ValueRelations &predGraph = changeLocations[0]->relations;\n    HandlePtr from = getCorrespondingByContent(predGraph, froms);\n    assert(from);\n    Handle pointedTo = predGraph.getPointedTo(*from);\n\n    for (auto pair : predGraph.getRelated(pointedTo, comparative)) {\n        Handle relatedH = pair.first;\n        Relations relations = pair.second;\n\n        assert(predGraph.are(pointedTo, relations, relatedH));\n\n        if (relatedH == pointedTo && !predGraph.getEqual(relatedH).empty())\n            continue;\n\n        for (V related : predGraph.getEqual(relatedH)) {\n            Relations common = getCommonByPointedTo(froms, changeLocations,\n                                                    related, relations);\n            if (common.any())\n                newGraph.set(placeholder, common, related);\n        }\n\n        size_t mBorderId = predGraph.getBorderId(relatedH);\n        if (mBorderId != std::string::npos) {\n            Relations common = getCommonByPointedTo(froms, changeLocations,\n                                                    mBorderId, relations);\n\n            if (common.any()) {\n                auto borderH = newGraph.getBorderH(mBorderId);\n                if (!borderH)\n                    borderH = &newGraph.newBorderBucket(mBorderId);\n                newGraph.set(placeholder, common, *borderH);\n            }\n        }\n    }\n}\n\n// **************************** merge ******************************* //\nvoid RelationsAnalyzer::mergeRelations(VRLocation &location) {\n    assert(location.predsSize() > 1);\n\n    const ValueRelations &predGraph = location.getTreePredecessor().relations;\n\n    for (const auto &bucketVal : predGraph.getBucketToVals()) {\n        for (const auto &related :\n             predGraph.getRelated(bucketVal.first, restricted)) {\n            inferFromPreds(location, bucketVal.first, related.second,\n                           related.first);\n        }\n    }\n\n    ValueRelations &thisGraph = location.relations;\n\n    // merge relations from tree predecessor only\n    if (location.isJustLoopJoin()) {\n        __attribute__((unused)) bool result =\n                thisGraph.merge(predGraph, comparative);\n        assert(result);\n    }\n}\n\nvoid RelationsAnalyzer::mergeRelationsByPointedTo(VRLocation &loc) {\n    ValueRelations &newGraph = loc.relations;\n    ValueRelations &predGraph = loc.getTreePredecessor().relations;\n\n    for (auto it = predGraph.begin_buckets(Relations().pt());\n         it != predGraph.end_buckets(); ++it) {\n        const VectorSet<V> &froms = predGraph.getEqual(it->from());\n        if (!froms.empty()) {\n            std::vector<const VRLocation *> changeLocations =\n                    getChangeLocations(loc, froms);\n\n            if (changeLocations.empty())\n                continue;\n\n            Handle placeholder = newGraph.newPlaceholderBucket(*froms.begin());\n\n            if (loc.isJustLoopJoin())\n                inferShiftInLoop(changeLocations, froms, newGraph, placeholder);\n            relateBounds(changeLocations, froms, newGraph, placeholder);\n            relateValues(changeLocations, froms, newGraph, placeholder);\n\n            if (!newGraph.getEqual(placeholder).empty() ||\n                newGraph.hasAnyRelation(placeholder))\n                newGraph.setLoad(*froms.begin(), placeholder);\n            else\n                newGraph.erasePlaceholderBucket(placeholder);\n        }\n\n        if (froms.empty()) {\n            V arg = getArgument(predGraph, it->from());\n            if (!arg)\n                continue;\n            std::vector<const VRLocation *> changeLocations =\n                    getChangeLocations(loc, {arg});\n\n            if (changeLocations.size() == 1) {\n                Relations between = predGraph.between(arg, it->from());\n                assert(!between.has(Relations::EQ));\n                size_t id = predGraph.getBorderId(it->from());\n                if (id == std::string::npos)\n                    continue;\n                auto borderH = newGraph.getBorderH(id);\n                if (!borderH)\n                    borderH = &newGraph.newBorderBucket(id);\n\n                newGraph.set(arg, between, *borderH);\n                for (V to : predGraph.getEqual(it->to()))\n                    newGraph.set(*borderH, Relations::PT, to);\n            }\n        }\n    }\n}\n\n// ***************************** edge ******************************* //\nvoid RelationsAnalyzer::processInstruction(ValueRelations &graph, I inst) {\n    switch (inst->getOpcode()) {\n    case llvm::Instruction::Store:\n        return storeGen(graph, llvm::cast<llvm::StoreInst>(inst));\n    case llvm::Instruction::Load:\n        return loadGen(graph, llvm::cast<llvm::LoadInst>(inst));\n    case llvm::Instruction::GetElementPtr:\n        return gepGen(graph, llvm::cast<llvm::GetElementPtrInst>(inst));\n    case llvm::Instruction::ZExt:\n    case llvm::Instruction::SExt: // (S)ZExt should not change value\n        return extGen(graph, llvm::cast<llvm::CastInst>(inst));\n    case llvm::Instruction::Add:\n    case llvm::Instruction::Sub:\n    case llvm::Instruction::Mul:\n        return opGen(graph, llvm::cast<llvm::BinaryOperator>(inst));\n    case llvm::Instruction::SRem:\n    case llvm::Instruction::URem:\n        return remGen(graph, llvm::cast<llvm::BinaryOperator>(inst));\n    default:\n        if (const auto *cast = llvm::dyn_cast<llvm::CastInst>(inst)) {\n            return castGen(graph, cast);\n        }\n    }\n}\n\nvoid RelationsAnalyzer::rememberValidated(const ValueRelations &prev,\n                                          ValueRelations &graph, I inst) const {\n    assert(&prev == &codeGraph.getVRLocation(inst).relations);\n\n    for (auto it = prev.begin_buckets(Relations().pt());\n         it != prev.end_buckets(); ++it) {\n        for (V from : prev.getEqual(it->from())) {\n            if (!mayOverwrite(inst, from)) {\n                for (V to : prev.getEqual(it->to()))\n                    graph.set(from, Relations::PT, to);\n            }\n            if (const auto *store = llvm::dyn_cast<llvm::StoreInst>(inst)) {\n                if (prev.are(it->to(), Relations::EQ,\n                             store->getValueOperand())) {\n                    for (V to : prev.getEqual(it->to()))\n                        graph.set(from, Relations::PT, to);\n                }\n            }\n        }\n\n        if (prev.getEqual(it->from()).empty() &&\n            !it->from().hasRelation(Relations::PF)) {\n            V arg = getArgument(prev, it->from());\n            if (arg && !mayOverwrite(inst, arg)) {\n                auto mH = graph.getBorderH(prev.getBorderId(it->from()));\n                assert(mH);\n\n                for (V to : prev.getEqual(it->to()))\n                    graph.set(*mH, Relations::PT, to);\n            }\n        }\n    }\n}\n\nbool RelationsAnalyzer::processAssumeBool(const ValueRelations &oldGraph,\n                                          ValueRelations &newGraph,\n                                          VRAssumeBool *assume) {\n    if (llvm::isa<llvm::ICmpInst>(assume->getValue()))\n        return processICMP(oldGraph, newGraph, assume);\n    if (llvm::isa<llvm::PHINode>(assume->getValue()))\n        return processPhi(newGraph, assume);\n    return false; // TODO; probably call\n}\n\nbool RelationsAnalyzer::processAssumeEqual(const ValueRelations &oldGraph,\n                                           ValueRelations &newGraph,\n                                           VRAssumeEqual *assume) {\n    V val1 = assume->getValue();\n    V val2 = assume->getAssumption();\n    if (oldGraph.hasConflictingRelation(val1, val2, Relation::EQ))\n        return false;\n    newGraph.setEqual(val1, val2);\n    return true;\n}\n\n// ************************* topmost ******************************* //\nvoid RelationsAnalyzer::processOperation(VRLocation *source, VRLocation *target,\n                                         VROp *op) {\n    if (!target)\n        return;\n    assert(source && target && op);\n\n    ValueRelations &newGraph = target->relations;\n\n    if (op->isInstruction()) {\n        newGraph.merge(source->relations, comparative);\n        I inst = static_cast<VRInstruction *>(op)->getInstruction();\n        rememberValidated(source->relations, newGraph, inst);\n        processInstruction(newGraph, inst);\n\n    } else if (op->isAssume()) {\n        bool shouldMerge;\n        if (op->isAssumeBool())\n            shouldMerge = processAssumeBool(source->relations, newGraph,\n                                            static_cast<VRAssumeBool *>(op));\n        else // isAssumeEqual\n            shouldMerge = processAssumeEqual(source->relations, newGraph,\n                                             static_cast<VRAssumeEqual *>(op));\n        if (shouldMerge) {\n            __attribute__((unused)) bool result =\n                    newGraph.merge(source->relations);\n            assert(result);\n        }\n\n        if (op->isAssumeBool())\n            inferFromNEPointers(newGraph, static_cast<VRAssumeBool *>(op));\n    } else { // else op is noop\n        newGraph.merge(source->relations, allRelations);\n    }\n}\n\nbool RelationsAnalyzer::passFunction(const llvm::Function &function,\n                                     __attribute__((unused)) bool print) {\n    bool changed = false;\n\n    for (auto it = codeGraph.lazy_dfs_begin(function);\n         it != codeGraph.lazy_dfs_end(); ++it) {\n        VRLocation &location = *it;\n#ifndef NDEBUG\n        const bool cond = location.id == 91;\n        if (print && cond) {\n            std::cerr << \"LOCATION \" << location.id << \"\\n\";\n            for (unsigned i = 0; i < location.predsSize(); ++i) {\n                std::cerr << \"pred\" << i << \" \"\n                          << location.getPredEdge(i)->op->toStr() << \"\\n\";\n                std::cerr << location.getPredLocation(i)->relations << \"\\n\";\n            }\n            std::cerr << \"before\\n\" << location.relations << \"\\n\";\n            std::cerr << \"inside\\n\";\n        }\n#endif\n\n        if (location.predsSize() > 1) {\n            mergeRelations(location);\n            mergeRelationsByPointedTo(location);\n        } else if (location.predsSize() == 1) {\n            VREdge *edge = location.getPredEdge(0);\n            processOperation(edge->source, edge->target, edge->op.get());\n        } // else no predecessors => nothing to be passed\n\n        bool locationChanged = location.relations.unsetChanged();\n#ifndef NDEBUG\n        if (print && cond) {\n            std::cerr << \"after\\n\";\n            if (locationChanged)\n                std::cerr << location.relations;\n            // return false;\n        }\n#endif\n        changed |= locationChanged;\n    }\n    return changed;\n}\n\nunsigned RelationsAnalyzer::analyze(unsigned maxPass) {\n    unsigned maxExecutedPass = 0;\n\n    for (const auto &function : module) {\n        if (function.isDeclaration())\n            continue;\n\n        bool changed = true;\n        unsigned passNum = 0;\n        while (changed && passNum < maxPass) {\n            changed = passFunction(function, false); // passNum + 1 == maxPass);\n            ++passNum;\n        }\n\n        maxExecutedPass = std::max(maxExecutedPass, passNum);\n    }\n\n    return maxExecutedPass;\n}\n\nstd::vector<V> RelationsAnalyzer::getFroms(const ValueRelations &rels, V val) {\n    std::vector<V> result;\n    const auto *load = rels.getInstance<llvm::LoadInst>(val);\n    const auto *mH = rels.getHandle(val);\n\n    while (load || (mH && rels.has(*mH, Relations::PF))) {\n        if (load) {\n            val = load->getPointerOperand();\n            mH = rels.getHandle(val);\n            load = rels.getInstance<llvm::LoadInst>(val);\n            result.emplace_back(val);\n        } else {\n            const auto &pointedFrom = rels.getRelated(val, Relations().pf());\n            if (pointedFrom.size() != 1)\n                return result;\n            mH = &pointedFrom.begin()->first.get();\n            load = rels.getInstance<llvm::LoadInst>(*mH);\n            if (load)\n                result.emplace_back(load);\n            else if (const auto *gep =\n                             rels.getInstance<llvm::GetElementPtrInst>(*mH))\n                result.emplace_back(gep);\n            else {\n                const auto &eqvals = rels.getEqual(*mH);\n                if (eqvals.empty())\n                    return result;\n                result.emplace_back(*eqvals.begin());\n            }\n        }\n    }\n\n    return result;\n}\n\nRelationsAnalyzer::HandlePtr\nRelationsAnalyzer::getHandleFromFroms(const ValueRelations &rels,\n                                      const std::vector<V> &froms) {\n    if (froms.empty())\n        return nullptr;\n    auto *from = rels.getHandle(froms.back());\n    for (unsigned i = 0; i < froms.size(); ++i) {\n        if (!from || !rels.has(*from, Relations::PT))\n            return nullptr;\n        from = &rels.getPointedTo(*from);\n    }\n    return from;\n}\n\nRelationsAnalyzer::HandlePtr\nRelationsAnalyzer::getHandleFromFroms(const ValueRelations &toRels,\n                                      const ValueRelations &fromRels, V val) {\n    auto froms = getFroms(fromRels, val);\n    auto to = getHandleFromFroms(toRels, froms);\n    return to;\n}\n\nRelationsAnalyzer::HandlePtr\nRelationsAnalyzer::getCorrespondingByContent(const ValueRelations &toRels,\n                                             const ValueRelations &fromRels,\n                                             Handle h) {\n    return getCorrespondingByContent(toRels, fromRels.getEqual(h));\n}\n\nRelationsAnalyzer::HandlePtr\nRelationsAnalyzer::getCorrespondingByContent(const ValueRelations &toRels,\n                                             const VectorSet<V> &vals) {\n    HandlePtr result = nullptr;\n    for (const auto *val : vals) {\n        auto *mThisH = toRels.getHandle(val);\n        if (!mThisH)\n            continue;\n        if (result && result != mThisH)\n            return nullptr;\n        result = mThisH;\n    }\n    return result;\n}\n\nRelationsAnalyzer::HandlePtr\nRelationsAnalyzer::getCorrespondingByFrom(const ValueRelations &toRels,\n                                          const ValueRelations &fromRels,\n                                          Handle h) {\n    const auto &froms = fromRels.getRelated(h, Relations().pf());\n    if (froms.size() != 1)\n        return nullptr;\n\n    const auto &fromFromH = froms.begin()->first;\n    const auto *toFromH =\n            getCorrespondingByContent(toRels, fromRels, fromFromH);\n    if (!toFromH)\n        return nullptr;\n\n    if (!toRels.has(*toFromH, Relations::PT))\n        return nullptr;\n\n    return &toRels.getPointedTo(*toFromH);\n}\n\nconst llvm::AllocaInst *RelationsAnalyzer::getOrigin(const ValueRelations &rels,\n                                                     V val) {\n    for (const auto &related : rels.getRelated(val, Relations().sge())) {\n        if (const auto *alloca =\n                    rels.getInstance<llvm::AllocaInst>(related.first.get())) {\n            return alloca;\n        }\n    }\n    return nullptr;\n}\n\n} // namespace vr\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ValueRelations/StructureAnalyzer.cpp",
    "content": "#include \"dg/llvm/ValueRelations/StructureAnalyzer.h\"\n\n#include \"llvm/llvm-utils.h\"\n\n#include <llvm/IR/Constants.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/IntrinsicInst.h>\n#include <llvm/IR/Module.h>\n#include <llvm/IR/Value.h>\n\n#include <algorithm>\n\n#ifndef NDEBUG\n#include \"dg/llvm/ValueRelations/getValName.h\"\n#endif\n\nnamespace dg {\nnamespace vr {\n\nconst llvm::Value *AllocatedArea::stripCasts(const llvm::Value *inst) {\n    while (const auto *cast = llvm::dyn_cast<llvm::CastInst>(inst))\n        inst = cast->getOperand(0);\n    return inst;\n}\n\nuint64_t AllocatedArea::getBytes(const llvm::Type *type) {\n    const unsigned byteWidth = 8;\n    assert(type->isSized());\n\n    uint64_t size = type->getPrimitiveSizeInBits();\n\n    return size / byteWidth;\n}\n\nAllocatedArea::AllocatedArea(const llvm::AllocaInst *alloca) : ptr(alloca) {\n    const llvm::Type *allocatedType = alloca->getAllocatedType();\n\n    if (allocatedType->isArrayTy()) {\n        const llvm::Type *elemType = allocatedType->getArrayElementType();\n        // DANGER just an arbitrary type\n        llvm::Type *i32 = llvm::Type::getInt32Ty(elemType->getContext());\n        uint64_t intCount = allocatedType->getArrayNumElements();\n\n        originalSizeView = AllocatedSizeView(\n                llvm::ConstantInt::get(i32, intCount), getBytes(elemType));\n    } else {\n        originalSizeView = AllocatedSizeView(alloca->getOperand(0),\n                                             getBytes(allocatedType));\n    }\n}\n\nAllocatedArea::AllocatedArea(const llvm::CallInst *call) : ptr(call) {\n    const std::string &name = call->getCalledFunction()->getName().str();\n    AnalysisOptions options;\n\n    if (options.getAllocationFunction(name) == AllocationFunction::ALLOCA ||\n        options.getAllocationFunction(name) == AllocationFunction::MALLOC) {\n        originalSizeView = AllocatedSizeView(call->getOperand(0), 1);\n    }\n\n    if (options.getAllocationFunction(name) == AllocationFunction::CALLOC) {\n        const auto *size = llvm::cast<llvm::ConstantInt>(call->getOperand(1));\n        originalSizeView =\n                AllocatedSizeView(call->getOperand(0), size->getZExtValue());\n    }\n\n    if (options.getAllocationFunction(name) == AllocationFunction::REALLOC) {\n        originalSizeView = AllocatedSizeView(call->getOperand(0), 1);\n        reallocatedPtr = call->getOperand(0);\n    }\n}\n\nstd::vector<AllocatedSizeView> AllocatedArea::getAllocatedSizeViews() const {\n    std::vector<AllocatedSizeView> result;\n    result.emplace_back(originalSizeView);\n\n    AllocatedSizeView currentView = originalSizeView;\n\n    while (const auto *op = llvm::dyn_cast<llvm::BinaryOperator>(\n                   stripCasts(currentView.elementCount))) {\n        uint64_t size = currentView.elementSize;\n\n        if (op->getOpcode() != llvm::Instruction::Add &&\n            op->getOpcode() != llvm::Instruction::Mul)\n            // TODO could also handle subtraction of negative constant\n            break;\n\n        const auto *c1 = llvm::dyn_cast<llvm::ConstantInt>(op->getOperand(0));\n        const auto *c2 = llvm::dyn_cast<llvm::ConstantInt>(op->getOperand(1));\n\n        if (c1 && c2) {\n            uint64_t newCount;\n            uint64_t newSize;\n            switch (op->getOpcode()) {\n            case llvm::Instruction::Add:\n                // XXX can these overflow?\n                newCount = c1->getValue().getZExtValue() +\n                           c2->getValue().getZExtValue();\n                result.emplace_back(\n                        llvm::ConstantInt::get(c1->getType(), newCount), size);\n                break;\n\n            case llvm::Instruction::Mul:\n                // XXX can these overflow?\n                newSize = c1->getValue().getZExtValue() * size;\n                result.emplace_back(c2, newSize);\n                newSize = c2->getValue().getZExtValue() * size;\n                result.emplace_back(c1, newSize);\n\n                newCount = c1->getValue().getZExtValue() *\n                           c2->getValue().getZExtValue();\n                result.emplace_back(\n                        llvm::ConstantInt::get(c1->getType(), newCount), size);\n                break;\n\n            default:\n                assert(0 && \"unreachable\");\n            }\n            // if we found two-constant operation, non of them can be binary\n            // operator to further unwrap\n            break;\n        }\n\n        // TODO use more info here\n        if (!c1 && !c2)\n            break;\n\n        // else one of c1, c2 is constant and the other is variable\n        const llvm::Value *param = nullptr;\n        if (c2) {\n            c1 = c2;\n            param = op->getOperand(0);\n        } else\n            param = op->getOperand(1);\n\n        // now c1 is constant and param is variable\n        assert(c1 && param);\n\n        switch (op->getOpcode()) {\n        case llvm::Instruction::Add:\n            result.emplace_back(param, size);\n            break;\n\n        case llvm::Instruction::Mul:\n            result.emplace_back(param, size * c1->getZExtValue());\n            break;\n\n        default:\n            assert(0 && \"unreachable\");\n        }\n        currentView = result.back();\n        // reachable only in this last c1 && param case\n    }\n    return result;\n}\n\n#ifndef NDEBUG\nvoid AllocatedArea::ddump() const {\n    std::cerr << \"Allocated area:\"\n              << \"\\n\";\n    std::cerr << \"    ptr \" << debug::getValName(ptr) << \"\\n\";\n    std::cerr << \"    count \"\n              << debug::getValName(originalSizeView.elementCount) << \"\\n\";\n    std::cerr << \"    size \" << originalSizeView.elementSize << \"\\n\";\n    std::cerr << \"\\n\";\n}\n#endif\n\nvoid StructureAnalyzer::categorizeEdges() {\n    for (const auto &function : module) {\n        if (function.isDeclaration())\n            continue;\n\n        for (auto it = codeGraph.dfs_begin(function); it != codeGraph.dfs_end();\n             ++it) {\n            VRLocation &current = *it;\n            VREdge *predEdge = it.getEdge();\n\n            if (predEdge)\n                predEdge->type = EdgeType::TREE;\n\n            for (unsigned i = 0; i < current.succsSize(); ++i) {\n                VREdge *succEdge = current.getSuccEdge(i);\n                VRLocation *successor = succEdge->target;\n\n                if (!successor)\n                    succEdge->type = EdgeType::TREE;\n                else if (it.wasVisited(successor)) {\n                    if (it.onStack(successor))\n                        succEdge->type = EdgeType::BACK;\n                    else\n                        succEdge->type = EdgeType::FORWARD;\n                }\n            }\n        }\n    }\n\n    codeGraph.hasCategorizedEdges();\n}\n\nvoid StructureAnalyzer::findLoops() {\n    for (const auto &function : module) {\n        if (function.isDeclaration())\n            continue;\n\n        for (auto it = codeGraph.lazy_dfs_begin(function);\n             it != codeGraph.lazy_dfs_end(); ++it) {\n            VRLocation &location = *it;\n\n            if (!location.isJustLoopJoin())\n                continue;\n\n            auto backwardReach = collectBackward(function, location);\n\n            auto &loop =\n                    inloopValues\n                            .emplace(&location,\n                                     std::vector<const llvm::Instruction *>())\n                            .first->second;\n\n            for (auto it = codeGraph.lazy_dfs_begin(function, location);\n                 it != codeGraph.lazy_dfs_end(); ++it) {\n                VRLocation &source = *it;\n\n                if (backwardReach.find(&source) == backwardReach.end())\n                    continue;\n\n                for (size_t i = 0; i < source.succsSize(); ++i) {\n                    VREdge *edge = source.getSuccEdge(i);\n                    if (!edge->target)\n                        continue;\n\n                    if (backwardReach.find(edge->target) !=\n                        backwardReach.end()) {\n                        if (edge->op->isInstruction()) {\n                            auto *op = static_cast<VRInstruction *>(\n                                    edge->op.get());\n                            loop.emplace_back(op->getInstruction());\n                        }\n                    } else\n                        location.loopEnds.emplace_back(edge);\n                }\n\n                if (&source != &location && (!source.join || location.join))\n                    source.join = &location;\n            }\n        }\n    }\n}\n\nstd::set<VRLocation *>\nStructureAnalyzer::collectBackward(const llvm::Function &f, VRLocation &from) {\n    std::vector<VREdge *> &predEdges = from.predecessors;\n\n    // remove the incoming tree edge, so that backwardReach would\n    // really go only backwards\n    VREdge *treePred = nullptr;\n    for (auto it = predEdges.begin(); it != predEdges.end(); ++it) {\n        if ((*it)->type == EdgeType::TREE) {\n            treePred = *it;\n            predEdges.erase(it);\n            break;\n        }\n    }\n    assert(treePred); // every join has to have exactly one tree predecessor\n\n    std::set<VRLocation *> result;\n    for (auto it = codeGraph.backward_dfs_begin(f, from);\n         it != codeGraph.backward_dfs_end(); ++it) {\n        result.emplace(&*it);\n    }\n\n    assert(result.find(&from) != result.end());\n\n    // put the tree edge back in\n    predEdges.emplace_back(treePred);\n\n    return result;\n}\n\nvoid StructureAnalyzer::initializeDefined() {\n    for (const llvm::Function &function : module) {\n        if (function.isDeclaration())\n            continue;\n\n        std::list<VRLocation *> toVisit = {\n                &codeGraph.getEntryLocation(function)};\n\n        // prepare sets of defined values for each location\n        for (auto &location : codeGraph) {\n            defined.emplace(&location, std::set<const llvm::Value *>());\n        }\n\n        while (!toVisit.empty()) {\n            VRLocation *current = toVisit.front();\n            toVisit.pop_front();\n\n            for (unsigned i = 0; i < current->succsSize(); ++i) {\n                VREdge *succEdge = current->getSuccEdge(i);\n\n                // if edge leads to nowhere, just continue\n                VRLocation *succLoc = succEdge->target;\n                if (!succLoc)\n                    continue;\n\n                // if edge leads back, we would add values we exactly dont\n                // want\n                if (succEdge->type == EdgeType::BACK)\n                    continue;\n\n                auto &definedSucc = defined.at(succLoc);\n                auto &definedHere = defined.at(current);\n\n                // copy from this location to its successor\n                definedSucc.insert(definedHere.begin(), definedHere.end());\n\n                // add instruction, if edge carries any\n                if (succEdge->op->isInstruction()) {\n                    auto *op = static_cast<VRInstruction *>(succEdge->op.get());\n                    definedSucc.emplace(op->getInstruction());\n                }\n\n                toVisit.push_back(succLoc);\n            }\n        }\n    }\n}\n\nvoid StructureAnalyzer::collectInstructionSet() {\n    for (unsigned opcode : collected)\n        instructionSets.emplace(opcode, std::set<const llvm::Instruction *>());\n\n    for (const llvm::Function &function : module) {\n        for (const llvm::BasicBlock &block : function) {\n            for (const llvm::Instruction &inst : block) {\n                // if we collect instructions with this opcode\n                // add it to its set\n                auto found = instructionSets.find(inst.getOpcode());\n                if (found != instructionSets.end())\n                    found->second.emplace(&inst);\n            }\n        }\n    }\n}\n\nbool StructureAnalyzer::isValidAllocationCall(const llvm::Value *val) {\n    if (!llvm::isa<llvm::CallInst>(val))\n        return false;\n\n    const llvm::CallInst *call = llvm::cast<llvm::CallInst>(val);\n    const auto *function = call->getCalledFunction();\n\n    AnalysisOptions options;\n    return function &&\n           options.isAllocationFunction(function->getName().str()) &&\n           (options.getAllocationFunction(function->getName().str()) !=\n                    AllocationFunction::CALLOC ||\n            llvm::isa<llvm::ConstantInt>(call->getOperand(1)));\n}\n\nvoid StructureAnalyzer::collectAllocatedAreas() {\n    // compute allocated areas throughout the code\n    for (const llvm::Function &function : module) {\n        for (const llvm::BasicBlock &block : function) {\n            for (const llvm::Instruction &inst : block) {\n                if (const auto *alloca =\n                            llvm::dyn_cast<llvm::AllocaInst>(&inst)) {\n                    allocatedAreas.emplace_back(alloca);\n                }\n\n                else if (const auto *call =\n                                 llvm::dyn_cast<llvm::CallInst>(&inst)) {\n                    if (isValidAllocationCall(call)) {\n                        allocatedAreas.emplace_back(call);\n                    }\n                }\n            }\n        }\n    }\n}\n\nvoid StructureAnalyzer::setValidAreasFromNoPredecessors(\n        std::vector<bool> &validAreas) const {\n    validAreas = std::vector<bool>(allocatedAreas.size(), false);\n}\n\nstd::pair<unsigned, const AllocatedArea *>\nStructureAnalyzer::getEqualArea(const ValueRelations &graph,\n                                const llvm::Value *ptr) const {\n    unsigned index = 0;\n    const AllocatedArea *area = nullptr;\n    for (const auto *equal : graph.getEqual(ptr)) {\n        std::tie(index, area) = getAllocatedAreaFor(equal);\n        if (area)\n            return {index, area};\n    }\n    return {0, nullptr};\n}\n\nvoid StructureAnalyzer::invalidateHeapAllocatedAreas(\n        std::vector<bool> &validAreas) const {\n    unsigned index = 0;\n    for (const AllocatedArea &area : allocatedAreas) {\n        if (llvm::isa<llvm::CallInst>(area.getPtr()))\n            validAreas[index] = false;\n        ++index;\n    }\n}\n\nvoid StructureAnalyzer::setValidAreasByInstruction(\n        VRLocation &location, std::vector<bool> &validAreas,\n        VRInstruction *vrinst) const {\n    const llvm::Instruction *inst = vrinst->getInstruction();\n    unsigned index = 0;\n    const AllocatedArea *area = nullptr;\n\n    // every memory allocated on stack is considered allocated successfully\n    if (llvm::isa<llvm::AllocaInst>(inst)) {\n        std::tie(index, area) = getAllocatedAreaFor(inst);\n        assert(area);\n        validAreas[index] = true;\n    }\n\n    // if came across lifetime_end call, then mark memory whose scope ended\n    // invalid\n    if (const auto *intrinsic = llvm::dyn_cast<llvm::IntrinsicInst>(inst)) {\n        if (intrinsic->getIntrinsicID() == llvm::Intrinsic::lifetime_end) {\n            std::tie(index, area) =\n                    getEqualArea(location.relations, intrinsic->getOperand(1));\n            assert(area);\n            validAreas[index] = false;\n        }\n    }\n\n    if (const auto *call = llvm::dyn_cast<llvm::CallInst>(inst)) {\n        auto *function = call->getCalledFunction();\n\n        if (!function)\n            return;\n\n        AnalysisOptions options;\n        if (options.getAllocationFunction(function->getName().str()) ==\n            AllocationFunction::REALLOC) {\n            // if realloc of memory occured, the reallocated memory cannot\n            // be considered valid until the realloc is proven unsuccessful\n            std::tie(index, area) =\n                    getEqualArea(location.relations, call->getOperand(0));\n            if (area)\n                validAreas[index] = false;\n            else if (!llvm::isa<llvm::ConstantPointerNull>(\n                             call->getOperand(0))) {\n                // else we do not know which area has been reallocated and\n                // thus possibly invalidated, so it may have been any of\n                // them\n                invalidateHeapAllocatedAreas(validAreas);\n            }\n        }\n\n        if (function->getName().equals(\"free\")) {\n            // if free occures, the freed memory cannot be considered valid\n            // anymore\n            std::tie(index, area) =\n                    getEqualArea(location.relations, call->getOperand(0));\n\n            if (area)\n                validAreas[index] = false;\n            else if (!llvm::isa<llvm::ConstantPointerNull>(\n                             call->getOperand(0))) {\n                // else we do not know which area has been freed, so it may\n                // have been any of them\n                invalidateHeapAllocatedAreas(validAreas);\n            }\n        }\n    }\n}\n\nvoid StructureAnalyzer::setValidArea(std::vector<bool> &validAreas,\n                                     const AllocatedArea *area, unsigned index,\n                                     bool validateThis) const {\n    unsigned preReallocIndex = 0;\n    const AllocatedArea *preReallocArea = nullptr;\n    if (area->getReallocatedPtr())\n        std::tie(preReallocIndex, preReallocArea) =\n                getAllocatedAreaFor(area->getReallocatedPtr());\n\n    if (validateThis) {\n        validAreas[index] = true;\n        if (preReallocArea)\n            assert(!validAreas[preReallocIndex]);\n\n        // else the original area, if any, should be validated\n    } else if (preReallocArea) {\n        validAreas[preReallocIndex] = true;\n        assert(!validAreas[index]);\n    }\n}\n\n// if heap allocation call was just checked as successful, mark memory valid\nvoid StructureAnalyzer::setValidAreasByAssumeBool(VRLocation &location,\n                                                  std::vector<bool> &validAreas,\n                                                  VRAssumeBool *assume) const {\n    const auto *icmp = llvm::dyn_cast<llvm::ICmpInst>(assume->getValue());\n    if (!icmp)\n        return;\n\n    const auto *c1 = llvm::dyn_cast<llvm::ConstantInt>(icmp->getOperand(0));\n    const auto *c2 = llvm::dyn_cast<llvm::ConstantInt>(icmp->getOperand(1));\n\n    // pointer must be compared to zero // TODO? or greater\n    if ((c1 && c2) || (!c1 && !c2) || (!c1 && !c2->isZero()) ||\n        (!c2 && !c1->isZero()))\n        return;\n\n    // get the compared parameter\n    const llvm::Value *param = c1 ? icmp->getOperand(1) : icmp->getOperand(0);\n\n    unsigned index = 0;\n    const AllocatedArea *area = nullptr;\n\n    for (const auto *equal : location.relations.getEqual(param)) {\n        std::tie(index, area) = getAllocatedAreaFor(equal);\n        // if compared pointer or equal belong to allocated area, this area\n        // can be marked valid\n        if (area)\n            break;\n    }\n    // the compared value is not a pointer to an allocated area\n    if (!area)\n        return;\n\n    llvm::ICmpInst::Predicate pred = assume->getAssumption()\n                                             ? icmp->getSignedPredicate()\n                                             : icmp->getInversePredicate();\n\n    // check that predicate implies wanted relation\n    switch (pred) {\n    case llvm::ICmpInst::Predicate::ICMP_EQ:\n        // if reallocated pointer is equal to zero, then original memory is\n        // still valid\n        setValidArea(validAreas, area, index, false);\n        return;\n\n    case llvm::ICmpInst::Predicate::ICMP_NE:\n        // pointer is not equal to zero, therefore it a valid result of heap\n        // allocation\n        setValidArea(validAreas, area, index, true);\n        return;\n\n    case llvm::ICmpInst::Predicate::ICMP_ULT:\n    case llvm::ICmpInst::Predicate::ICMP_SLT:\n        // if zero stands right to </<=, this proves invalidity\n        if (c2)\n            setValidArea(validAreas, area, index, false);\n        else\n            setValidArea(validAreas, area, index, true);\n        return;\n\n    case llvm::ICmpInst::Predicate::ICMP_UGT:\n    case llvm::ICmpInst::Predicate::ICMP_SGT:\n        // if zero stands left to >/>=, this proves invalidity\n        if (c1)\n            setValidArea(validAreas, area, index, false);\n        else\n            setValidArea(validAreas, area, index, true);\n        return;\n\n    case llvm::ICmpInst::Predicate::ICMP_ULE:\n    case llvm::ICmpInst::Predicate::ICMP_SLE:\n    case llvm::ICmpInst::Predicate::ICMP_UGE:\n    case llvm::ICmpInst::Predicate::ICMP_SGE:\n        // nothing to infer here, we do not get the information, whether\n        // pointer is zero or not\n        return;\n\n    default:\n        assert(0 && \"unreachable, would have failed in processICMP\");\n    }\n}\n\nvoid StructureAnalyzer::setValidAreasFromSinglePredecessor(\n        VRLocation &location, std::vector<bool> &validAreas) const {\n    // copy predecessors valid areas\n    VREdge *edge = location.getPredEdge(0);\n    validAreas = edge->source->relations.getValidAreas();\n\n    // and alter them according to info from edge\n    if (edge->op->isInstruction())\n        setValidAreasByInstruction(\n                location, validAreas,\n                static_cast<VRInstruction *>(edge->op.get()));\n\n    if (edge->op->isAssumeBool())\n        setValidAreasByAssumeBool(location, validAreas,\n                                  static_cast<VRAssumeBool *>(edge->op.get()));\n}\n\nbool StructureAnalyzer::trueInAll(\n        const std::vector<std::vector<bool>> &validInPreds, unsigned index) {\n    for (const auto &validInPred : validInPreds) {\n        if (validInPred.empty() || !validInPred[index])\n            return false;\n    }\n    return true;\n}\n\n// in returned vector, false signifies that corresponding area is\n// invalidated by some of the passed instructions\nstd::vector<bool> StructureAnalyzer::getInvalidatedAreas(\n        const std::vector<const llvm::Instruction *> &instructions) const {\n    std::vector<bool> validAreas(allocatedAreas.size(), true);\n\n    for (const llvm::Instruction *inst : instructions) {\n        VRLocation &location = codeGraph.getVRLocation(inst);\n        VRInstruction vrinst(inst);\n\n        setValidAreasByInstruction(location, validAreas, &vrinst);\n    }\n    return validAreas;\n}\n\nvoid StructureAnalyzer::setValidAreasFromMultiplePredecessors(\n        VRLocation &location, std::vector<bool> &validAreas) const {\n    std::vector<std::vector<bool>> validInPreds;\n\n    if (!location.isJustLoopJoin()) {\n        for (VREdge *predEdge : location.predecessors)\n            validInPreds.emplace_back(\n                    predEdge->source->relations.getValidAreas());\n    } else {\n        VRLocation *treePred = nullptr;\n        for (VREdge *predEdge : location.predecessors) {\n            if (predEdge->type == EdgeType::TREE) {\n                treePred = predEdge->source;\n                break;\n            }\n        }\n        assert(treePred);\n\n        validInPreds.emplace_back(treePred->relations.getValidAreas());\n        validInPreds.emplace_back(\n                getInvalidatedAreas(inloopValues.at(&location)));\n    }\n\n    // intersect valid areas from predecessors\n    for (unsigned i = 0; i < allocatedAreas.size(); ++i) {\n        validAreas.push_back(trueInAll(validInPreds, i));\n    }\n}\n\nvoid StructureAnalyzer::computeValidAreas() const {\n    for (auto &location : codeGraph) {\n        std::vector<bool> &validAreas = location.relations.getValidAreas();\n\n        switch (location.predsSize()) {\n        case 0:\n            setValidAreasFromNoPredecessors(validAreas);\n            break;\n        case 1:\n            setValidAreasFromSinglePredecessor(location, validAreas);\n            break;\n        default:\n            setValidAreasFromMultiplePredecessors(location, validAreas);\n            break;\n        }\n    }\n}\n\nvoid StructureAnalyzer::initializeCallRelations() {\n    for (const llvm::Function &function : module) {\n        if (function.isDeclaration())\n            continue;\n\n        auto pair = callRelationsMap.emplace(&function,\n                                             std::vector<CallRelation>());\n\n        // for each location, where the function is called\n        for (const llvm::Value *user : function.users()) {\n            // get call from user\n            const llvm::CallInst *call = llvm::dyn_cast<llvm::CallInst>(user);\n            if (!call)\n                continue;\n\n            std::vector<CallRelation> &callRelations = pair.first->second;\n\n            callRelations.emplace_back();\n            CallRelation &callRelation = callRelations.back();\n\n            // set pointer to the location from which the function is called\n            callRelation.callSite = &codeGraph.getVRLocation(call);\n\n            // set formal parameters equal to real\n            unsigned argCount = 0;\n            for (const llvm::Argument &formalArg : function.args()) {\n                if (argCount >= llvmutils::getNumArgOperands(call))\n                    break;\n                const llvm::Value *realArg = call->getArgOperand(argCount);\n\n                callRelation.equalPairs.emplace_back(&formalArg, realArg);\n                ++argCount;\n            }\n        }\n    }\n}\n\nvoid StructureAnalyzer::analyzeBeforeRelationsAnalysis() {\n    categorizeEdges();\n    findLoops();\n    collectInstructionSet();\n    initializeCallRelations();\n    // initializeDefined(m, blcs);\n}\n\nvoid StructureAnalyzer::analyzeAfterRelationsAnalysis() {\n    collectAllocatedAreas();\n    computeValidAreas();\n}\n\nbool StructureAnalyzer::isDefined(VRLocation *loc,\n                                  const llvm::Value *val) const {\n    if (llvm::isa<llvm::Constant>(val))\n        return true;\n\n    auto definedHere = defined.at(loc);\n    return definedHere.find(val) != definedHere.end();\n}\n\nstd::vector<const VREdge *>\nStructureAnalyzer::possibleSources(const llvm::PHINode *phi, bool bval) const {\n    std::vector<const VREdge *> result;\n    for (unsigned i = 0; i < phi->getNumIncomingValues(); ++i) {\n        const llvm::Value *val = phi->getIncomingValue(i);\n        const auto *cVal = llvm::dyn_cast<llvm::ConstantInt>(val);\n\n        if (!cVal || (cVal->isOne() && bval) || (cVal->isZero() && !bval)) {\n            const auto *block = phi->getIncomingBlock(i);\n            const VRLocation &end = codeGraph.getVRLocation(\n                    &*std::prev(std::prev(block->end())));\n            assert(end.succsSize() == 1);\n            result.emplace_back(end.getSuccEdge(0));\n        }\n    }\n    return result;\n}\n\nstd::vector<const llvm::ICmpInst *>\nStructureAnalyzer::getRelevantConditions(const VRAssumeBool *assume) const {\n    if (const auto *icmp = llvm::dyn_cast<llvm::ICmpInst>(assume->getValue()))\n        return {icmp};\n\n    const auto *phi = llvm::dyn_cast<llvm::PHINode>(assume->getValue());\n    if (!phi)\n        return {};\n\n    std::vector<const llvm::ICmpInst *> result;\n    std::vector<const llvm::PHINode *> to_process{phi};\n\n    while (!to_process.empty()) {\n        const auto *phi = to_process.back();\n        to_process.pop_back();\n\n        for (const auto *sourceEdge :\n             possibleSources(phi, assume->getAssumption())) {\n            assert(sourceEdge->op->isInstruction());\n            const llvm::Instruction *inst =\n                    static_cast<const VRInstruction *>(sourceEdge->op.get())\n                            ->getInstruction();\n            if (const auto *icmp = llvm::dyn_cast<llvm::ICmpInst>(inst))\n                result.emplace_back(icmp);\n            else if (const auto *phi = llvm::dyn_cast<llvm::PHINode>(inst))\n                to_process.emplace_back(phi);\n            else\n                return {};\n        }\n    }\n    return result;\n}\n\nstd::pair<unsigned, const AllocatedArea *>\nStructureAnalyzer::getAllocatedAreaFor(const llvm::Value *ptr) const {\n    unsigned i = 0;\n    for (const auto &area : allocatedAreas) {\n        if (area.getPtr() == ptr)\n            return {i, &area};\n        ++i;\n    }\n    return {0, nullptr};\n}\n\nconst std::vector<CallRelation> &\nStructureAnalyzer::getCallRelationsFor(const llvm::Instruction *inst) const {\n#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 7\n    const llvm::Function *function = inst->getParent()->getParent();\n#else\n    const llvm::Function *function = inst->getFunction();\n#endif\n    assert(function);\n    return callRelationsMap.at(function);\n}\n\nvoid StructureAnalyzer::addPrecondition(const llvm::Function *func,\n                                        const llvm::Argument *lt,\n                                        Relations::Type rel,\n                                        const llvm::Value *rt) {\n    preconditionsMap[func].emplace_back(lt, rel, rt);\n}\n\nbool StructureAnalyzer::hasPreconditions(const llvm::Function *func) const {\n    return preconditionsMap.find(func) != preconditionsMap.end();\n}\n\nconst std::vector<Precondition> &\nStructureAnalyzer::getPreconditionsFor(const llvm::Function *func) const {\n    assert(preconditionsMap.find(func) != preconditionsMap.end());\n    return preconditionsMap.find(func)->second;\n}\n\nsize_t StructureAnalyzer::addBorderValue(const llvm::Function *func,\n                                         const llvm::Argument *from,\n                                         const llvm::Value *stored) {\n    auto &borderVals = borderValues[func];\n    auto id = borderVals.size();\n    borderVals.emplace_back(id, from, stored);\n    return id;\n}\n\nbool StructureAnalyzer::hasBorderValues(const llvm::Function *func) const {\n    return borderValues.find(func) != borderValues.end();\n}\n\nconst std::vector<BorderValue> &\nStructureAnalyzer::getBorderValuesFor(const llvm::Function *func) const {\n    assert(hasBorderValues(func));\n    return borderValues.find(func)->second;\n}\n\nBorderValue StructureAnalyzer::getBorderValueFor(const llvm::Function *func,\n                                                 size_t id) const {\n    for (const auto &bv : getBorderValuesFor(func)) {\n        if (bv.id == id)\n            return bv;\n    }\n    assert(0 && \"unreachable\");\n    abort();\n}\n\n#ifndef NDEBUG\nvoid StructureAnalyzer::dumpBorderValues(std::ostream &out) const {\n    out << \"[ \\n\";\n    for (auto &foo : borderValues) {\n        out << \"    \" << foo.first->getName().str() << \": \";\n        for (auto &bv : foo.second)\n            out << \"(\"\n                << \"id \" << bv.id << \", \"\n                << \"from \" << debug::getValName(bv.from) << \", \"\n                << \"stored \" << debug::getValName(bv.stored) << \"), \";\n    }\n    out << \"\\n]\\n\";\n}\n#endif\n\n} // namespace vr\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/ValueRelations/ValueRelations.cpp",
    "content": "#include \"dg/llvm/ValueRelations/ValueRelations.h\"\n#ifndef NDEBUG\n#include <iostream>\n#endif\nnamespace dg {\nnamespace vr {\n\n// *********************** general between *************************** //\nRelations ValueRelations::_between(Handle lt, Handle rt) const {\n    Relations result = graph.getRelated(lt, allRelations)[rt];\n    if (result.any())\n        return result;\n    result = _between(lt, getInstance<llvm::ConstantInt>(rt));\n    if (result.any())\n        return result;\n    return _between(getInstance<llvm::ConstantInt>(lt), rt);\n}\nRelations ValueRelations::_between(Handle lt, V rt) const {\n    HandlePtr mRt = maybeGet(rt);\n    if (mRt)\n        return _between(lt, *mRt);\n\n    return _between(lt, llvm::dyn_cast<BareC>(rt));\n}\nRelations ValueRelations::_between(Handle lt, C cRt) const {\n    if (!cRt)\n        return {};\n\n    for (Relations::Type rel :\n         {Relations::SLE, Relations::ULE, Relations::SGE, Relations::UGE}) {\n        C boundLt;\n        Relations relsLt;\n        std::tie(boundLt, relsLt) = getBound(lt, Relations().set(rel));\n\n        if (!boundLt)\n            continue;\n\n        Relations relsBound = compare(boundLt, cRt);\n        // lt <= boundLt <= cRt || lt >= boundLt >= cRt\n        if (relsBound.has(rel))\n            return compose(relsLt, relsBound);\n    }\n    return {};\n}\nRelations ValueRelations::_between(V lt, Handle rt) const {\n    return _between(rt, lt).invert();\n}\nRelations ValueRelations::_between(C lt, Handle rt) const {\n    return _between(rt, lt).invert();\n}\nRelations ValueRelations::_between(V lt, V rt) const {\n    if (lt == rt)\n        return Relations().eq().addImplied();\n\n    if (HandlePtr mLt = maybeGet(lt))\n        return _between(*mLt, rt);\n\n    if (HandlePtr mRt = maybeGet(rt))\n        return _between(llvm::dyn_cast<BareC>(lt), *mRt);\n\n    C cLt = llvm::dyn_cast<BareC>(lt);\n    C cRt = llvm::dyn_cast<BareC>(rt);\n\n    if (!cLt || !cRt)\n        return {};\n    return compare(cLt, cRt);\n}\n\nRelations ValueRelations::_between(Handle lt, size_t rt) const {\n    HandlePtr mH = getBorderH(rt);\n    return mH ? _between(lt, *mH) : Relations();\n}\nRelations ValueRelations::_between(V lt, size_t rt) const {\n    HandlePtr mH = getBorderH(rt);\n    return mH ? _between(lt, *mH) : Relations();\n}\n\n// *************************** iterators ****************************** //\nValueRelations::rel_iterator\nValueRelations::begin_related(V val, const Relations &rels) const {\n    assert(valToBucket.find(val) != valToBucket.end());\n    Handle h = valToBucket.find(val)->second;\n    return {*this, h, rels};\n}\n\nValueRelations::rel_iterator ValueRelations::end_related(V /*val*/) const {\n    return rel_iterator(*this);\n}\n\nValueRelations::RelGraph::iterator\nValueRelations::begin_related(Handle h, const Relations &rels) const {\n    return graph.begin_related(h, rels);\n}\n\nValueRelations::RelGraph::iterator ValueRelations::end_related(Handle h) const {\n    return graph.end_related(h);\n}\n\nValueRelations::plain_iterator ValueRelations::begin() const {\n    return {bucketToVals.begin(), bucketToVals.end()};\n}\n\nValueRelations::plain_iterator ValueRelations::end() const {\n    return {bucketToVals.end()};\n}\n\nValueRelations::RelGraph::iterator\nValueRelations::begin_buckets(const Relations &rels) const {\n    return graph.begin(rels);\n}\n\nValueRelations::RelGraph::iterator ValueRelations::end_buckets() const {\n    return graph.end();\n}\n\n// ****************************** get ********************************* //\nValueRelations::HandlePtr ValueRelations::maybeGet(V val) const {\n    auto found = valToBucket.find(val);\n    return (found == valToBucket.end() ? nullptr : &found->second.get());\n}\n\nstd::pair<ValueRelations::BRef, bool> ValueRelations::get(size_t id) {\n    HandlePtr mH = getBorderH(id);\n    return {mH ? *mH : newBorderBucket(id), false};\n}\n\nstd::pair<ValueRelations::BRef, bool> ValueRelations::get(V val) {\n    if (HandlePtr mh = maybeGet(val))\n        return {*mh, false};\n    Handle newH = graph.getNewBucket();\n    return add(val, newH);\n}\n\nValueRelations::V ValueRelations::getAny(Handle h) const {\n    auto found = bucketToVals.find(h);\n    assert(found != bucketToVals.end() && !found->second.empty());\n    return *found->second.begin();\n}\n\nValueRelations::C ValueRelations::getAnyConst(Handle h) const {\n    for (V val : bucketToVals.find(h)->second) {\n        if (C c = llvm::dyn_cast<BareC>(val))\n            return c;\n    }\n    return nullptr;\n}\n\nconst VectorSet<ValueRelations::V> &ValueRelations::getEqual(Handle h) const {\n    return bucketToVals.find(h)->second;\n}\n\nVectorSet<ValueRelations::V> ValueRelations::getEqual(V val) const {\n    HandlePtr mH = maybeGet(val);\n    if (!mH)\n        return {val};\n    return getEqual(*mH);\n}\n\nstd::vector<ValueRelations::V>\nValueRelations::getDirectlyRelated(V val, const Relations &rels) const {\n    HandlePtr mH = maybeGet(val);\n    if (!mH)\n        return {};\n    RelationsMap related = graph.getRelated(*mH, rels, true);\n\n    std::vector<ValueRelations::V> result;\n    std::transform(related.begin(), related.end(), std::back_inserter(result),\n                   [this](const RelationsMap::value_type &pair) {\n                       return this->getAny(pair.first);\n                   });\n    return result;\n}\n\nstd::pair<ValueRelations::C, Relations>\nValueRelations::getBound(Handle h, Relations rels) const {\n    RelationsMap related = graph.getRelated(h, rels);\n\n    C resultC = nullptr;\n    Relations resultR;\n    for (const auto &pair : related) {\n        C c = getAnyConst(pair.first);\n        if (c && (!resultC || compare(c, rels, resultC))) {\n            resultC = c;\n            resultR = pair.second;\n        }\n    }\n\n    return {resultC, resultR};\n}\n\nstd::pair<ValueRelations::C, Relations>\nValueRelations::getBound(V val, Relations rel) const {\n    HandlePtr mH = maybeGet(val);\n    if (!mH)\n        return {llvm::dyn_cast<BareC>(val), Relations().eq()};\n\n    return getBound(*mH, rel);\n}\n\nValueRelations::C ValueRelations::getLesserEqualBound(V val) const {\n    return getLowerBound(val).first;\n}\n\nValueRelations::C ValueRelations::getGreaterEqualBound(V val) const {\n    return getUpperBound(val).first;\n}\n\nValueRelations::HandlePtr ValueRelations::getHandleByPtr(Handle h) {\n    if (!h.hasRelation(Relations::PT))\n        return nullptr;\n    return &h.getRelated(Relations::PT);\n}\n\nVectorSet<ValueRelations::V> ValueRelations::getValsByPtr(V from) const {\n    HandlePtr mH = maybeGet(from);\n    if (!mH)\n        return {};\n    HandlePtr toH = getHandleByPtr(*mH);\n    if (!toH)\n        return {};\n    return getEqual(*toH);\n}\n\nValueRelations::HandlePtr ValueRelations::getHandle(V val) const {\n    return maybeGet(val);\n}\n\n// ************************** placeholder ***************************** //\nvoid ValueRelations::erasePlaceholderBucket(Handle h) {\n    auto found = bucketToVals.find(h);\n    assert(found != bucketToVals.end());\n    for (V val : found->second) {\n        assert(valToBucket.find(val) != valToBucket.end() &&\n               valToBucket.at(val) == h);\n        valToBucket.erase(val);\n    }\n    bucketToVals.erase(h);\n    graph.erase(h);\n}\n\n// ***************************** other ******************************** //\nbool ValueRelations::compare(C lt, Relations::Type rel, C rt) {\n    return compare(lt, rt).has(rel);\n}\n\nbool ValueRelations::compare(C lt, Relations rels, C rt) {\n    return compare(lt, rt).anyCommon(rels);\n}\n\nRelations ValueRelations::compare(C lt, C rt) {\n    // ignore bool values\n    if ((lt->getBitWidth() == 1 || rt->getBitWidth() == 1) &&\n        lt->getBitWidth() != rt->getBitWidth())\n        return {};\n    int64_t isLt = lt->getSExtValue();\n    int64_t isRt = rt->getSExtValue();\n    Relations result;\n    if (isLt < isRt)\n        result.slt();\n    else if (isLt > isRt)\n        result.sgt();\n    else\n        result.eq();\n\n    // possible to collect unsigned relations between constants here\n\n    return result.addImplied();\n}\n\nbool ValueRelations::holdsAnyRelations() const {\n    return !valToBucket.empty() && !graph.empty();\n}\n\nValueRelations::HandlePtr\nValueRelations::getCorresponding(const ValueRelations &other, Handle otherH,\n                                 const VectorSet<V> &otherEqual) {\n    if (otherEqual.empty()) { // other is a placeholder bucket, therefore it is\n                              // pointed to from other bucket\n        if (!otherH.hasRelation(Relations::PF)) {\n            HandlePtr thisH = getBorderH(other.getBorderId(otherH));\n            return thisH ? thisH : &newBorderBucket(other.getBorderId(otherH));\n        }\n        assert(otherH.hasRelation(Relations::PF));\n        Handle otherFromH = otherH.getRelated(Relations::PF);\n        HandlePtr thisFromH = getCorresponding(other, otherFromH);\n        if (!thisFromH)\n            return nullptr;\n\n        Handle h = newPlaceholderBucket(*thisFromH);\n        bool ch = graph.addRelation(*thisFromH, Relations::PT, h);\n        updateChanged(ch);\n        return &h;\n    }\n\n    // otherwise find unique handle for all equal elements from other\n    HandlePtr mH = nullptr;\n    for (V val : otherEqual) {\n        HandlePtr oH = maybeGet(val);\n        if (!mH) // first handle found\n            mH = oH;\n        else if (oH && oH != mH) { // found non-equal handle in this\n            if (hasConflictingRelation(*oH, *mH, Relations::EQ))\n                return nullptr;\n            set(*oH, Relations::EQ, *mH);\n            mH = maybeGet(val); // update possibly invalidated handle\n            assert(mH);\n        }\n    }\n    return mH ? mH : &add(otherEqual.any(), graph.getNewBucket()).first.get();\n}\n\nValueRelations::HandlePtr\nValueRelations::getCorresponding(const ValueRelations &other, Handle otherH) {\n    return getCorresponding(other, otherH, other.getEqual(otherH));\n}\n\nValueRelations::HandlePtr\nValueRelations::getAndMerge(const ValueRelations &other, Handle otherH) {\n    const VectorSet<V> &otherEqual = other.getEqual(otherH);\n    HandlePtr thisH = getCorresponding(other, otherH, otherEqual);\n\n    if (!thisH)\n        return nullptr;\n\n    size_t borderId = other.getBorderId(otherH);\n    if (borderId != std::string::npos)\n        graph.makeBorderBucket(*thisH, borderId);\n\n    for (V val : otherEqual)\n        add(val, *thisH);\n\n    return thisH;\n}\n\nbool ValueRelations::merge(const ValueRelations &other, Relations relations) {\n    bool noConflict = true;\n    for (const auto &edge : other.graph) {\n        if (!relations.has(edge.rel()) ||\n            (edge.rel() == Relations::EQ && !other.hasEqual(edge.to())))\n            continue;\n\n        HandlePtr thisToH = getAndMerge(other, edge.to());\n        HandlePtr thisFromH = getCorresponding(other, edge.from());\n\n        if (!thisToH || !thisFromH ||\n            graph.haveConflictingRelation(*thisFromH, edge.rel(), *thisToH)) {\n            noConflict = false;\n            continue;\n        }\n\n        bool ch = graph.addRelation(*thisFromH, edge.rel(), *thisToH);\n        updateChanged(ch);\n    }\n    return noConflict;\n}\n\nvoid ValueRelations::add(V val, Handle h, VectorSet<V> &vals) {\n    ValToBucket::iterator it = valToBucket.lower_bound(val);\n    // val already bound to a handle\n    if (it != valToBucket.end() && !(valToBucket.key_comp()(val, it->first))) {\n        // it is already bound to passed handle\n        if (it->second == h)\n            return;\n        V oldVal = it->first;\n        Handle oldH = it->second;\n        assert(bucketToVals.find(oldH) != bucketToVals.end());\n        assert(bucketToVals.at(oldH).find(oldVal) !=\n               bucketToVals.at(oldH).end());\n        bucketToVals.find(oldH)->second.erase(oldVal);\n        it->second = h;\n    } else\n        valToBucket.emplace_hint(it, val, h);\n\n    assert(valToBucket.find(val)->second == h);\n    vals.emplace(val);\n    updateChanged(true);\n}\n\nstd::pair<ValueRelations::BRef, bool> ValueRelations::add(V val, Handle h) {\n    add(val, h, bucketToVals[h]);\n\n    C c = llvm::dyn_cast<BareC>(val);\n    if (!c)\n        return {h, false};\n\n    for (auto &pair : bucketToVals) {\n        if (pair.second.empty())\n            continue;\n\n        Handle otherH = pair.first;\n        if (C otherC = getAnyConst(otherH)) {\n            if (compare(c, Relations::EQ, otherC)) {\n                graph.addRelation(h, Relations::EQ, otherH);\n                assert(valToBucket.find(val) != valToBucket.end());\n                return {valToBucket.find(val)->second, true};\n            }\n        }\n    }\n\n    return {h, false};\n}\n\nvoid ValueRelations::areMerged(Handle to, Handle from) {\n    VectorSet<V> &toVals = bucketToVals.find(to)->second;\n    assert(bucketToVals.find(from) != bucketToVals.end());\n    const VectorSet<V> fromVals = bucketToVals.find(from)->second;\n\n    for (V val : fromVals)\n        add(val, to, toVals);\n\n    assert(bucketToVals.at(from).empty());\n    bucketToVals.erase(from);\n}\n\nValueRelations::HandlePtr ValueRelations::getBorderH(size_t id) const {\n    return graph.getBorderB(id);\n}\n\nsize_t ValueRelations::getBorderId(Handle h) const {\n    return graph.getBorderId(h);\n}\n\nstd::string strip(std::string str, size_t skipSpaces) {\n    assert(!str.empty() && !std::isspace(str[0]));\n\n    size_t lastIndex = 0;\n    for (size_t i = 0; i < skipSpaces; ++i) {\n        size_t nextIndex = str.find(' ', lastIndex + 1);\n        if (nextIndex == std::string::npos)\n            return str;\n        lastIndex = nextIndex;\n    }\n    return str.substr(0, lastIndex);\n}\n\n#ifndef NDEBUG\nvoid ValueRelations::dump(ValueRelations::Handle h, std::ostream &out) const {\n    auto found = bucketToVals.find(h);\n    assert(found != bucketToVals.end());\n    const VectorSet<ValueRelations::V> &vals = found->second;\n\n    out << \"{{ \";\n    if (vals.empty())\n        out << \"placeholder \" << h.id << \" \";\n    else\n        for (ValueRelations::V val : vals)\n            out << (val == *vals.begin() ? \"\" : \" | \")\n                << strip(debug::getValName(val), 4);\n    out << \" }}\";\n}\n\nvoid ValueRelations::dotDump(std::ostream &out) const {\n    out << \"digraph G {\\n\";\n    for (auto it = begin_buckets(Relations().eq().slt().sle().ult().ule().pt());\n         it != end_buckets(); ++it) {\n        out << \"  RNODE\" << it->from().id << \" [label=\\\"\" << it->from().id\n            << \": \";\n        dump(it->from(), out);\n        out << \"\\\"]; \";\n        if (it->rel() != Relations::EQ)\n            out << \"  RNODE\" << it->from().id << \" -> \"\n                << \"RNODE\" << it->to().id << \" [label=\\\"\" << it->rel()\n                << \"\\\"];\";\n    }\n    out << \"}\\n\";\n}\n\nstd::ostream &operator<<(std::ostream &out, const ValueRelations &vr) {\n    for (const auto &edge : vr.graph) {\n        if (edge.rel() == Relations::EQ) {\n            if (!edge.to().hasAnyRelation()) {\n                out << \"              \";\n                vr.dump(edge.to(), out);\n                out << \"\\n\";\n            }\n            continue;\n        }\n        out << \"    \" << edge << \"    \";\n        vr.dump(edge.from(), out);\n        out << \" \" << edge.rel() << \" \";\n        vr.dump(edge.to(), out);\n        out << \"\\n\";\n    }\n    vr.graph.dumpBorderBuckets(out);\n    return out;\n}\n#endif\n} // namespace vr\n} // namespace dg\n"
  },
  {
    "path": "lib/llvm/llvm-utils.h",
    "content": "#ifndef DG_LLVM_UTILS_H_\n#define DG_LLVM_UTILS_H_\n\n#include <llvm/ADT/iterator_range.h>\n#include <llvm/IR/DataLayout.h>\n#include <llvm/IR/Function.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/IntrinsicInst.h>\n#include <llvm/IR/Type.h>\n#include <llvm/Support/raw_ostream.h>\n\n#include \"dg/Offset.h\"\n\nnamespace dg {\nnamespace llvmutils {\n\nusing namespace llvm;\n\n/* ----------------------------------------------\n * -- COMPAT\n * ---------------------------------------------- */\n\n// FIXME: Remove this when LLVM 8 is the minimal version for DG!\ninline iterator_range<User::op_iterator> args(CallInst *CI) {\n    return make_range(CI->arg_begin(), CI->arg_end());\n}\n\ninline iterator_range<User::const_op_iterator> args(const CallInst *CI) {\n    return make_range(CI->arg_begin(), CI->arg_end());\n}\n\ninline iterator_range<User::op_iterator> args(CallInst &CI) {\n    return args(&CI);\n}\n\ninline iterator_range<User::const_op_iterator> args(const CallInst &CI) {\n    return args(&CI);\n}\n\ninline unsigned getNumArgOperands(const CallInst *CI) {\n#if LLVM_VERSION_MAJOR >= 8\n    return CI->arg_size();\n#else\n    return CI->getNumArgOperands();\n#endif\n}\n\ninline unsigned getNumArgOperands(const CallInst &CI) {\n    return getNumArgOperands(&CI);\n}\n\n/* ----------------------------------------------\n * -- PRINTING\n * ---------------------------------------------- */\ninline void print(const Value *val, raw_ostream &os,\n                  const char *prefix = nullptr, bool newline = false) {\n    if (prefix)\n        os << prefix;\n\n    if (isa<Function>(val))\n        os << val->getName().data();\n    else\n        os << *val;\n\n    if (newline)\n        os << \"\\n\";\n}\n\ninline void printerr(const char *msg, const Value *val, bool newline = true) {\n    print(val, errs(), msg, newline);\n}\n\n/* ----------------------------------------------\n * -- CASTING\n * ---------------------------------------------- */\ninline bool isPointerOrIntegerTy(const Type *Ty) {\n    return Ty->isPointerTy() || Ty->isIntegerTy();\n}\n\n// can the given function be called by the given call inst?\nenum class CallCompatibility {\n    STRICT,       // require full compatibility\n    LOOSE,        // ignore some incompatible patterns that usually work\n                  // in practice, e.g., calling a function of 2 arguments\n                  // with 3 arguments.\n    MATCHING_ARGS // check only that matching arguments are compatible,\n                  // ignore the number of arguments, etc.\n};\n\ninline bool\ncallIsCompatible(const Function *F, const CallInst *CI,\n                 CallCompatibility policy = CallCompatibility::LOOSE) {\n    using namespace llvm;\n\n    auto ci_arg_size = getNumArgOperands(CI);\n    if (policy != CallCompatibility::MATCHING_ARGS) {\n        if (F->isVarArg()) {\n            if (F->arg_size() > ci_arg_size) {\n                return false;\n            }\n        } else if (F->arg_size() != ci_arg_size) {\n            if (policy == CallCompatibility::STRICT ||\n                F->arg_size() > ci_arg_size) {\n                // too few arguments\n                return false;\n            }\n        }\n\n        if (!F->getReturnType()->canLosslesslyBitCastTo(CI->getType())) {\n            // it showed up that the loosless bitcast is too strict\n            // alternative since we can use the constexpr castings\n            if (!(isPointerOrIntegerTy(F->getReturnType()) &&\n                  isPointerOrIntegerTy(CI->getType()))) {\n                return false;\n            }\n        }\n    }\n\n    size_t idx = 0;\n    for (auto A = F->arg_begin(), E = F->arg_end(); idx < ci_arg_size && A != E;\n         ++A, ++idx) {\n        Type *CTy = CI->getArgOperand(idx)->getType();\n        Type *ATy = A->getType();\n\n        if (!(isPointerOrIntegerTy(CTy) && isPointerOrIntegerTy(ATy)))\n            if (!CTy->canLosslesslyBitCastTo(ATy)) {\n                return false;\n            }\n    }\n\n    return true;\n}\n\n/* ----------------------------------------------\n * -- analysis helpers\n * ---------------------------------------------- */\n\ninline unsigned getPointerBitwidth(const llvm::DataLayout *DL,\n                                   const llvm::Value *ptr)\n\n{\n    const llvm::Type *Ty = ptr->getType();\n    return DL->getPointerSizeInBits(Ty->getPointerAddressSpace());\n}\n\ninline uint64_t getConstantValue(const llvm::Value *op) {\n    using namespace llvm;\n\n    // FIXME: we should get rid of this dependency\n    static_assert(sizeof(Offset::type) == sizeof(uint64_t),\n                  \"The code relies on Offset::type having 8 bytes\");\n\n    uint64_t size = Offset::UNKNOWN;\n    if (const ConstantInt *C = dyn_cast<ConstantInt>(op)) {\n        size = C->getLimitedValue();\n    }\n\n    // size is ~((uint64_t)0) if it is unknown\n    return size;\n}\n\n// get size of memory allocation argument\ninline uint64_t getConstantSizeValue(const llvm::Value *op) {\n    auto sz = getConstantValue(op);\n    // if the size is unknown, make it 0, so that pointer\n    // analysis correctly computes offets into this memory\n    // (which is always UNKNOWN)\n    if (sz == ~static_cast<uint64_t>(0))\n        return 0;\n    return sz;\n}\n\ninline uint64_t getAllocatedSize(const llvm::AllocaInst *AI,\n                                 const llvm::DataLayout *DL) {\n    llvm::Type *Ty = AI->getAllocatedType();\n    if (!Ty->isSized())\n        return 0;\n\n    if (AI->isArrayAllocation()) {\n        return getConstantSizeValue(AI->getArraySize()) *\n               DL->getTypeAllocSize(Ty);\n    }\n    return DL->getTypeAllocSize(Ty);\n}\n\ninline uint64_t getAllocatedSize(llvm::Type *Ty, const llvm::DataLayout *DL) {\n    // Type can be i8 *null or similar\n    if (!Ty->isSized())\n        return 0;\n\n    return DL->getTypeAllocSize(Ty);\n}\n\ninline bool isConstantZero(const llvm::Value *val) {\n    using namespace llvm;\n\n    if (const ConstantInt *C = dyn_cast<ConstantInt>(val))\n        return C->isZero();\n\n    return false;\n}\n\n/* ----------------------------------------------\n * -- pointer analysis helpers\n * ---------------------------------------------- */\ninline bool memsetIsZeroInitialization(const llvm::IntrinsicInst *I) {\n    return isConstantZero(I->getOperand(1));\n}\n\n// recursively find out if type contains a pointer type as a subtype\n// (or if it is a pointer type itself)\ninline bool tyContainsPointer(const llvm::Type *Ty) {\n    if (Ty->isAggregateType()) {\n        for (auto I = Ty->subtype_begin(), E = Ty->subtype_end(); I != E; ++I) {\n            if (tyContainsPointer(*I))\n                return true;\n        }\n    } else\n        return Ty->isPointerTy();\n\n    return false;\n}\n\ninline bool typeCanBePointer(const llvm::DataLayout *DL, llvm::Type *Ty) {\n    if (Ty->isPointerTy())\n        return true;\n\n    if (Ty->isIntegerTy() && Ty->isSized())\n        return DL->getTypeSizeInBits(Ty) >=\n               DL->getPointerSizeInBits(/*Ty->getPointerAddressSpace()*/);\n\n    return false;\n}\n\n} // namespace llvmutils\n} // namespace dg\n\n#endif //  DG_LLVM_UTILS_H_\n"
  },
  {
    "path": "misc/benchexec/README.md",
    "content": "## Benchexec modules for running tools from DG\n\nCopy the python files to `benchexec/benchexec/tools` and then you can\nuse the tool in the XML spec of benchexec.\n\n### An example\n\nIf you setup benchexec, copy `dgtool.py` to `benchexec/benchexec/tools.py` and\nput the path to `dgtool` into PATH (`llvm-slicer` too in the case of\nout-of-source build) and run:\n\n```\nbenchexec llvm-slicer-tests.xml\n```\n\nthen benchexec will benchmark llvm-slicer on the test files from DG.\n"
  },
  {
    "path": "misc/benchexec/dgtool.py",
    "content": "# This file is part of BenchExec, a framework for reliable benchmarking:\n# https://github.com/sosy-lab/benchexec\n#\n# SPDX-FileCopyrightText: 2007-2020 Dirk Beyer <https://www.sosy-lab.org>\n# SPDX-FileCopyrightText: 2020 Marek Chalupa <https://www.sosy-lab.org>\n#\n# SPDX-License-Identifier: Apache-2.0\n\nfrom os.path import basename\n\nimport benchexec.util as util\nimport benchexec.tools.template\nimport benchexec.result as result\n\nclass Tool(benchexec.tools.template.BaseTool):\n    \"\"\"\n    A benchexec module for running dgtool with given tool\n    on benchmarks\n    \"\"\"\n\n    def executable(self):\n        return util.find_executable(\"dgtool\")\n\n    def version(self, executable):\n        return self._version_from_tool(executable)\n\n    def name(self):\n        return \"dgtool\"\n\n    def cmdline(self, executable, options, tasks, propertyfile, rlimits):\n        self.tool = basename(options[0])\n        return [executable] + options + ['-Xdg', 'dbg'] + tasks\n\n    def get_phase(self, tool, output):\n        phase='start'\n        for line in output:\n            if '> clang' in line:\n                phase='clang'\n            elif '> opt' in line:\n                phase='opt'\n            elif '> llvm-link' in line:\n                phase='llvm-link'\n            elif tool in line:\n                phase=tool\n        return phase\n                \n    def determine_result(self, returncode, returnsignal, output, isTimeout):\n\n        if isTimeout:\n            return f\"{self.get_phase(self.tool, output)}\"\n\n        if returnsignal == 0 and returncode == 0:\n            return result.RESULT_DONE\n        return f\"{result.RESULT_ERROR}({self.get_phase(self.tool, output)})\"\n"
  },
  {
    "path": "misc/benchexec/llvm-slicer-tests.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE benchmark PUBLIC \"+//IDN sosy-lab.org//DTD BenchExec benchmark 1.9//EN\" \"https://www.sosy-lab.org/benchexec/benchmark-1.9.dtd\">\n<benchmark tool=\"dgtool\" timelimit=\"20 s\" memlimit=\"6 GB\" cpuCores=\"1\">\n\n<option name=\"llvm-slicer\"/>\n<option name=\"-c\">test_assert</option>\n\n<rundefinition name=\"slicer-tests\">\n  <tasks name=\"BenchmarkingSlicingTests\">\n    <includesfile>slicing-tests.set</includesfile>\n  </tasks>\n</rundefinition>\n\n</benchmark>\n"
  },
  {
    "path": "misc/benchexec/slicing-tests.set",
    "content": "../../tests/slicing/sources/*.c\n"
  },
  {
    "path": "tests/CMakeLists.txt",
    "content": "# use debug info in tests\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -g\")\n\n# add check target\nenable_testing()\n\ninclude(ProcessorCount)\nProcessorCount(N)\nif(N EQUAL 0)\n    set(N 1)\nendif()\n\nset(CTEST_OPTS -j${N} --output-on-failure --progress ${CTEST_OPTS})\nadd_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} ${CTEST_OPTS}\n                        USES_TERMINAL)\n\n# --------------------------------------------------\n# Catch2\n# --------------------------------------------------\n\n# version of bundled Catch2\nset(CATCH_VERSION 2.13.9)\n\n# Catch2 main\nadd_library(catch-main OBJECT catch-main.cpp)\n\n# If we can find the same version or newer, use it as it may contain\n# additional fixes relevant to the given OS\nfind_package(Catch2 ${CATCH_VERSION} QUIET CONFIG)\nif(Catch2_FOUND)\n    message(STATUS \"Found Catch2 (found version \\\"${Catch2_VERSION}\\\")\")\n    # Issue a warning if there is a newer version, so that we will be notified\n    # to update the bundled one.\n    if(${Catch2_VERSION} VERSION_GREATER ${CATCH_VERSION})\n        message(WARNING\n            \"The bundled Catch2 seems to be outdated: \\\"${CATCH_VERSION}\\\"\\n\"\n            \"Please report this to our issue tracker. Thank you!\")\n    endif()\n\n    # use correct include directories\n    target_link_libraries(catch-main PRIVATE Catch2::Catch2)\nelse()\n    include_directories(${CMAKE_CURRENT_SOURCE_DIR})\nendif()\n\nmacro(add_catch_test TEST_FILE)\n    if (NOT EXISTS \"${CMAKE_CURRENT_LIST_DIR}/${TEST_FILE}\")\n        message(FATAL_ERROR \"Test '${TEST_FILE}' does not exist!\")\n    endif()\n    get_filename_component(TEST ${TEST_FILE} NAME_WE)\n\n    add_executable(${TEST} ${TEST_FILE} $<TARGET_OBJECTS:catch-main>)\n    add_test(${TEST} ${TEST})\n    add_dependencies(check ${TEST})\n\n    if(Catch2_FOUND)\n        target_link_libraries(${TEST} PRIVATE Catch2::Catch2)\n    endif()\nendmacro()\n\n# --------------------------------------------------\n# find compatible clang, lli, llvm-link and opt\n# --------------------------------------------------\nforeach(TOOL CLANG LLVM-LINK LLI OPT)\n    string(TOLOWER ${TOOL} TOOL_LOWER)\n\n    # REQUIRED available only with CMake 3.18+\n    find_program(${TOOL} ${TOOL_LOWER} PATHS ${LLVM_TOOLS_BINARY_DIR}\n                                       NO_DEFAULT_PATH)\n    if(NOT ${TOOL})\n        message(FATAL_ERROR \"${TOOL_LOWER}: version compatible with \\\n                             LLVM ${LLVM_PACKAGE_VERSION} not found\")\n    endif()\n    message(STATUS \"${TOOL_LOWER}: ${${TOOL}}\")\nendforeach()\n\n# FIXME:\n# This is a rather ugly hack to always use the correct path in test-runner.py.\n# Using configure_file to generate the correct script would probably be much\n# nicer.\n\n# all tools have the same dirname\nset(LLVM_TOOLS_DIR \"${LLVM_TOOLS_BINARY_DIR}\" CACHE PATH\n                   \"contains lli ${LLVM_PACKAGE_VERSION}, etc.\" FORCE)\n\n# check whether ${CLANG} accepts -fsanitize=address,undefined\nmessage(STATUS \"Performing test sanitizers_work with ${CLANG}\")\n\nfile(WRITE \"${CMAKE_CURRENT_BINARY_DIR}/sanitizer_test.c\"\n           \"int main(int argc, char* argv[]) {}\")\nexecute_process(COMMAND \"${CLANG}\" \"-fsanitize=address,undefined\"\n                        \"${CMAKE_CURRENT_BINARY_DIR}/sanitizer_test.c\"\n                RESULT_VARIABLE EXIT_CODE)\n\nif(EXIT_CODE EQUAL 0)\n    set(CLANG_HAS_SANITIZERS ON CACHE BOOL\n                             \"${CLANG} supports ASAN and UBSAN\" FORCE)\n    message(STATUS \"Performing test sanitizers_work with ${CLANG} - Success\")\nelse()\n    message(STATUS \"Performing test sanitizers_work with ${CLANG} - Failure\")\nendif()\n\n# --------------------------------------------------\n# cmd-arguments-tests\n# --------------------------------------------------\n\n# TODO: It's not possible to add dependency on all so that we test every\n# buildable binary. (https://gitlab.kitware.com/cmake/cmake/-/issues/8438)\nadd_test(NAME cmd-arguments-test\n         COMMAND \"${CMAKE_CURRENT_LIST_DIR}/cmd-args.py\"\n         WORKING_DIRECTORY \"${CMAKE_BINARY_DIR}/tools\")\n\n# --------------------------------------------------\n# points-to-test\n# --------------------------------------------------\nadd_catch_test(points-to-test.cpp)\ntarget_link_libraries(points-to-test PRIVATE dgpta)\n\n# --------------------------------------------------\n# readwritegraph-test\n# --------------------------------------------------\nadd_catch_test(readwritegraph-test.cpp)\ntarget_link_libraries(readwritegraph-test PRIVATE dgdda)\n\n# --------------------------------------------------\n# adt-test\n# --------------------------------------------------\nadd_catch_test(adt-test.cpp)\ntarget_link_libraries(adt-test PRIVATE dganalysis)\n\n# --------------------------------------------------\n# bitvector-test\n# --------------------------------------------------\nadd_catch_test(bitvector-test.cpp)\n\n# --------------------------------------------------\n# numbers-set-test\n# --------------------------------------------------\nadd_catch_test(numbers-set-test.cpp)\n\n# --------------------------------------------------\n# points-to-set-test\n# --------------------------------------------------\nadd_catch_test(points-to-set-test.cpp)\ntarget_link_libraries(points-to-set-test PRIVATE dganalysis dgpta)\n\n# --------------------------------------------------\n# disjunctive-intervals-map-test\n# --------------------------------------------------\nadd_catch_test(disjunctive-intervals-map-test.cpp)\ntarget_link_libraries(disjunctive-intervals-map-test PRIVATE dganalysis)\n\n# --------------------------------------------------\n# nodes-walk-test\n# --------------------------------------------------\nadd_catch_test(nodes-walk-test.cpp)\n\n# --------------------------------------------------\n# fuzzing tests\n# --------------------------------------------------\nif(ENABLE_FUZZING)\n    add_subdirectory(fuzzing)\nendif()\n\n# --------------------------------------------------\n# ThreadRegions test\n# --------------------------------------------------\n\nadd_custom_command(OUTPUT simple.ll pthread_exit.ll\n                   COMMAND ${CLANG} -S -emit-llvm ${CMAKE_CURRENT_LIST_DIR}/thread-regions-test-files/simple.c\n                   COMMAND ${CLANG} -S -emit-llvm ${CMAKE_CURRENT_LIST_DIR}/thread-regions-test-files/pthread_exit.c\n                   DEPENDS ${CMAKE_CURRENT_LIST_DIR}/thread-regions-test-files/simple.c\n                           ${CMAKE_CURRENT_LIST_DIR}/thread-regions-test-files/pthread_exit.c)\n\nadd_custom_target(thread-regions-test-file DEPENDS simple.ll)\n\nadd_catch_test(thread-regions-test.cpp)\nadd_dependencies(thread-regions-test thread-regions-test-file)\n\ntarget_compile_definitions(thread-regions-test\n    PRIVATE\n        SIMPLE_FILE=\"${CMAKE_CURRENT_BINARY_DIR}/simple.ll\"\n        PTHREAD_EXIT_FILE=\"${CMAKE_CURRENT_BINARY_DIR}/pthread_exit.ll\")\n\ntarget_link_libraries(thread-regions-test PRIVATE dgllvmthreadregions\n                                          PRIVATE ${llvm_irreader})\n\n# --------------------------------------------------\n# llvm-dg-test\n# --------------------------------------------------\nadd_catch_test(llvm-dg-test.cpp)\ntarget_link_libraries(llvm-dg-test PRIVATE dgllvmdg\n                                   PRIVATE ${llvm_irreader})\n\n# --------------------------------------------------\n# slicing tests\n# --------------------------------------------------\nadd_subdirectory(slicing)\nadd_dependencies(check llvm-slicer)\n\n# --------------------------------------------------\n# benchmarking\n# --------------------------------------------------\nadd_executable(ptset-benchmark ptset-benchmark.cpp)\ntarget_link_libraries(ptset-benchmark PRIVATE dganalysis dgpta)\n\n# --------------------------------------------------\n# value-relations-test\n# --------------------------------------------------\nadd_catch_test(value-relations-test.cpp)\ntarget_link_libraries(value-relations-test PRIVATE dgvra)\n"
  },
  {
    "path": "tests/adt-test.cpp",
    "content": "#include <catch2/catch.hpp>\n\n#include \"dg/ADT/Bitvector.h\"\n#include \"dg/ADT/Queue.h\"\n#include \"dg/ReadWriteGraph/DefSite.h\"\n\nusing namespace dg::ADT;\nusing dg::Offset;\n\nTEST_CASE(\"QuieieLIFO basic manimp\", \"QueueLIFO\") {\n    QueueLIFO<int> queue;\n    REQUIRE(queue.empty());\n\n    queue.push(1);\n    queue.push(13);\n    queue.push(4);\n    queue.push(2);\n    queue.push(2);\n\n    REQUIRE(queue.pop() == 2);\n    REQUIRE(queue.pop() == 2);\n    REQUIRE(queue.pop() == 4);\n    REQUIRE(queue.pop() == 13);\n    REQUIRE(queue.pop() == 1);\n    REQUIRE(queue.empty());\n}\n\nTEST_CASE(\"QueueFIFo basic manimp\", \"QueueFIFO\") {\n    QueueFIFO<int> queue;\n    REQUIRE(queue.empty());\n\n    queue.push(1);\n    queue.push(13);\n    queue.push(4);\n    queue.push(4);\n    queue.push(2);\n\n    REQUIRE(queue.pop() == 1);\n    REQUIRE(queue.pop() == 13);\n    REQUIRE(queue.pop() == 4);\n    REQUIRE(queue.pop() == 4);\n    REQUIRE(queue.pop() == 2);\n    REQUIRE(queue.empty());\n}\n\nstruct mycomp {\n    bool operator()(int a, int b) const { return a > b; }\n};\n\nTEST_CASE(\"Priority queue basic manimp\", \"Priority Queue\") {\n    PrioritySet<int, mycomp> queue;\n    REQUIRE(queue.empty());\n\n    queue.push(1);\n    queue.push(13);\n    queue.push(4);\n    queue.push(4);\n    queue.push(2);\n\n    // we inserted twice, but it is a set\n    REQUIRE(queue.size() == 4);\n\n    REQUIRE(queue.pop() == 13);\n    REQUIRE(queue.pop() == 4);\n    REQUIRE(queue.pop() == 2);\n    REQUIRE(queue.pop() == 1);\n    REQUIRE(queue.empty());\n}\n\nTEST_CASE(\"Intervals handling\", \"RWG intervals\") {\n    using namespace dg::dda;\n\n    REQUIRE(intervalsDisjunctive(0, 1, 2, 20));\n    REQUIRE(intervalsDisjunctive(0, 1, 1, 2));\n    REQUIRE(!intervalsDisjunctive(1, 1, 1, 2));\n    REQUIRE(!intervalsDisjunctive(1, 1, 1, 1));\n    REQUIRE(!intervalsDisjunctive(3, 5, 3, 5));\n    REQUIRE(!intervalsDisjunctive(3, 7, 3, 5));\n    REQUIRE(!intervalsDisjunctive(3, 5, 3, 7));\n    REQUIRE(intervalsDisjunctive(1, 1, 2, 2));\n    REQUIRE(!intervalsDisjunctive(0, 4, 2, 2));\n\n    REQUIRE(!intervalsDisjunctive(0, 4, 2, Offset::UNKNOWN));\n    REQUIRE(intervalsDisjunctive(0, 4, 4, Offset::UNKNOWN));\n    REQUIRE(!intervalsDisjunctive(0, Offset::UNKNOWN, 4, Offset::UNKNOWN));\n    REQUIRE(!intervalsDisjunctive(0, Offset::UNKNOWN, 1, 4));\n\n    REQUIRE(!intervalsOverlap(0, 1, 2, 20));\n    REQUIRE(!intervalsOverlap(0, 1, 1, 2));\n    REQUIRE(intervalsOverlap(1, 1, 1, 2));\n    REQUIRE(intervalsOverlap(1, 1, 1, 1));\n    REQUIRE(intervalsOverlap(3, 5, 3, 5));\n    REQUIRE(intervalsOverlap(3, 7, 3, 5));\n    REQUIRE(intervalsOverlap(3, 5, 3, 7));\n    REQUIRE(!intervalsOverlap(1, 1, 2, 2));\n    REQUIRE(!intervalsOverlap(1, 2, 0, 1));\n    REQUIRE(intervalsOverlap(1, 2, 1, 1));\n    REQUIRE(intervalsOverlap(1, 2, 1, 2));\n    REQUIRE(intervalsOverlap(1, 2, 2, 2));\n    REQUIRE(intervalsOverlap(2, 2, 2, 2));\n    REQUIRE(intervalsOverlap(3, 3, 2, 2));\n    REQUIRE(!intervalsOverlap(1, 2, 3, 3));\n    REQUIRE(!intervalsOverlap(1, 2, 3, 3));\n}\n\n#include \"dg/ADT/STLHashMap.h\"\n\ntemplate <typename MapT>\nvoid hashMapTest() {\n    MapT M;\n    REQUIRE(M.get(0) == nullptr);\n    auto r = M.put(1, 2);\n    const int *x = M.get(1);\n    REQUIRE(r);\n    REQUIRE(x);\n    REQUIRE(*x == 2);\n    r = M.put(1, 3);\n    REQUIRE(!r);\n    M.put(5, 6);\n    x = M.get(1);\n    const int *y = M.get(5);\n    REQUIRE(x);\n    REQUIRE(*x == 2);\n    REQUIRE(y);\n    REQUIRE(*y == 6);\n    M.erase(1);\n    REQUIRE(M.get(1) == nullptr);\n    y = M.get(5);\n    REQUIRE(y);\n    REQUIRE(*y == 6);\n}\n\n// create an object for testing hashing function collision\nstruct MyInt {\n    int x{0};\n    MyInt() = default;\n    MyInt(int y) : x(y) {}\n    bool operator==(const MyInt &rhs) const { return x == rhs.x; }\n};\n\nnamespace std {\ntemplate <>\nstruct hash<MyInt> {\n    size_t operator()(const MyInt &mi) const { return mi.x % 2; }\n};\n} // namespace std\n\ntemplate <typename MapT>\nvoid hashCollisionTest() {\n    MapT M;\n    bool r;\n    r = M.put(MyInt(2), 2);\n    REQUIRE(r);\n    r = M.put(MyInt(3), 3);\n    REQUIRE(r);\n    // collision\n    r = M.put(MyInt(4), 4);\n    REQUIRE(r);\n    REQUIRE(M.size() == 3);\n    for (int i = 2; i <= 4; ++i) {\n        const int *x = M.get(MyInt(i));\n        REQUIRE(*x == i);\n    }\n}\n\nTEST_CASE(\"STL hashmap test\", \"HashMap\") {\n    hashMapTest<dg::STLHashMap<int, int>>();\n}\n\nTEST_CASE(\"STL hashmap collision test\", \"HashMap\") {\n    hashCollisionTest<dg::STLHashMap<MyInt, int>>();\n}\n\n#ifdef HAVE_TSL_HOPSCOTCH\n#include \"dg/ADT/TslHopscotchHashMap.h\"\n\nTEST_CASE(\"TSL Hopscotch hashmap test\", \"HashMap\") {\n    hashMapTest<dg::HopscotchHashMap<int, int>>();\n}\n\nTEST_CASE(\"TSL Hopscotch collision test\", \"HashMap\") {\n    hashCollisionTest<dg::HopscotchHashMap<MyInt, int>>();\n}\n#endif\n"
  },
  {
    "path": "tests/bitvector-test.cpp",
    "content": "#include <catch2/catch.hpp>\n\n#include <random>\n#include <set>\n\n#include \"dg/ADT/Bitvector.h\"\n\nusing dg::ADT::SparseBitvector;\n\nTEST_CASE(\"Querying empty set\", \"SparseBitvector\") {\n    SparseBitvector B;\n\n    for (uint64_t i = 1; i < uint64_t{1} << 63U; i *= 2) {\n        REQUIRE(B.get(i) == false);\n    }\n}\n\nTEST_CASE(\"Set few elements\", \"SparseBitvector\") {\n    SparseBitvector B;\n\n    REQUIRE(B.get(0) == false);\n    REQUIRE(B.get(1) == false);\n    REQUIRE(B.get(10) == false);\n    REQUIRE(B.get(1000) == false);\n    REQUIRE(B.get(100000) == false);\n    B.set(0);\n    B.set(1);\n    B.set(10);\n    B.set(1000);\n    B.set(100000);\n    REQUIRE(B.get(0) == true);\n    REQUIRE(B.get(1) == true);\n    REQUIRE(B.get(10) == true);\n    REQUIRE(B.get(1000) == true);\n    REQUIRE(B.get(100000) == true);\n}\n\nTEST_CASE(\"Extreme values\", \"SparseBitvector\") {\n    SparseBitvector B;\n\n    REQUIRE(B.get(0) == false);\n\n    for (unsigned int i = 0; i < 64; ++i) {\n        REQUIRE(B.get(uint64_t{1} << i) == false);\n        REQUIRE(B.set(uint64_t{1} << i) == false);\n    }\n\n    for (unsigned int i = 0; i < 64; ++i) {\n        REQUIRE(B.get(uint64_t{1} << i) == true);\n    }\n}\n\nTEST_CASE(\"Iterator and empty bitvector\", \"SparseBitvector\") {\n    SparseBitvector B;\n    auto it = B.begin();\n    auto et = B.end();\n\n    REQUIRE(it == et);\n    REQUIRE(B.empty());\n    REQUIRE(B.empty());\n}\n\nTEST_CASE(\"Iterator one element\", \"SparseBitvector\") {\n    SparseBitvector B;\n\n    auto it = B.begin();\n    auto et = B.end();\n\n    REQUIRE(it == et);\n\n    REQUIRE(B.empty());\n    REQUIRE(B.set(1000000) == false);\n\n    it = B.begin();\n    et = B.end();\n\n    REQUIRE(it != et);\n    REQUIRE(*it == 1000000);\n    ++it;\n    REQUIRE(it == et);\n}\n\nTEST_CASE(\"Iterator test\", \"SparseBitvector\") {\n    SparseBitvector B;\n    int n = 0;\n\n    B.set(0);\n    B.set(1);\n    B.set(10);\n    B.set(1000);\n    B.set(100000);\n\n    auto it = B.begin();\n    auto et = B.end();\n\n    for (; it != et; ++it) {\n        auto i = *it;\n        REQUIRE((i == 0 || i == 1 || i == 10 || i == 1000 || i == 100000));\n        ++n;\n    }\n    REQUIRE(n == 5);\n}\n\nTEST_CASE(\"Set continuous values\", \"SparseBitvector\") {\n    SparseBitvector B;\n\n#define NUM 10000\n    for (int i = 0; i < NUM; ++i) {\n        REQUIRE(B.get(i) == false);\n        B.set(i);\n    }\n\n    for (int i = 0; i < NUM; ++i) {\n        REQUIRE(B.get(i) == true);\n    }\n#undef NUM\n}\n\nTEST_CASE(\"Random\", \"SparseBitvector\") {\n    SparseBitvector B;\n    srand(time(nullptr));\n\n#define NUM 10000\n\n    std::set<uint64_t> numbers;\n    std::default_random_engine generator;\n    std::uniform_int_distribution<uint64_t> distribution(0, ~uint64_t{0});\n\n    SECTION(\"Generating random numbers and putting them to bitvector\") {\n        for (int i = 0; i < NUM; ++i) {\n            auto x = distribution(generator);\n            B.set(x);\n            numbers.insert(x);\n        }\n    }\n\n    SECTION(\"Checking that each generated number is in bitvector\") {\n        for (auto x : numbers) {\n            REQUIRE(B.get(x) == true);\n        }\n    }\n\n    SECTION(\"Checking that each generated number is in bitvector using \"\n            \"iterator\") {\n        // try iterators\n        for (auto x : B) {\n            REQUIRE(numbers.count(x) > 0);\n        }\n    }\n\n    SECTION(\"Checking random numbers\") {\n        for (int i = 0; i < NUM; ++i) {\n            auto x = distribution(generator);\n            if (numbers.count(x) > 0)\n                REQUIRE(B.get(x) == true);\n        }\n    }\n}\n\nTEST_CASE(\"Regression 1\", \"SparseBitvector\") {\n    SparseBitvector B;\n    REQUIRE(B.get(~uint64_t{0}) == false);\n    REQUIRE(B.set(~uint64_t{0}) == false);\n    REQUIRE(B.get(~uint64_t{0}) == true);\n    auto it = B.begin();\n    auto et = B.end();\n    REQUIRE(it != et);\n    REQUIRE(*it == ~uint64_t{0});\n    ++it;\n    REQUIRE(it == et);\n}\n\n/*\nTEST_CASE(\"Merge bitvectors (union)\", \"SparseBitvector\") {\n    SparseBitvector B;\n    REQUIRED(false);\n}\n*/\n\nTEST_CASE(\"Merge random bitvectors (union)\", \"SparseBitvector\") {\n    SparseBitvector B1;\n    SparseBitvector B2;\n\n    std::default_random_engine generator;\n    std::uniform_int_distribution<uint64_t> distribution(0, ~uint64_t{0});\n\n#undef NUM\n#define NUM 100\n    for (int i = 0; i < NUM; ++i) {\n        auto x = distribution(generator);\n        auto y = distribution(generator);\n        B1.set(x);\n        B2.set(y);\n    }\n\n    auto B1_old = B1;\n    B1.set(B2);\n    for (auto x : B1_old) {\n        REQUIRE(B1.get(x));\n    }\n    for (auto x : B2) {\n        REQUIRE(B1.get(x));\n    }\n\n    //    B2.merge(B1);\n    //    REQUIRE(B1 == B2);\n}\n"
  },
  {
    "path": "tests/catch-main.cpp",
    "content": "#define CATCH_CONFIG_MAIN\n#include <catch2/catch.hpp>\n"
  },
  {
    "path": "tests/catch2/catch.hpp",
    "content": "/*\n *  Catch v2.13.9\n *  Generated: 2022-04-12 22:37:23.260201\n *  ----------------------------------------------------------\n *  This file has been merged from multiple headers. Please don't edit it directly\n *  Copyright (c) 2022 Two Blue Cubes Ltd. All rights reserved.\n *\n *  Distributed under the Boost Software License, Version 1.0. (See accompanying\n *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n */\n#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n// start catch.hpp\n\n\n#define CATCH_VERSION_MAJOR 2\n#define CATCH_VERSION_MINOR 13\n#define CATCH_VERSION_PATCH 9\n\n#ifdef __clang__\n#    pragma clang system_header\n#elif defined __GNUC__\n#    pragma GCC system_header\n#endif\n\n// start catch_suppress_warnings.h\n\n#ifdef __clang__\n#   ifdef __ICC // icpc defines the __clang__ macro\n#       pragma warning(push)\n#       pragma warning(disable: 161 1682)\n#   else // __ICC\n#       pragma clang diagnostic push\n#       pragma clang diagnostic ignored \"-Wpadded\"\n#       pragma clang diagnostic ignored \"-Wswitch-enum\"\n#       pragma clang diagnostic ignored \"-Wcovered-switch-default\"\n#    endif\n#elif defined __GNUC__\n     // Because REQUIREs trigger GCC's -Wparentheses, and because still\n     // supported version of g++ have only buggy support for _Pragmas,\n     // Wparentheses have to be suppressed globally.\n#    pragma GCC diagnostic ignored \"-Wparentheses\" // See #674 for details\n\n#    pragma GCC diagnostic push\n#    pragma GCC diagnostic ignored \"-Wunused-variable\"\n#    pragma GCC diagnostic ignored \"-Wpadded\"\n#endif\n// end catch_suppress_warnings.h\n#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)\n#  define CATCH_IMPL\n#  define CATCH_CONFIG_ALL_PARTS\n#endif\n\n// In the impl file, we want to have access to all parts of the headers\n// Can also be used to sanely support PCHs\n#if defined(CATCH_CONFIG_ALL_PARTS)\n#  define CATCH_CONFIG_EXTERNAL_INTERFACES\n#  if defined(CATCH_CONFIG_DISABLE_MATCHERS)\n#    undef CATCH_CONFIG_DISABLE_MATCHERS\n#  endif\n#  if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)\n#    define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER\n#  endif\n#endif\n\n#if !defined(CATCH_CONFIG_IMPL_ONLY)\n// start catch_platform.h\n\n// See e.g.:\n// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html\n#ifdef __APPLE__\n#  include <TargetConditionals.h>\n#  if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \\\n      (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1)\n#    define CATCH_PLATFORM_MAC\n#  elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1)\n#    define CATCH_PLATFORM_IPHONE\n#  endif\n\n#elif defined(linux) || defined(__linux) || defined(__linux__)\n#  define CATCH_PLATFORM_LINUX\n\n#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__)\n#  define CATCH_PLATFORM_WINDOWS\n#endif\n\n// end catch_platform.h\n\n#ifdef CATCH_IMPL\n#  ifndef CLARA_CONFIG_MAIN\n#    define CLARA_CONFIG_MAIN_NOT_DEFINED\n#    define CLARA_CONFIG_MAIN\n#  endif\n#endif\n\n// start catch_user_interfaces.h\n\nnamespace Catch {\n    unsigned int rngSeed();\n}\n\n// end catch_user_interfaces.h\n// start catch_tag_alias_autoregistrar.h\n\n// start catch_common.h\n\n// start catch_compiler_capabilities.h\n\n// Detect a number of compiler features - by compiler\n// The following features are defined:\n//\n// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?\n// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?\n// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?\n// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled?\n// ****************\n// Note to maintainers: if new toggles are added please document them\n// in configuration.md, too\n// ****************\n\n// In general each macro has a _NO_<feature name> form\n// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature.\n// Many features, at point of detection, define an _INTERNAL_ macro, so they\n// can be combined, en-mass, with the _NO_ forms later.\n\n#ifdef __cplusplus\n\n#  if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)\n#    define CATCH_CPP14_OR_GREATER\n#  endif\n\n#  if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)\n#    define CATCH_CPP17_OR_GREATER\n#  endif\n\n#endif\n\n// Only GCC compiler should be used in this block, so other compilers trying to\n// mask themselves as GCC should be ignored.\n#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__)\n#    define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( \"GCC diagnostic push\" )\n#    define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION  _Pragma( \"GCC diagnostic pop\" )\n\n#    define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__)\n\n#endif\n\n#if defined(__clang__)\n\n#    define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( \"clang diagnostic push\" )\n#    define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION  _Pragma( \"clang diagnostic pop\" )\n\n// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug\n// which results in calls to destructors being emitted for each temporary,\n// without a matching initialization. In practice, this can result in something\n// like `std::string::~string` being called on an uninitialized value.\n//\n// For example, this code will likely segfault under IBM XL:\n// ```\n// REQUIRE(std::string(\"12\") + \"34\" == \"1234\")\n// ```\n//\n// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented.\n#  if !defined(__ibmxl__) && !defined(__CUDACC__)\n#    define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */\n#  endif\n\n#    define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \\\n         _Pragma( \"clang diagnostic ignored \\\"-Wexit-time-destructors\\\"\" ) \\\n         _Pragma( \"clang diagnostic ignored \\\"-Wglobal-constructors\\\"\")\n\n#    define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \\\n         _Pragma( \"clang diagnostic ignored \\\"-Wparentheses\\\"\" )\n\n#    define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \\\n         _Pragma( \"clang diagnostic ignored \\\"-Wunused-variable\\\"\" )\n\n#    define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \\\n         _Pragma( \"clang diagnostic ignored \\\"-Wgnu-zero-variadic-macro-arguments\\\"\" )\n\n#    define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \\\n         _Pragma( \"clang diagnostic ignored \\\"-Wunused-template\\\"\" )\n\n#endif // __clang__\n\n////////////////////////////////////////////////////////////////////////////////\n// Assume that non-Windows platforms support posix signals by default\n#if !defined(CATCH_PLATFORM_WINDOWS)\n    #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS\n#endif\n\n////////////////////////////////////////////////////////////////////////////////\n// We know some environments not to support full POSIX signals\n#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__)\n    #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS\n#endif\n\n#ifdef __OS400__\n#       define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS\n#       define CATCH_CONFIG_COLOUR_NONE\n#endif\n\n////////////////////////////////////////////////////////////////////////////////\n// Android somehow still does not support std::to_string\n#if defined(__ANDROID__)\n#    define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING\n#    define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE\n#endif\n\n////////////////////////////////////////////////////////////////////////////////\n// Not all Windows environments support SEH properly\n#if defined(__MINGW32__)\n#    define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH\n#endif\n\n////////////////////////////////////////////////////////////////////////////////\n// PS4\n#if defined(__ORBIS__)\n#    define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE\n#endif\n\n////////////////////////////////////////////////////////////////////////////////\n// Cygwin\n#ifdef __CYGWIN__\n\n// Required for some versions of Cygwin to declare gettimeofday\n// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin\n#   define _BSD_SOURCE\n// some versions of cygwin (most) do not support std::to_string. Use the libstd check.\n// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813\n# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \\\n           && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))\n\n#    define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING\n\n# endif\n#endif // __CYGWIN__\n\n////////////////////////////////////////////////////////////////////////////////\n// Visual C++\n#if defined(_MSC_VER)\n\n// Universal Windows platform does not support SEH\n// Or console colours (or console at all...)\n#  if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)\n#    define CATCH_CONFIG_COLOUR_NONE\n#  else\n#    define CATCH_INTERNAL_CONFIG_WINDOWS_SEH\n#  endif\n\n#  if !defined(__clang__) // Handle Clang masquerading for msvc\n\n// MSVC traditional preprocessor needs some workaround for __VA_ARGS__\n// _MSVC_TRADITIONAL == 0 means new conformant preprocessor\n// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor\n#    if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)\n#      define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n#    endif // MSVC_TRADITIONAL\n\n// Only do this if we're not using clang on Windows, which uses `diagnostic push` & `diagnostic pop`\n#    define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) )\n#    define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION  __pragma( warning(pop) )\n#  endif // __clang__\n\n#endif // _MSC_VER\n\n#if defined(_REENTRANT) || defined(_MSC_VER)\n// Enable async processing, as -pthread is specified or no additional linking is required\n# define CATCH_INTERNAL_CONFIG_USE_ASYNC\n#endif // _MSC_VER\n\n////////////////////////////////////////////////////////////////////////////////\n// Check if we are compiled with -fno-exceptions or equivalent\n#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)\n#  define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED\n#endif\n\n////////////////////////////////////////////////////////////////////////////////\n// DJGPP\n#ifdef __DJGPP__\n#  define CATCH_INTERNAL_CONFIG_NO_WCHAR\n#endif // __DJGPP__\n\n////////////////////////////////////////////////////////////////////////////////\n// Embarcadero C++Build\n#if defined(__BORLANDC__)\n    #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN\n#endif\n\n////////////////////////////////////////////////////////////////////////////////\n\n// Use of __COUNTER__ is suppressed during code analysis in\n// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly\n// handled by it.\n// Otherwise all supported compilers support COUNTER macro,\n// but user still might want to turn it off\n#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L )\n    #define CATCH_INTERNAL_CONFIG_COUNTER\n#endif\n\n////////////////////////////////////////////////////////////////////////////////\n\n// RTX is a special version of Windows that is real time.\n// This means that it is detected as Windows, but does not provide\n// the same set of capabilities as real Windows does.\n#if defined(UNDER_RTSS) || defined(RTX64_BUILD)\n    #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH\n    #define CATCH_INTERNAL_CONFIG_NO_ASYNC\n    #define CATCH_CONFIG_COLOUR_NONE\n#endif\n\n#if !defined(_GLIBCXX_USE_C99_MATH_TR1)\n#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER\n#endif\n\n// Various stdlib support checks that require __has_include\n#if defined(__has_include)\n  // Check if string_view is available and usable\n  #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)\n  #    define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW\n  #endif\n\n  // Check if optional is available and usable\n  #  if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)\n  #    define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL\n  #  endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)\n\n  // Check if byte is available and usable\n  #  if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)\n  #    include <cstddef>\n  #    if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0)\n  #      define CATCH_INTERNAL_CONFIG_CPP17_BYTE\n  #    endif\n  #  endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)\n\n  // Check if variant is available and usable\n  #  if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)\n  #    if defined(__clang__) && (__clang_major__ < 8)\n         // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852\n         // fix should be in clang 8, workaround in libstdc++ 8.2\n  #      include <ciso646>\n  #      if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)\n  #        define CATCH_CONFIG_NO_CPP17_VARIANT\n  #      else\n  #        define CATCH_INTERNAL_CONFIG_CPP17_VARIANT\n  #      endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)\n  #    else\n  #      define CATCH_INTERNAL_CONFIG_CPP17_VARIANT\n  #    endif // defined(__clang__) && (__clang_major__ < 8)\n  #  endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)\n#endif // defined(__has_include)\n\n#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)\n#   define CATCH_CONFIG_COUNTER\n#endif\n#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH)\n#   define CATCH_CONFIG_WINDOWS_SEH\n#endif\n// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.\n#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)\n#   define CATCH_CONFIG_POSIX_SIGNALS\n#endif\n// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions.\n#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR)\n#   define CATCH_CONFIG_WCHAR\n#endif\n\n#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING)\n#    define CATCH_CONFIG_CPP11_TO_STRING\n#endif\n\n#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL)\n#  define CATCH_CONFIG_CPP17_OPTIONAL\n#endif\n\n#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW)\n#  define CATCH_CONFIG_CPP17_STRING_VIEW\n#endif\n\n#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT)\n#  define CATCH_CONFIG_CPP17_VARIANT\n#endif\n\n#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE)\n#  define CATCH_CONFIG_CPP17_BYTE\n#endif\n\n#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)\n#  define CATCH_INTERNAL_CONFIG_NEW_CAPTURE\n#endif\n\n#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE)\n#  define CATCH_CONFIG_NEW_CAPTURE\n#endif\n\n#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)\n#  define CATCH_CONFIG_DISABLE_EXCEPTIONS\n#endif\n\n#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN)\n#  define CATCH_CONFIG_POLYFILL_ISNAN\n#endif\n\n#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC)  && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC)\n#  define CATCH_CONFIG_USE_ASYNC\n#endif\n\n#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE)\n#  define CATCH_CONFIG_ANDROID_LOGWRITE\n#endif\n\n#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)\n#  define CATCH_CONFIG_GLOBAL_NEXTAFTER\n#endif\n\n// Even if we do not think the compiler has that warning, we still have\n// to provide a macro that can be used by the code.\n#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION)\n#   define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION\n#endif\n#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION)\n#   define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION\n#endif\n#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)\n#   define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS\n#endif\n#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS)\n#   define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS\n#endif\n#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS)\n#   define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS\n#endif\n#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS)\n#   define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS\n#endif\n\n// The goal of this macro is to avoid evaluation of the arguments, but\n// still have the compiler warn on problems inside...\n#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN)\n#   define CATCH_INTERNAL_IGNORE_BUT_WARN(...)\n#endif\n\n#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10)\n#   undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS\n#elif defined(__clang__) && (__clang_major__ < 5)\n#   undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS\n#endif\n\n#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS)\n#   define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS\n#endif\n\n#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)\n#define CATCH_TRY if ((true))\n#define CATCH_CATCH_ALL if ((false))\n#define CATCH_CATCH_ANON(type) if ((false))\n#else\n#define CATCH_TRY try\n#define CATCH_CATCH_ALL catch (...)\n#define CATCH_CATCH_ANON(type) catch (type)\n#endif\n\n#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR)\n#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n#endif\n\n// end catch_compiler_capabilities.h\n#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line\n#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )\n#ifdef CATCH_CONFIG_COUNTER\n#  define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )\n#else\n#  define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )\n#endif\n\n#include <iosfwd>\n#include <string>\n#include <cstdint>\n\n// We need a dummy global operator<< so we can bring it into Catch namespace later\nstruct Catch_global_namespace_dummy {};\nstd::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);\n\nnamespace Catch {\n\n    struct CaseSensitive { enum Choice {\n        Yes,\n        No\n    }; };\n\n    class NonCopyable {\n        NonCopyable( NonCopyable const& )              = delete;\n        NonCopyable( NonCopyable && )                  = delete;\n        NonCopyable& operator = ( NonCopyable const& ) = delete;\n        NonCopyable& operator = ( NonCopyable && )     = delete;\n\n    protected:\n        NonCopyable();\n        virtual ~NonCopyable();\n    };\n\n    struct SourceLineInfo {\n\n        SourceLineInfo() = delete;\n        SourceLineInfo( char const* _file, std::size_t _line ) noexcept\n        :   file( _file ),\n            line( _line )\n        {}\n\n        SourceLineInfo( SourceLineInfo const& other )            = default;\n        SourceLineInfo& operator = ( SourceLineInfo const& )     = default;\n        SourceLineInfo( SourceLineInfo&& )              noexcept = default;\n        SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default;\n\n        bool empty() const noexcept { return file[0] == '\\0'; }\n        bool operator == ( SourceLineInfo const& other ) const noexcept;\n        bool operator < ( SourceLineInfo const& other ) const noexcept;\n\n        char const* file;\n        std::size_t line;\n    };\n\n    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );\n\n    // Bring in operator<< from global namespace into Catch namespace\n    // This is necessary because the overload of operator<< above makes\n    // lookup stop at namespace Catch\n    using ::operator<<;\n\n    // Use this in variadic streaming macros to allow\n    //    >> +StreamEndStop\n    // as well as\n    //    >> stuff +StreamEndStop\n    struct StreamEndStop {\n        std::string operator+() const;\n    };\n    template<typename T>\n    T const& operator + ( T const& value, StreamEndStop ) {\n        return value;\n    }\n}\n\n#define CATCH_INTERNAL_LINEINFO \\\n    ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )\n\n// end catch_common.h\nnamespace Catch {\n\n    struct RegistrarForTagAliases {\n        RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );\n    };\n\n} // end namespace Catch\n\n#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \\\n    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \\\n    CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \\\n    namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \\\n    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION\n\n// end catch_tag_alias_autoregistrar.h\n// start catch_test_registry.h\n\n// start catch_interfaces_testcase.h\n\n#include <vector>\n\nnamespace Catch {\n\n    class TestSpec;\n\n    struct ITestInvoker {\n        virtual void invoke () const = 0;\n        virtual ~ITestInvoker();\n    };\n\n    class TestCase;\n    struct IConfig;\n\n    struct ITestCaseRegistry {\n        virtual ~ITestCaseRegistry();\n        virtual std::vector<TestCase> const& getAllTests() const = 0;\n        virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;\n    };\n\n    bool isThrowSafe( TestCase const& testCase, IConfig const& config );\n    bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );\n    std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );\n    std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );\n\n}\n\n// end catch_interfaces_testcase.h\n// start catch_stringref.h\n\n#include <cstddef>\n#include <string>\n#include <iosfwd>\n#include <cassert>\n\nnamespace Catch {\n\n    /// A non-owning string class (similar to the forthcoming std::string_view)\n    /// Note that, because a StringRef may be a substring of another string,\n    /// it may not be null terminated.\n    class StringRef {\n    public:\n        using size_type = std::size_t;\n        using const_iterator = const char*;\n\n    private:\n        static constexpr char const* const s_empty = \"\";\n\n        char const* m_start = s_empty;\n        size_type m_size = 0;\n\n    public: // construction\n        constexpr StringRef() noexcept = default;\n\n        StringRef( char const* rawChars ) noexcept;\n\n        constexpr StringRef( char const* rawChars, size_type size ) noexcept\n        :   m_start( rawChars ),\n            m_size( size )\n        {}\n\n        StringRef( std::string const& stdString ) noexcept\n        :   m_start( stdString.c_str() ),\n            m_size( stdString.size() )\n        {}\n\n        explicit operator std::string() const {\n            return std::string(m_start, m_size);\n        }\n\n    public: // operators\n        auto operator == ( StringRef const& other ) const noexcept -> bool;\n        auto operator != (StringRef const& other) const noexcept -> bool {\n            return !(*this == other);\n        }\n\n        auto operator[] ( size_type index ) const noexcept -> char {\n            assert(index < m_size);\n            return m_start[index];\n        }\n\n    public: // named queries\n        constexpr auto empty() const noexcept -> bool {\n            return m_size == 0;\n        }\n        constexpr auto size() const noexcept -> size_type {\n            return m_size;\n        }\n\n        // Returns the current start pointer. If the StringRef is not\n        // null-terminated, throws std::domain_exception\n        auto c_str() const -> char const*;\n\n    public: // substrings and searches\n        // Returns a substring of [start, start + length).\n        // If start + length > size(), then the substring is [start, size()).\n        // If start > size(), then the substring is empty.\n        auto substr( size_type start, size_type length ) const noexcept -> StringRef;\n\n        // Returns the current start pointer. May not be null-terminated.\n        auto data() const noexcept -> char const*;\n\n        constexpr auto isNullTerminated() const noexcept -> bool {\n            return m_start[m_size] == '\\0';\n        }\n\n    public: // iterators\n        constexpr const_iterator begin() const { return m_start; }\n        constexpr const_iterator end() const { return m_start + m_size; }\n    };\n\n    auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&;\n    auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&;\n\n    constexpr auto operator \"\" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {\n        return StringRef( rawChars, size );\n    }\n} // namespace Catch\n\nconstexpr auto operator \"\" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {\n    return Catch::StringRef( rawChars, size );\n}\n\n// end catch_stringref.h\n// start catch_preprocessor.hpp\n\n\n#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__\n#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__)))\n#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__)))\n#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__)))\n#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__)))\n#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__)))\n\n#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__\n// MSVC needs more evaluations\n#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__)))\n#define CATCH_RECURSE(...)  CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__))\n#else\n#define CATCH_RECURSE(...)  CATCH_RECURSION_LEVEL5(__VA_ARGS__)\n#endif\n\n#define CATCH_REC_END(...)\n#define CATCH_REC_OUT\n\n#define CATCH_EMPTY()\n#define CATCH_DEFER(id) id CATCH_EMPTY()\n\n#define CATCH_REC_GET_END2() 0, CATCH_REC_END\n#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2\n#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1\n#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT\n#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0)\n#define CATCH_REC_NEXT(test, next)  CATCH_REC_NEXT1(CATCH_REC_GET_END test, next)\n\n#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )\n#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ )\n#define CATCH_REC_LIST2(f, x, peek, ...)   f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )\n\n#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ )\n#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ )\n#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...)   f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ )\n\n// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results,\n// and passes userdata as the first parameter to each invocation,\n// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c)\n#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0))\n\n#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))\n\n#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param)\n#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__\n#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__\n#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF\n#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__)\n#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__\n#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param))\n#else\n// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF\n#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__)\n#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__\n#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1)\n#endif\n\n#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__\n#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name)\n\n#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__)\n\n#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>())\n#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))\n#else\n#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>()))\n#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))\n#endif\n\n#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\\\n    CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__)\n\n#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0)\n#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1)\n#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2)\n#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3)\n#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4)\n#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5)\n#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6)\n#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7)\n#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8)\n#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9)\n#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10)\n\n#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N\n\n#define INTERNAL_CATCH_TYPE_GEN\\\n    template<typename...> struct TypeList {};\\\n    template<typename...Ts>\\\n    constexpr auto get_wrapper() noexcept -> TypeList<Ts...> { return {}; }\\\n    template<template<typename...> class...> struct TemplateTypeList{};\\\n    template<template<typename...> class...Cs>\\\n    constexpr auto get_wrapper() noexcept -> TemplateTypeList<Cs...> { return {}; }\\\n    template<typename...>\\\n    struct append;\\\n    template<typename...>\\\n    struct rewrap;\\\n    template<template<typename...> class, typename...>\\\n    struct create;\\\n    template<template<typename...> class, typename>\\\n    struct convert;\\\n    \\\n    template<typename T> \\\n    struct append<T> { using type = T; };\\\n    template< template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2, typename...Rest>\\\n    struct append<L1<E1...>, L2<E2...>, Rest...> { using type = typename append<L1<E1...,E2...>, Rest...>::type; };\\\n    template< template<typename...> class L1, typename...E1, typename...Rest>\\\n    struct append<L1<E1...>, TypeList<mpl_::na>, Rest...> { using type = L1<E1...>; };\\\n    \\\n    template< template<typename...> class Container, template<typename...> class List, typename...elems>\\\n    struct rewrap<TemplateTypeList<Container>, List<elems...>> { using type = TypeList<Container<elems...>>; };\\\n    template< template<typename...> class Container, template<typename...> class List, class...Elems, typename...Elements>\\\n    struct rewrap<TemplateTypeList<Container>, List<Elems...>, Elements...> { using type = typename append<TypeList<Container<Elems...>>, typename rewrap<TemplateTypeList<Container>, Elements...>::type>::type; };\\\n    \\\n    template<template <typename...> class Final, template< typename...> class...Containers, typename...Types>\\\n    struct create<Final, TemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<TemplateTypeList<Containers>, Types...>::type...>::type; };\\\n    template<template <typename...> class Final, template <typename...> class List, typename...Ts>\\\n    struct convert<Final, List<Ts...>> { using type = typename append<Final<>,TypeList<Ts>...>::type; };\n\n#define INTERNAL_CATCH_NTTP_1(signature, ...)\\\n    template<INTERNAL_CATCH_REMOVE_PARENS(signature)> struct Nttp{};\\\n    template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\\\n    constexpr auto get_wrapper() noexcept -> Nttp<__VA_ARGS__> { return {}; } \\\n    template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...> struct NttpTemplateTypeList{};\\\n    template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Cs>\\\n    constexpr auto get_wrapper() noexcept -> NttpTemplateTypeList<Cs...> { return {}; } \\\n    \\\n    template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature)>\\\n    struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>> { using type = TypeList<Container<__VA_ARGS__>>; };\\\n    template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature), typename...Elements>\\\n    struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>, Elements...> { using type = typename append<TypeList<Container<__VA_ARGS__>>, typename rewrap<NttpTemplateTypeList<Container>, Elements...>::type>::type; };\\\n    template<template <typename...> class Final, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Containers, typename...Types>\\\n    struct create<Final, NttpTemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<NttpTemplateTypeList<Containers>, Types...>::type...>::type; };\n\n#define INTERNAL_CATCH_DECLARE_SIG_TEST0(TestName)\n#define INTERNAL_CATCH_DECLARE_SIG_TEST1(TestName, signature)\\\n    template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\\\n    static void TestName()\n#define INTERNAL_CATCH_DECLARE_SIG_TEST_X(TestName, signature, ...)\\\n    template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\\\n    static void TestName()\n\n#define INTERNAL_CATCH_DEFINE_SIG_TEST0(TestName)\n#define INTERNAL_CATCH_DEFINE_SIG_TEST1(TestName, signature)\\\n    template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\\\n    static void TestName()\n#define INTERNAL_CATCH_DEFINE_SIG_TEST_X(TestName, signature,...)\\\n    template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\\\n    static void TestName()\n\n#define INTERNAL_CATCH_NTTP_REGISTER0(TestFunc, signature)\\\n    template<typename Type>\\\n    void reg_test(TypeList<Type>, Catch::NameAndTags nameAndTags)\\\n    {\\\n        Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<Type>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\\\n    }\n\n#define INTERNAL_CATCH_NTTP_REGISTER(TestFunc, signature, ...)\\\n    template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\\\n    void reg_test(Nttp<__VA_ARGS__>, Catch::NameAndTags nameAndTags)\\\n    {\\\n        Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<__VA_ARGS__>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\\\n    }\n\n#define INTERNAL_CATCH_NTTP_REGISTER_METHOD0(TestName, signature, ...)\\\n    template<typename Type>\\\n    void reg_test(TypeList<Type>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\\\n    {\\\n        Catch::AutoReg( Catch::makeTestInvoker(&TestName<Type>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\\\n    }\n\n#define INTERNAL_CATCH_NTTP_REGISTER_METHOD(TestName, signature, ...)\\\n    template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\\\n    void reg_test(Nttp<__VA_ARGS__>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\\\n    {\\\n        Catch::AutoReg( Catch::makeTestInvoker(&TestName<__VA_ARGS__>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\\\n    }\n\n#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0(TestName, ClassName)\n#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1(TestName, ClassName, signature)\\\n    template<typename TestType> \\\n    struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<TestType> { \\\n        void test();\\\n    }\n\n#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X(TestName, ClassName, signature, ...)\\\n    template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \\\n    struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<__VA_ARGS__> { \\\n        void test();\\\n    }\n\n#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0(TestName)\n#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1(TestName, signature)\\\n    template<typename TestType> \\\n    void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<TestType>::test()\n#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X(TestName, signature, ...)\\\n    template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \\\n    void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<__VA_ARGS__>::test()\n\n#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n#define INTERNAL_CATCH_NTTP_0\n#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__),INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_0)\n#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( \"dummy\", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__)\n#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( \"dummy\", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__)\n#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( \"dummy\", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__)\n#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_VA_NARGS_IMPL( \"dummy\", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__)\n#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( \"dummy\", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__)\n#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( \"dummy\", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__)\n#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__)\n#else\n#define INTERNAL_CATCH_NTTP_0(signature)\n#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1,INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_0)( __VA_ARGS__))\n#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( \"dummy\", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__))\n#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( \"dummy\", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__))\n#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( \"dummy\", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__))\n#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( \"dummy\", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__))\n#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( \"dummy\", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__))\n#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( \"dummy\", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__))\n#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__))\n#endif\n\n// end catch_preprocessor.hpp\n// start catch_meta.hpp\n\n\n#include <type_traits>\n\nnamespace Catch {\n    template<typename T>\n    struct always_false : std::false_type {};\n\n    template <typename> struct true_given : std::true_type {};\n    struct is_callable_tester {\n        template <typename Fun, typename... Args>\n        true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int);\n        template <typename...>\n        std::false_type static test(...);\n    };\n\n    template <typename T>\n    struct is_callable;\n\n    template <typename Fun, typename... Args>\n    struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {};\n\n#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703\n    // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is\n    // replaced with std::invoke_result here.\n    template <typename Func, typename... U>\n    using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U...>>>;\n#else\n    // Keep ::type here because we still support C++11\n    template <typename Func, typename... U>\n    using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U...)>::type>::type>::type;\n#endif\n\n} // namespace Catch\n\nnamespace mpl_{\n    struct na;\n}\n\n// end catch_meta.hpp\nnamespace Catch {\n\ntemplate<typename C>\nclass TestInvokerAsMethod : public ITestInvoker {\n    void (C::*m_testAsMethod)();\npublic:\n    TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {}\n\n    void invoke() const override {\n        C obj;\n        (obj.*m_testAsMethod)();\n    }\n};\n\nauto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*;\n\ntemplate<typename C>\nauto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* {\n    return new(std::nothrow) TestInvokerAsMethod<C>( testAsMethod );\n}\n\nstruct NameAndTags {\n    NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept;\n    StringRef name;\n    StringRef tags;\n};\n\nstruct AutoReg : NonCopyable {\n    AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept;\n    ~AutoReg();\n};\n\n} // end namespace Catch\n\n#if defined(CATCH_CONFIG_DISABLE)\n    #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \\\n        static void TestName()\n    #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \\\n        namespace{                        \\\n            struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \\\n                void test();              \\\n            };                            \\\n        }                                 \\\n        void TestName::test()\n    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( TestName, TestFunc, Name, Tags, Signature, ... )  \\\n        INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature))\n    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... )    \\\n        namespace{                                                                                  \\\n            namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) {                                      \\\n            INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\\\n        }                                                                                           \\\n        }                                                                                           \\\n        INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))\n\n    #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n        #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \\\n            INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ )\n    #else\n        #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \\\n            INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) )\n    #endif\n\n    #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n        #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \\\n            INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ )\n    #else\n        #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \\\n            INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) )\n    #endif\n\n    #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n        #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \\\n            INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )\n    #else\n        #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \\\n            INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )\n    #endif\n\n    #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n        #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \\\n            INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )\n    #else\n        #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \\\n            INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )\n    #endif\n#endif\n\n    ///////////////////////////////////////////////////////////////////////////////\n    #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \\\n        static void TestName(); \\\n        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \\\n        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \\\n        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \\\n        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \\\n        static void TestName()\n    #define INTERNAL_CATCH_TESTCASE( ... ) \\\n        INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), __VA_ARGS__ )\n\n    ///////////////////////////////////////////////////////////////////////////////\n    #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \\\n        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \\\n        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \\\n        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, \"&\" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \\\n        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION\n\n    ///////////////////////////////////////////////////////////////////////////////\n    #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\\\n        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \\\n        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \\\n        namespace{ \\\n            struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \\\n                void test(); \\\n            }; \\\n            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \\\n        } \\\n        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \\\n        void TestName::test()\n    #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \\\n        INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), ClassName, __VA_ARGS__ )\n\n    ///////////////////////////////////////////////////////////////////////////////\n    #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \\\n        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \\\n        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \\\n        Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \\\n        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION\n\n    ///////////////////////////////////////////////////////////////////////////////\n    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, Signature, ... )\\\n        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \\\n        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \\\n        CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \\\n        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \\\n        INTERNAL_CATCH_DECLARE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature));\\\n        namespace {\\\n        namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\\\n            INTERNAL_CATCH_TYPE_GEN\\\n            INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\\\n            INTERNAL_CATCH_NTTP_REG_GEN(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))\\\n            template<typename...Types> \\\n            struct TestName{\\\n                TestName(){\\\n                    int index = 0;                                    \\\n                    constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\\\n                    using expander = int[];\\\n                    (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name \" - \" + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \\\n                }\\\n            };\\\n            static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\\\n            TestName<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\\\n            return 0;\\\n        }();\\\n        }\\\n        }\\\n        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \\\n        INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))\n\n#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \\\n        INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ )\n#else\n    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \\\n        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) )\n#endif\n\n#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \\\n        INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ )\n#else\n    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \\\n        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) )\n#endif\n\n    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \\\n        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION                      \\\n        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS                      \\\n        CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS                \\\n        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS              \\\n        template<typename TestType> static void TestFuncName();       \\\n        namespace {\\\n        namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) {                                     \\\n            INTERNAL_CATCH_TYPE_GEN                                                  \\\n            INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))         \\\n            template<typename... Types>                               \\\n            struct TestName {                                         \\\n                void reg_tests() {                                          \\\n                    int index = 0;                                    \\\n                    using expander = int[];                           \\\n                    constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\\\n                    constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\\\n                    constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\\\n                    (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name \" - \" + std::string(tmpl_types[index / num_types]) + \"<\" + std::string(types_list[index % num_types]) + \">\", Tags } ), index++)... };/* NOLINT */\\\n                }                                                     \\\n            };                                                        \\\n            static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \\\n                using TestInit = typename create<TestName, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \\\n                TestInit t;                                           \\\n                t.reg_tests();                                        \\\n                return 0;                                             \\\n            }();                                                      \\\n        }                                                             \\\n        }                                                             \\\n        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION                       \\\n        template<typename TestType>                                   \\\n        static void TestFuncName()\n\n#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\\\n        INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename T,__VA_ARGS__)\n#else\n    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\\\n        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename T, __VA_ARGS__ ) )\n#endif\n\n#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\\\n        INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__)\n#else\n    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\\\n        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) )\n#endif\n\n    #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\\\n        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \\\n        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \\\n        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \\\n        template<typename TestType> static void TestFunc();       \\\n        namespace {\\\n        namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\\\n        INTERNAL_CATCH_TYPE_GEN\\\n        template<typename... Types>                               \\\n        struct TestName {                                         \\\n            void reg_tests() {                                          \\\n                int index = 0;                                    \\\n                using expander = int[];                           \\\n                (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name \" - \" + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + \" - \" + std::to_string(index), Tags } ), index++)... };/* NOLINT */\\\n            }                                                     \\\n        };\\\n        static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \\\n                using TestInit = typename convert<TestName, TmplList>::type; \\\n                TestInit t;                                           \\\n                t.reg_tests();                                        \\\n                return 0;                                             \\\n            }();                                                      \\\n        }}\\\n        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION                       \\\n        template<typename TestType>                                   \\\n        static void TestFunc()\n\n    #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \\\n        INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, TmplList )\n\n    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \\\n        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \\\n        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \\\n        CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \\\n        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \\\n        namespace {\\\n        namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \\\n            INTERNAL_CATCH_TYPE_GEN\\\n            INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\\\n            INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\\\n            INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))\\\n            template<typename...Types> \\\n            struct TestNameClass{\\\n                TestNameClass(){\\\n                    int index = 0;                                    \\\n                    constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\\\n                    using expander = int[];\\\n                    (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name \" - \" + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \\\n                }\\\n            };\\\n            static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\\\n                TestNameClass<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\\\n                return 0;\\\n        }();\\\n        }\\\n        }\\\n        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \\\n        INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))\n\n#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \\\n        INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )\n#else\n    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \\\n        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )\n#endif\n\n#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \\\n        INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )\n#else\n    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \\\n        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )\n#endif\n\n    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\\\n        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \\\n        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \\\n        CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \\\n        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \\\n        template<typename TestType> \\\n            struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \\\n                void test();\\\n            };\\\n        namespace {\\\n        namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\\\n            INTERNAL_CATCH_TYPE_GEN                  \\\n            INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\\\n            template<typename...Types>\\\n            struct TestNameClass{\\\n                void reg_tests(){\\\n                    int index = 0;\\\n                    using expander = int[];\\\n                    constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\\\n                    constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\\\n                    constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\\\n                    (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name \" - \" + std::string(tmpl_types[index / num_types]) + \"<\" + std::string(types_list[index % num_types]) + \">\", Tags } ), index++)... };/* NOLINT */ \\\n                }\\\n            };\\\n            static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\\\n                using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\\\n                TestInit t;\\\n                t.reg_tests();\\\n                return 0;\\\n            }(); \\\n        }\\\n        }\\\n        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \\\n        template<typename TestType> \\\n        void TestName<TestType>::test()\n\n#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\\\n        INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, typename T, __VA_ARGS__ )\n#else\n    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\\\n        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) )\n#endif\n\n#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\\\n        INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, Signature, __VA_ARGS__ )\n#else\n    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\\\n        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) )\n#endif\n\n    #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \\\n        CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \\\n        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \\\n        CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \\\n        template<typename TestType> \\\n        struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \\\n            void test();\\\n        };\\\n        namespace {\\\n        namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \\\n            INTERNAL_CATCH_TYPE_GEN\\\n            template<typename...Types>\\\n            struct TestNameClass{\\\n                void reg_tests(){\\\n                    int index = 0;\\\n                    using expander = int[];\\\n                    (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name \" - \" + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + \" - \" + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \\\n                }\\\n            };\\\n            static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\\\n                using TestInit = typename convert<TestNameClass, TmplList>::type;\\\n                TestInit t;\\\n                t.reg_tests();\\\n                return 0;\\\n            }(); \\\n        }}\\\n        CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \\\n        template<typename TestType> \\\n        void TestName<TestType>::test()\n\n#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \\\n        INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, TmplList )\n\n// end catch_test_registry.h\n// start catch_capture.hpp\n\n// start catch_assertionhandler.h\n\n// start catch_assertioninfo.h\n\n// start catch_result_type.h\n\nnamespace Catch {\n\n    // ResultWas::OfType enum\n    struct ResultWas { enum OfType {\n        Unknown = -1,\n        Ok = 0,\n        Info = 1,\n        Warning = 2,\n\n        FailureBit = 0x10,\n\n        ExpressionFailed = FailureBit | 1,\n        ExplicitFailure = FailureBit | 2,\n\n        Exception = 0x100 | FailureBit,\n\n        ThrewException = Exception | 1,\n        DidntThrowException = Exception | 2,\n\n        FatalErrorCondition = 0x200 | FailureBit\n\n    }; };\n\n    bool isOk( ResultWas::OfType resultType );\n    bool isJustInfo( int flags );\n\n    // ResultDisposition::Flags enum\n    struct ResultDisposition { enum Flags {\n        Normal = 0x01,\n\n        ContinueOnFailure = 0x02,   // Failures fail test, but execution continues\n        FalseTest = 0x04,           // Prefix expression with !\n        SuppressFail = 0x08         // Failures are reported but do not fail the test\n    }; };\n\n    ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs );\n\n    bool shouldContinueOnFailure( int flags );\n    inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; }\n    bool shouldSuppressFailure( int flags );\n\n} // end namespace Catch\n\n// end catch_result_type.h\nnamespace Catch {\n\n    struct AssertionInfo\n    {\n        StringRef macroName;\n        SourceLineInfo lineInfo;\n        StringRef capturedExpression;\n        ResultDisposition::Flags resultDisposition;\n\n        // We want to delete this constructor but a compiler bug in 4.8 means\n        // the struct is then treated as non-aggregate\n        //AssertionInfo() = delete;\n    };\n\n} // end namespace Catch\n\n// end catch_assertioninfo.h\n// start catch_decomposer.h\n\n// start catch_tostring.h\n\n#include <vector>\n#include <cstddef>\n#include <type_traits>\n#include <string>\n// start catch_stream.h\n\n#include <iosfwd>\n#include <cstddef>\n#include <ostream>\n\nnamespace Catch {\n\n    std::ostream& cout();\n    std::ostream& cerr();\n    std::ostream& clog();\n\n    class StringRef;\n\n    struct IStream {\n        virtual ~IStream();\n        virtual std::ostream& stream() const = 0;\n    };\n\n    auto makeStream( StringRef const &filename ) -> IStream const*;\n\n    class ReusableStringStream : NonCopyable {\n        std::size_t m_index;\n        std::ostream* m_oss;\n    public:\n        ReusableStringStream();\n        ~ReusableStringStream();\n\n        auto str() const -> std::string;\n\n        template<typename T>\n        auto operator << ( T const& value ) -> ReusableStringStream& {\n            *m_oss << value;\n            return *this;\n        }\n        auto get() -> std::ostream& { return *m_oss; }\n    };\n}\n\n// end catch_stream.h\n// start catch_interfaces_enum_values_registry.h\n\n#include <vector>\n\nnamespace Catch {\n\n    namespace Detail {\n        struct EnumInfo {\n            StringRef m_name;\n            std::vector<std::pair<int, StringRef>> m_values;\n\n            ~EnumInfo();\n\n            StringRef lookup( int value ) const;\n        };\n    } // namespace Detail\n\n    struct IMutableEnumValuesRegistry {\n        virtual ~IMutableEnumValuesRegistry();\n\n        virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0;\n\n        template<typename E>\n        Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) {\n            static_assert(sizeof(int) >= sizeof(E), \"Cannot serialize enum to int\");\n            std::vector<int> intValues;\n            intValues.reserve( values.size() );\n            for( auto enumValue : values )\n                intValues.push_back( static_cast<int>( enumValue ) );\n            return registerEnum( enumName, allEnums, intValues );\n        }\n    };\n\n} // Catch\n\n// end catch_interfaces_enum_values_registry.h\n\n#ifdef CATCH_CONFIG_CPP17_STRING_VIEW\n#include <string_view>\n#endif\n\n#ifdef __OBJC__\n// start catch_objc_arc.hpp\n\n#import <Foundation/Foundation.h>\n\n#ifdef __has_feature\n#define CATCH_ARC_ENABLED __has_feature(objc_arc)\n#else\n#define CATCH_ARC_ENABLED 0\n#endif\n\nvoid arcSafeRelease( NSObject* obj );\nid performOptionalSelector( id obj, SEL sel );\n\n#if !CATCH_ARC_ENABLED\ninline void arcSafeRelease( NSObject* obj ) {\n    [obj release];\n}\ninline id performOptionalSelector( id obj, SEL sel ) {\n    if( [obj respondsToSelector: sel] )\n        return [obj performSelector: sel];\n    return nil;\n}\n#define CATCH_UNSAFE_UNRETAINED\n#define CATCH_ARC_STRONG\n#else\ninline void arcSafeRelease( NSObject* ){}\ninline id performOptionalSelector( id obj, SEL sel ) {\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Warc-performSelector-leaks\"\n#endif\n    if( [obj respondsToSelector: sel] )\n        return [obj performSelector: sel];\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n    return nil;\n}\n#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained\n#define CATCH_ARC_STRONG __strong\n#endif\n\n// end catch_objc_arc.hpp\n#endif\n\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless\n#endif\n\nnamespace Catch {\n    namespace Detail {\n\n        extern const std::string unprintableString;\n\n        std::string rawMemoryToString( const void *object, std::size_t size );\n\n        template<typename T>\n        std::string rawMemoryToString( const T& object ) {\n          return rawMemoryToString( &object, sizeof(object) );\n        }\n\n        template<typename T>\n        class IsStreamInsertable {\n            template<typename Stream, typename U>\n            static auto test(int)\n                -> decltype(std::declval<Stream&>() << std::declval<U>(), std::true_type());\n\n            template<typename, typename>\n            static auto test(...)->std::false_type;\n\n        public:\n            static const bool value = decltype(test<std::ostream, const T&>(0))::value;\n        };\n\n        template<typename E>\n        std::string convertUnknownEnumToString( E e );\n\n        template<typename T>\n        typename std::enable_if<\n            !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,\n        std::string>::type convertUnstreamable( T const& ) {\n            return Detail::unprintableString;\n        }\n        template<typename T>\n        typename std::enable_if<\n            !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,\n         std::string>::type convertUnstreamable(T const& ex) {\n            return ex.what();\n        }\n\n        template<typename T>\n        typename std::enable_if<\n            std::is_enum<T>::value\n        , std::string>::type convertUnstreamable( T const& value ) {\n            return convertUnknownEnumToString( value );\n        }\n\n#if defined(_MANAGED)\n        //! Convert a CLR string to a utf8 std::string\n        template<typename T>\n        std::string clrReferenceToString( T^ ref ) {\n            if (ref == nullptr)\n                return std::string(\"null\");\n            auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString());\n            cli::pin_ptr<System::Byte> p = &bytes[0];\n            return std::string(reinterpret_cast<char const *>(p), bytes->Length);\n        }\n#endif\n\n    } // namespace Detail\n\n    // If we decide for C++14, change these to enable_if_ts\n    template <typename T, typename = void>\n    struct StringMaker {\n        template <typename Fake = T>\n        static\n        typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type\n            convert(const Fake& value) {\n                ReusableStringStream rss;\n                // NB: call using the function-like syntax to avoid ambiguity with\n                // user-defined templated operator<< under clang.\n                rss.operator<<(value);\n                return rss.str();\n        }\n\n        template <typename Fake = T>\n        static\n        typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type\n            convert( const Fake& value ) {\n#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)\n            return Detail::convertUnstreamable(value);\n#else\n            return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);\n#endif\n        }\n    };\n\n    namespace Detail {\n\n        // This function dispatches all stringification requests inside of Catch.\n        // Should be preferably called fully qualified, like ::Catch::Detail::stringify\n        template <typename T>\n        std::string stringify(const T& e) {\n            return ::Catch::StringMaker<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::convert(e);\n        }\n\n        template<typename E>\n        std::string convertUnknownEnumToString( E e ) {\n            return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<E>::type>(e));\n        }\n\n#if defined(_MANAGED)\n        template <typename T>\n        std::string stringify( T^ e ) {\n            return ::Catch::StringMaker<T^>::convert(e);\n        }\n#endif\n\n    } // namespace Detail\n\n    // Some predefined specializations\n\n    template<>\n    struct StringMaker<std::string> {\n        static std::string convert(const std::string& str);\n    };\n\n#ifdef CATCH_CONFIG_CPP17_STRING_VIEW\n    template<>\n    struct StringMaker<std::string_view> {\n        static std::string convert(std::string_view str);\n    };\n#endif\n\n    template<>\n    struct StringMaker<char const *> {\n        static std::string convert(char const * str);\n    };\n    template<>\n    struct StringMaker<char *> {\n        static std::string convert(char * str);\n    };\n\n#ifdef CATCH_CONFIG_WCHAR\n    template<>\n    struct StringMaker<std::wstring> {\n        static std::string convert(const std::wstring& wstr);\n    };\n\n# ifdef CATCH_CONFIG_CPP17_STRING_VIEW\n    template<>\n    struct StringMaker<std::wstring_view> {\n        static std::string convert(std::wstring_view str);\n    };\n# endif\n\n    template<>\n    struct StringMaker<wchar_t const *> {\n        static std::string convert(wchar_t const * str);\n    };\n    template<>\n    struct StringMaker<wchar_t *> {\n        static std::string convert(wchar_t * str);\n    };\n#endif\n\n    // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer,\n    //      while keeping string semantics?\n    template<int SZ>\n    struct StringMaker<char[SZ]> {\n        static std::string convert(char const* str) {\n            return ::Catch::Detail::stringify(std::string{ str });\n        }\n    };\n    template<int SZ>\n    struct StringMaker<signed char[SZ]> {\n        static std::string convert(signed char const* str) {\n            return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) });\n        }\n    };\n    template<int SZ>\n    struct StringMaker<unsigned char[SZ]> {\n        static std::string convert(unsigned char const* str) {\n            return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) });\n        }\n    };\n\n#if defined(CATCH_CONFIG_CPP17_BYTE)\n    template<>\n    struct StringMaker<std::byte> {\n        static std::string convert(std::byte value);\n    };\n#endif // defined(CATCH_CONFIG_CPP17_BYTE)\n    template<>\n    struct StringMaker<int> {\n        static std::string convert(int value);\n    };\n    template<>\n    struct StringMaker<long> {\n        static std::string convert(long value);\n    };\n    template<>\n    struct StringMaker<long long> {\n        static std::string convert(long long value);\n    };\n    template<>\n    struct StringMaker<unsigned int> {\n        static std::string convert(unsigned int value);\n    };\n    template<>\n    struct StringMaker<unsigned long> {\n        static std::string convert(unsigned long value);\n    };\n    template<>\n    struct StringMaker<unsigned long long> {\n        static std::string convert(unsigned long long value);\n    };\n\n    template<>\n    struct StringMaker<bool> {\n        static std::string convert(bool b);\n    };\n\n    template<>\n    struct StringMaker<char> {\n        static std::string convert(char c);\n    };\n    template<>\n    struct StringMaker<signed char> {\n        static std::string convert(signed char c);\n    };\n    template<>\n    struct StringMaker<unsigned char> {\n        static std::string convert(unsigned char c);\n    };\n\n    template<>\n    struct StringMaker<std::nullptr_t> {\n        static std::string convert(std::nullptr_t);\n    };\n\n    template<>\n    struct StringMaker<float> {\n        static std::string convert(float value);\n        static int precision;\n    };\n\n    template<>\n    struct StringMaker<double> {\n        static std::string convert(double value);\n        static int precision;\n    };\n\n    template <typename T>\n    struct StringMaker<T*> {\n        template <typename U>\n        static std::string convert(U* p) {\n            if (p) {\n                return ::Catch::Detail::rawMemoryToString(p);\n            } else {\n                return \"nullptr\";\n            }\n        }\n    };\n\n    template <typename R, typename C>\n    struct StringMaker<R C::*> {\n        static std::string convert(R C::* p) {\n            if (p) {\n                return ::Catch::Detail::rawMemoryToString(p);\n            } else {\n                return \"nullptr\";\n            }\n        }\n    };\n\n#if defined(_MANAGED)\n    template <typename T>\n    struct StringMaker<T^> {\n        static std::string convert( T^ ref ) {\n            return ::Catch::Detail::clrReferenceToString(ref);\n        }\n    };\n#endif\n\n    namespace Detail {\n        template<typename InputIterator, typename Sentinel = InputIterator>\n        std::string rangeToString(InputIterator first, Sentinel last) {\n            ReusableStringStream rss;\n            rss << \"{ \";\n            if (first != last) {\n                rss << ::Catch::Detail::stringify(*first);\n                for (++first; first != last; ++first)\n                    rss << \", \" << ::Catch::Detail::stringify(*first);\n            }\n            rss << \" }\";\n            return rss.str();\n        }\n    }\n\n#ifdef __OBJC__\n    template<>\n    struct StringMaker<NSString*> {\n        static std::string convert(NSString * nsstring) {\n            if (!nsstring)\n                return \"nil\";\n            return std::string(\"@\") + [nsstring UTF8String];\n        }\n    };\n    template<>\n    struct StringMaker<NSObject*> {\n        static std::string convert(NSObject* nsObject) {\n            return ::Catch::Detail::stringify([nsObject description]);\n        }\n\n    };\n    namespace Detail {\n        inline std::string stringify( NSString* nsstring ) {\n            return StringMaker<NSString*>::convert( nsstring );\n        }\n\n    } // namespace Detail\n#endif // __OBJC__\n\n} // namespace Catch\n\n//////////////////////////////////////////////////////\n// Separate std-lib types stringification, so it can be selectively enabled\n// This means that we do not bring in\n\n#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)\n#  define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER\n#  define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER\n#  define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER\n#  define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER\n#  define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER\n#endif\n\n// Separate std::pair specialization\n#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER)\n#include <utility>\nnamespace Catch {\n    template<typename T1, typename T2>\n    struct StringMaker<std::pair<T1, T2> > {\n        static std::string convert(const std::pair<T1, T2>& pair) {\n            ReusableStringStream rss;\n            rss << \"{ \"\n                << ::Catch::Detail::stringify(pair.first)\n                << \", \"\n                << ::Catch::Detail::stringify(pair.second)\n                << \" }\";\n            return rss.str();\n        }\n    };\n}\n#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER\n\n#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)\n#include <optional>\nnamespace Catch {\n    template<typename T>\n    struct StringMaker<std::optional<T> > {\n        static std::string convert(const std::optional<T>& optional) {\n            ReusableStringStream rss;\n            if (optional.has_value()) {\n                rss << ::Catch::Detail::stringify(*optional);\n            } else {\n                rss << \"{ }\";\n            }\n            return rss.str();\n        }\n    };\n}\n#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER\n\n// Separate std::tuple specialization\n#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)\n#include <tuple>\nnamespace Catch {\n    namespace Detail {\n        template<\n            typename Tuple,\n            std::size_t N = 0,\n            bool = (N < std::tuple_size<Tuple>::value)\n            >\n            struct TupleElementPrinter {\n            static void print(const Tuple& tuple, std::ostream& os) {\n                os << (N ? \", \" : \" \")\n                    << ::Catch::Detail::stringify(std::get<N>(tuple));\n                TupleElementPrinter<Tuple, N + 1>::print(tuple, os);\n            }\n        };\n\n        template<\n            typename Tuple,\n            std::size_t N\n        >\n            struct TupleElementPrinter<Tuple, N, false> {\n            static void print(const Tuple&, std::ostream&) {}\n        };\n\n    }\n\n    template<typename ...Types>\n    struct StringMaker<std::tuple<Types...>> {\n        static std::string convert(const std::tuple<Types...>& tuple) {\n            ReusableStringStream rss;\n            rss << '{';\n            Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get());\n            rss << \" }\";\n            return rss.str();\n        }\n    };\n}\n#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER\n\n#if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT)\n#include <variant>\nnamespace Catch {\n    template<>\n    struct StringMaker<std::monostate> {\n        static std::string convert(const std::monostate&) {\n            return \"{ }\";\n        }\n    };\n\n    template<typename... Elements>\n    struct StringMaker<std::variant<Elements...>> {\n        static std::string convert(const std::variant<Elements...>& variant) {\n            if (variant.valueless_by_exception()) {\n                return \"{valueless variant}\";\n            } else {\n                return std::visit(\n                    [](const auto& value) {\n                        return ::Catch::Detail::stringify(value);\n                    },\n                    variant\n                );\n            }\n        }\n    };\n}\n#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER\n\nnamespace Catch {\n    // Import begin/ end from std here\n    using std::begin;\n    using std::end;\n\n    namespace detail {\n        template <typename...>\n        struct void_type {\n            using type = void;\n        };\n\n        template <typename T, typename = void>\n        struct is_range_impl : std::false_type {\n        };\n\n        template <typename T>\n        struct is_range_impl<T, typename void_type<decltype(begin(std::declval<T>()))>::type> : std::true_type {\n        };\n    } // namespace detail\n\n    template <typename T>\n    struct is_range : detail::is_range_impl<T> {\n    };\n\n#if defined(_MANAGED) // Managed types are never ranges\n    template <typename T>\n    struct is_range<T^> {\n        static const bool value = false;\n    };\n#endif\n\n    template<typename Range>\n    std::string rangeToString( Range const& range ) {\n        return ::Catch::Detail::rangeToString( begin( range ), end( range ) );\n    }\n\n    // Handle vector<bool> specially\n    template<typename Allocator>\n    std::string rangeToString( std::vector<bool, Allocator> const& v ) {\n        ReusableStringStream rss;\n        rss << \"{ \";\n        bool first = true;\n        for( bool b : v ) {\n            if( first )\n                first = false;\n            else\n                rss << \", \";\n            rss << ::Catch::Detail::stringify( b );\n        }\n        rss << \" }\";\n        return rss.str();\n    }\n\n    template<typename R>\n    struct StringMaker<R, typename std::enable_if<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>::type> {\n        static std::string convert( R const& range ) {\n            return rangeToString( range );\n        }\n    };\n\n    template <typename T, int SZ>\n    struct StringMaker<T[SZ]> {\n        static std::string convert(T const(&arr)[SZ]) {\n            return rangeToString(arr);\n        }\n    };\n\n} // namespace Catch\n\n// Separate std::chrono::duration specialization\n#if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)\n#include <ctime>\n#include <ratio>\n#include <chrono>\n\nnamespace Catch {\n\ntemplate <class Ratio>\nstruct ratio_string {\n    static std::string symbol();\n};\n\ntemplate <class Ratio>\nstd::string ratio_string<Ratio>::symbol() {\n    Catch::ReusableStringStream rss;\n    rss << '[' << Ratio::num << '/'\n        << Ratio::den << ']';\n    return rss.str();\n}\ntemplate <>\nstruct ratio_string<std::atto> {\n    static std::string symbol();\n};\ntemplate <>\nstruct ratio_string<std::femto> {\n    static std::string symbol();\n};\ntemplate <>\nstruct ratio_string<std::pico> {\n    static std::string symbol();\n};\ntemplate <>\nstruct ratio_string<std::nano> {\n    static std::string symbol();\n};\ntemplate <>\nstruct ratio_string<std::micro> {\n    static std::string symbol();\n};\ntemplate <>\nstruct ratio_string<std::milli> {\n    static std::string symbol();\n};\n\n    ////////////\n    // std::chrono::duration specializations\n    template<typename Value, typename Ratio>\n    struct StringMaker<std::chrono::duration<Value, Ratio>> {\n        static std::string convert(std::chrono::duration<Value, Ratio> const& duration) {\n            ReusableStringStream rss;\n            rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's';\n            return rss.str();\n        }\n    };\n    template<typename Value>\n    struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> {\n        static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) {\n            ReusableStringStream rss;\n            rss << duration.count() << \" s\";\n            return rss.str();\n        }\n    };\n    template<typename Value>\n    struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> {\n        static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) {\n            ReusableStringStream rss;\n            rss << duration.count() << \" m\";\n            return rss.str();\n        }\n    };\n    template<typename Value>\n    struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> {\n        static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) {\n            ReusableStringStream rss;\n            rss << duration.count() << \" h\";\n            return rss.str();\n        }\n    };\n\n    ////////////\n    // std::chrono::time_point specialization\n    // Generic time_point cannot be specialized, only std::chrono::time_point<system_clock>\n    template<typename Clock, typename Duration>\n    struct StringMaker<std::chrono::time_point<Clock, Duration>> {\n        static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) {\n            return ::Catch::Detail::stringify(time_point.time_since_epoch()) + \" since epoch\";\n        }\n    };\n    // std::chrono::time_point<system_clock> specialization\n    template<typename Duration>\n    struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> {\n        static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) {\n            auto converted = std::chrono::system_clock::to_time_t(time_point);\n\n#ifdef _MSC_VER\n            std::tm timeInfo = {};\n            gmtime_s(&timeInfo, &converted);\n#else\n            std::tm* timeInfo = std::gmtime(&converted);\n#endif\n\n            auto const timeStampSize = sizeof(\"2017-01-16T17:06:45Z\");\n            char timeStamp[timeStampSize];\n            const char * const fmt = \"%Y-%m-%dT%H:%M:%SZ\";\n\n#ifdef _MSC_VER\n            std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);\n#else\n            std::strftime(timeStamp, timeStampSize, fmt, timeInfo);\n#endif\n            return std::string(timeStamp);\n        }\n    };\n}\n#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER\n\n#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \\\nnamespace Catch { \\\n    template<> struct StringMaker<enumName> { \\\n        static std::string convert( enumName value ) { \\\n            static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \\\n            return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \\\n        } \\\n    }; \\\n}\n\n#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ )\n\n#ifdef _MSC_VER\n#pragma warning(pop)\n#endif\n\n// end catch_tostring.h\n#include <iosfwd>\n\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable:4389) // '==' : signed/unsigned mismatch\n#pragma warning(disable:4018) // more \"signed/unsigned mismatch\"\n#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)\n#pragma warning(disable:4180) // qualifier applied to function type has no meaning\n#pragma warning(disable:4800) // Forcing result to true or false\n#endif\n\nnamespace Catch {\n\n    struct ITransientExpression {\n        auto isBinaryExpression() const -> bool { return m_isBinaryExpression; }\n        auto getResult() const -> bool { return m_result; }\n        virtual void streamReconstructedExpression( std::ostream &os ) const = 0;\n\n        ITransientExpression( bool isBinaryExpression, bool result )\n        :   m_isBinaryExpression( isBinaryExpression ),\n            m_result( result )\n        {}\n\n        // We don't actually need a virtual destructor, but many static analysers\n        // complain if it's not here :-(\n        virtual ~ITransientExpression();\n\n        bool m_isBinaryExpression;\n        bool m_result;\n\n    };\n\n    void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs );\n\n    template<typename LhsT, typename RhsT>\n    class BinaryExpr  : public ITransientExpression {\n        LhsT m_lhs;\n        StringRef m_op;\n        RhsT m_rhs;\n\n        void streamReconstructedExpression( std::ostream &os ) const override {\n            formatReconstructedExpression\n                    ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) );\n        }\n\n    public:\n        BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )\n        :   ITransientExpression{ true, comparisonResult },\n            m_lhs( lhs ),\n            m_op( op ),\n            m_rhs( rhs )\n        {}\n\n        template<typename T>\n        auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {\n            static_assert(always_false<T>::value,\n            \"chained comparisons are not supported inside assertions, \"\n            \"wrap the expression inside parentheses, or decompose it\");\n        }\n\n        template<typename T>\n        auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {\n            static_assert(always_false<T>::value,\n            \"chained comparisons are not supported inside assertions, \"\n            \"wrap the expression inside parentheses, or decompose it\");\n        }\n\n        template<typename T>\n        auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {\n            static_assert(always_false<T>::value,\n            \"chained comparisons are not supported inside assertions, \"\n            \"wrap the expression inside parentheses, or decompose it\");\n        }\n\n        template<typename T>\n        auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {\n            static_assert(always_false<T>::value,\n            \"chained comparisons are not supported inside assertions, \"\n            \"wrap the expression inside parentheses, or decompose it\");\n        }\n\n        template<typename T>\n        auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {\n            static_assert(always_false<T>::value,\n            \"chained comparisons are not supported inside assertions, \"\n            \"wrap the expression inside parentheses, or decompose it\");\n        }\n\n        template<typename T>\n        auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {\n            static_assert(always_false<T>::value,\n            \"chained comparisons are not supported inside assertions, \"\n            \"wrap the expression inside parentheses, or decompose it\");\n        }\n\n        template<typename T>\n        auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {\n            static_assert(always_false<T>::value,\n            \"chained comparisons are not supported inside assertions, \"\n            \"wrap the expression inside parentheses, or decompose it\");\n        }\n\n        template<typename T>\n        auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {\n            static_assert(always_false<T>::value,\n            \"chained comparisons are not supported inside assertions, \"\n            \"wrap the expression inside parentheses, or decompose it\");\n        }\n    };\n\n    template<typename LhsT>\n    class UnaryExpr : public ITransientExpression {\n        LhsT m_lhs;\n\n        void streamReconstructedExpression( std::ostream &os ) const override {\n            os << Catch::Detail::stringify( m_lhs );\n        }\n\n    public:\n        explicit UnaryExpr( LhsT lhs )\n        :   ITransientExpression{ false, static_cast<bool>(lhs) },\n            m_lhs( lhs )\n        {}\n    };\n\n    // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int)\n    template<typename LhsT, typename RhsT>\n    auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); }\n    template<typename T>\n    auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }\n    template<typename T>\n    auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }\n    template<typename T>\n    auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }\n    template<typename T>\n    auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }\n\n    template<typename LhsT, typename RhsT>\n    auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); }\n    template<typename T>\n    auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }\n    template<typename T>\n    auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }\n    template<typename T>\n    auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; }\n    template<typename T>\n    auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; }\n\n    template<typename LhsT>\n    class ExprLhs {\n        LhsT m_lhs;\n    public:\n        explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}\n\n        template<typename RhsT>\n        auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {\n            return { compareEqual( m_lhs, rhs ), m_lhs, \"==\", rhs };\n        }\n        auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const {\n            return { m_lhs == rhs, m_lhs, \"==\", rhs };\n        }\n\n        template<typename RhsT>\n        auto operator != ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {\n            return { compareNotEqual( m_lhs, rhs ), m_lhs, \"!=\", rhs };\n        }\n        auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const {\n            return { m_lhs != rhs, m_lhs, \"!=\", rhs };\n        }\n\n        template<typename RhsT>\n        auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {\n            return { static_cast<bool>(m_lhs > rhs), m_lhs, \">\", rhs };\n        }\n        template<typename RhsT>\n        auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {\n            return { static_cast<bool>(m_lhs < rhs), m_lhs, \"<\", rhs };\n        }\n        template<typename RhsT>\n        auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {\n            return { static_cast<bool>(m_lhs >= rhs), m_lhs, \">=\", rhs };\n        }\n        template<typename RhsT>\n        auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {\n            return { static_cast<bool>(m_lhs <= rhs), m_lhs, \"<=\", rhs };\n        }\n        template <typename RhsT>\n        auto operator | (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {\n            return { static_cast<bool>(m_lhs | rhs), m_lhs, \"|\", rhs };\n        }\n        template <typename RhsT>\n        auto operator & (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {\n            return { static_cast<bool>(m_lhs & rhs), m_lhs, \"&\", rhs };\n        }\n        template <typename RhsT>\n        auto operator ^ (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const {\n            return { static_cast<bool>(m_lhs ^ rhs), m_lhs, \"^\", rhs };\n        }\n\n        template<typename RhsT>\n        auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {\n            static_assert(always_false<RhsT>::value,\n            \"operator&& is not supported inside assertions, \"\n            \"wrap the expression inside parentheses, or decompose it\");\n        }\n\n        template<typename RhsT>\n        auto operator || ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {\n            static_assert(always_false<RhsT>::value,\n            \"operator|| is not supported inside assertions, \"\n            \"wrap the expression inside parentheses, or decompose it\");\n        }\n\n        auto makeUnaryExpr() const -> UnaryExpr<LhsT> {\n            return UnaryExpr<LhsT>{ m_lhs };\n        }\n    };\n\n    void handleExpression( ITransientExpression const& expr );\n\n    template<typename T>\n    void handleExpression( ExprLhs<T> const& expr ) {\n        handleExpression( expr.makeUnaryExpr() );\n    }\n\n    struct Decomposer {\n        template<typename T>\n        auto operator <= ( T const& lhs ) -> ExprLhs<T const&> {\n            return ExprLhs<T const&>{ lhs };\n        }\n\n        auto operator <=( bool value ) -> ExprLhs<bool> {\n            return ExprLhs<bool>{ value };\n        }\n    };\n\n} // end namespace Catch\n\n#ifdef _MSC_VER\n#pragma warning(pop)\n#endif\n\n// end catch_decomposer.h\n// start catch_interfaces_capture.h\n\n#include <string>\n#include <chrono>\n\nnamespace Catch {\n\n    class AssertionResult;\n    struct AssertionInfo;\n    struct SectionInfo;\n    struct SectionEndInfo;\n    struct MessageInfo;\n    struct MessageBuilder;\n    struct Counts;\n    struct AssertionReaction;\n    struct SourceLineInfo;\n\n    struct ITransientExpression;\n    struct IGeneratorTracker;\n\n#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\n    struct BenchmarkInfo;\n    template <typename Duration = std::chrono::duration<double, std::nano>>\n    struct BenchmarkStats;\n#endif // CATCH_CONFIG_ENABLE_BENCHMARKING\n\n    struct IResultCapture {\n\n        virtual ~IResultCapture();\n\n        virtual bool sectionStarted(    SectionInfo const& sectionInfo,\n                                        Counts& assertions ) = 0;\n        virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;\n        virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;\n\n        virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;\n\n#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\n        virtual void benchmarkPreparing( std::string const& name ) = 0;\n        virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;\n        virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;\n        virtual void benchmarkFailed( std::string const& error ) = 0;\n#endif // CATCH_CONFIG_ENABLE_BENCHMARKING\n\n        virtual void pushScopedMessage( MessageInfo const& message ) = 0;\n        virtual void popScopedMessage( MessageInfo const& message ) = 0;\n\n        virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0;\n\n        virtual void handleFatalErrorCondition( StringRef message ) = 0;\n\n        virtual void handleExpr\n                (   AssertionInfo const& info,\n                    ITransientExpression const& expr,\n                    AssertionReaction& reaction ) = 0;\n        virtual void handleMessage\n                (   AssertionInfo const& info,\n                    ResultWas::OfType resultType,\n                    StringRef const& message,\n                    AssertionReaction& reaction ) = 0;\n        virtual void handleUnexpectedExceptionNotThrown\n                (   AssertionInfo const& info,\n                    AssertionReaction& reaction ) = 0;\n        virtual void handleUnexpectedInflightException\n                (   AssertionInfo const& info,\n                    std::string const& message,\n                    AssertionReaction& reaction ) = 0;\n        virtual void handleIncomplete\n                (   AssertionInfo const& info ) = 0;\n        virtual void handleNonExpr\n                (   AssertionInfo const &info,\n                    ResultWas::OfType resultType,\n                    AssertionReaction &reaction ) = 0;\n\n        virtual bool lastAssertionPassed() = 0;\n        virtual void assertionPassed() = 0;\n\n        // Deprecated, do not use:\n        virtual std::string getCurrentTestName() const = 0;\n        virtual const AssertionResult* getLastResult() const = 0;\n        virtual void exceptionEarlyReported() = 0;\n    };\n\n    IResultCapture& getResultCapture();\n}\n\n// end catch_interfaces_capture.h\nnamespace Catch {\n\n    struct TestFailureException{};\n    struct AssertionResultData;\n    struct IResultCapture;\n    class RunContext;\n\n    class LazyExpression {\n        friend class AssertionHandler;\n        friend struct AssertionStats;\n        friend class RunContext;\n\n        ITransientExpression const* m_transientExpression = nullptr;\n        bool m_isNegated;\n    public:\n        LazyExpression( bool isNegated );\n        LazyExpression( LazyExpression const& other );\n        LazyExpression& operator = ( LazyExpression const& ) = delete;\n\n        explicit operator bool() const;\n\n        friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&;\n    };\n\n    struct AssertionReaction {\n        bool shouldDebugBreak = false;\n        bool shouldThrow = false;\n    };\n\n    class AssertionHandler {\n        AssertionInfo m_assertionInfo;\n        AssertionReaction m_reaction;\n        bool m_completed = false;\n        IResultCapture& m_resultCapture;\n\n    public:\n        AssertionHandler\n            (   StringRef const& macroName,\n                SourceLineInfo const& lineInfo,\n                StringRef capturedExpression,\n                ResultDisposition::Flags resultDisposition );\n        ~AssertionHandler() {\n            if ( !m_completed ) {\n                m_resultCapture.handleIncomplete( m_assertionInfo );\n            }\n        }\n\n        template<typename T>\n        void handleExpr( ExprLhs<T> const& expr ) {\n            handleExpr( expr.makeUnaryExpr() );\n        }\n        void handleExpr( ITransientExpression const& expr );\n\n        void handleMessage(ResultWas::OfType resultType, StringRef const& message);\n\n        void handleExceptionThrownAsExpected();\n        void handleUnexpectedExceptionNotThrown();\n        void handleExceptionNotThrownAsExpected();\n        void handleThrowingCallSkipped();\n        void handleUnexpectedInflightException();\n\n        void complete();\n        void setCompleted();\n\n        // query\n        auto allowThrows() const -> bool;\n    };\n\n    void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString );\n\n} // namespace Catch\n\n// end catch_assertionhandler.h\n// start catch_message.h\n\n#include <string>\n#include <vector>\n\nnamespace Catch {\n\n    struct MessageInfo {\n        MessageInfo(    StringRef const& _macroName,\n                        SourceLineInfo const& _lineInfo,\n                        ResultWas::OfType _type );\n\n        StringRef macroName;\n        std::string message;\n        SourceLineInfo lineInfo;\n        ResultWas::OfType type;\n        unsigned int sequence;\n\n        bool operator == ( MessageInfo const& other ) const;\n        bool operator < ( MessageInfo const& other ) const;\n    private:\n        static unsigned int globalCount;\n    };\n\n    struct MessageStream {\n\n        template<typename T>\n        MessageStream& operator << ( T const& value ) {\n            m_stream << value;\n            return *this;\n        }\n\n        ReusableStringStream m_stream;\n    };\n\n    struct MessageBuilder : MessageStream {\n        MessageBuilder( StringRef const& macroName,\n                        SourceLineInfo const& lineInfo,\n                        ResultWas::OfType type );\n\n        template<typename T>\n        MessageBuilder& operator << ( T const& value ) {\n            m_stream << value;\n            return *this;\n        }\n\n        MessageInfo m_info;\n    };\n\n    class ScopedMessage {\n    public:\n        explicit ScopedMessage( MessageBuilder const& builder );\n        ScopedMessage( ScopedMessage& duplicate ) = delete;\n        ScopedMessage( ScopedMessage&& old );\n        ~ScopedMessage();\n\n        MessageInfo m_info;\n        bool m_moved;\n    };\n\n    class Capturer {\n        std::vector<MessageInfo> m_messages;\n        IResultCapture& m_resultCapture = getResultCapture();\n        size_t m_captured = 0;\n    public:\n        Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );\n        ~Capturer();\n\n        void captureValue( size_t index, std::string const& value );\n\n        template<typename T>\n        void captureValues( size_t index, T const& value ) {\n            captureValue( index, Catch::Detail::stringify( value ) );\n        }\n\n        template<typename T, typename... Ts>\n        void captureValues( size_t index, T const& value, Ts const&... values ) {\n            captureValue( index, Catch::Detail::stringify(value) );\n            captureValues( index+1, values... );\n        }\n    };\n\n} // end namespace Catch\n\n// end catch_message.h\n#if !defined(CATCH_CONFIG_DISABLE)\n\n#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)\n  #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__\n#else\n  #define CATCH_INTERNAL_STRINGIFY(...) \"Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION\"\n#endif\n\n#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)\n\n///////////////////////////////////////////////////////////////////////////////\n// Another way to speed-up compilation is to omit local try-catch for REQUIRE*\n// macros.\n#define INTERNAL_CATCH_TRY\n#define INTERNAL_CATCH_CATCH( capturer )\n\n#else // CATCH_CONFIG_FAST_COMPILE\n\n#define INTERNAL_CATCH_TRY try\n#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); }\n\n#endif\n\n#define INTERNAL_CATCH_REACT( handler ) handler.complete();\n\n///////////////////////////////////////////////////////////////////////////////\n#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \\\n    do { \\\n        CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \\\n        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \\\n        INTERNAL_CATCH_TRY { \\\n            CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \\\n            CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \\\n            catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \\\n            CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \\\n        } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \\\n        INTERNAL_CATCH_REACT( catchAssertionHandler ) \\\n    } while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) )\n\n///////////////////////////////////////////////////////////////////////////////\n#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \\\n    INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \\\n    if( Catch::getResultCapture().lastAssertionPassed() )\n\n///////////////////////////////////////////////////////////////////////////////\n#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \\\n    INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \\\n    if( !Catch::getResultCapture().lastAssertionPassed() )\n\n///////////////////////////////////////////////////////////////////////////////\n#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \\\n    do { \\\n        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \\\n        try { \\\n            static_cast<void>(__VA_ARGS__); \\\n            catchAssertionHandler.handleExceptionNotThrownAsExpected(); \\\n        } \\\n        catch( ... ) { \\\n            catchAssertionHandler.handleUnexpectedInflightException(); \\\n        } \\\n        INTERNAL_CATCH_REACT( catchAssertionHandler ) \\\n    } while( false )\n\n///////////////////////////////////////////////////////////////////////////////\n#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \\\n    do { \\\n        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \\\n        if( catchAssertionHandler.allowThrows() ) \\\n            try { \\\n                static_cast<void>(__VA_ARGS__); \\\n                catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \\\n            } \\\n            catch( ... ) { \\\n                catchAssertionHandler.handleExceptionThrownAsExpected(); \\\n            } \\\n        else \\\n            catchAssertionHandler.handleThrowingCallSkipped(); \\\n        INTERNAL_CATCH_REACT( catchAssertionHandler ) \\\n    } while( false )\n\n///////////////////////////////////////////////////////////////////////////////\n#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \\\n    do { \\\n        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) \", \" CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \\\n        if( catchAssertionHandler.allowThrows() ) \\\n            try { \\\n                static_cast<void>(expr); \\\n                catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \\\n            } \\\n            catch( exceptionType const& ) { \\\n                catchAssertionHandler.handleExceptionThrownAsExpected(); \\\n            } \\\n            catch( ... ) { \\\n                catchAssertionHandler.handleUnexpectedInflightException(); \\\n            } \\\n        else \\\n            catchAssertionHandler.handleThrowingCallSkipped(); \\\n        INTERNAL_CATCH_REACT( catchAssertionHandler ) \\\n    } while( false )\n\n///////////////////////////////////////////////////////////////////////////////\n#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \\\n    do { \\\n        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \\\n        catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \\\n        INTERNAL_CATCH_REACT( catchAssertionHandler ) \\\n    } while( false )\n\n///////////////////////////////////////////////////////////////////////////////\n#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \\\n    auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \\\n    varName.captureValues( 0, __VA_ARGS__ )\n\n///////////////////////////////////////////////////////////////////////////////\n#define INTERNAL_CATCH_INFO( macroName, log ) \\\n    Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );\n\n///////////////////////////////////////////////////////////////////////////////\n#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \\\n    Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )\n\n///////////////////////////////////////////////////////////////////////////////\n// Although this is matcher-based, it can be used with just a string\n#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \\\n    do { \\\n        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) \", \" CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \\\n        if( catchAssertionHandler.allowThrows() ) \\\n            try { \\\n                static_cast<void>(__VA_ARGS__); \\\n                catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \\\n            } \\\n            catch( ... ) { \\\n                Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \\\n            } \\\n        else \\\n            catchAssertionHandler.handleThrowingCallSkipped(); \\\n        INTERNAL_CATCH_REACT( catchAssertionHandler ) \\\n    } while( false )\n\n#endif // CATCH_CONFIG_DISABLE\n\n// end catch_capture.hpp\n// start catch_section.h\n\n// start catch_section_info.h\n\n// start catch_totals.h\n\n#include <cstddef>\n\nnamespace Catch {\n\n    struct Counts {\n        Counts operator - ( Counts const& other ) const;\n        Counts& operator += ( Counts const& other );\n\n        std::size_t total() const;\n        bool allPassed() const;\n        bool allOk() const;\n\n        std::size_t passed = 0;\n        std::size_t failed = 0;\n        std::size_t failedButOk = 0;\n    };\n\n    struct Totals {\n\n        Totals operator - ( Totals const& other ) const;\n        Totals& operator += ( Totals const& other );\n\n        Totals delta( Totals const& prevTotals ) const;\n\n        int error = 0;\n        Counts assertions;\n        Counts testCases;\n    };\n}\n\n// end catch_totals.h\n#include <string>\n\nnamespace Catch {\n\n    struct SectionInfo {\n        SectionInfo\n            (   SourceLineInfo const& _lineInfo,\n                std::string const& _name );\n\n        // Deprecated\n        SectionInfo\n            (   SourceLineInfo const& _lineInfo,\n                std::string const& _name,\n                std::string const& ) : SectionInfo( _lineInfo, _name ) {}\n\n        std::string name;\n        std::string description; // !Deprecated: this will always be empty\n        SourceLineInfo lineInfo;\n    };\n\n    struct SectionEndInfo {\n        SectionInfo sectionInfo;\n        Counts prevAssertions;\n        double durationInSeconds;\n    };\n\n} // end namespace Catch\n\n// end catch_section_info.h\n// start catch_timer.h\n\n#include <cstdint>\n\nnamespace Catch {\n\n    auto getCurrentNanosecondsSinceEpoch() -> uint64_t;\n    auto getEstimatedClockResolution() -> uint64_t;\n\n    class Timer {\n        uint64_t m_nanoseconds = 0;\n    public:\n        void start();\n        auto getElapsedNanoseconds() const -> uint64_t;\n        auto getElapsedMicroseconds() const -> uint64_t;\n        auto getElapsedMilliseconds() const -> unsigned int;\n        auto getElapsedSeconds() const -> double;\n    };\n\n} // namespace Catch\n\n// end catch_timer.h\n#include <string>\n\nnamespace Catch {\n\n    class Section : NonCopyable {\n    public:\n        Section( SectionInfo const& info );\n        ~Section();\n\n        // This indicates whether the section should be executed or not\n        explicit operator bool() const;\n\n    private:\n        SectionInfo m_info;\n\n        std::string m_name;\n        Counts m_assertions;\n        bool m_sectionIncluded;\n        Timer m_timer;\n    };\n\n} // end namespace Catch\n\n#define INTERNAL_CATCH_SECTION( ... ) \\\n    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \\\n    CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \\\n    if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \\\n    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION\n\n#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \\\n    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \\\n    CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \\\n    if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \\\n    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION\n\n// end catch_section.h\n// start catch_interfaces_exception.h\n\n// start catch_interfaces_registry_hub.h\n\n#include <string>\n#include <memory>\n\nnamespace Catch {\n\n    class TestCase;\n    struct ITestCaseRegistry;\n    struct IExceptionTranslatorRegistry;\n    struct IExceptionTranslator;\n    struct IReporterRegistry;\n    struct IReporterFactory;\n    struct ITagAliasRegistry;\n    struct IMutableEnumValuesRegistry;\n\n    class StartupExceptionRegistry;\n\n    using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;\n\n    struct IRegistryHub {\n        virtual ~IRegistryHub();\n\n        virtual IReporterRegistry const& getReporterRegistry() const = 0;\n        virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;\n        virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;\n        virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;\n\n        virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;\n    };\n\n    struct IMutableRegistryHub {\n        virtual ~IMutableRegistryHub();\n        virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0;\n        virtual void registerListener( IReporterFactoryPtr const& factory ) = 0;\n        virtual void registerTest( TestCase const& testInfo ) = 0;\n        virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;\n        virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;\n        virtual void registerStartupException() noexcept = 0;\n        virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0;\n    };\n\n    IRegistryHub const& getRegistryHub();\n    IMutableRegistryHub& getMutableRegistryHub();\n    void cleanUp();\n    std::string translateActiveException();\n\n}\n\n// end catch_interfaces_registry_hub.h\n#if defined(CATCH_CONFIG_DISABLE)\n    #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \\\n        static std::string translatorName( signature )\n#endif\n\n#include <exception>\n#include <string>\n#include <vector>\n\nnamespace Catch {\n    using exceptionTranslateFunction = std::string(*)();\n\n    struct IExceptionTranslator;\n    using ExceptionTranslators = std::vector<std::unique_ptr<IExceptionTranslator const>>;\n\n    struct IExceptionTranslator {\n        virtual ~IExceptionTranslator();\n        virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;\n    };\n\n    struct IExceptionTranslatorRegistry {\n        virtual ~IExceptionTranslatorRegistry();\n\n        virtual std::string translateActiveException() const = 0;\n    };\n\n    class ExceptionTranslatorRegistrar {\n        template<typename T>\n        class ExceptionTranslator : public IExceptionTranslator {\n        public:\n\n            ExceptionTranslator( std::string(*translateFunction)( T& ) )\n            : m_translateFunction( translateFunction )\n            {}\n\n            std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {\n#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)\n                return \"\";\n#else\n                try {\n                    if( it == itEnd )\n                        std::rethrow_exception(std::current_exception());\n                    else\n                        return (*it)->translate( it+1, itEnd );\n                }\n                catch( T& ex ) {\n                    return m_translateFunction( ex );\n                }\n#endif\n            }\n\n        protected:\n            std::string(*m_translateFunction)( T& );\n        };\n\n    public:\n        template<typename T>\n        ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {\n            getMutableRegistryHub().registerTranslator\n                ( new ExceptionTranslator<T>( translateFunction ) );\n        }\n    };\n}\n\n///////////////////////////////////////////////////////////////////////////////\n#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \\\n    static std::string translatorName( signature ); \\\n    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \\\n    CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \\\n    namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \\\n    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \\\n    static std::string translatorName( signature )\n\n#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )\n\n// end catch_interfaces_exception.h\n// start catch_approx.h\n\n#include <type_traits>\n\nnamespace Catch {\nnamespace Detail {\n\n    class Approx {\n    private:\n        bool equalityComparisonImpl(double other) const;\n        // Validates the new margin (margin >= 0)\n        // out-of-line to avoid including stdexcept in the header\n        void setMargin(double margin);\n        // Validates the new epsilon (0 < epsilon < 1)\n        // out-of-line to avoid including stdexcept in the header\n        void setEpsilon(double epsilon);\n\n    public:\n        explicit Approx ( double value );\n\n        static Approx custom();\n\n        Approx operator-() const;\n\n        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>\n        Approx operator()( T const& value ) const {\n            Approx approx( static_cast<double>(value) );\n            approx.m_epsilon = m_epsilon;\n            approx.m_margin = m_margin;\n            approx.m_scale = m_scale;\n            return approx;\n        }\n\n        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>\n        explicit Approx( T const& value ): Approx(static_cast<double>(value))\n        {}\n\n        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>\n        friend bool operator == ( const T& lhs, Approx const& rhs ) {\n            auto lhs_v = static_cast<double>(lhs);\n            return rhs.equalityComparisonImpl(lhs_v);\n        }\n\n        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>\n        friend bool operator == ( Approx const& lhs, const T& rhs ) {\n            return operator==( rhs, lhs );\n        }\n\n        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>\n        friend bool operator != ( T const& lhs, Approx const& rhs ) {\n            return !operator==( lhs, rhs );\n        }\n\n        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>\n        friend bool operator != ( Approx const& lhs, T const& rhs ) {\n            return !operator==( rhs, lhs );\n        }\n\n        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>\n        friend bool operator <= ( T const& lhs, Approx const& rhs ) {\n            return static_cast<double>(lhs) < rhs.m_value || lhs == rhs;\n        }\n\n        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>\n        friend bool operator <= ( Approx const& lhs, T const& rhs ) {\n            return lhs.m_value < static_cast<double>(rhs) || lhs == rhs;\n        }\n\n        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>\n        friend bool operator >= ( T const& lhs, Approx const& rhs ) {\n            return static_cast<double>(lhs) > rhs.m_value || lhs == rhs;\n        }\n\n        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>\n        friend bool operator >= ( Approx const& lhs, T const& rhs ) {\n            return lhs.m_value > static_cast<double>(rhs) || lhs == rhs;\n        }\n\n        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>\n        Approx& epsilon( T const& newEpsilon ) {\n            double epsilonAsDouble = static_cast<double>(newEpsilon);\n            setEpsilon(epsilonAsDouble);\n            return *this;\n        }\n\n        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>\n        Approx& margin( T const& newMargin ) {\n            double marginAsDouble = static_cast<double>(newMargin);\n            setMargin(marginAsDouble);\n            return *this;\n        }\n\n        template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>\n        Approx& scale( T const& newScale ) {\n            m_scale = static_cast<double>(newScale);\n            return *this;\n        }\n\n        std::string toString() const;\n\n    private:\n        double m_epsilon;\n        double m_margin;\n        double m_scale;\n        double m_value;\n    };\n} // end namespace Detail\n\nnamespace literals {\n    Detail::Approx operator \"\" _a(long double val);\n    Detail::Approx operator \"\" _a(unsigned long long val);\n} // end namespace literals\n\ntemplate<>\nstruct StringMaker<Catch::Detail::Approx> {\n    static std::string convert(Catch::Detail::Approx const& value);\n};\n\n} // end namespace Catch\n\n// end catch_approx.h\n// start catch_string_manip.h\n\n#include <string>\n#include <iosfwd>\n#include <vector>\n\nnamespace Catch {\n\n    bool startsWith( std::string const& s, std::string const& prefix );\n    bool startsWith( std::string const& s, char prefix );\n    bool endsWith( std::string const& s, std::string const& suffix );\n    bool endsWith( std::string const& s, char suffix );\n    bool contains( std::string const& s, std::string const& infix );\n    void toLowerInPlace( std::string& s );\n    std::string toLower( std::string const& s );\n    //! Returns a new string without whitespace at the start/end\n    std::string trim( std::string const& str );\n    //! Returns a substring of the original ref without whitespace. Beware lifetimes!\n    StringRef trim(StringRef ref);\n\n    // !!! Be aware, returns refs into original string - make sure original string outlives them\n    std::vector<StringRef> splitStringRef( StringRef str, char delimiter );\n    bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );\n\n    struct pluralise {\n        pluralise( std::size_t count, std::string const& label );\n\n        friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );\n\n        std::size_t m_count;\n        std::string m_label;\n    };\n}\n\n// end catch_string_manip.h\n#ifndef CATCH_CONFIG_DISABLE_MATCHERS\n// start catch_capture_matchers.h\n\n// start catch_matchers.h\n\n#include <string>\n#include <vector>\n\nnamespace Catch {\nnamespace Matchers {\n    namespace Impl {\n\n        template<typename ArgT> struct MatchAllOf;\n        template<typename ArgT> struct MatchAnyOf;\n        template<typename ArgT> struct MatchNotOf;\n\n        class MatcherUntypedBase {\n        public:\n            MatcherUntypedBase() = default;\n            MatcherUntypedBase ( MatcherUntypedBase const& ) = default;\n            MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete;\n            std::string toString() const;\n\n        protected:\n            virtual ~MatcherUntypedBase();\n            virtual std::string describe() const = 0;\n            mutable std::string m_cachedToString;\n        };\n\n#ifdef __clang__\n#    pragma clang diagnostic push\n#    pragma clang diagnostic ignored \"-Wnon-virtual-dtor\"\n#endif\n\n        template<typename ObjectT>\n        struct MatcherMethod {\n            virtual bool match( ObjectT const& arg ) const = 0;\n        };\n\n#if defined(__OBJC__)\n        // Hack to fix Catch GH issue #1661. Could use id for generic Object support.\n        // use of const for Object pointers is very uncommon and under ARC it causes some kind of signature mismatch that breaks compilation\n        template<>\n        struct MatcherMethod<NSString*> {\n            virtual bool match( NSString* arg ) const = 0;\n        };\n#endif\n\n#ifdef __clang__\n#    pragma clang diagnostic pop\n#endif\n\n        template<typename T>\n        struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> {\n\n            MatchAllOf<T> operator && ( MatcherBase const& other ) const;\n            MatchAnyOf<T> operator || ( MatcherBase const& other ) const;\n            MatchNotOf<T> operator ! () const;\n        };\n\n        template<typename ArgT>\n        struct MatchAllOf : MatcherBase<ArgT> {\n            bool match( ArgT const& arg ) const override {\n                for( auto matcher : m_matchers ) {\n                    if (!matcher->match(arg))\n                        return false;\n                }\n                return true;\n            }\n            std::string describe() const override {\n                std::string description;\n                description.reserve( 4 + m_matchers.size()*32 );\n                description += \"( \";\n                bool first = true;\n                for( auto matcher : m_matchers ) {\n                    if( first )\n                        first = false;\n                    else\n                        description += \" and \";\n                    description += matcher->toString();\n                }\n                description += \" )\";\n                return description;\n            }\n\n            MatchAllOf<ArgT> operator && ( MatcherBase<ArgT> const& other ) {\n                auto copy(*this);\n                copy.m_matchers.push_back( &other );\n                return copy;\n            }\n\n            std::vector<MatcherBase<ArgT> const*> m_matchers;\n        };\n        template<typename ArgT>\n        struct MatchAnyOf : MatcherBase<ArgT> {\n\n            bool match( ArgT const& arg ) const override {\n                for( auto matcher : m_matchers ) {\n                    if (matcher->match(arg))\n                        return true;\n                }\n                return false;\n            }\n            std::string describe() const override {\n                std::string description;\n                description.reserve( 4 + m_matchers.size()*32 );\n                description += \"( \";\n                bool first = true;\n                for( auto matcher : m_matchers ) {\n                    if( first )\n                        first = false;\n                    else\n                        description += \" or \";\n                    description += matcher->toString();\n                }\n                description += \" )\";\n                return description;\n            }\n\n            MatchAnyOf<ArgT> operator || ( MatcherBase<ArgT> const& other ) {\n                auto copy(*this);\n                copy.m_matchers.push_back( &other );\n                return copy;\n            }\n\n            std::vector<MatcherBase<ArgT> const*> m_matchers;\n        };\n\n        template<typename ArgT>\n        struct MatchNotOf : MatcherBase<ArgT> {\n\n            MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {}\n\n            bool match( ArgT const& arg ) const override {\n                return !m_underlyingMatcher.match( arg );\n            }\n\n            std::string describe() const override {\n                return \"not \" + m_underlyingMatcher.toString();\n            }\n            MatcherBase<ArgT> const& m_underlyingMatcher;\n        };\n\n        template<typename T>\n        MatchAllOf<T> MatcherBase<T>::operator && ( MatcherBase const& other ) const {\n            return MatchAllOf<T>() && *this && other;\n        }\n        template<typename T>\n        MatchAnyOf<T> MatcherBase<T>::operator || ( MatcherBase const& other ) const {\n            return MatchAnyOf<T>() || *this || other;\n        }\n        template<typename T>\n        MatchNotOf<T> MatcherBase<T>::operator ! () const {\n            return MatchNotOf<T>( *this );\n        }\n\n    } // namespace Impl\n\n} // namespace Matchers\n\nusing namespace Matchers;\nusing Matchers::Impl::MatcherBase;\n\n} // namespace Catch\n\n// end catch_matchers.h\n// start catch_matchers_exception.hpp\n\nnamespace Catch {\nnamespace Matchers {\nnamespace Exception {\n\nclass ExceptionMessageMatcher : public MatcherBase<std::exception> {\n    std::string m_message;\npublic:\n\n    ExceptionMessageMatcher(std::string const& message):\n        m_message(message)\n    {}\n\n    bool match(std::exception const& ex) const override;\n\n    std::string describe() const override;\n};\n\n} // namespace Exception\n\nException::ExceptionMessageMatcher Message(std::string const& message);\n\n} // namespace Matchers\n} // namespace Catch\n\n// end catch_matchers_exception.hpp\n// start catch_matchers_floating.h\n\nnamespace Catch {\nnamespace Matchers {\n\n    namespace Floating {\n\n        enum class FloatingPointKind : uint8_t;\n\n        struct WithinAbsMatcher : MatcherBase<double> {\n            WithinAbsMatcher(double target, double margin);\n            bool match(double const& matchee) const override;\n            std::string describe() const override;\n        private:\n            double m_target;\n            double m_margin;\n        };\n\n        struct WithinUlpsMatcher : MatcherBase<double> {\n            WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType);\n            bool match(double const& matchee) const override;\n            std::string describe() const override;\n        private:\n            double m_target;\n            uint64_t m_ulps;\n            FloatingPointKind m_type;\n        };\n\n        // Given IEEE-754 format for floats and doubles, we can assume\n        // that float -> double promotion is lossless. Given this, we can\n        // assume that if we do the standard relative comparison of\n        // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get\n        // the same result if we do this for floats, as if we do this for\n        // doubles that were promoted from floats.\n        struct WithinRelMatcher : MatcherBase<double> {\n            WithinRelMatcher(double target, double epsilon);\n            bool match(double const& matchee) const override;\n            std::string describe() const override;\n        private:\n            double m_target;\n            double m_epsilon;\n        };\n\n    } // namespace Floating\n\n    // The following functions create the actual matcher objects.\n    // This allows the types to be inferred\n    Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);\n    Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);\n    Floating::WithinAbsMatcher WithinAbs(double target, double margin);\n    Floating::WithinRelMatcher WithinRel(double target, double eps);\n    // defaults epsilon to 100*numeric_limits<double>::epsilon()\n    Floating::WithinRelMatcher WithinRel(double target);\n    Floating::WithinRelMatcher WithinRel(float target, float eps);\n    // defaults epsilon to 100*numeric_limits<float>::epsilon()\n    Floating::WithinRelMatcher WithinRel(float target);\n\n} // namespace Matchers\n} // namespace Catch\n\n// end catch_matchers_floating.h\n// start catch_matchers_generic.hpp\n\n#include <functional>\n#include <string>\n\nnamespace Catch {\nnamespace Matchers {\nnamespace Generic {\n\nnamespace Detail {\n    std::string finalizeDescription(const std::string& desc);\n}\n\ntemplate <typename T>\nclass PredicateMatcher : public MatcherBase<T> {\n    std::function<bool(T const&)> m_predicate;\n    std::string m_description;\npublic:\n\n    PredicateMatcher(std::function<bool(T const&)> const& elem, std::string const& descr)\n        :m_predicate(std::move(elem)),\n        m_description(Detail::finalizeDescription(descr))\n    {}\n\n    bool match( T const& item ) const override {\n        return m_predicate(item);\n    }\n\n    std::string describe() const override {\n        return m_description;\n    }\n};\n\n} // namespace Generic\n\n    // The following functions create the actual matcher objects.\n    // The user has to explicitly specify type to the function, because\n    // inferring std::function<bool(T const&)> is hard (but possible) and\n    // requires a lot of TMP.\n    template<typename T>\n    Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = \"\") {\n        return Generic::PredicateMatcher<T>(predicate, description);\n    }\n\n} // namespace Matchers\n} // namespace Catch\n\n// end catch_matchers_generic.hpp\n// start catch_matchers_string.h\n\n#include <string>\n\nnamespace Catch {\nnamespace Matchers {\n\n    namespace StdString {\n\n        struct CasedString\n        {\n            CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity );\n            std::string adjustString( std::string const& str ) const;\n            std::string caseSensitivitySuffix() const;\n\n            CaseSensitive::Choice m_caseSensitivity;\n            std::string m_str;\n        };\n\n        struct StringMatcherBase : MatcherBase<std::string> {\n            StringMatcherBase( std::string const& operation, CasedString const& comparator );\n            std::string describe() const override;\n\n            CasedString m_comparator;\n            std::string m_operation;\n        };\n\n        struct EqualsMatcher : StringMatcherBase {\n            EqualsMatcher( CasedString const& comparator );\n            bool match( std::string const& source ) const override;\n        };\n        struct ContainsMatcher : StringMatcherBase {\n            ContainsMatcher( CasedString const& comparator );\n            bool match( std::string const& source ) const override;\n        };\n        struct StartsWithMatcher : StringMatcherBase {\n            StartsWithMatcher( CasedString const& comparator );\n            bool match( std::string const& source ) const override;\n        };\n        struct EndsWithMatcher : StringMatcherBase {\n            EndsWithMatcher( CasedString const& comparator );\n            bool match( std::string const& source ) const override;\n        };\n\n        struct RegexMatcher : MatcherBase<std::string> {\n            RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity );\n            bool match( std::string const& matchee ) const override;\n            std::string describe() const override;\n\n        private:\n            std::string m_regex;\n            CaseSensitive::Choice m_caseSensitivity;\n        };\n\n    } // namespace StdString\n\n    // The following functions create the actual matcher objects.\n    // This allows the types to be inferred\n\n    StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );\n    StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );\n    StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );\n    StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );\n    StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );\n\n} // namespace Matchers\n} // namespace Catch\n\n// end catch_matchers_string.h\n// start catch_matchers_vector.h\n\n#include <algorithm>\n\nnamespace Catch {\nnamespace Matchers {\n\n    namespace Vector {\n        template<typename T, typename Alloc>\n        struct ContainsElementMatcher : MatcherBase<std::vector<T, Alloc>> {\n\n            ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}\n\n            bool match(std::vector<T, Alloc> const &v) const override {\n                for (auto const& el : v) {\n                    if (el == m_comparator) {\n                        return true;\n                    }\n                }\n                return false;\n            }\n\n            std::string describe() const override {\n                return \"Contains: \" + ::Catch::Detail::stringify( m_comparator );\n            }\n\n            T const& m_comparator;\n        };\n\n        template<typename T, typename AllocComp, typename AllocMatch>\n        struct ContainsMatcher : MatcherBase<std::vector<T, AllocMatch>> {\n\n            ContainsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {}\n\n            bool match(std::vector<T, AllocMatch> const &v) const override {\n                // !TBD: see note in EqualsMatcher\n                if (m_comparator.size() > v.size())\n                    return false;\n                for (auto const& comparator : m_comparator) {\n                    auto present = false;\n                    for (const auto& el : v) {\n                        if (el == comparator) {\n                            present = true;\n                            break;\n                        }\n                    }\n                    if (!present) {\n                        return false;\n                    }\n                }\n                return true;\n            }\n            std::string describe() const override {\n                return \"Contains: \" + ::Catch::Detail::stringify( m_comparator );\n            }\n\n            std::vector<T, AllocComp> const& m_comparator;\n        };\n\n        template<typename T, typename AllocComp, typename AllocMatch>\n        struct EqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {\n\n            EqualsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {}\n\n            bool match(std::vector<T, AllocMatch> const &v) const override {\n                // !TBD: This currently works if all elements can be compared using !=\n                // - a more general approach would be via a compare template that defaults\n                // to using !=. but could be specialised for, e.g. std::vector<T, Alloc> etc\n                // - then just call that directly\n                if (m_comparator.size() != v.size())\n                    return false;\n                for (std::size_t i = 0; i < v.size(); ++i)\n                    if (m_comparator[i] != v[i])\n                        return false;\n                return true;\n            }\n            std::string describe() const override {\n                return \"Equals: \" + ::Catch::Detail::stringify( m_comparator );\n            }\n            std::vector<T, AllocComp> const& m_comparator;\n        };\n\n        template<typename T, typename AllocComp, typename AllocMatch>\n        struct ApproxMatcher : MatcherBase<std::vector<T, AllocMatch>> {\n\n            ApproxMatcher(std::vector<T, AllocComp> const& comparator) : m_comparator( comparator ) {}\n\n            bool match(std::vector<T, AllocMatch> const &v) const override {\n                if (m_comparator.size() != v.size())\n                    return false;\n                for (std::size_t i = 0; i < v.size(); ++i)\n                    if (m_comparator[i] != approx(v[i]))\n                        return false;\n                return true;\n            }\n            std::string describe() const override {\n                return \"is approx: \" + ::Catch::Detail::stringify( m_comparator );\n            }\n            template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>\n            ApproxMatcher& epsilon( T const& newEpsilon ) {\n                approx.epsilon(newEpsilon);\n                return *this;\n            }\n            template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>\n            ApproxMatcher& margin( T const& newMargin ) {\n                approx.margin(newMargin);\n                return *this;\n            }\n            template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>\n            ApproxMatcher& scale( T const& newScale ) {\n                approx.scale(newScale);\n                return *this;\n            }\n\n            std::vector<T, AllocComp> const& m_comparator;\n            mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom();\n        };\n\n        template<typename T, typename AllocComp, typename AllocMatch>\n        struct UnorderedEqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> {\n            UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target) : m_target(target) {}\n            bool match(std::vector<T, AllocMatch> const& vec) const override {\n                if (m_target.size() != vec.size()) {\n                    return false;\n                }\n                return std::is_permutation(m_target.begin(), m_target.end(), vec.begin());\n            }\n\n            std::string describe() const override {\n                return \"UnorderedEquals: \" + ::Catch::Detail::stringify(m_target);\n            }\n        private:\n            std::vector<T, AllocComp> const& m_target;\n        };\n\n    } // namespace Vector\n\n    // The following functions create the actual matcher objects.\n    // This allows the types to be inferred\n\n    template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>\n    Vector::ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) {\n        return Vector::ContainsMatcher<T, AllocComp, AllocMatch>( comparator );\n    }\n\n    template<typename T, typename Alloc = std::allocator<T>>\n    Vector::ContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) {\n        return Vector::ContainsElementMatcher<T, Alloc>( comparator );\n    }\n\n    template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>\n    Vector::EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) {\n        return Vector::EqualsMatcher<T, AllocComp, AllocMatch>( comparator );\n    }\n\n    template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>\n    Vector::ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) {\n        return Vector::ApproxMatcher<T, AllocComp, AllocMatch>( comparator );\n    }\n\n    template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>\n    Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) {\n        return Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch>( target );\n    }\n\n} // namespace Matchers\n} // namespace Catch\n\n// end catch_matchers_vector.h\nnamespace Catch {\n\n    template<typename ArgT, typename MatcherT>\n    class MatchExpr : public ITransientExpression {\n        ArgT const& m_arg;\n        MatcherT m_matcher;\n        StringRef m_matcherString;\n    public:\n        MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString )\n        :   ITransientExpression{ true, matcher.match( arg ) },\n            m_arg( arg ),\n            m_matcher( matcher ),\n            m_matcherString( matcherString )\n        {}\n\n        void streamReconstructedExpression( std::ostream &os ) const override {\n            auto matcherAsString = m_matcher.toString();\n            os << Catch::Detail::stringify( m_arg ) << ' ';\n            if( matcherAsString == Detail::unprintableString )\n                os << m_matcherString;\n            else\n                os << matcherAsString;\n        }\n    };\n\n    using StringMatcher = Matchers::Impl::MatcherBase<std::string>;\n\n    void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString  );\n\n    template<typename ArgT, typename MatcherT>\n    auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString  ) -> MatchExpr<ArgT, MatcherT> {\n        return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString );\n    }\n\n} // namespace Catch\n\n///////////////////////////////////////////////////////////////////////////////\n#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \\\n    do { \\\n        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) \", \" CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \\\n        INTERNAL_CATCH_TRY { \\\n            catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \\\n        } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \\\n        INTERNAL_CATCH_REACT( catchAssertionHandler ) \\\n    } while( false )\n\n///////////////////////////////////////////////////////////////////////////////\n#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \\\n    do { \\\n        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) \", \" CATCH_INTERNAL_STRINGIFY(exceptionType) \", \" CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \\\n        if( catchAssertionHandler.allowThrows() ) \\\n            try { \\\n                static_cast<void>(__VA_ARGS__ ); \\\n                catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \\\n            } \\\n            catch( exceptionType const& ex ) { \\\n                catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \\\n            } \\\n            catch( ... ) { \\\n                catchAssertionHandler.handleUnexpectedInflightException(); \\\n            } \\\n        else \\\n            catchAssertionHandler.handleThrowingCallSkipped(); \\\n        INTERNAL_CATCH_REACT( catchAssertionHandler ) \\\n    } while( false )\n\n// end catch_capture_matchers.h\n#endif\n// start catch_generators.hpp\n\n// start catch_interfaces_generatortracker.h\n\n\n#include <memory>\n\nnamespace Catch {\n\n    namespace Generators {\n        class GeneratorUntypedBase {\n        public:\n            GeneratorUntypedBase() = default;\n            virtual ~GeneratorUntypedBase();\n            // Attempts to move the generator to the next element\n             //\n             // Returns true iff the move succeeded (and a valid element\n             // can be retrieved).\n            virtual bool next() = 0;\n        };\n        using GeneratorBasePtr = std::unique_ptr<GeneratorUntypedBase>;\n\n    } // namespace Generators\n\n    struct IGeneratorTracker {\n        virtual ~IGeneratorTracker();\n        virtual auto hasGenerator() const -> bool = 0;\n        virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;\n        virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;\n    };\n\n} // namespace Catch\n\n// end catch_interfaces_generatortracker.h\n// start catch_enforce.h\n\n#include <exception>\n\nnamespace Catch {\n#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)\n    template <typename Ex>\n    [[noreturn]]\n    void throw_exception(Ex const& e) {\n        throw e;\n    }\n#else // ^^ Exceptions are enabled //  Exceptions are disabled vv\n    [[noreturn]]\n    void throw_exception(std::exception const& e);\n#endif\n\n    [[noreturn]]\n    void throw_logic_error(std::string const& msg);\n    [[noreturn]]\n    void throw_domain_error(std::string const& msg);\n    [[noreturn]]\n    void throw_runtime_error(std::string const& msg);\n\n} // namespace Catch;\n\n#define CATCH_MAKE_MSG(...) \\\n    (Catch::ReusableStringStream() << __VA_ARGS__).str()\n\n#define CATCH_INTERNAL_ERROR(...) \\\n    Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << \": Internal Catch2 error: \" << __VA_ARGS__))\n\n#define CATCH_ERROR(...) \\\n    Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ ))\n\n#define CATCH_RUNTIME_ERROR(...) \\\n    Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ ))\n\n#define CATCH_ENFORCE( condition, ... ) \\\n    do{ if( !(condition) ) CATCH_ERROR( __VA_ARGS__ ); } while(false)\n\n// end catch_enforce.h\n#include <memory>\n#include <vector>\n#include <cassert>\n\n#include <utility>\n#include <exception>\n\nnamespace Catch {\n\nclass GeneratorException : public std::exception {\n    const char* const m_msg = \"\";\n\npublic:\n    GeneratorException(const char* msg):\n        m_msg(msg)\n    {}\n\n    const char* what() const noexcept override final;\n};\n\nnamespace Generators {\n\n    // !TBD move this into its own location?\n    namespace pf{\n        template<typename T, typename... Args>\n        std::unique_ptr<T> make_unique( Args&&... args ) {\n            return std::unique_ptr<T>(new T(std::forward<Args>(args)...));\n        }\n    }\n\n    template<typename T>\n    struct IGenerator : GeneratorUntypedBase {\n        virtual ~IGenerator() = default;\n\n        // Returns the current element of the generator\n        //\n        // \\Precondition The generator is either freshly constructed,\n        // or the last call to `next()` returned true\n        virtual T const& get() const = 0;\n        using type = T;\n    };\n\n    template<typename T>\n    class SingleValueGenerator final : public IGenerator<T> {\n        T m_value;\n    public:\n        SingleValueGenerator(T&& value) : m_value(std::move(value)) {}\n\n        T const& get() const override {\n            return m_value;\n        }\n        bool next() override {\n            return false;\n        }\n    };\n\n    template<typename T>\n    class FixedValuesGenerator final : public IGenerator<T> {\n        static_assert(!std::is_same<T, bool>::value,\n            \"FixedValuesGenerator does not support bools because of std::vector<bool>\"\n            \"specialization, use SingleValue Generator instead.\");\n        std::vector<T> m_values;\n        size_t m_idx = 0;\n    public:\n        FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}\n\n        T const& get() const override {\n            return m_values[m_idx];\n        }\n        bool next() override {\n            ++m_idx;\n            return m_idx < m_values.size();\n        }\n    };\n\n    template <typename T>\n    class GeneratorWrapper final {\n        std::unique_ptr<IGenerator<T>> m_generator;\n    public:\n        GeneratorWrapper(std::unique_ptr<IGenerator<T>> generator):\n            m_generator(std::move(generator))\n        {}\n        T const& get() const {\n            return m_generator->get();\n        }\n        bool next() {\n            return m_generator->next();\n        }\n    };\n\n    template <typename T>\n    GeneratorWrapper<T> value(T&& value) {\n        return GeneratorWrapper<T>(pf::make_unique<SingleValueGenerator<T>>(std::forward<T>(value)));\n    }\n    template <typename T>\n    GeneratorWrapper<T> values(std::initializer_list<T> values) {\n        return GeneratorWrapper<T>(pf::make_unique<FixedValuesGenerator<T>>(values));\n    }\n\n    template<typename T>\n    class Generators : public IGenerator<T> {\n        std::vector<GeneratorWrapper<T>> m_generators;\n        size_t m_current = 0;\n\n        void populate(GeneratorWrapper<T>&& generator) {\n            m_generators.emplace_back(std::move(generator));\n        }\n        void populate(T&& val) {\n            m_generators.emplace_back(value(std::forward<T>(val)));\n        }\n        template<typename U>\n        void populate(U&& val) {\n            populate(T(std::forward<U>(val)));\n        }\n        template<typename U, typename... Gs>\n        void populate(U&& valueOrGenerator, Gs &&... moreGenerators) {\n            populate(std::forward<U>(valueOrGenerator));\n            populate(std::forward<Gs>(moreGenerators)...);\n        }\n\n    public:\n        template <typename... Gs>\n        Generators(Gs &&... moreGenerators) {\n            m_generators.reserve(sizeof...(Gs));\n            populate(std::forward<Gs>(moreGenerators)...);\n        }\n\n        T const& get() const override {\n            return m_generators[m_current].get();\n        }\n\n        bool next() override {\n            if (m_current >= m_generators.size()) {\n                return false;\n            }\n            const bool current_status = m_generators[m_current].next();\n            if (!current_status) {\n                ++m_current;\n            }\n            return m_current < m_generators.size();\n        }\n    };\n\n    template<typename... Ts>\n    GeneratorWrapper<std::tuple<Ts...>> table( std::initializer_list<std::tuple<typename std::decay<Ts>::type...>> tuples ) {\n        return values<std::tuple<Ts...>>( tuples );\n    }\n\n    // Tag type to signal that a generator sequence should convert arguments to a specific type\n    template <typename T>\n    struct as {};\n\n    template<typename T, typename... Gs>\n    auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> {\n        return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...);\n    }\n    template<typename T>\n    auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> {\n        return Generators<T>(std::move(generator));\n    }\n    template<typename T, typename... Gs>\n    auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<T> {\n        return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );\n    }\n    template<typename T, typename U, typename... Gs>\n    auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> {\n        return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );\n    }\n\n    auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;\n\n    template<typename L>\n    // Note: The type after -> is weird, because VS2015 cannot parse\n    //       the expression used in the typedef inside, when it is in\n    //       return type. Yeah.\n    auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {\n        using UnderlyingType = typename decltype(generatorExpression())::type;\n\n        IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo );\n        if (!tracker.hasGenerator()) {\n            tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression()));\n        }\n\n        auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() );\n        return generator.get();\n    }\n\n} // namespace Generators\n} // namespace Catch\n\n#define GENERATE( ... ) \\\n    Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \\\n                                 CATCH_INTERNAL_LINEINFO, \\\n                                 [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)\n#define GENERATE_COPY( ... ) \\\n    Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \\\n                                 CATCH_INTERNAL_LINEINFO, \\\n                                 [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)\n#define GENERATE_REF( ... ) \\\n    Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \\\n                                 CATCH_INTERNAL_LINEINFO, \\\n                                 [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)\n\n// end catch_generators.hpp\n// start catch_generators_generic.hpp\n\nnamespace Catch {\nnamespace Generators {\n\n    template <typename T>\n    class TakeGenerator : public IGenerator<T> {\n        GeneratorWrapper<T> m_generator;\n        size_t m_returned = 0;\n        size_t m_target;\n    public:\n        TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):\n            m_generator(std::move(generator)),\n            m_target(target)\n        {\n            assert(target != 0 && \"Empty generators are not allowed\");\n        }\n        T const& get() const override {\n            return m_generator.get();\n        }\n        bool next() override {\n            ++m_returned;\n            if (m_returned >= m_target) {\n                return false;\n            }\n\n            const auto success = m_generator.next();\n            // If the underlying generator does not contain enough values\n            // then we cut short as well\n            if (!success) {\n                m_returned = m_target;\n            }\n            return success;\n        }\n    };\n\n    template <typename T>\n    GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {\n        return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator)));\n    }\n\n    template <typename T, typename Predicate>\n    class FilterGenerator : public IGenerator<T> {\n        GeneratorWrapper<T> m_generator;\n        Predicate m_predicate;\n    public:\n        template <typename P = Predicate>\n        FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):\n            m_generator(std::move(generator)),\n            m_predicate(std::forward<P>(pred))\n        {\n            if (!m_predicate(m_generator.get())) {\n                // It might happen that there are no values that pass the\n                // filter. In that case we throw an exception.\n                auto has_initial_value = nextImpl();\n                if (!has_initial_value) {\n                    Catch::throw_exception(GeneratorException(\"No valid value found in filtered generator\"));\n                }\n            }\n        }\n\n        T const& get() const override {\n            return m_generator.get();\n        }\n\n        bool next() override {\n            return nextImpl();\n        }\n\n    private:\n        bool nextImpl() {\n            bool success = m_generator.next();\n            if (!success) {\n                return false;\n            }\n            while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);\n            return success;\n        }\n    };\n\n    template <typename T, typename Predicate>\n    GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {\n        return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator))));\n    }\n\n    template <typename T>\n    class RepeatGenerator : public IGenerator<T> {\n        static_assert(!std::is_same<T, bool>::value,\n            \"RepeatGenerator currently does not support bools\"\n            \"because of std::vector<bool> specialization\");\n        GeneratorWrapper<T> m_generator;\n        mutable std::vector<T> m_returned;\n        size_t m_target_repeats;\n        size_t m_current_repeat = 0;\n        size_t m_repeat_index = 0;\n    public:\n        RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):\n            m_generator(std::move(generator)),\n            m_target_repeats(repeats)\n        {\n            assert(m_target_repeats > 0 && \"Repeat generator must repeat at least once\");\n        }\n\n        T const& get() const override {\n            if (m_current_repeat == 0) {\n                m_returned.push_back(m_generator.get());\n                return m_returned.back();\n            }\n            return m_returned[m_repeat_index];\n        }\n\n        bool next() override {\n            // There are 2 basic cases:\n            // 1) We are still reading the generator\n            // 2) We are reading our own cache\n\n            // In the first case, we need to poke the underlying generator.\n            // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache\n            if (m_current_repeat == 0) {\n                const auto success = m_generator.next();\n                if (!success) {\n                    ++m_current_repeat;\n                }\n                return m_current_repeat < m_target_repeats;\n            }\n\n            // In the second case, we need to move indices forward and check that we haven't run up against the end\n            ++m_repeat_index;\n            if (m_repeat_index == m_returned.size()) {\n                m_repeat_index = 0;\n                ++m_current_repeat;\n            }\n            return m_current_repeat < m_target_repeats;\n        }\n    };\n\n    template <typename T>\n    GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {\n        return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator)));\n    }\n\n    template <typename T, typename U, typename Func>\n    class MapGenerator : public IGenerator<T> {\n        // TBD: provide static assert for mapping function, for friendly error message\n        GeneratorWrapper<U> m_generator;\n        Func m_function;\n        // To avoid returning dangling reference, we have to save the values\n        T m_cache;\n    public:\n        template <typename F2 = Func>\n        MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :\n            m_generator(std::move(generator)),\n            m_function(std::forward<F2>(function)),\n            m_cache(m_function(m_generator.get()))\n        {}\n\n        T const& get() const override {\n            return m_cache;\n        }\n        bool next() override {\n            const auto success = m_generator.next();\n            if (success) {\n                m_cache = m_function(m_generator.get());\n            }\n            return success;\n        }\n    };\n\n    template <typename Func, typename U, typename T = FunctionReturnType<Func, U>>\n    GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {\n        return GeneratorWrapper<T>(\n            pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))\n        );\n    }\n\n    template <typename T, typename U, typename Func>\n    GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {\n        return GeneratorWrapper<T>(\n            pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))\n        );\n    }\n\n    template <typename T>\n    class ChunkGenerator final : public IGenerator<std::vector<T>> {\n        std::vector<T> m_chunk;\n        size_t m_chunk_size;\n        GeneratorWrapper<T> m_generator;\n        bool m_used_up = false;\n    public:\n        ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :\n            m_chunk_size(size), m_generator(std::move(generator))\n        {\n            m_chunk.reserve(m_chunk_size);\n            if (m_chunk_size != 0) {\n                m_chunk.push_back(m_generator.get());\n                for (size_t i = 1; i < m_chunk_size; ++i) {\n                    if (!m_generator.next()) {\n                        Catch::throw_exception(GeneratorException(\"Not enough values to initialize the first chunk\"));\n                    }\n                    m_chunk.push_back(m_generator.get());\n                }\n            }\n        }\n        std::vector<T> const& get() const override {\n            return m_chunk;\n        }\n        bool next() override {\n            m_chunk.clear();\n            for (size_t idx = 0; idx < m_chunk_size; ++idx) {\n                if (!m_generator.next()) {\n                    return false;\n                }\n                m_chunk.push_back(m_generator.get());\n            }\n            return true;\n        }\n    };\n\n    template <typename T>\n    GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {\n        return GeneratorWrapper<std::vector<T>>(\n            pf::make_unique<ChunkGenerator<T>>(size, std::move(generator))\n        );\n    }\n\n} // namespace Generators\n} // namespace Catch\n\n// end catch_generators_generic.hpp\n// start catch_generators_specific.hpp\n\n// start catch_context.h\n\n#include <memory>\n\nnamespace Catch {\n\n    struct IResultCapture;\n    struct IRunner;\n    struct IConfig;\n    struct IMutableContext;\n\n    using IConfigPtr = std::shared_ptr<IConfig const>;\n\n    struct IContext\n    {\n        virtual ~IContext();\n\n        virtual IResultCapture* getResultCapture() = 0;\n        virtual IRunner* getRunner() = 0;\n        virtual IConfigPtr const& getConfig() const = 0;\n    };\n\n    struct IMutableContext : IContext\n    {\n        virtual ~IMutableContext();\n        virtual void setResultCapture( IResultCapture* resultCapture ) = 0;\n        virtual void setRunner( IRunner* runner ) = 0;\n        virtual void setConfig( IConfigPtr const& config ) = 0;\n\n    private:\n        static IMutableContext *currentContext;\n        friend IMutableContext& getCurrentMutableContext();\n        friend void cleanUpContext();\n        static void createContext();\n    };\n\n    inline IMutableContext& getCurrentMutableContext()\n    {\n        if( !IMutableContext::currentContext )\n            IMutableContext::createContext();\n        // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)\n        return *IMutableContext::currentContext;\n    }\n\n    inline IContext& getCurrentContext()\n    {\n        return getCurrentMutableContext();\n    }\n\n    void cleanUpContext();\n\n    class SimplePcg32;\n    SimplePcg32& rng();\n}\n\n// end catch_context.h\n// start catch_interfaces_config.h\n\n// start catch_option.hpp\n\nnamespace Catch {\n\n    // An optional type\n    template<typename T>\n    class Option {\n    public:\n        Option() : nullableValue( nullptr ) {}\n        Option( T const& _value )\n        : nullableValue( new( storage ) T( _value ) )\n        {}\n        Option( Option const& _other )\n        : nullableValue( _other ? new( storage ) T( *_other ) : nullptr )\n        {}\n\n        ~Option() {\n            reset();\n        }\n\n        Option& operator= ( Option const& _other ) {\n            if( &_other != this ) {\n                reset();\n                if( _other )\n                    nullableValue = new( storage ) T( *_other );\n            }\n            return *this;\n        }\n        Option& operator = ( T const& _value ) {\n            reset();\n            nullableValue = new( storage ) T( _value );\n            return *this;\n        }\n\n        void reset() {\n            if( nullableValue )\n                nullableValue->~T();\n            nullableValue = nullptr;\n        }\n\n        T& operator*() { return *nullableValue; }\n        T const& operator*() const { return *nullableValue; }\n        T* operator->() { return nullableValue; }\n        const T* operator->() const { return nullableValue; }\n\n        T valueOr( T const& defaultValue ) const {\n            return nullableValue ? *nullableValue : defaultValue;\n        }\n\n        bool some() const { return nullableValue != nullptr; }\n        bool none() const { return nullableValue == nullptr; }\n\n        bool operator !() const { return nullableValue == nullptr; }\n        explicit operator bool() const {\n            return some();\n        }\n\n    private:\n        T *nullableValue;\n        alignas(alignof(T)) char storage[sizeof(T)];\n    };\n\n} // end namespace Catch\n\n// end catch_option.hpp\n#include <chrono>\n#include <iosfwd>\n#include <string>\n#include <vector>\n#include <memory>\n\nnamespace Catch {\n\n    enum class Verbosity {\n        Quiet = 0,\n        Normal,\n        High\n    };\n\n    struct WarnAbout { enum What {\n        Nothing = 0x00,\n        NoAssertions = 0x01,\n        NoTests = 0x02\n    }; };\n\n    struct ShowDurations { enum OrNot {\n        DefaultForReporter,\n        Always,\n        Never\n    }; };\n    struct RunTests { enum InWhatOrder {\n        InDeclarationOrder,\n        InLexicographicalOrder,\n        InRandomOrder\n    }; };\n    struct UseColour { enum YesOrNo {\n        Auto,\n        Yes,\n        No\n    }; };\n    struct WaitForKeypress { enum When {\n        Never,\n        BeforeStart = 1,\n        BeforeExit = 2,\n        BeforeStartAndExit = BeforeStart | BeforeExit\n    }; };\n\n    class TestSpec;\n\n    struct IConfig : NonCopyable {\n\n        virtual ~IConfig();\n\n        virtual bool allowThrows() const = 0;\n        virtual std::ostream& stream() const = 0;\n        virtual std::string name() const = 0;\n        virtual bool includeSuccessfulResults() const = 0;\n        virtual bool shouldDebugBreak() const = 0;\n        virtual bool warnAboutMissingAssertions() const = 0;\n        virtual bool warnAboutNoTests() const = 0;\n        virtual int abortAfter() const = 0;\n        virtual bool showInvisibles() const = 0;\n        virtual ShowDurations::OrNot showDurations() const = 0;\n        virtual double minDuration() const = 0;\n        virtual TestSpec const& testSpec() const = 0;\n        virtual bool hasTestFilters() const = 0;\n        virtual std::vector<std::string> const& getTestsOrTags() const = 0;\n        virtual RunTests::InWhatOrder runOrder() const = 0;\n        virtual unsigned int rngSeed() const = 0;\n        virtual UseColour::YesOrNo useColour() const = 0;\n        virtual std::vector<std::string> const& getSectionsToRun() const = 0;\n        virtual Verbosity verbosity() const = 0;\n\n        virtual bool benchmarkNoAnalysis() const = 0;\n        virtual int benchmarkSamples() const = 0;\n        virtual double benchmarkConfidenceInterval() const = 0;\n        virtual unsigned int benchmarkResamples() const = 0;\n        virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0;\n    };\n\n    using IConfigPtr = std::shared_ptr<IConfig const>;\n}\n\n// end catch_interfaces_config.h\n// start catch_random_number_generator.h\n\n#include <cstdint>\n\nnamespace Catch {\n\n    // This is a simple implementation of C++11 Uniform Random Number\n    // Generator. It does not provide all operators, because Catch2\n    // does not use it, but it should behave as expected inside stdlib's\n    // distributions.\n    // The implementation is based on the PCG family (http://pcg-random.org)\n    class SimplePcg32 {\n        using state_type = std::uint64_t;\n    public:\n        using result_type = std::uint32_t;\n        static constexpr result_type (min)() {\n            return 0;\n        }\n        static constexpr result_type (max)() {\n            return static_cast<result_type>(-1);\n        }\n\n        // Provide some default initial state for the default constructor\n        SimplePcg32():SimplePcg32(0xed743cc4U) {}\n\n        explicit SimplePcg32(result_type seed_);\n\n        void seed(result_type seed_);\n        void discard(uint64_t skip);\n\n        result_type operator()();\n\n    private:\n        friend bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs);\n        friend bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs);\n\n        // In theory we also need operator<< and operator>>\n        // In practice we do not use them, so we will skip them for now\n\n        std::uint64_t m_state;\n        // This part of the state determines which \"stream\" of the numbers\n        // is chosen -- we take it as a constant for Catch2, so we only\n        // need to deal with seeding the main state.\n        // Picked by reading 8 bytes from `/dev/random` :-)\n        static const std::uint64_t s_inc = (0x13ed0cc53f939476ULL << 1ULL) | 1ULL;\n    };\n\n} // end namespace Catch\n\n// end catch_random_number_generator.h\n#include <random>\n\nnamespace Catch {\nnamespace Generators {\n\ntemplate <typename Float>\nclass RandomFloatingGenerator final : public IGenerator<Float> {\n    Catch::SimplePcg32& m_rng;\n    std::uniform_real_distribution<Float> m_dist;\n    Float m_current_number;\npublic:\n\n    RandomFloatingGenerator(Float a, Float b):\n        m_rng(rng()),\n        m_dist(a, b) {\n        static_cast<void>(next());\n    }\n\n    Float const& get() const override {\n        return m_current_number;\n    }\n    bool next() override {\n        m_current_number = m_dist(m_rng);\n        return true;\n    }\n};\n\ntemplate <typename Integer>\nclass RandomIntegerGenerator final : public IGenerator<Integer> {\n    Catch::SimplePcg32& m_rng;\n    std::uniform_int_distribution<Integer> m_dist;\n    Integer m_current_number;\npublic:\n\n    RandomIntegerGenerator(Integer a, Integer b):\n        m_rng(rng()),\n        m_dist(a, b) {\n        static_cast<void>(next());\n    }\n\n    Integer const& get() const override {\n        return m_current_number;\n    }\n    bool next() override {\n        m_current_number = m_dist(m_rng);\n        return true;\n    }\n};\n\n// TODO: Ideally this would be also constrained against the various char types,\n//       but I don't expect users to run into that in practice.\ntemplate <typename T>\ntypename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value,\nGeneratorWrapper<T>>::type\nrandom(T a, T b) {\n    return GeneratorWrapper<T>(\n        pf::make_unique<RandomIntegerGenerator<T>>(a, b)\n    );\n}\n\ntemplate <typename T>\ntypename std::enable_if<std::is_floating_point<T>::value,\nGeneratorWrapper<T>>::type\nrandom(T a, T b) {\n    return GeneratorWrapper<T>(\n        pf::make_unique<RandomFloatingGenerator<T>>(a, b)\n    );\n}\n\ntemplate <typename T>\nclass RangeGenerator final : public IGenerator<T> {\n    T m_current;\n    T m_end;\n    T m_step;\n    bool m_positive;\n\npublic:\n    RangeGenerator(T const& start, T const& end, T const& step):\n        m_current(start),\n        m_end(end),\n        m_step(step),\n        m_positive(m_step > T(0))\n    {\n        assert(m_current != m_end && \"Range start and end cannot be equal\");\n        assert(m_step != T(0) && \"Step size cannot be zero\");\n        assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && \"Step moves away from end\");\n    }\n\n    RangeGenerator(T const& start, T const& end):\n        RangeGenerator(start, end, (start < end) ? T(1) : T(-1))\n    {}\n\n    T const& get() const override {\n        return m_current;\n    }\n\n    bool next() override {\n        m_current += m_step;\n        return (m_positive) ? (m_current < m_end) : (m_current > m_end);\n    }\n};\n\ntemplate <typename T>\nGeneratorWrapper<T> range(T const& start, T const& end, T const& step) {\n    static_assert(std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, \"Type must be numeric\");\n    return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step));\n}\n\ntemplate <typename T>\nGeneratorWrapper<T> range(T const& start, T const& end) {\n    static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, \"Type must be an integer\");\n    return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end));\n}\n\ntemplate <typename T>\nclass IteratorGenerator final : public IGenerator<T> {\n    static_assert(!std::is_same<T, bool>::value,\n        \"IteratorGenerator currently does not support bools\"\n        \"because of std::vector<bool> specialization\");\n\n    std::vector<T> m_elems;\n    size_t m_current = 0;\npublic:\n    template <typename InputIterator, typename InputSentinel>\n    IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) {\n        if (m_elems.empty()) {\n            Catch::throw_exception(GeneratorException(\"IteratorGenerator received no valid values\"));\n        }\n    }\n\n    T const& get() const override {\n        return m_elems[m_current];\n    }\n\n    bool next() override {\n        ++m_current;\n        return m_current != m_elems.size();\n    }\n};\n\ntemplate <typename InputIterator,\n          typename InputSentinel,\n          typename ResultType = typename std::iterator_traits<InputIterator>::value_type>\nGeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) {\n    return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(from, to));\n}\n\ntemplate <typename Container,\n          typename ResultType = typename Container::value_type>\nGeneratorWrapper<ResultType> from_range(Container const& cnt) {\n    return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(cnt.begin(), cnt.end()));\n}\n\n} // namespace Generators\n} // namespace Catch\n\n// end catch_generators_specific.hpp\n\n// These files are included here so the single_include script doesn't put them\n// in the conditionally compiled sections\n// start catch_test_case_info.h\n\n#include <string>\n#include <vector>\n#include <memory>\n\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n#endif\n\nnamespace Catch {\n\n    struct ITestInvoker;\n\n    struct TestCaseInfo {\n        enum SpecialProperties{\n            None = 0,\n            IsHidden = 1 << 1,\n            ShouldFail = 1 << 2,\n            MayFail = 1 << 3,\n            Throws = 1 << 4,\n            NonPortable = 1 << 5,\n            Benchmark = 1 << 6\n        };\n\n        TestCaseInfo(   std::string const& _name,\n                        std::string const& _className,\n                        std::string const& _description,\n                        std::vector<std::string> const& _tags,\n                        SourceLineInfo const& _lineInfo );\n\n        friend void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags );\n\n        bool isHidden() const;\n        bool throws() const;\n        bool okToFail() const;\n        bool expectedToFail() const;\n\n        std::string tagsAsString() const;\n\n        std::string name;\n        std::string className;\n        std::string description;\n        std::vector<std::string> tags;\n        std::vector<std::string> lcaseTags;\n        SourceLineInfo lineInfo;\n        SpecialProperties properties;\n    };\n\n    class TestCase : public TestCaseInfo {\n    public:\n\n        TestCase( ITestInvoker* testCase, TestCaseInfo&& info );\n\n        TestCase withName( std::string const& _newName ) const;\n\n        void invoke() const;\n\n        TestCaseInfo const& getTestCaseInfo() const;\n\n        bool operator == ( TestCase const& other ) const;\n        bool operator < ( TestCase const& other ) const;\n\n    private:\n        std::shared_ptr<ITestInvoker> test;\n    };\n\n    TestCase makeTestCase(  ITestInvoker* testCase,\n                            std::string const& className,\n                            NameAndTags const& nameAndTags,\n                            SourceLineInfo const& lineInfo );\n}\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n\n// end catch_test_case_info.h\n// start catch_interfaces_runner.h\n\nnamespace Catch {\n\n    struct IRunner {\n        virtual ~IRunner();\n        virtual bool aborting() const = 0;\n    };\n}\n\n// end catch_interfaces_runner.h\n\n#ifdef __OBJC__\n// start catch_objc.hpp\n\n#import <objc/runtime.h>\n\n#include <string>\n\n// NB. Any general catch headers included here must be included\n// in catch.hpp first to make sure they are included by the single\n// header for non obj-usage\n\n///////////////////////////////////////////////////////////////////////////////\n// This protocol is really only here for (self) documenting purposes, since\n// all its methods are optional.\n@protocol OcFixture\n\n@optional\n\n-(void) setUp;\n-(void) tearDown;\n\n@end\n\nnamespace Catch {\n\n    class OcMethod : public ITestInvoker {\n\n    public:\n        OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}\n\n        virtual void invoke() const {\n            id obj = [[m_cls alloc] init];\n\n            performOptionalSelector( obj, @selector(setUp)  );\n            performOptionalSelector( obj, m_sel );\n            performOptionalSelector( obj, @selector(tearDown)  );\n\n            arcSafeRelease( obj );\n        }\n    private:\n        virtual ~OcMethod() {}\n\n        Class m_cls;\n        SEL m_sel;\n    };\n\n    namespace Detail{\n\n        inline std::string getAnnotation(   Class cls,\n                                            std::string const& annotationName,\n                                            std::string const& testCaseName ) {\n            NSString* selStr = [[NSString alloc] initWithFormat:@\"Catch_%s_%s\", annotationName.c_str(), testCaseName.c_str()];\n            SEL sel = NSSelectorFromString( selStr );\n            arcSafeRelease( selStr );\n            id value = performOptionalSelector( cls, sel );\n            if( value )\n                return [(NSString*)value UTF8String];\n            return \"\";\n        }\n    }\n\n    inline std::size_t registerTestMethods() {\n        std::size_t noTestMethods = 0;\n        int noClasses = objc_getClassList( nullptr, 0 );\n\n        Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);\n        objc_getClassList( classes, noClasses );\n\n        for( int c = 0; c < noClasses; c++ ) {\n            Class cls = classes[c];\n            {\n                u_int count;\n                Method* methods = class_copyMethodList( cls, &count );\n                for( u_int m = 0; m < count ; m++ ) {\n                    SEL selector = method_getName(methods[m]);\n                    std::string methodName = sel_getName(selector);\n                    if( startsWith( methodName, \"Catch_TestCase_\" ) ) {\n                        std::string testCaseName = methodName.substr( 15 );\n                        std::string name = Detail::getAnnotation( cls, \"Name\", testCaseName );\n                        std::string desc = Detail::getAnnotation( cls, \"Description\", testCaseName );\n                        const char* className = class_getName( cls );\n\n                        getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo(\"\",0) ) );\n                        noTestMethods++;\n                    }\n                }\n                free(methods);\n            }\n        }\n        return noTestMethods;\n    }\n\n#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)\n\n    namespace Matchers {\n        namespace Impl {\n        namespace NSStringMatchers {\n\n            struct StringHolder : MatcherBase<NSString*>{\n                StringHolder( NSString* substr ) : m_substr( [substr copy] ){}\n                StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}\n                StringHolder() {\n                    arcSafeRelease( m_substr );\n                }\n\n                bool match( NSString* str ) const override {\n                    return false;\n                }\n\n                NSString* CATCH_ARC_STRONG m_substr;\n            };\n\n            struct Equals : StringHolder {\n                Equals( NSString* substr ) : StringHolder( substr ){}\n\n                bool match( NSString* str ) const override {\n                    return  (str != nil || m_substr == nil ) &&\n                            [str isEqualToString:m_substr];\n                }\n\n                std::string describe() const override {\n                    return \"equals string: \" + Catch::Detail::stringify( m_substr );\n                }\n            };\n\n            struct Contains : StringHolder {\n                Contains( NSString* substr ) : StringHolder( substr ){}\n\n                bool match( NSString* str ) const override {\n                    return  (str != nil || m_substr == nil ) &&\n                            [str rangeOfString:m_substr].location != NSNotFound;\n                }\n\n                std::string describe() const override {\n                    return \"contains string: \" + Catch::Detail::stringify( m_substr );\n                }\n            };\n\n            struct StartsWith : StringHolder {\n                StartsWith( NSString* substr ) : StringHolder( substr ){}\n\n                bool match( NSString* str ) const override {\n                    return  (str != nil || m_substr == nil ) &&\n                            [str rangeOfString:m_substr].location == 0;\n                }\n\n                std::string describe() const override {\n                    return \"starts with: \" + Catch::Detail::stringify( m_substr );\n                }\n            };\n            struct EndsWith : StringHolder {\n                EndsWith( NSString* substr ) : StringHolder( substr ){}\n\n                bool match( NSString* str ) const override {\n                    return  (str != nil || m_substr == nil ) &&\n                            [str rangeOfString:m_substr].location == [str length] - [m_substr length];\n                }\n\n                std::string describe() const override {\n                    return \"ends with: \" + Catch::Detail::stringify( m_substr );\n                }\n            };\n\n        } // namespace NSStringMatchers\n        } // namespace Impl\n\n        inline Impl::NSStringMatchers::Equals\n            Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }\n\n        inline Impl::NSStringMatchers::Contains\n            Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }\n\n        inline Impl::NSStringMatchers::StartsWith\n            StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }\n\n        inline Impl::NSStringMatchers::EndsWith\n            EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }\n\n    } // namespace Matchers\n\n    using namespace Matchers;\n\n#endif // CATCH_CONFIG_DISABLE_MATCHERS\n\n} // namespace Catch\n\n///////////////////////////////////////////////////////////////////////////////\n#define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix\n#define OC_TEST_CASE2( name, desc, uniqueSuffix ) \\\n+(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \\\n{ \\\nreturn @ name; \\\n} \\\n+(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \\\n{ \\\nreturn @ desc; \\\n} \\\n-(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix )\n\n#define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ )\n\n// end catch_objc.hpp\n#endif\n\n// Benchmarking needs the externally-facing parts of reporters to work\n#if defined(CATCH_CONFIG_EXTERNAL_INTERFACES) || defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\n// start catch_external_interfaces.h\n\n// start catch_reporter_bases.hpp\n\n// start catch_interfaces_reporter.h\n\n// start catch_config.hpp\n\n// start catch_test_spec_parser.h\n\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n#endif\n\n// start catch_test_spec.h\n\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n#endif\n\n// start catch_wildcard_pattern.h\n\nnamespace Catch\n{\n    class WildcardPattern {\n        enum WildcardPosition {\n            NoWildcard = 0,\n            WildcardAtStart = 1,\n            WildcardAtEnd = 2,\n            WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd\n        };\n\n    public:\n\n        WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity );\n        virtual ~WildcardPattern() = default;\n        virtual bool matches( std::string const& str ) const;\n\n    private:\n        std::string normaliseString( std::string const& str ) const;\n        CaseSensitive::Choice m_caseSensitivity;\n        WildcardPosition m_wildcard = NoWildcard;\n        std::string m_pattern;\n    };\n}\n\n// end catch_wildcard_pattern.h\n#include <string>\n#include <vector>\n#include <memory>\n\nnamespace Catch {\n\n    struct IConfig;\n\n    class TestSpec {\n        class Pattern {\n        public:\n            explicit Pattern( std::string const& name );\n            virtual ~Pattern();\n            virtual bool matches( TestCaseInfo const& testCase ) const = 0;\n            std::string const& name() const;\n        private:\n            std::string const m_name;\n        };\n        using PatternPtr = std::shared_ptr<Pattern>;\n\n        class NamePattern : public Pattern {\n        public:\n            explicit NamePattern( std::string const& name, std::string const& filterString );\n            bool matches( TestCaseInfo const& testCase ) const override;\n        private:\n            WildcardPattern m_wildcardPattern;\n        };\n\n        class TagPattern : public Pattern {\n        public:\n            explicit TagPattern( std::string const& tag, std::string const& filterString );\n            bool matches( TestCaseInfo const& testCase ) const override;\n        private:\n            std::string m_tag;\n        };\n\n        class ExcludedPattern : public Pattern {\n        public:\n            explicit ExcludedPattern( PatternPtr const& underlyingPattern );\n            bool matches( TestCaseInfo const& testCase ) const override;\n        private:\n            PatternPtr m_underlyingPattern;\n        };\n\n        struct Filter {\n            std::vector<PatternPtr> m_patterns;\n\n            bool matches( TestCaseInfo const& testCase ) const;\n            std::string name() const;\n        };\n\n    public:\n        struct FilterMatch {\n            std::string name;\n            std::vector<TestCase const*> tests;\n        };\n        using Matches = std::vector<FilterMatch>;\n        using vectorStrings = std::vector<std::string>;\n\n        bool hasFilters() const;\n        bool matches( TestCaseInfo const& testCase ) const;\n        Matches matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const;\n        const vectorStrings & getInvalidArgs() const;\n\n    private:\n        std::vector<Filter> m_filters;\n        std::vector<std::string> m_invalidArgs;\n        friend class TestSpecParser;\n    };\n}\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n\n// end catch_test_spec.h\n// start catch_interfaces_tag_alias_registry.h\n\n#include <string>\n\nnamespace Catch {\n\n    struct TagAlias;\n\n    struct ITagAliasRegistry {\n        virtual ~ITagAliasRegistry();\n        // Nullptr if not present\n        virtual TagAlias const* find( std::string const& alias ) const = 0;\n        virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;\n\n        static ITagAliasRegistry const& get();\n    };\n\n} // end namespace Catch\n\n// end catch_interfaces_tag_alias_registry.h\nnamespace Catch {\n\n    class TestSpecParser {\n        enum Mode{ None, Name, QuotedName, Tag, EscapedName };\n        Mode m_mode = None;\n        Mode lastMode = None;\n        bool m_exclusion = false;\n        std::size_t m_pos = 0;\n        std::size_t m_realPatternPos = 0;\n        std::string m_arg;\n        std::string m_substring;\n        std::string m_patternName;\n        std::vector<std::size_t> m_escapeChars;\n        TestSpec::Filter m_currentFilter;\n        TestSpec m_testSpec;\n        ITagAliasRegistry const* m_tagAliases = nullptr;\n\n    public:\n        TestSpecParser( ITagAliasRegistry const& tagAliases );\n\n        TestSpecParser& parse( std::string const& arg );\n        TestSpec testSpec();\n\n    private:\n        bool visitChar( char c );\n        void startNewMode( Mode mode );\n        bool processNoneChar( char c );\n        void processNameChar( char c );\n        bool processOtherChar( char c );\n        void endMode();\n        void escape();\n        bool isControlChar( char c ) const;\n        void saveLastMode();\n        void revertBackToLastMode();\n        void addFilter();\n        bool separate();\n\n        // Handles common preprocessing of the pattern for name/tag patterns\n        std::string preprocessPattern();\n        // Adds the current pattern as a test name\n        void addNamePattern();\n        // Adds the current pattern as a tag\n        void addTagPattern();\n\n        inline void addCharToPattern(char c) {\n            m_substring += c;\n            m_patternName += c;\n            m_realPatternPos++;\n        }\n\n    };\n    TestSpec parseTestSpec( std::string const& arg );\n\n} // namespace Catch\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n\n// end catch_test_spec_parser.h\n// Libstdc++ doesn't like incomplete classes for unique_ptr\n\n#include <memory>\n#include <vector>\n#include <string>\n\n#ifndef CATCH_CONFIG_CONSOLE_WIDTH\n#define CATCH_CONFIG_CONSOLE_WIDTH 80\n#endif\n\nnamespace Catch {\n\n    struct IStream;\n\n    struct ConfigData {\n        bool listTests = false;\n        bool listTags = false;\n        bool listReporters = false;\n        bool listTestNamesOnly = false;\n\n        bool showSuccessfulTests = false;\n        bool shouldDebugBreak = false;\n        bool noThrow = false;\n        bool showHelp = false;\n        bool showInvisibles = false;\n        bool filenamesAsTags = false;\n        bool libIdentify = false;\n\n        int abortAfter = -1;\n        unsigned int rngSeed = 0;\n\n        bool benchmarkNoAnalysis = false;\n        unsigned int benchmarkSamples = 100;\n        double benchmarkConfidenceInterval = 0.95;\n        unsigned int benchmarkResamples = 100000;\n        std::chrono::milliseconds::rep benchmarkWarmupTime = 100;\n\n        Verbosity verbosity = Verbosity::Normal;\n        WarnAbout::What warnings = WarnAbout::Nothing;\n        ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter;\n        double minDuration = -1;\n        RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder;\n        UseColour::YesOrNo useColour = UseColour::Auto;\n        WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;\n\n        std::string outputFilename;\n        std::string name;\n        std::string processName;\n#ifndef CATCH_CONFIG_DEFAULT_REPORTER\n#define CATCH_CONFIG_DEFAULT_REPORTER \"console\"\n#endif\n        std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER;\n#undef CATCH_CONFIG_DEFAULT_REPORTER\n\n        std::vector<std::string> testsOrTags;\n        std::vector<std::string> sectionsToRun;\n    };\n\n    class Config : public IConfig {\n    public:\n\n        Config() = default;\n        Config( ConfigData const& data );\n        virtual ~Config() = default;\n\n        std::string const& getFilename() const;\n\n        bool listTests() const;\n        bool listTestNamesOnly() const;\n        bool listTags() const;\n        bool listReporters() const;\n\n        std::string getProcessName() const;\n        std::string const& getReporterName() const;\n\n        std::vector<std::string> const& getTestsOrTags() const override;\n        std::vector<std::string> const& getSectionsToRun() const override;\n\n        TestSpec const& testSpec() const override;\n        bool hasTestFilters() const override;\n\n        bool showHelp() const;\n\n        // IConfig interface\n        bool allowThrows() const override;\n        std::ostream& stream() const override;\n        std::string name() const override;\n        bool includeSuccessfulResults() const override;\n        bool warnAboutMissingAssertions() const override;\n        bool warnAboutNoTests() const override;\n        ShowDurations::OrNot showDurations() const override;\n        double minDuration() const override;\n        RunTests::InWhatOrder runOrder() const override;\n        unsigned int rngSeed() const override;\n        UseColour::YesOrNo useColour() const override;\n        bool shouldDebugBreak() const override;\n        int abortAfter() const override;\n        bool showInvisibles() const override;\n        Verbosity verbosity() const override;\n        bool benchmarkNoAnalysis() const override;\n        int benchmarkSamples() const override;\n        double benchmarkConfidenceInterval() const override;\n        unsigned int benchmarkResamples() const override;\n        std::chrono::milliseconds benchmarkWarmupTime() const override;\n\n    private:\n\n        IStream const* openStream();\n        ConfigData m_data;\n\n        std::unique_ptr<IStream const> m_stream;\n        TestSpec m_testSpec;\n        bool m_hasTestFilters = false;\n    };\n\n} // end namespace Catch\n\n// end catch_config.hpp\n// start catch_assertionresult.h\n\n#include <string>\n\nnamespace Catch {\n\n    struct AssertionResultData\n    {\n        AssertionResultData() = delete;\n\n        AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression );\n\n        std::string message;\n        mutable std::string reconstructedExpression;\n        LazyExpression lazyExpression;\n        ResultWas::OfType resultType;\n\n        std::string reconstructExpression() const;\n    };\n\n    class AssertionResult {\n    public:\n        AssertionResult() = delete;\n        AssertionResult( AssertionInfo const& info, AssertionResultData const& data );\n\n        bool isOk() const;\n        bool succeeded() const;\n        ResultWas::OfType getResultType() const;\n        bool hasExpression() const;\n        bool hasMessage() const;\n        std::string getExpression() const;\n        std::string getExpressionInMacro() const;\n        bool hasExpandedExpression() const;\n        std::string getExpandedExpression() const;\n        std::string getMessage() const;\n        SourceLineInfo getSourceInfo() const;\n        StringRef getTestMacroName() const;\n\n    //protected:\n        AssertionInfo m_info;\n        AssertionResultData m_resultData;\n    };\n\n} // end namespace Catch\n\n// end catch_assertionresult.h\n#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\n// start catch_estimate.hpp\n\n // Statistics estimates\n\n\nnamespace Catch {\n    namespace Benchmark {\n        template <typename Duration>\n        struct Estimate {\n            Duration point;\n            Duration lower_bound;\n            Duration upper_bound;\n            double confidence_interval;\n\n            template <typename Duration2>\n            operator Estimate<Duration2>() const {\n                return { point, lower_bound, upper_bound, confidence_interval };\n            }\n        };\n    } // namespace Benchmark\n} // namespace Catch\n\n// end catch_estimate.hpp\n// start catch_outlier_classification.hpp\n\n// Outlier information\n\nnamespace Catch {\n    namespace Benchmark {\n        struct OutlierClassification {\n            int samples_seen = 0;\n            int low_severe = 0;     // more than 3 times IQR below Q1\n            int low_mild = 0;       // 1.5 to 3 times IQR below Q1\n            int high_mild = 0;      // 1.5 to 3 times IQR above Q3\n            int high_severe = 0;    // more than 3 times IQR above Q3\n\n            int total() const {\n                return low_severe + low_mild + high_mild + high_severe;\n            }\n        };\n    } // namespace Benchmark\n} // namespace Catch\n\n// end catch_outlier_classification.hpp\n\n#include <iterator>\n#endif // CATCH_CONFIG_ENABLE_BENCHMARKING\n\n#include <string>\n#include <iosfwd>\n#include <map>\n#include <set>\n#include <memory>\n#include <algorithm>\n\nnamespace Catch {\n\n    struct ReporterConfig {\n        explicit ReporterConfig( IConfigPtr const& _fullConfig );\n\n        ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream );\n\n        std::ostream& stream() const;\n        IConfigPtr fullConfig() const;\n\n    private:\n        std::ostream* m_stream;\n        IConfigPtr m_fullConfig;\n    };\n\n    struct ReporterPreferences {\n        bool shouldRedirectStdOut = false;\n        bool shouldReportAllAssertions = false;\n    };\n\n    template<typename T>\n    struct LazyStat : Option<T> {\n        LazyStat& operator=( T const& _value ) {\n            Option<T>::operator=( _value );\n            used = false;\n            return *this;\n        }\n        void reset() {\n            Option<T>::reset();\n            used = false;\n        }\n        bool used = false;\n    };\n\n    struct TestRunInfo {\n        TestRunInfo( std::string const& _name );\n        std::string name;\n    };\n    struct GroupInfo {\n        GroupInfo(  std::string const& _name,\n                    std::size_t _groupIndex,\n                    std::size_t _groupsCount );\n\n        std::string name;\n        std::size_t groupIndex;\n        std::size_t groupsCounts;\n    };\n\n    struct AssertionStats {\n        AssertionStats( AssertionResult const& _assertionResult,\n                        std::vector<MessageInfo> const& _infoMessages,\n                        Totals const& _totals );\n\n        AssertionStats( AssertionStats const& )              = default;\n        AssertionStats( AssertionStats && )                  = default;\n        AssertionStats& operator = ( AssertionStats const& ) = delete;\n        AssertionStats& operator = ( AssertionStats && )     = delete;\n        virtual ~AssertionStats();\n\n        AssertionResult assertionResult;\n        std::vector<MessageInfo> infoMessages;\n        Totals totals;\n    };\n\n    struct SectionStats {\n        SectionStats(   SectionInfo const& _sectionInfo,\n                        Counts const& _assertions,\n                        double _durationInSeconds,\n                        bool _missingAssertions );\n        SectionStats( SectionStats const& )              = default;\n        SectionStats( SectionStats && )                  = default;\n        SectionStats& operator = ( SectionStats const& ) = default;\n        SectionStats& operator = ( SectionStats && )     = default;\n        virtual ~SectionStats();\n\n        SectionInfo sectionInfo;\n        Counts assertions;\n        double durationInSeconds;\n        bool missingAssertions;\n    };\n\n    struct TestCaseStats {\n        TestCaseStats(  TestCaseInfo const& _testInfo,\n                        Totals const& _totals,\n                        std::string const& _stdOut,\n                        std::string const& _stdErr,\n                        bool _aborting );\n\n        TestCaseStats( TestCaseStats const& )              = default;\n        TestCaseStats( TestCaseStats && )                  = default;\n        TestCaseStats& operator = ( TestCaseStats const& ) = default;\n        TestCaseStats& operator = ( TestCaseStats && )     = default;\n        virtual ~TestCaseStats();\n\n        TestCaseInfo testInfo;\n        Totals totals;\n        std::string stdOut;\n        std::string stdErr;\n        bool aborting;\n    };\n\n    struct TestGroupStats {\n        TestGroupStats( GroupInfo const& _groupInfo,\n                        Totals const& _totals,\n                        bool _aborting );\n        TestGroupStats( GroupInfo const& _groupInfo );\n\n        TestGroupStats( TestGroupStats const& )              = default;\n        TestGroupStats( TestGroupStats && )                  = default;\n        TestGroupStats& operator = ( TestGroupStats const& ) = default;\n        TestGroupStats& operator = ( TestGroupStats && )     = default;\n        virtual ~TestGroupStats();\n\n        GroupInfo groupInfo;\n        Totals totals;\n        bool aborting;\n    };\n\n    struct TestRunStats {\n        TestRunStats(   TestRunInfo const& _runInfo,\n                        Totals const& _totals,\n                        bool _aborting );\n\n        TestRunStats( TestRunStats const& )              = default;\n        TestRunStats( TestRunStats && )                  = default;\n        TestRunStats& operator = ( TestRunStats const& ) = default;\n        TestRunStats& operator = ( TestRunStats && )     = default;\n        virtual ~TestRunStats();\n\n        TestRunInfo runInfo;\n        Totals totals;\n        bool aborting;\n    };\n\n#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\n    struct BenchmarkInfo {\n        std::string name;\n        double estimatedDuration;\n        int iterations;\n        int samples;\n        unsigned int resamples;\n        double clockResolution;\n        double clockCost;\n    };\n\n    template <class Duration>\n    struct BenchmarkStats {\n        BenchmarkInfo info;\n\n        std::vector<Duration> samples;\n        Benchmark::Estimate<Duration> mean;\n        Benchmark::Estimate<Duration> standardDeviation;\n        Benchmark::OutlierClassification outliers;\n        double outlierVariance;\n\n        template <typename Duration2>\n        operator BenchmarkStats<Duration2>() const {\n            std::vector<Duration2> samples2;\n            samples2.reserve(samples.size());\n            std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); });\n            return {\n                info,\n                std::move(samples2),\n                mean,\n                standardDeviation,\n                outliers,\n                outlierVariance,\n            };\n        }\n    };\n#endif // CATCH_CONFIG_ENABLE_BENCHMARKING\n\n    struct IStreamingReporter {\n        virtual ~IStreamingReporter() = default;\n\n        // Implementing class must also provide the following static methods:\n        // static std::string getDescription();\n        // static std::set<Verbosity> getSupportedVerbosities()\n\n        virtual ReporterPreferences getPreferences() const = 0;\n\n        virtual void noMatchingTestCases( std::string const& spec ) = 0;\n\n        virtual void reportInvalidArguments(std::string const&) {}\n\n        virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;\n        virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;\n\n        virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;\n        virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;\n\n#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\n        virtual void benchmarkPreparing( std::string const& ) {}\n        virtual void benchmarkStarting( BenchmarkInfo const& ) {}\n        virtual void benchmarkEnded( BenchmarkStats<> const& ) {}\n        virtual void benchmarkFailed( std::string const& ) {}\n#endif // CATCH_CONFIG_ENABLE_BENCHMARKING\n\n        virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;\n\n        // The return value indicates if the messages buffer should be cleared:\n        virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;\n\n        virtual void sectionEnded( SectionStats const& sectionStats ) = 0;\n        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;\n        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;\n        virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;\n\n        virtual void skipTest( TestCaseInfo const& testInfo ) = 0;\n\n        // Default empty implementation provided\n        virtual void fatalErrorEncountered( StringRef name );\n\n        virtual bool isMulti() const;\n    };\n    using IStreamingReporterPtr = std::unique_ptr<IStreamingReporter>;\n\n    struct IReporterFactory {\n        virtual ~IReporterFactory();\n        virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0;\n        virtual std::string getDescription() const = 0;\n    };\n    using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;\n\n    struct IReporterRegistry {\n        using FactoryMap = std::map<std::string, IReporterFactoryPtr>;\n        using Listeners = std::vector<IReporterFactoryPtr>;\n\n        virtual ~IReporterRegistry();\n        virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0;\n        virtual FactoryMap const& getFactories() const = 0;\n        virtual Listeners const& getListeners() const = 0;\n    };\n\n} // end namespace Catch\n\n// end catch_interfaces_reporter.h\n#include <algorithm>\n#include <cstring>\n#include <cfloat>\n#include <cstdio>\n#include <cassert>\n#include <memory>\n#include <ostream>\n\nnamespace Catch {\n    void prepareExpandedExpression(AssertionResult& result);\n\n    // Returns double formatted as %.3f (format expected on output)\n    std::string getFormattedDuration( double duration );\n\n    //! Should the reporter show\n    bool shouldShowDuration( IConfig const& config, double duration );\n\n    std::string serializeFilters( std::vector<std::string> const& container );\n\n    template<typename DerivedT>\n    struct StreamingReporterBase : IStreamingReporter {\n\n        StreamingReporterBase( ReporterConfig const& _config )\n        :   m_config( _config.fullConfig() ),\n            stream( _config.stream() )\n        {\n            m_reporterPrefs.shouldRedirectStdOut = false;\n            if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )\n                CATCH_ERROR( \"Verbosity level not supported by this reporter\" );\n        }\n\n        ReporterPreferences getPreferences() const override {\n            return m_reporterPrefs;\n        }\n\n        static std::set<Verbosity> getSupportedVerbosities() {\n            return { Verbosity::Normal };\n        }\n\n        ~StreamingReporterBase() override = default;\n\n        void noMatchingTestCases(std::string const&) override {}\n\n        void reportInvalidArguments(std::string const&) override {}\n\n        void testRunStarting(TestRunInfo const& _testRunInfo) override {\n            currentTestRunInfo = _testRunInfo;\n        }\n\n        void testGroupStarting(GroupInfo const& _groupInfo) override {\n            currentGroupInfo = _groupInfo;\n        }\n\n        void testCaseStarting(TestCaseInfo const& _testInfo) override  {\n            currentTestCaseInfo = _testInfo;\n        }\n        void sectionStarting(SectionInfo const& _sectionInfo) override {\n            m_sectionStack.push_back(_sectionInfo);\n        }\n\n        void sectionEnded(SectionStats const& /* _sectionStats */) override {\n            m_sectionStack.pop_back();\n        }\n        void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override {\n            currentTestCaseInfo.reset();\n        }\n        void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override {\n            currentGroupInfo.reset();\n        }\n        void testRunEnded(TestRunStats const& /* _testRunStats */) override {\n            currentTestCaseInfo.reset();\n            currentGroupInfo.reset();\n            currentTestRunInfo.reset();\n        }\n\n        void skipTest(TestCaseInfo const&) override {\n            // Don't do anything with this by default.\n            // It can optionally be overridden in the derived class.\n        }\n\n        IConfigPtr m_config;\n        std::ostream& stream;\n\n        LazyStat<TestRunInfo> currentTestRunInfo;\n        LazyStat<GroupInfo> currentGroupInfo;\n        LazyStat<TestCaseInfo> currentTestCaseInfo;\n\n        std::vector<SectionInfo> m_sectionStack;\n        ReporterPreferences m_reporterPrefs;\n    };\n\n    template<typename DerivedT>\n    struct CumulativeReporterBase : IStreamingReporter {\n        template<typename T, typename ChildNodeT>\n        struct Node {\n            explicit Node( T const& _value ) : value( _value ) {}\n            virtual ~Node() {}\n\n            using ChildNodes = std::vector<std::shared_ptr<ChildNodeT>>;\n            T value;\n            ChildNodes children;\n        };\n        struct SectionNode {\n            explicit SectionNode(SectionStats const& _stats) : stats(_stats) {}\n            virtual ~SectionNode() = default;\n\n            bool operator == (SectionNode const& other) const {\n                return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;\n            }\n            bool operator == (std::shared_ptr<SectionNode> const& other) const {\n                return operator==(*other);\n            }\n\n            SectionStats stats;\n            using ChildSections = std::vector<std::shared_ptr<SectionNode>>;\n            using Assertions = std::vector<AssertionStats>;\n            ChildSections childSections;\n            Assertions assertions;\n            std::string stdOut;\n            std::string stdErr;\n        };\n\n        struct BySectionInfo {\n            BySectionInfo( SectionInfo const& other ) : m_other( other ) {}\n            BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}\n            bool operator() (std::shared_ptr<SectionNode> const& node) const {\n                return ((node->stats.sectionInfo.name == m_other.name) &&\n                        (node->stats.sectionInfo.lineInfo == m_other.lineInfo));\n            }\n            void operator=(BySectionInfo const&) = delete;\n\n        private:\n            SectionInfo const& m_other;\n        };\n\n        using TestCaseNode = Node<TestCaseStats, SectionNode>;\n        using TestGroupNode = Node<TestGroupStats, TestCaseNode>;\n        using TestRunNode = Node<TestRunStats, TestGroupNode>;\n\n        CumulativeReporterBase( ReporterConfig const& _config )\n        :   m_config( _config.fullConfig() ),\n            stream( _config.stream() )\n        {\n            m_reporterPrefs.shouldRedirectStdOut = false;\n            if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )\n                CATCH_ERROR( \"Verbosity level not supported by this reporter\" );\n        }\n        ~CumulativeReporterBase() override = default;\n\n        ReporterPreferences getPreferences() const override {\n            return m_reporterPrefs;\n        }\n\n        static std::set<Verbosity> getSupportedVerbosities() {\n            return { Verbosity::Normal };\n        }\n\n        void testRunStarting( TestRunInfo const& ) override {}\n        void testGroupStarting( GroupInfo const& ) override {}\n\n        void testCaseStarting( TestCaseInfo const& ) override {}\n\n        void sectionStarting( SectionInfo const& sectionInfo ) override {\n            SectionStats incompleteStats( sectionInfo, Counts(), 0, false );\n            std::shared_ptr<SectionNode> node;\n            if( m_sectionStack.empty() ) {\n                if( !m_rootSection )\n                    m_rootSection = std::make_shared<SectionNode>( incompleteStats );\n                node = m_rootSection;\n            }\n            else {\n                SectionNode& parentNode = *m_sectionStack.back();\n                auto it =\n                    std::find_if(   parentNode.childSections.begin(),\n                                    parentNode.childSections.end(),\n                                    BySectionInfo( sectionInfo ) );\n                if( it == parentNode.childSections.end() ) {\n                    node = std::make_shared<SectionNode>( incompleteStats );\n                    parentNode.childSections.push_back( node );\n                }\n                else\n                    node = *it;\n            }\n            m_sectionStack.push_back( node );\n            m_deepestSection = std::move(node);\n        }\n\n        void assertionStarting(AssertionInfo const&) override {}\n\n        bool assertionEnded(AssertionStats const& assertionStats) override {\n            assert(!m_sectionStack.empty());\n            // AssertionResult holds a pointer to a temporary DecomposedExpression,\n            // which getExpandedExpression() calls to build the expression string.\n            // Our section stack copy of the assertionResult will likely outlive the\n            // temporary, so it must be expanded or discarded now to avoid calling\n            // a destroyed object later.\n            prepareExpandedExpression(const_cast<AssertionResult&>( assertionStats.assertionResult ) );\n            SectionNode& sectionNode = *m_sectionStack.back();\n            sectionNode.assertions.push_back(assertionStats);\n            return true;\n        }\n        void sectionEnded(SectionStats const& sectionStats) override {\n            assert(!m_sectionStack.empty());\n            SectionNode& node = *m_sectionStack.back();\n            node.stats = sectionStats;\n            m_sectionStack.pop_back();\n        }\n        void testCaseEnded(TestCaseStats const& testCaseStats) override {\n            auto node = std::make_shared<TestCaseNode>(testCaseStats);\n            assert(m_sectionStack.size() == 0);\n            node->children.push_back(m_rootSection);\n            m_testCases.push_back(node);\n            m_rootSection.reset();\n\n            assert(m_deepestSection);\n            m_deepestSection->stdOut = testCaseStats.stdOut;\n            m_deepestSection->stdErr = testCaseStats.stdErr;\n        }\n        void testGroupEnded(TestGroupStats const& testGroupStats) override {\n            auto node = std::make_shared<TestGroupNode>(testGroupStats);\n            node->children.swap(m_testCases);\n            m_testGroups.push_back(node);\n        }\n        void testRunEnded(TestRunStats const& testRunStats) override {\n            auto node = std::make_shared<TestRunNode>(testRunStats);\n            node->children.swap(m_testGroups);\n            m_testRuns.push_back(node);\n            testRunEndedCumulative();\n        }\n        virtual void testRunEndedCumulative() = 0;\n\n        void skipTest(TestCaseInfo const&) override {}\n\n        IConfigPtr m_config;\n        std::ostream& stream;\n        std::vector<AssertionStats> m_assertions;\n        std::vector<std::vector<std::shared_ptr<SectionNode>>> m_sections;\n        std::vector<std::shared_ptr<TestCaseNode>> m_testCases;\n        std::vector<std::shared_ptr<TestGroupNode>> m_testGroups;\n\n        std::vector<std::shared_ptr<TestRunNode>> m_testRuns;\n\n        std::shared_ptr<SectionNode> m_rootSection;\n        std::shared_ptr<SectionNode> m_deepestSection;\n        std::vector<std::shared_ptr<SectionNode>> m_sectionStack;\n        ReporterPreferences m_reporterPrefs;\n    };\n\n    template<char C>\n    char const* getLineOfChars() {\n        static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};\n        if( !*line ) {\n            std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );\n            line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;\n        }\n        return line;\n    }\n\n    struct TestEventListenerBase : StreamingReporterBase<TestEventListenerBase> {\n        TestEventListenerBase( ReporterConfig const& _config );\n\n        static std::set<Verbosity> getSupportedVerbosities();\n\n        void assertionStarting(AssertionInfo const&) override;\n        bool assertionEnded(AssertionStats const&) override;\n    };\n\n} // end namespace Catch\n\n// end catch_reporter_bases.hpp\n// start catch_console_colour.h\n\nnamespace Catch {\n\n    struct Colour {\n        enum Code {\n            None = 0,\n\n            White,\n            Red,\n            Green,\n            Blue,\n            Cyan,\n            Yellow,\n            Grey,\n\n            Bright = 0x10,\n\n            BrightRed = Bright | Red,\n            BrightGreen = Bright | Green,\n            LightGrey = Bright | Grey,\n            BrightWhite = Bright | White,\n            BrightYellow = Bright | Yellow,\n\n            // By intention\n            FileName = LightGrey,\n            Warning = BrightYellow,\n            ResultError = BrightRed,\n            ResultSuccess = BrightGreen,\n            ResultExpectedFailure = Warning,\n\n            Error = BrightRed,\n            Success = Green,\n\n            OriginalExpression = Cyan,\n            ReconstructedExpression = BrightYellow,\n\n            SecondaryText = LightGrey,\n            Headers = White\n        };\n\n        // Use constructed object for RAII guard\n        Colour( Code _colourCode );\n        Colour( Colour&& other ) noexcept;\n        Colour& operator=( Colour&& other ) noexcept;\n        ~Colour();\n\n        // Use static method for one-shot changes\n        static void use( Code _colourCode );\n\n    private:\n        bool m_moved = false;\n    };\n\n    std::ostream& operator << ( std::ostream& os, Colour const& );\n\n} // end namespace Catch\n\n// end catch_console_colour.h\n// start catch_reporter_registrars.hpp\n\n\nnamespace Catch {\n\n    template<typename T>\n    class ReporterRegistrar {\n\n        class ReporterFactory : public IReporterFactory {\n\n            IStreamingReporterPtr create( ReporterConfig const& config ) const override {\n                return std::unique_ptr<T>( new T( config ) );\n            }\n\n            std::string getDescription() const override {\n                return T::getDescription();\n            }\n        };\n\n    public:\n\n        explicit ReporterRegistrar( std::string const& name ) {\n            getMutableRegistryHub().registerReporter( name, std::make_shared<ReporterFactory>() );\n        }\n    };\n\n    template<typename T>\n    class ListenerRegistrar {\n\n        class ListenerFactory : public IReporterFactory {\n\n            IStreamingReporterPtr create( ReporterConfig const& config ) const override {\n                return std::unique_ptr<T>( new T( config ) );\n            }\n            std::string getDescription() const override {\n                return std::string();\n            }\n        };\n\n    public:\n\n        ListenerRegistrar() {\n            getMutableRegistryHub().registerListener( std::make_shared<ListenerFactory>() );\n        }\n    };\n}\n\n#if !defined(CATCH_CONFIG_DISABLE)\n\n#define CATCH_REGISTER_REPORTER( name, reporterType ) \\\n    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION         \\\n    CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS          \\\n    namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \\\n    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION\n\n#define CATCH_REGISTER_LISTENER( listenerType ) \\\n    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION   \\\n    CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS    \\\n    namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \\\n    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION\n#else // CATCH_CONFIG_DISABLE\n\n#define CATCH_REGISTER_REPORTER(name, reporterType)\n#define CATCH_REGISTER_LISTENER(listenerType)\n\n#endif // CATCH_CONFIG_DISABLE\n\n// end catch_reporter_registrars.hpp\n// Allow users to base their work off existing reporters\n// start catch_reporter_compact.h\n\nnamespace Catch {\n\n    struct CompactReporter : StreamingReporterBase<CompactReporter> {\n\n        using StreamingReporterBase::StreamingReporterBase;\n\n        ~CompactReporter() override;\n\n        static std::string getDescription();\n\n        void noMatchingTestCases(std::string const& spec) override;\n\n        void assertionStarting(AssertionInfo const&) override;\n\n        bool assertionEnded(AssertionStats const& _assertionStats) override;\n\n        void sectionEnded(SectionStats const& _sectionStats) override;\n\n        void testRunEnded(TestRunStats const& _testRunStats) override;\n\n    };\n\n} // end namespace Catch\n\n// end catch_reporter_compact.h\n// start catch_reporter_console.h\n\n#if defined(_MSC_VER)\n#pragma warning(push)\n#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch\n                              // Note that 4062 (not all labels are handled\n                              // and default is missing) is enabled\n#endif\n\nnamespace Catch {\n    // Fwd decls\n    struct SummaryColumn;\n    class TablePrinter;\n\n    struct ConsoleReporter : StreamingReporterBase<ConsoleReporter> {\n        std::unique_ptr<TablePrinter> m_tablePrinter;\n\n        ConsoleReporter(ReporterConfig const& config);\n        ~ConsoleReporter() override;\n        static std::string getDescription();\n\n        void noMatchingTestCases(std::string const& spec) override;\n\n        void reportInvalidArguments(std::string const&arg) override;\n\n        void assertionStarting(AssertionInfo const&) override;\n\n        bool assertionEnded(AssertionStats const& _assertionStats) override;\n\n        void sectionStarting(SectionInfo const& _sectionInfo) override;\n        void sectionEnded(SectionStats const& _sectionStats) override;\n\n#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\n        void benchmarkPreparing(std::string const& name) override;\n        void benchmarkStarting(BenchmarkInfo const& info) override;\n        void benchmarkEnded(BenchmarkStats<> const& stats) override;\n        void benchmarkFailed(std::string const& error) override;\n#endif // CATCH_CONFIG_ENABLE_BENCHMARKING\n\n        void testCaseEnded(TestCaseStats const& _testCaseStats) override;\n        void testGroupEnded(TestGroupStats const& _testGroupStats) override;\n        void testRunEnded(TestRunStats const& _testRunStats) override;\n        void testRunStarting(TestRunInfo const& _testRunInfo) override;\n    private:\n\n        void lazyPrint();\n\n        void lazyPrintWithoutClosingBenchmarkTable();\n        void lazyPrintRunInfo();\n        void lazyPrintGroupInfo();\n        void printTestCaseAndSectionHeader();\n\n        void printClosedHeader(std::string const& _name);\n        void printOpenHeader(std::string const& _name);\n\n        // if string has a : in first line will set indent to follow it on\n        // subsequent lines\n        void printHeaderString(std::string const& _string, std::size_t indent = 0);\n\n        void printTotals(Totals const& totals);\n        void printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row);\n\n        void printTotalsDivider(Totals const& totals);\n        void printSummaryDivider();\n        void printTestFilters();\n\n    private:\n        bool m_headerPrinted = false;\n    };\n\n} // end namespace Catch\n\n#if defined(_MSC_VER)\n#pragma warning(pop)\n#endif\n\n// end catch_reporter_console.h\n// start catch_reporter_junit.h\n\n// start catch_xmlwriter.h\n\n#include <vector>\n\nnamespace Catch {\n    enum class XmlFormatting {\n        None = 0x00,\n        Indent = 0x01,\n        Newline = 0x02,\n    };\n\n    XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs);\n    XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs);\n\n    class XmlEncode {\n    public:\n        enum ForWhat { ForTextNodes, ForAttributes };\n\n        XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes );\n\n        void encodeTo( std::ostream& os ) const;\n\n        friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );\n\n    private:\n        std::string m_str;\n        ForWhat m_forWhat;\n    };\n\n    class XmlWriter {\n    public:\n\n        class ScopedElement {\n        public:\n            ScopedElement( XmlWriter* writer, XmlFormatting fmt );\n\n            ScopedElement( ScopedElement&& other ) noexcept;\n            ScopedElement& operator=( ScopedElement&& other ) noexcept;\n\n            ~ScopedElement();\n\n            ScopedElement& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent );\n\n            template<typename T>\n            ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {\n                m_writer->writeAttribute( name, attribute );\n                return *this;\n            }\n\n        private:\n            mutable XmlWriter* m_writer = nullptr;\n            XmlFormatting m_fmt;\n        };\n\n        XmlWriter( std::ostream& os = Catch::cout() );\n        ~XmlWriter();\n\n        XmlWriter( XmlWriter const& ) = delete;\n        XmlWriter& operator=( XmlWriter const& ) = delete;\n\n        XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);\n\n        ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);\n\n        XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);\n\n        XmlWriter& writeAttribute( std::string const& name, std::string const& attribute );\n\n        XmlWriter& writeAttribute( std::string const& name, bool attribute );\n\n        template<typename T>\n        XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {\n            ReusableStringStream rss;\n            rss << attribute;\n            return writeAttribute( name, rss.str() );\n        }\n\n        XmlWriter& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);\n\n        XmlWriter& writeComment(std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);\n\n        void writeStylesheetRef( std::string const& url );\n\n        XmlWriter& writeBlankLine();\n\n        void ensureTagClosed();\n\n    private:\n\n        void applyFormatting(XmlFormatting fmt);\n\n        void writeDeclaration();\n\n        void newlineIfNecessary();\n\n        bool m_tagIsOpen = false;\n        bool m_needsNewline = false;\n        std::vector<std::string> m_tags;\n        std::string m_indent;\n        std::ostream& m_os;\n    };\n\n}\n\n// end catch_xmlwriter.h\nnamespace Catch {\n\n    class JunitReporter : public CumulativeReporterBase<JunitReporter> {\n    public:\n        JunitReporter(ReporterConfig const& _config);\n\n        ~JunitReporter() override;\n\n        static std::string getDescription();\n\n        void noMatchingTestCases(std::string const& /*spec*/) override;\n\n        void testRunStarting(TestRunInfo const& runInfo) override;\n\n        void testGroupStarting(GroupInfo const& groupInfo) override;\n\n        void testCaseStarting(TestCaseInfo const& testCaseInfo) override;\n        bool assertionEnded(AssertionStats const& assertionStats) override;\n\n        void testCaseEnded(TestCaseStats const& testCaseStats) override;\n\n        void testGroupEnded(TestGroupStats const& testGroupStats) override;\n\n        void testRunEndedCumulative() override;\n\n        void writeGroup(TestGroupNode const& groupNode, double suiteTime);\n\n        void writeTestCase(TestCaseNode const& testCaseNode);\n\n        void writeSection( std::string const& className,\n                           std::string const& rootName,\n                           SectionNode const& sectionNode,\n                           bool testOkToFail );\n\n        void writeAssertions(SectionNode const& sectionNode);\n        void writeAssertion(AssertionStats const& stats);\n\n        XmlWriter xml;\n        Timer suiteTimer;\n        std::string stdOutForSuite;\n        std::string stdErrForSuite;\n        unsigned int unexpectedExceptions = 0;\n        bool m_okToFail = false;\n    };\n\n} // end namespace Catch\n\n// end catch_reporter_junit.h\n// start catch_reporter_xml.h\n\nnamespace Catch {\n    class XmlReporter : public StreamingReporterBase<XmlReporter> {\n    public:\n        XmlReporter(ReporterConfig const& _config);\n\n        ~XmlReporter() override;\n\n        static std::string getDescription();\n\n        virtual std::string getStylesheetRef() const;\n\n        void writeSourceInfo(SourceLineInfo const& sourceInfo);\n\n    public: // StreamingReporterBase\n\n        void noMatchingTestCases(std::string const& s) override;\n\n        void testRunStarting(TestRunInfo const& testInfo) override;\n\n        void testGroupStarting(GroupInfo const& groupInfo) override;\n\n        void testCaseStarting(TestCaseInfo const& testInfo) override;\n\n        void sectionStarting(SectionInfo const& sectionInfo) override;\n\n        void assertionStarting(AssertionInfo const&) override;\n\n        bool assertionEnded(AssertionStats const& assertionStats) override;\n\n        void sectionEnded(SectionStats const& sectionStats) override;\n\n        void testCaseEnded(TestCaseStats const& testCaseStats) override;\n\n        void testGroupEnded(TestGroupStats const& testGroupStats) override;\n\n        void testRunEnded(TestRunStats const& testRunStats) override;\n\n#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\n        void benchmarkPreparing(std::string const& name) override;\n        void benchmarkStarting(BenchmarkInfo const&) override;\n        void benchmarkEnded(BenchmarkStats<> const&) override;\n        void benchmarkFailed(std::string const&) override;\n#endif // CATCH_CONFIG_ENABLE_BENCHMARKING\n\n    private:\n        Timer m_testCaseTimer;\n        XmlWriter m_xml;\n        int m_sectionDepth = 0;\n    };\n\n} // end namespace Catch\n\n// end catch_reporter_xml.h\n\n// end catch_external_interfaces.h\n#endif\n\n#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\n// start catch_benchmarking_all.hpp\n\n// A proxy header that includes all of the benchmarking headers to allow\n// concise include of the benchmarking features. You should prefer the\n// individual includes in standard use.\n\n// start catch_benchmark.hpp\n\n // Benchmark\n\n// start catch_chronometer.hpp\n\n// User-facing chronometer\n\n\n// start catch_clock.hpp\n\n// Clocks\n\n\n#include <chrono>\n#include <ratio>\n\nnamespace Catch {\n    namespace Benchmark {\n        template <typename Clock>\n        using ClockDuration = typename Clock::duration;\n        template <typename Clock>\n        using FloatDuration = std::chrono::duration<double, typename Clock::period>;\n\n        template <typename Clock>\n        using TimePoint = typename Clock::time_point;\n\n        using default_clock = std::chrono::steady_clock;\n\n        template <typename Clock>\n        struct now {\n            TimePoint<Clock> operator()() const {\n                return Clock::now();\n            }\n        };\n\n        using fp_seconds = std::chrono::duration<double, std::ratio<1>>;\n    } // namespace Benchmark\n} // namespace Catch\n\n// end catch_clock.hpp\n// start catch_optimizer.hpp\n\n // Hinting the optimizer\n\n\n#if defined(_MSC_VER)\n#   include <atomic> // atomic_thread_fence\n#endif\n\nnamespace Catch {\n    namespace Benchmark {\n#if defined(__GNUC__) || defined(__clang__)\n        template <typename T>\n        inline void keep_memory(T* p) {\n            asm volatile(\"\" : : \"g\"(p) : \"memory\");\n        }\n        inline void keep_memory() {\n            asm volatile(\"\" : : : \"memory\");\n        }\n\n        namespace Detail {\n            inline void optimizer_barrier() { keep_memory(); }\n        } // namespace Detail\n#elif defined(_MSC_VER)\n\n#pragma optimize(\"\", off)\n        template <typename T>\n        inline void keep_memory(T* p) {\n            // thanks @milleniumbug\n            *reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p);\n        }\n        // TODO equivalent keep_memory()\n#pragma optimize(\"\", on)\n\n        namespace Detail {\n            inline void optimizer_barrier() {\n                std::atomic_thread_fence(std::memory_order_seq_cst);\n            }\n        } // namespace Detail\n\n#endif\n\n        template <typename T>\n        inline void deoptimize_value(T&& x) {\n            keep_memory(&x);\n        }\n\n        template <typename Fn, typename... Args>\n        inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<!std::is_same<void, decltype(fn(args...))>::value>::type {\n            deoptimize_value(std::forward<Fn>(fn) (std::forward<Args...>(args...)));\n        }\n\n        template <typename Fn, typename... Args>\n        inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<std::is_same<void, decltype(fn(args...))>::value>::type {\n            std::forward<Fn>(fn) (std::forward<Args...>(args...));\n        }\n    } // namespace Benchmark\n} // namespace Catch\n\n// end catch_optimizer.hpp\n// start catch_complete_invoke.hpp\n\n// Invoke with a special case for void\n\n\n#include <type_traits>\n#include <utility>\n\nnamespace Catch {\n    namespace Benchmark {\n        namespace Detail {\n            template <typename T>\n            struct CompleteType { using type = T; };\n            template <>\n            struct CompleteType<void> { struct type {}; };\n\n            template <typename T>\n            using CompleteType_t = typename CompleteType<T>::type;\n\n            template <typename Result>\n            struct CompleteInvoker {\n                template <typename Fun, typename... Args>\n                static Result invoke(Fun&& fun, Args&&... args) {\n                    return std::forward<Fun>(fun)(std::forward<Args>(args)...);\n                }\n            };\n            template <>\n            struct CompleteInvoker<void> {\n                template <typename Fun, typename... Args>\n                static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) {\n                    std::forward<Fun>(fun)(std::forward<Args>(args)...);\n                    return {};\n                }\n            };\n\n            // invoke and not return void :(\n            template <typename Fun, typename... Args>\n            CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) {\n                return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...);\n            }\n\n            const std::string benchmarkErrorMsg = \"a benchmark failed to run successfully\";\n        } // namespace Detail\n\n        template <typename Fun>\n        Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) {\n            CATCH_TRY{\n                return Detail::complete_invoke(std::forward<Fun>(fun));\n            } CATCH_CATCH_ALL{\n                getResultCapture().benchmarkFailed(translateActiveException());\n                CATCH_RUNTIME_ERROR(Detail::benchmarkErrorMsg);\n            }\n        }\n    } // namespace Benchmark\n} // namespace Catch\n\n// end catch_complete_invoke.hpp\nnamespace Catch {\n    namespace Benchmark {\n        namespace Detail {\n            struct ChronometerConcept {\n                virtual void start() = 0;\n                virtual void finish() = 0;\n                virtual ~ChronometerConcept() = default;\n            };\n            template <typename Clock>\n            struct ChronometerModel final : public ChronometerConcept {\n                void start() override { started = Clock::now(); }\n                void finish() override { finished = Clock::now(); }\n\n                ClockDuration<Clock> elapsed() const { return finished - started; }\n\n                TimePoint<Clock> started;\n                TimePoint<Clock> finished;\n            };\n        } // namespace Detail\n\n        struct Chronometer {\n        public:\n            template <typename Fun>\n            void measure(Fun&& fun) { measure(std::forward<Fun>(fun), is_callable<Fun(int)>()); }\n\n            int runs() const { return k; }\n\n            Chronometer(Detail::ChronometerConcept& meter, int k)\n                : impl(&meter)\n                , k(k) {}\n\n        private:\n            template <typename Fun>\n            void measure(Fun&& fun, std::false_type) {\n                measure([&fun](int) { return fun(); }, std::true_type());\n            }\n\n            template <typename Fun>\n            void measure(Fun&& fun, std::true_type) {\n                Detail::optimizer_barrier();\n                impl->start();\n                for (int i = 0; i < k; ++i) invoke_deoptimized(fun, i);\n                impl->finish();\n                Detail::optimizer_barrier();\n            }\n\n            Detail::ChronometerConcept* impl;\n            int k;\n        };\n    } // namespace Benchmark\n} // namespace Catch\n\n// end catch_chronometer.hpp\n// start catch_environment.hpp\n\n// Environment information\n\n\nnamespace Catch {\n    namespace Benchmark {\n        template <typename Duration>\n        struct EnvironmentEstimate {\n            Duration mean;\n            OutlierClassification outliers;\n\n            template <typename Duration2>\n            operator EnvironmentEstimate<Duration2>() const {\n                return { mean, outliers };\n            }\n        };\n        template <typename Clock>\n        struct Environment {\n            using clock_type = Clock;\n            EnvironmentEstimate<FloatDuration<Clock>> clock_resolution;\n            EnvironmentEstimate<FloatDuration<Clock>> clock_cost;\n        };\n    } // namespace Benchmark\n} // namespace Catch\n\n// end catch_environment.hpp\n// start catch_execution_plan.hpp\n\n // Execution plan\n\n\n// start catch_benchmark_function.hpp\n\n // Dumb std::function implementation for consistent call overhead\n\n\n#include <cassert>\n#include <type_traits>\n#include <utility>\n#include <memory>\n\nnamespace Catch {\n    namespace Benchmark {\n        namespace Detail {\n            template <typename T>\n            using Decay = typename std::decay<T>::type;\n            template <typename T, typename U>\n            struct is_related\n                : std::is_same<Decay<T>, Decay<U>> {};\n\n            /// We need to reinvent std::function because every piece of code that might add overhead\n            /// in a measurement context needs to have consistent performance characteristics so that we\n            /// can account for it in the measurement.\n            /// Implementations of std::function with optimizations that aren't always applicable, like\n            /// small buffer optimizations, are not uncommon.\n            /// This is effectively an implementation of std::function without any such optimizations;\n            /// it may be slow, but it is consistently slow.\n            struct BenchmarkFunction {\n            private:\n                struct callable {\n                    virtual void call(Chronometer meter) const = 0;\n                    virtual callable* clone() const = 0;\n                    virtual ~callable() = default;\n                };\n                template <typename Fun>\n                struct model : public callable {\n                    model(Fun&& fun) : fun(std::move(fun)) {}\n                    model(Fun const& fun) : fun(fun) {}\n\n                    model<Fun>* clone() const override { return new model<Fun>(*this); }\n\n                    void call(Chronometer meter) const override {\n                        call(meter, is_callable<Fun(Chronometer)>());\n                    }\n                    void call(Chronometer meter, std::true_type) const {\n                        fun(meter);\n                    }\n                    void call(Chronometer meter, std::false_type) const {\n                        meter.measure(fun);\n                    }\n\n                    Fun fun;\n                };\n\n                struct do_nothing { void operator()() const {} };\n\n                template <typename T>\n                BenchmarkFunction(model<T>* c) : f(c) {}\n\n            public:\n                BenchmarkFunction()\n                    : f(new model<do_nothing>{ {} }) {}\n\n                template <typename Fun,\n                    typename std::enable_if<!is_related<Fun, BenchmarkFunction>::value, int>::type = 0>\n                    BenchmarkFunction(Fun&& fun)\n                    : f(new model<typename std::decay<Fun>::type>(std::forward<Fun>(fun))) {}\n\n                BenchmarkFunction(BenchmarkFunction&& that)\n                    : f(std::move(that.f)) {}\n\n                BenchmarkFunction(BenchmarkFunction const& that)\n                    : f(that.f->clone()) {}\n\n                BenchmarkFunction& operator=(BenchmarkFunction&& that) {\n                    f = std::move(that.f);\n                    return *this;\n                }\n\n                BenchmarkFunction& operator=(BenchmarkFunction const& that) {\n                    f.reset(that.f->clone());\n                    return *this;\n                }\n\n                void operator()(Chronometer meter) const { f->call(meter); }\n\n            private:\n                std::unique_ptr<callable> f;\n            };\n        } // namespace Detail\n    } // namespace Benchmark\n} // namespace Catch\n\n// end catch_benchmark_function.hpp\n// start catch_repeat.hpp\n\n// repeat algorithm\n\n\n#include <type_traits>\n#include <utility>\n\nnamespace Catch {\n    namespace Benchmark {\n        namespace Detail {\n            template <typename Fun>\n            struct repeater {\n                void operator()(int k) const {\n                    for (int i = 0; i < k; ++i) {\n                        fun();\n                    }\n                }\n                Fun fun;\n            };\n            template <typename Fun>\n            repeater<typename std::decay<Fun>::type> repeat(Fun&& fun) {\n                return { std::forward<Fun>(fun) };\n            }\n        } // namespace Detail\n    } // namespace Benchmark\n} // namespace Catch\n\n// end catch_repeat.hpp\n// start catch_run_for_at_least.hpp\n\n// Run a function for a minimum amount of time\n\n\n// start catch_measure.hpp\n\n// Measure\n\n\n// start catch_timing.hpp\n\n// Timing\n\n\n#include <tuple>\n#include <type_traits>\n\nnamespace Catch {\n    namespace Benchmark {\n        template <typename Duration, typename Result>\n        struct Timing {\n            Duration elapsed;\n            Result result;\n            int iterations;\n        };\n        template <typename Clock, typename Func, typename... Args>\n        using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>;\n    } // namespace Benchmark\n} // namespace Catch\n\n// end catch_timing.hpp\n#include <utility>\n\nnamespace Catch {\n    namespace Benchmark {\n        namespace Detail {\n            template <typename Clock, typename Fun, typename... Args>\n            TimingOf<Clock, Fun, Args...> measure(Fun&& fun, Args&&... args) {\n                auto start = Clock::now();\n                auto&& r = Detail::complete_invoke(fun, std::forward<Args>(args)...);\n                auto end = Clock::now();\n                auto delta = end - start;\n                return { delta, std::forward<decltype(r)>(r), 1 };\n            }\n        } // namespace Detail\n    } // namespace Benchmark\n} // namespace Catch\n\n// end catch_measure.hpp\n#include <utility>\n#include <type_traits>\n\nnamespace Catch {\n    namespace Benchmark {\n        namespace Detail {\n            template <typename Clock, typename Fun>\n            TimingOf<Clock, Fun, int> measure_one(Fun&& fun, int iters, std::false_type) {\n                return Detail::measure<Clock>(fun, iters);\n            }\n            template <typename Clock, typename Fun>\n            TimingOf<Clock, Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) {\n                Detail::ChronometerModel<Clock> meter;\n                auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));\n\n                return { meter.elapsed(), std::move(result), iters };\n            }\n\n            template <typename Clock, typename Fun>\n            using run_for_at_least_argument_t = typename std::conditional<is_callable<Fun(Chronometer)>::value, Chronometer, int>::type;\n\n            struct optimized_away_error : std::exception {\n                const char* what() const noexcept override {\n                    return \"could not measure benchmark, maybe it was optimized away\";\n                }\n            };\n\n            template <typename Clock, typename Fun>\n            TimingOf<Clock, Fun, run_for_at_least_argument_t<Clock, Fun>> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) {\n                auto iters = seed;\n                while (iters < (1 << 30)) {\n                    auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());\n\n                    if (Timing.elapsed >= how_long) {\n                        return { Timing.elapsed, std::move(Timing.result), iters };\n                    }\n                    iters *= 2;\n                }\n                Catch::throw_exception(optimized_away_error{});\n            }\n        } // namespace Detail\n    } // namespace Benchmark\n} // namespace Catch\n\n// end catch_run_for_at_least.hpp\n#include <algorithm>\n#include <iterator>\n\nnamespace Catch {\n    namespace Benchmark {\n        template <typename Duration>\n        struct ExecutionPlan {\n            int iterations_per_sample;\n            Duration estimated_duration;\n            Detail::BenchmarkFunction benchmark;\n            Duration warmup_time;\n            int warmup_iterations;\n\n            template <typename Duration2>\n            operator ExecutionPlan<Duration2>() const {\n                return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations };\n            }\n\n            template <typename Clock>\n            std::vector<FloatDuration<Clock>> run(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {\n                // warmup a bit\n                Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{}));\n\n                std::vector<FloatDuration<Clock>> times;\n                times.reserve(cfg.benchmarkSamples());\n                std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] {\n                    Detail::ChronometerModel<Clock> model;\n                    this->benchmark(Chronometer(model, iterations_per_sample));\n                    auto sample_time = model.elapsed() - env.clock_cost.mean;\n                    if (sample_time < FloatDuration<Clock>::zero()) sample_time = FloatDuration<Clock>::zero();\n                    return sample_time / iterations_per_sample;\n                });\n                return times;\n            }\n        };\n    } // namespace Benchmark\n} // namespace Catch\n\n// end catch_execution_plan.hpp\n// start catch_estimate_clock.hpp\n\n // Environment measurement\n\n\n// start catch_stats.hpp\n\n// Statistical analysis tools\n\n\n#include <algorithm>\n#include <functional>\n#include <vector>\n#include <iterator>\n#include <numeric>\n#include <tuple>\n#include <cmath>\n#include <utility>\n#include <cstddef>\n#include <random>\n\nnamespace Catch {\n    namespace Benchmark {\n        namespace Detail {\n            using sample = std::vector<double>;\n\n            double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last);\n\n            template <typename Iterator>\n            OutlierClassification classify_outliers(Iterator first, Iterator last) {\n                std::vector<double> copy(first, last);\n\n                auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end());\n                auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end());\n                auto iqr = q3 - q1;\n                auto los = q1 - (iqr * 3.);\n                auto lom = q1 - (iqr * 1.5);\n                auto him = q3 + (iqr * 1.5);\n                auto his = q3 + (iqr * 3.);\n\n                OutlierClassification o;\n                for (; first != last; ++first) {\n                    auto&& t = *first;\n                    if (t < los) ++o.low_severe;\n                    else if (t < lom) ++o.low_mild;\n                    else if (t > his) ++o.high_severe;\n                    else if (t > him) ++o.high_mild;\n                    ++o.samples_seen;\n                }\n                return o;\n            }\n\n            template <typename Iterator>\n            double mean(Iterator first, Iterator last) {\n                auto count = last - first;\n                double sum = std::accumulate(first, last, 0.);\n                return sum / count;\n            }\n\n            template <typename URng, typename Iterator, typename Estimator>\n            sample resample(URng& rng, int resamples, Iterator first, Iterator last, Estimator& estimator) {\n                auto n = last - first;\n                std::uniform_int_distribution<decltype(n)> dist(0, n - 1);\n\n                sample out;\n                out.reserve(resamples);\n                std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] {\n                    std::vector<double> resampled;\n                    resampled.reserve(n);\n                    std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[dist(rng)]; });\n                    return estimator(resampled.begin(), resampled.end());\n                });\n                std::sort(out.begin(), out.end());\n                return out;\n            }\n\n            template <typename Estimator, typename Iterator>\n            sample jackknife(Estimator&& estimator, Iterator first, Iterator last) {\n                auto n = last - first;\n                auto second = std::next(first);\n                sample results;\n                results.reserve(n);\n\n                for (auto it = first; it != last; ++it) {\n                    std::iter_swap(it, first);\n                    results.push_back(estimator(second, last));\n                }\n\n                return results;\n            }\n\n            inline double normal_cdf(double x) {\n                return std::erfc(-x / std::sqrt(2.0)) / 2.0;\n            }\n\n            double erfc_inv(double x);\n\n            double normal_quantile(double p);\n\n            template <typename Iterator, typename Estimator>\n            Estimate<double> bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) {\n                auto n_samples = last - first;\n\n                double point = estimator(first, last);\n                // Degenerate case with a single sample\n                if (n_samples == 1) return { point, point, point, confidence_level };\n\n                sample jack = jackknife(estimator, first, last);\n                double jack_mean = mean(jack.begin(), jack.end());\n                double sum_squares, sum_cubes;\n                std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair<double, double> sqcb, double x) -> std::pair<double, double> {\n                    auto d = jack_mean - x;\n                    auto d2 = d * d;\n                    auto d3 = d2 * d;\n                    return { sqcb.first + d2, sqcb.second + d3 };\n                });\n\n                double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5));\n                int n = static_cast<int>(resample.size());\n                double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / (double)n;\n                // degenerate case with uniform samples\n                if (prob_n == 0) return { point, point, point, confidence_level };\n\n                double bias = normal_quantile(prob_n);\n                double z1 = normal_quantile((1. - confidence_level) / 2.);\n\n                auto cumn = [n](double x) -> int {\n                    return std::lround(normal_cdf(x) * n); };\n                auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); };\n                double b1 = bias + z1;\n                double b2 = bias - z1;\n                double a1 = a(b1);\n                double a2 = a(b2);\n                auto lo = (std::max)(cumn(a1), 0);\n                auto hi = (std::min)(cumn(a2), n - 1);\n\n                return { point, resample[lo], resample[hi], confidence_level };\n            }\n\n            double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n);\n\n            struct bootstrap_analysis {\n                Estimate<double> mean;\n                Estimate<double> standard_deviation;\n                double outlier_variance;\n            };\n\n            bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last);\n        } // namespace Detail\n    } // namespace Benchmark\n} // namespace Catch\n\n// end catch_stats.hpp\n#include <algorithm>\n#include <iterator>\n#include <tuple>\n#include <vector>\n#include <cmath>\n\nnamespace Catch {\n    namespace Benchmark {\n        namespace Detail {\n            template <typename Clock>\n            std::vector<double> resolution(int k) {\n                std::vector<TimePoint<Clock>> times;\n                times.reserve(k + 1);\n                std::generate_n(std::back_inserter(times), k + 1, now<Clock>{});\n\n                std::vector<double> deltas;\n                deltas.reserve(k);\n                std::transform(std::next(times.begin()), times.end(), times.begin(),\n                    std::back_inserter(deltas),\n                    [](TimePoint<Clock> a, TimePoint<Clock> b) { return static_cast<double>((a - b).count()); });\n\n                return deltas;\n            }\n\n            const auto warmup_iterations = 10000;\n            const auto warmup_time = std::chrono::milliseconds(100);\n            const auto minimum_ticks = 1000;\n            const auto warmup_seed = 10000;\n            const auto clock_resolution_estimation_time = std::chrono::milliseconds(500);\n            const auto clock_cost_estimation_time_limit = std::chrono::seconds(1);\n            const auto clock_cost_estimation_tick_limit = 100000;\n            const auto clock_cost_estimation_time = std::chrono::milliseconds(10);\n            const auto clock_cost_estimation_iterations = 10000;\n\n            template <typename Clock>\n            int warmup() {\n                return run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_seed, &resolution<Clock>)\n                    .iterations;\n            }\n            template <typename Clock>\n            EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_resolution(int iterations) {\n                auto r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_resolution_estimation_time), iterations, &resolution<Clock>)\n                    .result;\n                return {\n                    FloatDuration<Clock>(mean(r.begin(), r.end())),\n                    classify_outliers(r.begin(), r.end()),\n                };\n            }\n            template <typename Clock>\n            EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) {\n                auto time_limit = (std::min)(\n                    resolution * clock_cost_estimation_tick_limit,\n                    FloatDuration<Clock>(clock_cost_estimation_time_limit));\n                auto time_clock = [](int k) {\n                    return Detail::measure<Clock>([k] {\n                        for (int i = 0; i < k; ++i) {\n                            volatile auto ignored = Clock::now();\n                            (void)ignored;\n                        }\n                    }).elapsed;\n                };\n                time_clock(1);\n                int iters = clock_cost_estimation_iterations;\n                auto&& r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_cost_estimation_time), iters, time_clock);\n                std::vector<double> times;\n                int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));\n                times.reserve(nsamples);\n                std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] {\n                    return static_cast<double>((time_clock(r.iterations) / r.iterations).count());\n                });\n                return {\n                    FloatDuration<Clock>(mean(times.begin(), times.end())),\n                    classify_outliers(times.begin(), times.end()),\n                };\n            }\n\n            template <typename Clock>\n            Environment<FloatDuration<Clock>> measure_environment() {\n                static Environment<FloatDuration<Clock>>* env = nullptr;\n                if (env) {\n                    return *env;\n                }\n\n                auto iters = Detail::warmup<Clock>();\n                auto resolution = Detail::estimate_clock_resolution<Clock>(iters);\n                auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean);\n\n                env = new Environment<FloatDuration<Clock>>{ resolution, cost };\n                return *env;\n            }\n        } // namespace Detail\n    } // namespace Benchmark\n} // namespace Catch\n\n// end catch_estimate_clock.hpp\n// start catch_analyse.hpp\n\n // Run and analyse one benchmark\n\n\n// start catch_sample_analysis.hpp\n\n// Benchmark results\n\n\n#include <algorithm>\n#include <vector>\n#include <string>\n#include <iterator>\n\nnamespace Catch {\n    namespace Benchmark {\n        template <typename Duration>\n        struct SampleAnalysis {\n            std::vector<Duration> samples;\n            Estimate<Duration> mean;\n            Estimate<Duration> standard_deviation;\n            OutlierClassification outliers;\n            double outlier_variance;\n\n            template <typename Duration2>\n            operator SampleAnalysis<Duration2>() const {\n                std::vector<Duration2> samples2;\n                samples2.reserve(samples.size());\n                std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); });\n                return {\n                    std::move(samples2),\n                    mean,\n                    standard_deviation,\n                    outliers,\n                    outlier_variance,\n                };\n            }\n        };\n    } // namespace Benchmark\n} // namespace Catch\n\n// end catch_sample_analysis.hpp\n#include <algorithm>\n#include <iterator>\n#include <vector>\n\nnamespace Catch {\n    namespace Benchmark {\n        namespace Detail {\n            template <typename Duration, typename Iterator>\n            SampleAnalysis<Duration> analyse(const IConfig &cfg, Environment<Duration>, Iterator first, Iterator last) {\n                if (!cfg.benchmarkNoAnalysis()) {\n                    std::vector<double> samples;\n                    samples.reserve(last - first);\n                    std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); });\n\n                    auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end());\n                    auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end());\n\n                    auto wrap_estimate = [](Estimate<double> e) {\n                        return Estimate<Duration> {\n                            Duration(e.point),\n                                Duration(e.lower_bound),\n                                Duration(e.upper_bound),\n                                e.confidence_interval,\n                        };\n                    };\n                    std::vector<Duration> samples2;\n                    samples2.reserve(samples.size());\n                    std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); });\n                    return {\n                        std::move(samples2),\n                        wrap_estimate(analysis.mean),\n                        wrap_estimate(analysis.standard_deviation),\n                        outliers,\n                        analysis.outlier_variance,\n                    };\n                } else {\n                    std::vector<Duration> samples;\n                    samples.reserve(last - first);\n\n                    Duration mean = Duration(0);\n                    int i = 0;\n                    for (auto it = first; it < last; ++it, ++i) {\n                        samples.push_back(Duration(*it));\n                        mean += Duration(*it);\n                    }\n                    mean /= i;\n\n                    return {\n                        std::move(samples),\n                        Estimate<Duration>{mean, mean, mean, 0.0},\n                        Estimate<Duration>{Duration(0), Duration(0), Duration(0), 0.0},\n                        OutlierClassification{},\n                        0.0\n                    };\n                }\n            }\n        } // namespace Detail\n    } // namespace Benchmark\n} // namespace Catch\n\n// end catch_analyse.hpp\n#include <algorithm>\n#include <functional>\n#include <string>\n#include <vector>\n#include <cmath>\n\nnamespace Catch {\n    namespace Benchmark {\n        struct Benchmark {\n            Benchmark(std::string &&name)\n                : name(std::move(name)) {}\n\n            template <class FUN>\n            Benchmark(std::string &&name, FUN &&func)\n                : fun(std::move(func)), name(std::move(name)) {}\n\n            template <typename Clock>\n            ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {\n                auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;\n                auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));\n                auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun);\n                int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));\n                return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };\n            }\n\n            template <typename Clock = default_clock>\n            void run() {\n                IConfigPtr cfg = getCurrentContext().getConfig();\n\n                auto env = Detail::measure_environment<Clock>();\n\n                getResultCapture().benchmarkPreparing(name);\n                CATCH_TRY{\n                    auto plan = user_code([&] {\n                        return prepare<Clock>(*cfg, env);\n                    });\n\n                    BenchmarkInfo info {\n                        name,\n                        plan.estimated_duration.count(),\n                        plan.iterations_per_sample,\n                        cfg->benchmarkSamples(),\n                        cfg->benchmarkResamples(),\n                        env.clock_resolution.mean.count(),\n                        env.clock_cost.mean.count()\n                    };\n\n                    getResultCapture().benchmarkStarting(info);\n\n                    auto samples = user_code([&] {\n                        return plan.template run<Clock>(*cfg, env);\n                    });\n\n                    auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());\n                    BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };\n                    getResultCapture().benchmarkEnded(stats);\n\n                } CATCH_CATCH_ALL{\n                    if (translateActiveException() != Detail::benchmarkErrorMsg) // benchmark errors have been reported, otherwise rethrow.\n                        std::rethrow_exception(std::current_exception());\n                }\n            }\n\n            // sets lambda to be used in fun *and* executes benchmark!\n            template <typename Fun,\n                typename std::enable_if<!Detail::is_related<Fun, Benchmark>::value, int>::type = 0>\n                Benchmark & operator=(Fun func) {\n                fun = Detail::BenchmarkFunction(func);\n                run();\n                return *this;\n            }\n\n            explicit operator bool() {\n                return true;\n            }\n\n        private:\n            Detail::BenchmarkFunction fun;\n            std::string name;\n        };\n    }\n} // namespace Catch\n\n#define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1\n#define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2\n\n#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\\\n    if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \\\n        BenchmarkName = [&](int benchmarkIndex)\n\n#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\\\n    if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \\\n        BenchmarkName = [&]\n\n// end catch_benchmark.hpp\n// start catch_constructor.hpp\n\n// Constructor and destructor helpers\n\n\n#include <type_traits>\n\nnamespace Catch {\n    namespace Benchmark {\n        namespace Detail {\n            template <typename T, bool Destruct>\n            struct ObjectStorage\n            {\n                using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;\n\n                ObjectStorage() : data() {}\n\n                ObjectStorage(const ObjectStorage& other)\n                {\n                    new(&data) T(other.stored_object());\n                }\n\n                ObjectStorage(ObjectStorage&& other)\n                {\n                    new(&data) T(std::move(other.stored_object()));\n                }\n\n                ~ObjectStorage() { destruct_on_exit<T>(); }\n\n                template <typename... Args>\n                void construct(Args&&... args)\n                {\n                    new (&data) T(std::forward<Args>(args)...);\n                }\n\n                template <bool AllowManualDestruction = !Destruct>\n                typename std::enable_if<AllowManualDestruction>::type destruct()\n                {\n                    stored_object().~T();\n                }\n\n            private:\n                // If this is a constructor benchmark, destruct the underlying object\n                template <typename U>\n                void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); }\n                // Otherwise, don't\n                template <typename U>\n                void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { }\n\n                T& stored_object() {\n                    return *static_cast<T*>(static_cast<void*>(&data));\n                }\n\n                T const& stored_object() const {\n                    return *static_cast<T*>(static_cast<void*>(&data));\n                }\n\n                TStorage data;\n            };\n        }\n\n        template <typename T>\n        using storage_for = Detail::ObjectStorage<T, true>;\n\n        template <typename T>\n        using destructable_object = Detail::ObjectStorage<T, false>;\n    }\n}\n\n// end catch_constructor.hpp\n// end catch_benchmarking_all.hpp\n#endif\n\n#endif // ! CATCH_CONFIG_IMPL_ONLY\n\n#ifdef CATCH_IMPL\n// start catch_impl.hpp\n\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wweak-vtables\"\n#endif\n\n// Keep these here for external reporters\n// start catch_test_case_tracker.h\n\n#include <string>\n#include <vector>\n#include <memory>\n\nnamespace Catch {\nnamespace TestCaseTracking {\n\n    struct NameAndLocation {\n        std::string name;\n        SourceLineInfo location;\n\n        NameAndLocation( std::string const& _name, SourceLineInfo const& _location );\n        friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) {\n            return lhs.name == rhs.name\n                && lhs.location == rhs.location;\n        }\n    };\n\n    class ITracker;\n\n    using ITrackerPtr = std::shared_ptr<ITracker>;\n\n    class  ITracker {\n        NameAndLocation m_nameAndLocation;\n\n    public:\n        ITracker(NameAndLocation const& nameAndLoc) :\n            m_nameAndLocation(nameAndLoc)\n        {}\n\n        // static queries\n        NameAndLocation const& nameAndLocation() const {\n            return m_nameAndLocation;\n        }\n\n        virtual ~ITracker();\n\n        // dynamic queries\n        virtual bool isComplete() const = 0; // Successfully completed or failed\n        virtual bool isSuccessfullyCompleted() const = 0;\n        virtual bool isOpen() const = 0; // Started but not complete\n        virtual bool hasChildren() const = 0;\n        virtual bool hasStarted() const = 0;\n\n        virtual ITracker& parent() = 0;\n\n        // actions\n        virtual void close() = 0; // Successfully complete\n        virtual void fail() = 0;\n        virtual void markAsNeedingAnotherRun() = 0;\n\n        virtual void addChild( ITrackerPtr const& child ) = 0;\n        virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0;\n        virtual void openChild() = 0;\n\n        // Debug/ checking\n        virtual bool isSectionTracker() const = 0;\n        virtual bool isGeneratorTracker() const = 0;\n    };\n\n    class TrackerContext {\n\n        enum RunState {\n            NotStarted,\n            Executing,\n            CompletedCycle\n        };\n\n        ITrackerPtr m_rootTracker;\n        ITracker* m_currentTracker = nullptr;\n        RunState m_runState = NotStarted;\n\n    public:\n\n        ITracker& startRun();\n        void endRun();\n\n        void startCycle();\n        void completeCycle();\n\n        bool completedCycle() const;\n        ITracker& currentTracker();\n        void setCurrentTracker( ITracker* tracker );\n    };\n\n    class TrackerBase : public ITracker {\n    protected:\n        enum CycleState {\n            NotStarted,\n            Executing,\n            ExecutingChildren,\n            NeedsAnotherRun,\n            CompletedSuccessfully,\n            Failed\n        };\n\n        using Children = std::vector<ITrackerPtr>;\n        TrackerContext& m_ctx;\n        ITracker* m_parent;\n        Children m_children;\n        CycleState m_runState = NotStarted;\n\n    public:\n        TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );\n\n        bool isComplete() const override;\n        bool isSuccessfullyCompleted() const override;\n        bool isOpen() const override;\n        bool hasChildren() const override;\n        bool hasStarted() const override {\n            return m_runState != NotStarted;\n        }\n\n        void addChild( ITrackerPtr const& child ) override;\n\n        ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override;\n        ITracker& parent() override;\n\n        void openChild() override;\n\n        bool isSectionTracker() const override;\n        bool isGeneratorTracker() const override;\n\n        void open();\n\n        void close() override;\n        void fail() override;\n        void markAsNeedingAnotherRun() override;\n\n    private:\n        void moveToParent();\n        void moveToThis();\n    };\n\n    class SectionTracker : public TrackerBase {\n        std::vector<std::string> m_filters;\n        std::string m_trimmed_name;\n    public:\n        SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );\n\n        bool isSectionTracker() const override;\n\n        bool isComplete() const override;\n\n        static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation );\n\n        void tryOpen();\n\n        void addInitialFilters( std::vector<std::string> const& filters );\n        void addNextFilters( std::vector<std::string> const& filters );\n        //! Returns filters active in this tracker\n        std::vector<std::string> const& getFilters() const;\n        //! Returns whitespace-trimmed name of the tracked section\n        std::string const& trimmedName() const;\n    };\n\n} // namespace TestCaseTracking\n\nusing TestCaseTracking::ITracker;\nusing TestCaseTracking::TrackerContext;\nusing TestCaseTracking::SectionTracker;\n\n} // namespace Catch\n\n// end catch_test_case_tracker.h\n\n// start catch_leak_detector.h\n\nnamespace Catch {\n\n    struct LeakDetector {\n        LeakDetector();\n        ~LeakDetector();\n    };\n\n}\n// end catch_leak_detector.h\n// Cpp files will be included in the single-header file here\n// start catch_stats.cpp\n\n// Statistical analysis tools\n\n#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\n\n#include <cassert>\n#include <random>\n\n#if defined(CATCH_CONFIG_USE_ASYNC)\n#include <future>\n#endif\n\nnamespace {\n    double erf_inv(double x) {\n        // Code accompanying the article \"Approximating the erfinv function\" in GPU Computing Gems, Volume 2\n        double w, p;\n\n        w = -log((1.0 - x) * (1.0 + x));\n\n        if (w < 6.250000) {\n            w = w - 3.125000;\n            p = -3.6444120640178196996e-21;\n            p = -1.685059138182016589e-19 + p * w;\n            p = 1.2858480715256400167e-18 + p * w;\n            p = 1.115787767802518096e-17 + p * w;\n            p = -1.333171662854620906e-16 + p * w;\n            p = 2.0972767875968561637e-17 + p * w;\n            p = 6.6376381343583238325e-15 + p * w;\n            p = -4.0545662729752068639e-14 + p * w;\n            p = -8.1519341976054721522e-14 + p * w;\n            p = 2.6335093153082322977e-12 + p * w;\n            p = -1.2975133253453532498e-11 + p * w;\n            p = -5.4154120542946279317e-11 + p * w;\n            p = 1.051212273321532285e-09 + p * w;\n            p = -4.1126339803469836976e-09 + p * w;\n            p = -2.9070369957882005086e-08 + p * w;\n            p = 4.2347877827932403518e-07 + p * w;\n            p = -1.3654692000834678645e-06 + p * w;\n            p = -1.3882523362786468719e-05 + p * w;\n            p = 0.0001867342080340571352 + p * w;\n            p = -0.00074070253416626697512 + p * w;\n            p = -0.0060336708714301490533 + p * w;\n            p = 0.24015818242558961693 + p * w;\n            p = 1.6536545626831027356 + p * w;\n        } else if (w < 16.000000) {\n            w = sqrt(w) - 3.250000;\n            p = 2.2137376921775787049e-09;\n            p = 9.0756561938885390979e-08 + p * w;\n            p = -2.7517406297064545428e-07 + p * w;\n            p = 1.8239629214389227755e-08 + p * w;\n            p = 1.5027403968909827627e-06 + p * w;\n            p = -4.013867526981545969e-06 + p * w;\n            p = 2.9234449089955446044e-06 + p * w;\n            p = 1.2475304481671778723e-05 + p * w;\n            p = -4.7318229009055733981e-05 + p * w;\n            p = 6.8284851459573175448e-05 + p * w;\n            p = 2.4031110387097893999e-05 + p * w;\n            p = -0.0003550375203628474796 + p * w;\n            p = 0.00095328937973738049703 + p * w;\n            p = -0.0016882755560235047313 + p * w;\n            p = 0.0024914420961078508066 + p * w;\n            p = -0.0037512085075692412107 + p * w;\n            p = 0.005370914553590063617 + p * w;\n            p = 1.0052589676941592334 + p * w;\n            p = 3.0838856104922207635 + p * w;\n        } else {\n            w = sqrt(w) - 5.000000;\n            p = -2.7109920616438573243e-11;\n            p = -2.5556418169965252055e-10 + p * w;\n            p = 1.5076572693500548083e-09 + p * w;\n            p = -3.7894654401267369937e-09 + p * w;\n            p = 7.6157012080783393804e-09 + p * w;\n            p = -1.4960026627149240478e-08 + p * w;\n            p = 2.9147953450901080826e-08 + p * w;\n            p = -6.7711997758452339498e-08 + p * w;\n            p = 2.2900482228026654717e-07 + p * w;\n            p = -9.9298272942317002539e-07 + p * w;\n            p = 4.5260625972231537039e-06 + p * w;\n            p = -1.9681778105531670567e-05 + p * w;\n            p = 7.5995277030017761139e-05 + p * w;\n            p = -0.00021503011930044477347 + p * w;\n            p = -0.00013871931833623122026 + p * w;\n            p = 1.0103004648645343977 + p * w;\n            p = 4.8499064014085844221 + p * w;\n        }\n        return p * x;\n    }\n\n    double standard_deviation(std::vector<double>::iterator first, std::vector<double>::iterator last) {\n        auto m = Catch::Benchmark::Detail::mean(first, last);\n        double variance = std::accumulate(first, last, 0., [m](double a, double b) {\n            double diff = b - m;\n            return a + diff * diff;\n            }) / (last - first);\n            return std::sqrt(variance);\n    }\n\n}\n\nnamespace Catch {\n    namespace Benchmark {\n        namespace Detail {\n\n            double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last) {\n                auto count = last - first;\n                double idx = (count - 1) * k / static_cast<double>(q);\n                int j = static_cast<int>(idx);\n                double g = idx - j;\n                std::nth_element(first, first + j, last);\n                auto xj = first[j];\n                if (g == 0) return xj;\n\n                auto xj1 = *std::min_element(first + (j + 1), last);\n                return xj + g * (xj1 - xj);\n            }\n\n            double erfc_inv(double x) {\n                return erf_inv(1.0 - x);\n            }\n\n            double normal_quantile(double p) {\n                static const double ROOT_TWO = std::sqrt(2.0);\n\n                double result = 0.0;\n                assert(p >= 0 && p <= 1);\n                if (p < 0 || p > 1) {\n                    return result;\n                }\n\n                result = -erfc_inv(2.0 * p);\n                // result *= normal distribution standard deviation (1.0) * sqrt(2)\n                result *= /*sd * */ ROOT_TWO;\n                // result += normal disttribution mean (0)\n                return result;\n            }\n\n            double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n) {\n                double sb = stddev.point;\n                double mn = mean.point / n;\n                double mg_min = mn / 2.;\n                double sg = (std::min)(mg_min / 4., sb / std::sqrt(n));\n                double sg2 = sg * sg;\n                double sb2 = sb * sb;\n\n                auto c_max = [n, mn, sb2, sg2](double x) -> double {\n                    double k = mn - x;\n                    double d = k * k;\n                    double nd = n * d;\n                    double k0 = -n * nd;\n                    double k1 = sb2 - n * sg2 + nd;\n                    double det = k1 * k1 - 4 * sg2 * k0;\n                    return (int)(-2. * k0 / (k1 + std::sqrt(det)));\n                };\n\n                auto var_out = [n, sb2, sg2](double c) {\n                    double nc = n - c;\n                    return (nc / n) * (sb2 - nc * sg2);\n                };\n\n                return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2;\n            }\n\n            bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) {\n                CATCH_INTERNAL_START_WARNINGS_SUPPRESSION\n                CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS\n                static std::random_device entropy;\n                CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION\n\n                auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++\n\n                auto mean = &Detail::mean<std::vector<double>::iterator>;\n                auto stddev = &standard_deviation;\n\n#if defined(CATCH_CONFIG_USE_ASYNC)\n                auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {\n                    auto seed = entropy();\n                    return std::async(std::launch::async, [=] {\n                        std::mt19937 rng(seed);\n                        auto resampled = resample(rng, n_resamples, first, last, f);\n                        return bootstrap(confidence_level, first, last, resampled, f);\n                    });\n                };\n\n                auto mean_future = Estimate(mean);\n                auto stddev_future = Estimate(stddev);\n\n                auto mean_estimate = mean_future.get();\n                auto stddev_estimate = stddev_future.get();\n#else\n                auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) {\n                    auto seed = entropy();\n                    std::mt19937 rng(seed);\n                    auto resampled = resample(rng, n_resamples, first, last, f);\n                    return bootstrap(confidence_level, first, last, resampled, f);\n                };\n\n                auto mean_estimate = Estimate(mean);\n                auto stddev_estimate = Estimate(stddev);\n#endif // CATCH_USE_ASYNC\n\n                double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n);\n\n                return { mean_estimate, stddev_estimate, outlier_variance };\n            }\n        } // namespace Detail\n    } // namespace Benchmark\n} // namespace Catch\n\n#endif // CATCH_CONFIG_ENABLE_BENCHMARKING\n// end catch_stats.cpp\n// start catch_approx.cpp\n\n#include <cmath>\n#include <limits>\n\nnamespace {\n\n// Performs equivalent check of std::fabs(lhs - rhs) <= margin\n// But without the subtraction to allow for INFINITY in comparison\nbool marginComparison(double lhs, double rhs, double margin) {\n    return (lhs + margin >= rhs) && (rhs + margin >= lhs);\n}\n\n}\n\nnamespace Catch {\nnamespace Detail {\n\n    Approx::Approx ( double value )\n    :   m_epsilon( std::numeric_limits<float>::epsilon()*100 ),\n        m_margin( 0.0 ),\n        m_scale( 0.0 ),\n        m_value( value )\n    {}\n\n    Approx Approx::custom() {\n        return Approx( 0 );\n    }\n\n    Approx Approx::operator-() const {\n        auto temp(*this);\n        temp.m_value = -temp.m_value;\n        return temp;\n    }\n\n    std::string Approx::toString() const {\n        ReusableStringStream rss;\n        rss << \"Approx( \" << ::Catch::Detail::stringify( m_value ) << \" )\";\n        return rss.str();\n    }\n\n    bool Approx::equalityComparisonImpl(const double other) const {\n        // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value\n        // Thanks to Richard Harris for his help refining the scaled margin value\n        return marginComparison(m_value, other, m_margin)\n            || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));\n    }\n\n    void Approx::setMargin(double newMargin) {\n        CATCH_ENFORCE(newMargin >= 0,\n            \"Invalid Approx::margin: \" << newMargin << '.'\n            << \" Approx::Margin has to be non-negative.\");\n        m_margin = newMargin;\n    }\n\n    void Approx::setEpsilon(double newEpsilon) {\n        CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0,\n            \"Invalid Approx::epsilon: \" << newEpsilon << '.'\n            << \" Approx::epsilon has to be in [0, 1]\");\n        m_epsilon = newEpsilon;\n    }\n\n} // end namespace Detail\n\nnamespace literals {\n    Detail::Approx operator \"\" _a(long double val) {\n        return Detail::Approx(val);\n    }\n    Detail::Approx operator \"\" _a(unsigned long long val) {\n        return Detail::Approx(val);\n    }\n} // end namespace literals\n\nstd::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) {\n    return value.toString();\n}\n\n} // end namespace Catch\n// end catch_approx.cpp\n// start catch_assertionhandler.cpp\n\n// start catch_debugger.h\n\nnamespace Catch {\n    bool isDebuggerActive();\n}\n\n#ifdef CATCH_PLATFORM_MAC\n\n    #if defined(__i386__) || defined(__x86_64__)\n        #define CATCH_TRAP() __asm__(\"int $3\\n\" : : ) /* NOLINT */\n    #elif defined(__aarch64__)\n        #define CATCH_TRAP()  __asm__(\".inst 0xd4200000\")\n    #endif\n\n#elif defined(CATCH_PLATFORM_IPHONE)\n\n    // use inline assembler\n    #if defined(__i386__) || defined(__x86_64__)\n        #define CATCH_TRAP()  __asm__(\"int $3\")\n    #elif defined(__aarch64__)\n        #define CATCH_TRAP()  __asm__(\".inst 0xd4200000\")\n    #elif defined(__arm__) && !defined(__thumb__)\n        #define CATCH_TRAP()  __asm__(\".inst 0xe7f001f0\")\n    #elif defined(__arm__) &&  defined(__thumb__)\n        #define CATCH_TRAP()  __asm__(\".inst 0xde01\")\n    #endif\n\n#elif defined(CATCH_PLATFORM_LINUX)\n    // If we can use inline assembler, do it because this allows us to break\n    // directly at the location of the failing check instead of breaking inside\n    // raise() called from it, i.e. one stack frame below.\n    #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))\n        #define CATCH_TRAP() asm volatile (\"int $3\") /* NOLINT */\n    #else // Fall back to the generic way.\n        #include <signal.h>\n\n        #define CATCH_TRAP() raise(SIGTRAP)\n    #endif\n#elif defined(_MSC_VER)\n    #define CATCH_TRAP() __debugbreak()\n#elif defined(__MINGW32__)\n    extern \"C\" __declspec(dllimport) void __stdcall DebugBreak();\n    #define CATCH_TRAP() DebugBreak()\n#endif\n\n#ifndef CATCH_BREAK_INTO_DEBUGGER\n    #ifdef CATCH_TRAP\n        #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()\n    #else\n        #define CATCH_BREAK_INTO_DEBUGGER() []{}()\n    #endif\n#endif\n\n// end catch_debugger.h\n// start catch_run_context.h\n\n// start catch_fatal_condition.h\n\n#include <cassert>\n\nnamespace Catch {\n\n    // Wrapper for platform-specific fatal error (signals/SEH) handlers\n    //\n    // Tries to be cooperative with other handlers, and not step over\n    // other handlers. This means that unknown structured exceptions\n    // are passed on, previous signal handlers are called, and so on.\n    //\n    // Can only be instantiated once, and assumes that once a signal\n    // is caught, the binary will end up terminating. Thus, there\n    class FatalConditionHandler {\n        bool m_started = false;\n\n        // Install/disengage implementation for specific platform.\n        // Should be if-defed to work on current platform, can assume\n        // engage-disengage 1:1 pairing.\n        void engage_platform();\n        void disengage_platform();\n    public:\n        // Should also have platform-specific implementations as needed\n        FatalConditionHandler();\n        ~FatalConditionHandler();\n\n        void engage() {\n            assert(!m_started && \"Handler cannot be installed twice.\");\n            m_started = true;\n            engage_platform();\n        }\n\n        void disengage() {\n            assert(m_started && \"Handler cannot be uninstalled without being installed first\");\n            m_started = false;\n            disengage_platform();\n        }\n    };\n\n    //! Simple RAII guard for (dis)engaging the FatalConditionHandler\n    class FatalConditionHandlerGuard {\n        FatalConditionHandler* m_handler;\n    public:\n        FatalConditionHandlerGuard(FatalConditionHandler* handler):\n            m_handler(handler) {\n            m_handler->engage();\n        }\n        ~FatalConditionHandlerGuard() {\n            m_handler->disengage();\n        }\n    };\n\n} // end namespace Catch\n\n// end catch_fatal_condition.h\n#include <string>\n\nnamespace Catch {\n\n    struct IMutableContext;\n\n    ///////////////////////////////////////////////////////////////////////////\n\n    class RunContext : public IResultCapture, public IRunner {\n\n    public:\n        RunContext( RunContext const& ) = delete;\n        RunContext& operator =( RunContext const& ) = delete;\n\n        explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter );\n\n        ~RunContext() override;\n\n        void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount );\n        void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount );\n\n        Totals runTest(TestCase const& testCase);\n\n        IConfigPtr config() const;\n        IStreamingReporter& reporter() const;\n\n    public: // IResultCapture\n\n        // Assertion handlers\n        void handleExpr\n                (   AssertionInfo const& info,\n                    ITransientExpression const& expr,\n                    AssertionReaction& reaction ) override;\n        void handleMessage\n                (   AssertionInfo const& info,\n                    ResultWas::OfType resultType,\n                    StringRef const& message,\n                    AssertionReaction& reaction ) override;\n        void handleUnexpectedExceptionNotThrown\n                (   AssertionInfo const& info,\n                    AssertionReaction& reaction ) override;\n        void handleUnexpectedInflightException\n                (   AssertionInfo const& info,\n                    std::string const& message,\n                    AssertionReaction& reaction ) override;\n        void handleIncomplete\n                (   AssertionInfo const& info ) override;\n        void handleNonExpr\n                (   AssertionInfo const &info,\n                    ResultWas::OfType resultType,\n                    AssertionReaction &reaction ) override;\n\n        bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override;\n\n        void sectionEnded( SectionEndInfo const& endInfo ) override;\n        void sectionEndedEarly( SectionEndInfo const& endInfo ) override;\n\n        auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;\n\n#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\n        void benchmarkPreparing( std::string const& name ) override;\n        void benchmarkStarting( BenchmarkInfo const& info ) override;\n        void benchmarkEnded( BenchmarkStats<> const& stats ) override;\n        void benchmarkFailed( std::string const& error ) override;\n#endif // CATCH_CONFIG_ENABLE_BENCHMARKING\n\n        void pushScopedMessage( MessageInfo const& message ) override;\n        void popScopedMessage( MessageInfo const& message ) override;\n\n        void emplaceUnscopedMessage( MessageBuilder const& builder ) override;\n\n        std::string getCurrentTestName() const override;\n\n        const AssertionResult* getLastResult() const override;\n\n        void exceptionEarlyReported() override;\n\n        void handleFatalErrorCondition( StringRef message ) override;\n\n        bool lastAssertionPassed() override;\n\n        void assertionPassed() override;\n\n    public:\n        // !TBD We need to do this another way!\n        bool aborting() const final;\n\n    private:\n\n        void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr );\n        void invokeActiveTestCase();\n\n        void resetAssertionInfo();\n        bool testForMissingAssertions( Counts& assertions );\n\n        void assertionEnded( AssertionResult const& result );\n        void reportExpr\n                (   AssertionInfo const &info,\n                    ResultWas::OfType resultType,\n                    ITransientExpression const *expr,\n                    bool negated );\n\n        void populateReaction( AssertionReaction& reaction );\n\n    private:\n\n        void handleUnfinishedSections();\n\n        TestRunInfo m_runInfo;\n        IMutableContext& m_context;\n        TestCase const* m_activeTestCase = nullptr;\n        ITracker* m_testCaseTracker = nullptr;\n        Option<AssertionResult> m_lastResult;\n\n        IConfigPtr m_config;\n        Totals m_totals;\n        IStreamingReporterPtr m_reporter;\n        std::vector<MessageInfo> m_messages;\n        std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */\n        AssertionInfo m_lastAssertionInfo;\n        std::vector<SectionEndInfo> m_unfinishedSections;\n        std::vector<ITracker*> m_activeSections;\n        TrackerContext m_trackerContext;\n        FatalConditionHandler m_fatalConditionhandler;\n        bool m_lastAssertionPassed = false;\n        bool m_shouldReportUnexpected = true;\n        bool m_includeSuccessfulResults;\n    };\n\n    void seedRng(IConfig const& config);\n    unsigned int rngSeed();\n} // end namespace Catch\n\n// end catch_run_context.h\nnamespace Catch {\n\n    namespace {\n        auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {\n            expr.streamReconstructedExpression( os );\n            return os;\n        }\n    }\n\n    LazyExpression::LazyExpression( bool isNegated )\n    :   m_isNegated( isNegated )\n    {}\n\n    LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {}\n\n    LazyExpression::operator bool() const {\n        return m_transientExpression != nullptr;\n    }\n\n    auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& {\n        if( lazyExpr.m_isNegated )\n            os << \"!\";\n\n        if( lazyExpr ) {\n            if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() )\n                os << \"(\" << *lazyExpr.m_transientExpression << \")\";\n            else\n                os << *lazyExpr.m_transientExpression;\n        }\n        else {\n            os << \"{** error - unchecked empty expression requested **}\";\n        }\n        return os;\n    }\n\n    AssertionHandler::AssertionHandler\n        (   StringRef const& macroName,\n            SourceLineInfo const& lineInfo,\n            StringRef capturedExpression,\n            ResultDisposition::Flags resultDisposition )\n    :   m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },\n        m_resultCapture( getResultCapture() )\n    {}\n\n    void AssertionHandler::handleExpr( ITransientExpression const& expr ) {\n        m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction );\n    }\n    void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) {\n        m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction );\n    }\n\n    auto AssertionHandler::allowThrows() const -> bool {\n        return getCurrentContext().getConfig()->allowThrows();\n    }\n\n    void AssertionHandler::complete() {\n        setCompleted();\n        if( m_reaction.shouldDebugBreak ) {\n\n            // If you find your debugger stopping you here then go one level up on the\n            // call-stack for the code that caused it (typically a failed assertion)\n\n            // (To go back to the test and change execution, jump over the throw, next)\n            CATCH_BREAK_INTO_DEBUGGER();\n        }\n        if (m_reaction.shouldThrow) {\n#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)\n            throw Catch::TestFailureException();\n#else\n            CATCH_ERROR( \"Test failure requires aborting test!\" );\n#endif\n        }\n    }\n    void AssertionHandler::setCompleted() {\n        m_completed = true;\n    }\n\n    void AssertionHandler::handleUnexpectedInflightException() {\n        m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction );\n    }\n\n    void AssertionHandler::handleExceptionThrownAsExpected() {\n        m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);\n    }\n    void AssertionHandler::handleExceptionNotThrownAsExpected() {\n        m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);\n    }\n\n    void AssertionHandler::handleUnexpectedExceptionNotThrown() {\n        m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction );\n    }\n\n    void AssertionHandler::handleThrowingCallSkipped() {\n        m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);\n    }\n\n    // This is the overload that takes a string and infers the Equals matcher from it\n    // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp\n    void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString  ) {\n        handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString );\n    }\n\n} // namespace Catch\n// end catch_assertionhandler.cpp\n// start catch_assertionresult.cpp\n\nnamespace Catch {\n    AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression):\n        lazyExpression(_lazyExpression),\n        resultType(_resultType) {}\n\n    std::string AssertionResultData::reconstructExpression() const {\n\n        if( reconstructedExpression.empty() ) {\n            if( lazyExpression ) {\n                ReusableStringStream rss;\n                rss << lazyExpression;\n                reconstructedExpression = rss.str();\n            }\n        }\n        return reconstructedExpression;\n    }\n\n    AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )\n    :   m_info( info ),\n        m_resultData( data )\n    {}\n\n    // Result was a success\n    bool AssertionResult::succeeded() const {\n        return Catch::isOk( m_resultData.resultType );\n    }\n\n    // Result was a success, or failure is suppressed\n    bool AssertionResult::isOk() const {\n        return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );\n    }\n\n    ResultWas::OfType AssertionResult::getResultType() const {\n        return m_resultData.resultType;\n    }\n\n    bool AssertionResult::hasExpression() const {\n        return !m_info.capturedExpression.empty();\n    }\n\n    bool AssertionResult::hasMessage() const {\n        return !m_resultData.message.empty();\n    }\n\n    std::string AssertionResult::getExpression() const {\n        // Possibly overallocating by 3 characters should be basically free\n        std::string expr; expr.reserve(m_info.capturedExpression.size() + 3);\n        if (isFalseTest(m_info.resultDisposition)) {\n            expr += \"!(\";\n        }\n        expr += m_info.capturedExpression;\n        if (isFalseTest(m_info.resultDisposition)) {\n            expr += ')';\n        }\n        return expr;\n    }\n\n    std::string AssertionResult::getExpressionInMacro() const {\n        std::string expr;\n        if( m_info.macroName.empty() )\n            expr = static_cast<std::string>(m_info.capturedExpression);\n        else {\n            expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );\n            expr += m_info.macroName;\n            expr += \"( \";\n            expr += m_info.capturedExpression;\n            expr += \" )\";\n        }\n        return expr;\n    }\n\n    bool AssertionResult::hasExpandedExpression() const {\n        return hasExpression() && getExpandedExpression() != getExpression();\n    }\n\n    std::string AssertionResult::getExpandedExpression() const {\n        std::string expr = m_resultData.reconstructExpression();\n        return expr.empty()\n                ? getExpression()\n                : expr;\n    }\n\n    std::string AssertionResult::getMessage() const {\n        return m_resultData.message;\n    }\n    SourceLineInfo AssertionResult::getSourceInfo() const {\n        return m_info.lineInfo;\n    }\n\n    StringRef AssertionResult::getTestMacroName() const {\n        return m_info.macroName;\n    }\n\n} // end namespace Catch\n// end catch_assertionresult.cpp\n// start catch_capture_matchers.cpp\n\nnamespace Catch {\n\n    using StringMatcher = Matchers::Impl::MatcherBase<std::string>;\n\n    // This is the general overload that takes a any string matcher\n    // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers\n    // the Equals matcher (so the header does not mention matchers)\n    void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString  ) {\n        std::string exceptionMessage = Catch::translateActiveException();\n        MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString );\n        handler.handleExpr( expr );\n    }\n\n} // namespace Catch\n// end catch_capture_matchers.cpp\n// start catch_commandline.cpp\n\n// start catch_commandline.h\n\n// start catch_clara.h\n\n// Use Catch's value for console width (store Clara's off to the side, if present)\n#ifdef CLARA_CONFIG_CONSOLE_WIDTH\n#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH\n#undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH\n#endif\n#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1\n\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wweak-vtables\"\n#pragma clang diagnostic ignored \"-Wexit-time-destructors\"\n#pragma clang diagnostic ignored \"-Wshadow\"\n#endif\n\n// start clara.hpp\n// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n// See https://github.com/philsquared/Clara for more details\n\n// Clara v1.1.5\n\n\n#ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH\n#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80\n#endif\n\n#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH\n#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH\n#endif\n\n#ifndef CLARA_CONFIG_OPTIONAL_TYPE\n#ifdef __has_include\n#if __has_include(<optional>) && __cplusplus >= 201703L\n#include <optional>\n#define CLARA_CONFIG_OPTIONAL_TYPE std::optional\n#endif\n#endif\n#endif\n\n// ----------- #included from clara_textflow.hpp -----------\n\n// TextFlowCpp\n//\n// A single-header library for wrapping and laying out basic text, by Phil Nash\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n// This project is hosted at https://github.com/philsquared/textflowcpp\n\n\n#include <cassert>\n#include <ostream>\n#include <sstream>\n#include <vector>\n\n#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH\n#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80\n#endif\n\nnamespace Catch {\nnamespace clara {\nnamespace TextFlow {\n\ninline auto isWhitespace(char c) -> bool {\n\tstatic std::string chars = \" \\t\\n\\r\";\n\treturn chars.find(c) != std::string::npos;\n}\ninline auto isBreakableBefore(char c) -> bool {\n\tstatic std::string chars = \"[({<|\";\n\treturn chars.find(c) != std::string::npos;\n}\ninline auto isBreakableAfter(char c) -> bool {\n\tstatic std::string chars = \"])}>.,:;*+-=&/\\\\\";\n\treturn chars.find(c) != std::string::npos;\n}\n\nclass Columns;\n\nclass Column {\n\tstd::vector<std::string> m_strings;\n\tsize_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH;\n\tsize_t m_indent = 0;\n\tsize_t m_initialIndent = std::string::npos;\n\npublic:\n\tclass iterator {\n\t\tfriend Column;\n\n\t\tColumn const& m_column;\n\t\tsize_t m_stringIndex = 0;\n\t\tsize_t m_pos = 0;\n\n\t\tsize_t m_len = 0;\n\t\tsize_t m_end = 0;\n\t\tbool m_suffix = false;\n\n\t\titerator(Column const& column, size_t stringIndex)\n\t\t\t: m_column(column),\n\t\t\tm_stringIndex(stringIndex) {}\n\n\t\tauto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }\n\n\t\tauto isBoundary(size_t at) const -> bool {\n\t\t\tassert(at > 0);\n\t\t\tassert(at <= line().size());\n\n\t\t\treturn at == line().size() ||\n\t\t\t\t(isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) ||\n\t\t\t\tisBreakableBefore(line()[at]) ||\n\t\t\t\tisBreakableAfter(line()[at - 1]);\n\t\t}\n\n\t\tvoid calcLength() {\n\t\t\tassert(m_stringIndex < m_column.m_strings.size());\n\n\t\t\tm_suffix = false;\n\t\t\tauto width = m_column.m_width - indent();\n\t\t\tm_end = m_pos;\n\t\t\tif (line()[m_pos] == '\\n') {\n\t\t\t\t++m_end;\n\t\t\t}\n\t\t\twhile (m_end < line().size() && line()[m_end] != '\\n')\n\t\t\t\t++m_end;\n\n\t\t\tif (m_end < m_pos + width) {\n\t\t\t\tm_len = m_end - m_pos;\n\t\t\t} else {\n\t\t\t\tsize_t len = width;\n\t\t\t\twhile (len > 0 && !isBoundary(m_pos + len))\n\t\t\t\t\t--len;\n\t\t\t\twhile (len > 0 && isWhitespace(line()[m_pos + len - 1]))\n\t\t\t\t\t--len;\n\n\t\t\t\tif (len > 0) {\n\t\t\t\t\tm_len = len;\n\t\t\t\t} else {\n\t\t\t\t\tm_suffix = true;\n\t\t\t\t\tm_len = width - 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tauto indent() const -> size_t {\n\t\t\tauto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;\n\t\t\treturn initial == std::string::npos ? m_column.m_indent : initial;\n\t\t}\n\n\t\tauto addIndentAndSuffix(std::string const &plain) const -> std::string {\n\t\t\treturn std::string(indent(), ' ') + (m_suffix ? plain + \"-\" : plain);\n\t\t}\n\n\tpublic:\n\t\tusing difference_type = std::ptrdiff_t;\n\t\tusing value_type = std::string;\n\t\tusing pointer = value_type * ;\n\t\tusing reference = value_type & ;\n\t\tusing iterator_category = std::forward_iterator_tag;\n\n\t\texplicit iterator(Column const& column) : m_column(column) {\n\t\t\tassert(m_column.m_width > m_column.m_indent);\n\t\t\tassert(m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent);\n\t\t\tcalcLength();\n\t\t\tif (m_len == 0)\n\t\t\t\tm_stringIndex++; // Empty string\n\t\t}\n\n\t\tauto operator *() const -> std::string {\n\t\t\tassert(m_stringIndex < m_column.m_strings.size());\n\t\t\tassert(m_pos <= m_end);\n\t\t\treturn addIndentAndSuffix(line().substr(m_pos, m_len));\n\t\t}\n\n\t\tauto operator ++() -> iterator& {\n\t\t\tm_pos += m_len;\n\t\t\tif (m_pos < line().size() && line()[m_pos] == '\\n')\n\t\t\t\tm_pos += 1;\n\t\t\telse\n\t\t\t\twhile (m_pos < line().size() && isWhitespace(line()[m_pos]))\n\t\t\t\t\t++m_pos;\n\n\t\t\tif (m_pos == line().size()) {\n\t\t\t\tm_pos = 0;\n\t\t\t\t++m_stringIndex;\n\t\t\t}\n\t\t\tif (m_stringIndex < m_column.m_strings.size())\n\t\t\t\tcalcLength();\n\t\t\treturn *this;\n\t\t}\n\t\tauto operator ++(int) -> iterator {\n\t\t\titerator prev(*this);\n\t\t\toperator++();\n\t\t\treturn prev;\n\t\t}\n\n\t\tauto operator ==(iterator const& other) const -> bool {\n\t\t\treturn\n\t\t\t\tm_pos == other.m_pos &&\n\t\t\t\tm_stringIndex == other.m_stringIndex &&\n\t\t\t\t&m_column == &other.m_column;\n\t\t}\n\t\tauto operator !=(iterator const& other) const -> bool {\n\t\t\treturn !operator==(other);\n\t\t}\n\t};\n\tusing const_iterator = iterator;\n\n\texplicit Column(std::string const& text) { m_strings.push_back(text); }\n\n\tauto width(size_t newWidth) -> Column& {\n\t\tassert(newWidth > 0);\n\t\tm_width = newWidth;\n\t\treturn *this;\n\t}\n\tauto indent(size_t newIndent) -> Column& {\n\t\tm_indent = newIndent;\n\t\treturn *this;\n\t}\n\tauto initialIndent(size_t newIndent) -> Column& {\n\t\tm_initialIndent = newIndent;\n\t\treturn *this;\n\t}\n\n\tauto width() const -> size_t { return m_width; }\n\tauto begin() const -> iterator { return iterator(*this); }\n\tauto end() const -> iterator { return { *this, m_strings.size() }; }\n\n\tinline friend std::ostream& operator << (std::ostream& os, Column const& col) {\n\t\tbool first = true;\n\t\tfor (auto line : col) {\n\t\t\tif (first)\n\t\t\t\tfirst = false;\n\t\t\telse\n\t\t\t\tos << \"\\n\";\n\t\t\tos << line;\n\t\t}\n\t\treturn os;\n\t}\n\n\tauto operator + (Column const& other)->Columns;\n\n\tauto toString() const -> std::string {\n\t\tstd::ostringstream oss;\n\t\toss << *this;\n\t\treturn oss.str();\n\t}\n};\n\nclass Spacer : public Column {\n\npublic:\n\texplicit Spacer(size_t spaceWidth) : Column(\"\") {\n\t\twidth(spaceWidth);\n\t}\n};\n\nclass Columns {\n\tstd::vector<Column> m_columns;\n\npublic:\n\n\tclass iterator {\n\t\tfriend Columns;\n\t\tstruct EndTag {};\n\n\t\tstd::vector<Column> const& m_columns;\n\t\tstd::vector<Column::iterator> m_iterators;\n\t\tsize_t m_activeIterators;\n\n\t\titerator(Columns const& columns, EndTag)\n\t\t\t: m_columns(columns.m_columns),\n\t\t\tm_activeIterators(0) {\n\t\t\tm_iterators.reserve(m_columns.size());\n\n\t\t\tfor (auto const& col : m_columns)\n\t\t\t\tm_iterators.push_back(col.end());\n\t\t}\n\n\tpublic:\n\t\tusing difference_type = std::ptrdiff_t;\n\t\tusing value_type = std::string;\n\t\tusing pointer = value_type * ;\n\t\tusing reference = value_type & ;\n\t\tusing iterator_category = std::forward_iterator_tag;\n\n\t\texplicit iterator(Columns const& columns)\n\t\t\t: m_columns(columns.m_columns),\n\t\t\tm_activeIterators(m_columns.size()) {\n\t\t\tm_iterators.reserve(m_columns.size());\n\n\t\t\tfor (auto const& col : m_columns)\n\t\t\t\tm_iterators.push_back(col.begin());\n\t\t}\n\n\t\tauto operator ==(iterator const& other) const -> bool {\n\t\t\treturn m_iterators == other.m_iterators;\n\t\t}\n\t\tauto operator !=(iterator const& other) const -> bool {\n\t\t\treturn m_iterators != other.m_iterators;\n\t\t}\n\t\tauto operator *() const -> std::string {\n\t\t\tstd::string row, padding;\n\n\t\t\tfor (size_t i = 0; i < m_columns.size(); ++i) {\n\t\t\t\tauto width = m_columns[i].width();\n\t\t\t\tif (m_iterators[i] != m_columns[i].end()) {\n\t\t\t\t\tstd::string col = *m_iterators[i];\n\t\t\t\t\trow += padding + col;\n\t\t\t\t\tif (col.size() < width)\n\t\t\t\t\t\tpadding = std::string(width - col.size(), ' ');\n\t\t\t\t\telse\n\t\t\t\t\t\tpadding = \"\";\n\t\t\t\t} else {\n\t\t\t\t\tpadding += std::string(width, ' ');\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn row;\n\t\t}\n\t\tauto operator ++() -> iterator& {\n\t\t\tfor (size_t i = 0; i < m_columns.size(); ++i) {\n\t\t\t\tif (m_iterators[i] != m_columns[i].end())\n\t\t\t\t\t++m_iterators[i];\n\t\t\t}\n\t\t\treturn *this;\n\t\t}\n\t\tauto operator ++(int) -> iterator {\n\t\t\titerator prev(*this);\n\t\t\toperator++();\n\t\t\treturn prev;\n\t\t}\n\t};\n\tusing const_iterator = iterator;\n\n\tauto begin() const -> iterator { return iterator(*this); }\n\tauto end() const -> iterator { return { *this, iterator::EndTag() }; }\n\n\tauto operator += (Column const& col) -> Columns& {\n\t\tm_columns.push_back(col);\n\t\treturn *this;\n\t}\n\tauto operator + (Column const& col) -> Columns {\n\t\tColumns combined = *this;\n\t\tcombined += col;\n\t\treturn combined;\n\t}\n\n\tinline friend std::ostream& operator << (std::ostream& os, Columns const& cols) {\n\n\t\tbool first = true;\n\t\tfor (auto line : cols) {\n\t\t\tif (first)\n\t\t\t\tfirst = false;\n\t\t\telse\n\t\t\t\tos << \"\\n\";\n\t\t\tos << line;\n\t\t}\n\t\treturn os;\n\t}\n\n\tauto toString() const -> std::string {\n\t\tstd::ostringstream oss;\n\t\toss << *this;\n\t\treturn oss.str();\n\t}\n};\n\ninline auto Column::operator + (Column const& other) -> Columns {\n\tColumns cols;\n\tcols += *this;\n\tcols += other;\n\treturn cols;\n}\n}\n\n}\n}\n\n// ----------- end of #include from clara_textflow.hpp -----------\n// ........... back in clara.hpp\n\n#include <cctype>\n#include <string>\n#include <memory>\n#include <set>\n#include <algorithm>\n\n#if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) )\n#define CATCH_PLATFORM_WINDOWS\n#endif\n\nnamespace Catch { namespace clara {\nnamespace detail {\n\n    // Traits for extracting arg and return type of lambdas (for single argument lambdas)\n    template<typename L>\n    struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {};\n\n    template<typename ClassT, typename ReturnT, typename... Args>\n    struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> {\n        static const bool isValid = false;\n    };\n\n    template<typename ClassT, typename ReturnT, typename ArgT>\n    struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {\n        static const bool isValid = true;\n        using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;\n        using ReturnType = ReturnT;\n    };\n\n    class TokenStream;\n\n    // Transport for raw args (copied from main args, or supplied via init list for testing)\n    class Args {\n        friend TokenStream;\n        std::string m_exeName;\n        std::vector<std::string> m_args;\n\n    public:\n        Args( int argc, char const* const* argv )\n            : m_exeName(argv[0]),\n              m_args(argv + 1, argv + argc) {}\n\n        Args( std::initializer_list<std::string> args )\n        :   m_exeName( *args.begin() ),\n            m_args( args.begin()+1, args.end() )\n        {}\n\n        auto exeName() const -> std::string {\n            return m_exeName;\n        }\n    };\n\n    // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string\n    // may encode an option + its argument if the : or = form is used\n    enum class TokenType {\n        Option, Argument\n    };\n    struct Token {\n        TokenType type;\n        std::string token;\n    };\n\n    inline auto isOptPrefix( char c ) -> bool {\n        return c == '-'\n#ifdef CATCH_PLATFORM_WINDOWS\n            || c == '/'\n#endif\n        ;\n    }\n\n    // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled\n    class TokenStream {\n        using Iterator = std::vector<std::string>::const_iterator;\n        Iterator it;\n        Iterator itEnd;\n        std::vector<Token> m_tokenBuffer;\n\n        void loadBuffer() {\n            m_tokenBuffer.resize( 0 );\n\n            // Skip any empty strings\n            while( it != itEnd && it->empty() )\n                ++it;\n\n            if( it != itEnd ) {\n                auto const &next = *it;\n                if( isOptPrefix( next[0] ) ) {\n                    auto delimiterPos = next.find_first_of( \" :=\" );\n                    if( delimiterPos != std::string::npos ) {\n                        m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } );\n                        m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } );\n                    } else {\n                        if( next[1] != '-' && next.size() > 2 ) {\n                            std::string opt = \"- \";\n                            for( size_t i = 1; i < next.size(); ++i ) {\n                                opt[1] = next[i];\n                                m_tokenBuffer.push_back( { TokenType::Option, opt } );\n                            }\n                        } else {\n                            m_tokenBuffer.push_back( { TokenType::Option, next } );\n                        }\n                    }\n                } else {\n                    m_tokenBuffer.push_back( { TokenType::Argument, next } );\n                }\n            }\n        }\n\n    public:\n        explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {}\n\n        TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) {\n            loadBuffer();\n        }\n\n        explicit operator bool() const {\n            return !m_tokenBuffer.empty() || it != itEnd;\n        }\n\n        auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); }\n\n        auto operator*() const -> Token {\n            assert( !m_tokenBuffer.empty() );\n            return m_tokenBuffer.front();\n        }\n\n        auto operator->() const -> Token const * {\n            assert( !m_tokenBuffer.empty() );\n            return &m_tokenBuffer.front();\n        }\n\n        auto operator++() -> TokenStream & {\n            if( m_tokenBuffer.size() >= 2 ) {\n                m_tokenBuffer.erase( m_tokenBuffer.begin() );\n            } else {\n                if( it != itEnd )\n                    ++it;\n                loadBuffer();\n            }\n            return *this;\n        }\n    };\n\n    class ResultBase {\n    public:\n        enum Type {\n            Ok, LogicError, RuntimeError\n        };\n\n    protected:\n        ResultBase( Type type ) : m_type( type ) {}\n        virtual ~ResultBase() = default;\n\n        virtual void enforceOk() const = 0;\n\n        Type m_type;\n    };\n\n    template<typename T>\n    class ResultValueBase : public ResultBase {\n    public:\n        auto value() const -> T const & {\n            enforceOk();\n            return m_value;\n        }\n\n    protected:\n        ResultValueBase( Type type ) : ResultBase( type ) {}\n\n        ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) {\n            if( m_type == ResultBase::Ok )\n                new( &m_value ) T( other.m_value );\n        }\n\n        ResultValueBase( Type, T const &value ) : ResultBase( Ok ) {\n            new( &m_value ) T( value );\n        }\n\n        auto operator=( ResultValueBase const &other ) -> ResultValueBase & {\n            if( m_type == ResultBase::Ok )\n                m_value.~T();\n            ResultBase::operator=(other);\n            if( m_type == ResultBase::Ok )\n                new( &m_value ) T( other.m_value );\n            return *this;\n        }\n\n        ~ResultValueBase() override {\n            if( m_type == Ok )\n                m_value.~T();\n        }\n\n        union {\n            T m_value;\n        };\n    };\n\n    template<>\n    class ResultValueBase<void> : public ResultBase {\n    protected:\n        using ResultBase::ResultBase;\n    };\n\n    template<typename T = void>\n    class BasicResult : public ResultValueBase<T> {\n    public:\n        template<typename U>\n        explicit BasicResult( BasicResult<U> const &other )\n        :   ResultValueBase<T>( other.type() ),\n            m_errorMessage( other.errorMessage() )\n        {\n            assert( type() != ResultBase::Ok );\n        }\n\n        template<typename U>\n        static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; }\n        static auto ok() -> BasicResult { return { ResultBase::Ok }; }\n        static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; }\n        static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; }\n\n        explicit operator bool() const { return m_type == ResultBase::Ok; }\n        auto type() const -> ResultBase::Type { return m_type; }\n        auto errorMessage() const -> std::string { return m_errorMessage; }\n\n    protected:\n        void enforceOk() const override {\n\n            // Errors shouldn't reach this point, but if they do\n            // the actual error message will be in m_errorMessage\n            assert( m_type != ResultBase::LogicError );\n            assert( m_type != ResultBase::RuntimeError );\n            if( m_type != ResultBase::Ok )\n                std::abort();\n        }\n\n        std::string m_errorMessage; // Only populated if resultType is an error\n\n        BasicResult( ResultBase::Type type, std::string const &message )\n        :   ResultValueBase<T>(type),\n            m_errorMessage(message)\n        {\n            assert( m_type != ResultBase::Ok );\n        }\n\n        using ResultValueBase<T>::ResultValueBase;\n        using ResultBase::m_type;\n    };\n\n    enum class ParseResultType {\n        Matched, NoMatch, ShortCircuitAll, ShortCircuitSame\n    };\n\n    class ParseState {\n    public:\n\n        ParseState( ParseResultType type, TokenStream const &remainingTokens )\n        : m_type(type),\n          m_remainingTokens( remainingTokens )\n        {}\n\n        auto type() const -> ParseResultType { return m_type; }\n        auto remainingTokens() const -> TokenStream { return m_remainingTokens; }\n\n    private:\n        ParseResultType m_type;\n        TokenStream m_remainingTokens;\n    };\n\n    using Result = BasicResult<void>;\n    using ParserResult = BasicResult<ParseResultType>;\n    using InternalParseResult = BasicResult<ParseState>;\n\n    struct HelpColumns {\n        std::string left;\n        std::string right;\n    };\n\n    template<typename T>\n    inline auto convertInto( std::string const &source, T& target ) -> ParserResult {\n        std::stringstream ss;\n        ss << source;\n        ss >> target;\n        if( ss.fail() )\n            return ParserResult::runtimeError( \"Unable to convert '\" + source + \"' to destination type\" );\n        else\n            return ParserResult::ok( ParseResultType::Matched );\n    }\n    inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult {\n        target = source;\n        return ParserResult::ok( ParseResultType::Matched );\n    }\n    inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {\n        std::string srcLC = source;\n        std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned char c ) { return static_cast<char>( std::tolower(c) ); } );\n        if (srcLC == \"y\" || srcLC == \"1\" || srcLC == \"true\" || srcLC == \"yes\" || srcLC == \"on\")\n            target = true;\n        else if (srcLC == \"n\" || srcLC == \"0\" || srcLC == \"false\" || srcLC == \"no\" || srcLC == \"off\")\n            target = false;\n        else\n            return ParserResult::runtimeError( \"Expected a boolean value but did not recognise: '\" + source + \"'\" );\n        return ParserResult::ok( ParseResultType::Matched );\n    }\n#ifdef CLARA_CONFIG_OPTIONAL_TYPE\n    template<typename T>\n    inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult {\n        T temp;\n        auto result = convertInto( source, temp );\n        if( result )\n            target = std::move(temp);\n        return result;\n    }\n#endif // CLARA_CONFIG_OPTIONAL_TYPE\n\n    struct NonCopyable {\n        NonCopyable() = default;\n        NonCopyable( NonCopyable const & ) = delete;\n        NonCopyable( NonCopyable && ) = delete;\n        NonCopyable &operator=( NonCopyable const & ) = delete;\n        NonCopyable &operator=( NonCopyable && ) = delete;\n    };\n\n    struct BoundRef : NonCopyable {\n        virtual ~BoundRef() = default;\n        virtual auto isContainer() const -> bool { return false; }\n        virtual auto isFlag() const -> bool { return false; }\n    };\n    struct BoundValueRefBase : BoundRef {\n        virtual auto setValue( std::string const &arg ) -> ParserResult = 0;\n    };\n    struct BoundFlagRefBase : BoundRef {\n        virtual auto setFlag( bool flag ) -> ParserResult = 0;\n        virtual auto isFlag() const -> bool { return true; }\n    };\n\n    template<typename T>\n    struct BoundValueRef : BoundValueRefBase {\n        T &m_ref;\n\n        explicit BoundValueRef( T &ref ) : m_ref( ref ) {}\n\n        auto setValue( std::string const &arg ) -> ParserResult override {\n            return convertInto( arg, m_ref );\n        }\n    };\n\n    template<typename T>\n    struct BoundValueRef<std::vector<T>> : BoundValueRefBase {\n        std::vector<T> &m_ref;\n\n        explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {}\n\n        auto isContainer() const -> bool override { return true; }\n\n        auto setValue( std::string const &arg ) -> ParserResult override {\n            T temp;\n            auto result = convertInto( arg, temp );\n            if( result )\n                m_ref.push_back( temp );\n            return result;\n        }\n    };\n\n    struct BoundFlagRef : BoundFlagRefBase {\n        bool &m_ref;\n\n        explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {}\n\n        auto setFlag( bool flag ) -> ParserResult override {\n            m_ref = flag;\n            return ParserResult::ok( ParseResultType::Matched );\n        }\n    };\n\n    template<typename ReturnType>\n    struct LambdaInvoker {\n        static_assert( std::is_same<ReturnType, ParserResult>::value, \"Lambda must return void or clara::ParserResult\" );\n\n        template<typename L, typename ArgType>\n        static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {\n            return lambda( arg );\n        }\n    };\n\n    template<>\n    struct LambdaInvoker<void> {\n        template<typename L, typename ArgType>\n        static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {\n            lambda( arg );\n            return ParserResult::ok( ParseResultType::Matched );\n        }\n    };\n\n    template<typename ArgType, typename L>\n    inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {\n        ArgType temp{};\n        auto result = convertInto( arg, temp );\n        return !result\n           ? result\n           : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );\n    }\n\n    template<typename L>\n    struct BoundLambda : BoundValueRefBase {\n        L m_lambda;\n\n        static_assert( UnaryLambdaTraits<L>::isValid, \"Supplied lambda must take exactly one argument\" );\n        explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {}\n\n        auto setValue( std::string const &arg ) -> ParserResult override {\n            return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg );\n        }\n    };\n\n    template<typename L>\n    struct BoundFlagLambda : BoundFlagRefBase {\n        L m_lambda;\n\n        static_assert( UnaryLambdaTraits<L>::isValid, \"Supplied lambda must take exactly one argument\" );\n        static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, \"flags must be boolean\" );\n\n        explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {}\n\n        auto setFlag( bool flag ) -> ParserResult override {\n            return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag );\n        }\n    };\n\n    enum class Optionality { Optional, Required };\n\n    struct Parser;\n\n    class ParserBase {\n    public:\n        virtual ~ParserBase() = default;\n        virtual auto validate() const -> Result { return Result::ok(); }\n        virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult  = 0;\n        virtual auto cardinality() const -> size_t { return 1; }\n\n        auto parse( Args const &args ) const -> InternalParseResult {\n            return parse( args.exeName(), TokenStream( args ) );\n        }\n    };\n\n    template<typename DerivedT>\n    class ComposableParserImpl : public ParserBase {\n    public:\n        template<typename T>\n        auto operator|( T const &other ) const -> Parser;\n\n\t\ttemplate<typename T>\n        auto operator+( T const &other ) const -> Parser;\n    };\n\n    // Common code and state for Args and Opts\n    template<typename DerivedT>\n    class ParserRefImpl : public ComposableParserImpl<DerivedT> {\n    protected:\n        Optionality m_optionality = Optionality::Optional;\n        std::shared_ptr<BoundRef> m_ref;\n        std::string m_hint;\n        std::string m_description;\n\n        explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {}\n\n    public:\n        template<typename T>\n        ParserRefImpl( T &ref, std::string const &hint )\n        :   m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),\n            m_hint( hint )\n        {}\n\n        template<typename LambdaT>\n        ParserRefImpl( LambdaT const &ref, std::string const &hint )\n        :   m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),\n            m_hint(hint)\n        {}\n\n        auto operator()( std::string const &description ) -> DerivedT & {\n            m_description = description;\n            return static_cast<DerivedT &>( *this );\n        }\n\n        auto optional() -> DerivedT & {\n            m_optionality = Optionality::Optional;\n            return static_cast<DerivedT &>( *this );\n        };\n\n        auto required() -> DerivedT & {\n            m_optionality = Optionality::Required;\n            return static_cast<DerivedT &>( *this );\n        };\n\n        auto isOptional() const -> bool {\n            return m_optionality == Optionality::Optional;\n        }\n\n        auto cardinality() const -> size_t override {\n            if( m_ref->isContainer() )\n                return 0;\n            else\n                return 1;\n        }\n\n        auto hint() const -> std::string { return m_hint; }\n    };\n\n    class ExeName : public ComposableParserImpl<ExeName> {\n        std::shared_ptr<std::string> m_name;\n        std::shared_ptr<BoundValueRefBase> m_ref;\n\n        template<typename LambdaT>\n        static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {\n            return std::make_shared<BoundLambda<LambdaT>>( lambda) ;\n        }\n\n    public:\n        ExeName() : m_name( std::make_shared<std::string>( \"<executable>\" ) ) {}\n\n        explicit ExeName( std::string &ref ) : ExeName() {\n            m_ref = std::make_shared<BoundValueRef<std::string>>( ref );\n        }\n\n        template<typename LambdaT>\n        explicit ExeName( LambdaT const& lambda ) : ExeName() {\n            m_ref = std::make_shared<BoundLambda<LambdaT>>( lambda );\n        }\n\n        // The exe name is not parsed out of the normal tokens, but is handled specially\n        auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {\n            return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );\n        }\n\n        auto name() const -> std::string { return *m_name; }\n        auto set( std::string const& newName ) -> ParserResult {\n\n            auto lastSlash = newName.find_last_of( \"\\\\/\" );\n            auto filename = ( lastSlash == std::string::npos )\n                    ? newName\n                    : newName.substr( lastSlash+1 );\n\n            *m_name = filename;\n            if( m_ref )\n                return m_ref->setValue( filename );\n            else\n                return ParserResult::ok( ParseResultType::Matched );\n        }\n    };\n\n    class Arg : public ParserRefImpl<Arg> {\n    public:\n        using ParserRefImpl::ParserRefImpl;\n\n        auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override {\n            auto validationResult = validate();\n            if( !validationResult )\n                return InternalParseResult( validationResult );\n\n            auto remainingTokens = tokens;\n            auto const &token = *remainingTokens;\n            if( token.type != TokenType::Argument )\n                return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );\n\n            assert( !m_ref->isFlag() );\n            auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );\n\n            auto result = valueRef->setValue( remainingTokens->token );\n            if( !result )\n                return InternalParseResult( result );\n            else\n                return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );\n        }\n    };\n\n    inline auto normaliseOpt( std::string const &optName ) -> std::string {\n#ifdef CATCH_PLATFORM_WINDOWS\n        if( optName[0] == '/' )\n            return \"-\" + optName.substr( 1 );\n        else\n#endif\n            return optName;\n    }\n\n    class Opt : public ParserRefImpl<Opt> {\n    protected:\n        std::vector<std::string> m_optNames;\n\n    public:\n        template<typename LambdaT>\n        explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {}\n\n        explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {}\n\n        template<typename LambdaT>\n        Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}\n\n        template<typename T>\n        Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}\n\n        auto operator[]( std::string const &optName ) -> Opt & {\n            m_optNames.push_back( optName );\n            return *this;\n        }\n\n        auto getHelpColumns() const -> std::vector<HelpColumns> {\n            std::ostringstream oss;\n            bool first = true;\n            for( auto const &opt : m_optNames ) {\n                if (first)\n                    first = false;\n                else\n                    oss << \", \";\n                oss << opt;\n            }\n            if( !m_hint.empty() )\n                oss << \" <\" << m_hint << \">\";\n            return { { oss.str(), m_description } };\n        }\n\n        auto isMatch( std::string const &optToken ) const -> bool {\n            auto normalisedToken = normaliseOpt( optToken );\n            for( auto const &name : m_optNames ) {\n                if( normaliseOpt( name ) == normalisedToken )\n                    return true;\n            }\n            return false;\n        }\n\n        using ParserBase::parse;\n\n        auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {\n            auto validationResult = validate();\n            if( !validationResult )\n                return InternalParseResult( validationResult );\n\n            auto remainingTokens = tokens;\n            if( remainingTokens && remainingTokens->type == TokenType::Option ) {\n                auto const &token = *remainingTokens;\n                if( isMatch(token.token ) ) {\n                    if( m_ref->isFlag() ) {\n                        auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() );\n                        auto result = flagRef->setFlag( true );\n                        if( !result )\n                            return InternalParseResult( result );\n                        if( result.value() == ParseResultType::ShortCircuitAll )\n                            return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );\n                    } else {\n                        auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );\n                        ++remainingTokens;\n                        if( !remainingTokens )\n                            return InternalParseResult::runtimeError( \"Expected argument following \" + token.token );\n                        auto const &argToken = *remainingTokens;\n                        if( argToken.type != TokenType::Argument )\n                            return InternalParseResult::runtimeError( \"Expected argument following \" + token.token );\n                        auto result = valueRef->setValue( argToken.token );\n                        if( !result )\n                            return InternalParseResult( result );\n                        if( result.value() == ParseResultType::ShortCircuitAll )\n                            return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );\n                    }\n                    return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );\n                }\n            }\n            return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );\n        }\n\n        auto validate() const -> Result override {\n            if( m_optNames.empty() )\n                return Result::logicError( \"No options supplied to Opt\" );\n            for( auto const &name : m_optNames ) {\n                if( name.empty() )\n                    return Result::logicError( \"Option name cannot be empty\" );\n#ifdef CATCH_PLATFORM_WINDOWS\n                if( name[0] != '-' && name[0] != '/' )\n                    return Result::logicError( \"Option name must begin with '-' or '/'\" );\n#else\n                if( name[0] != '-' )\n                    return Result::logicError( \"Option name must begin with '-'\" );\n#endif\n            }\n            return ParserRefImpl::validate();\n        }\n    };\n\n    struct Help : Opt {\n        Help( bool &showHelpFlag )\n        :   Opt([&]( bool flag ) {\n                showHelpFlag = flag;\n                return ParserResult::ok( ParseResultType::ShortCircuitAll );\n            })\n        {\n            static_cast<Opt &>( *this )\n                    (\"display usage information\")\n                    [\"-?\"][\"-h\"][\"--help\"]\n                    .optional();\n        }\n    };\n\n    struct Parser : ParserBase {\n\n        mutable ExeName m_exeName;\n        std::vector<Opt> m_options;\n        std::vector<Arg> m_args;\n\n        auto operator|=( ExeName const &exeName ) -> Parser & {\n            m_exeName = exeName;\n            return *this;\n        }\n\n        auto operator|=( Arg const &arg ) -> Parser & {\n            m_args.push_back(arg);\n            return *this;\n        }\n\n        auto operator|=( Opt const &opt ) -> Parser & {\n            m_options.push_back(opt);\n            return *this;\n        }\n\n        auto operator|=( Parser const &other ) -> Parser & {\n            m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end());\n            m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end());\n            return *this;\n        }\n\n        template<typename T>\n        auto operator|( T const &other ) const -> Parser {\n            return Parser( *this ) |= other;\n        }\n\n        // Forward deprecated interface with '+' instead of '|'\n        template<typename T>\n        auto operator+=( T const &other ) -> Parser & { return operator|=( other ); }\n        template<typename T>\n        auto operator+( T const &other ) const -> Parser { return operator|( other ); }\n\n        auto getHelpColumns() const -> std::vector<HelpColumns> {\n            std::vector<HelpColumns> cols;\n            for (auto const &o : m_options) {\n                auto childCols = o.getHelpColumns();\n                cols.insert( cols.end(), childCols.begin(), childCols.end() );\n            }\n            return cols;\n        }\n\n        void writeToStream( std::ostream &os ) const {\n            if (!m_exeName.name().empty()) {\n                os << \"usage:\\n\" << \"  \" << m_exeName.name() << \" \";\n                bool required = true, first = true;\n                for( auto const &arg : m_args ) {\n                    if (first)\n                        first = false;\n                    else\n                        os << \" \";\n                    if( arg.isOptional() && required ) {\n                        os << \"[\";\n                        required = false;\n                    }\n                    os << \"<\" << arg.hint() << \">\";\n                    if( arg.cardinality() == 0 )\n                        os << \" ... \";\n                }\n                if( !required )\n                    os << \"]\";\n                if( !m_options.empty() )\n                    os << \" options\";\n                os << \"\\n\\nwhere options are:\" << std::endl;\n            }\n\n            auto rows = getHelpColumns();\n            size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH;\n            size_t optWidth = 0;\n            for( auto const &cols : rows )\n                optWidth = (std::max)(optWidth, cols.left.size() + 2);\n\n            optWidth = (std::min)(optWidth, consoleWidth/2);\n\n            for( auto const &cols : rows ) {\n                auto row =\n                        TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +\n                        TextFlow::Spacer(4) +\n                        TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth );\n                os << row << std::endl;\n            }\n        }\n\n        friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& {\n            parser.writeToStream( os );\n            return os;\n        }\n\n        auto validate() const -> Result override {\n            for( auto const &opt : m_options ) {\n                auto result = opt.validate();\n                if( !result )\n                    return result;\n            }\n            for( auto const &arg : m_args ) {\n                auto result = arg.validate();\n                if( !result )\n                    return result;\n            }\n            return Result::ok();\n        }\n\n        using ParserBase::parse;\n\n        auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override {\n\n            struct ParserInfo {\n                ParserBase const* parser = nullptr;\n                size_t count = 0;\n            };\n            const size_t totalParsers = m_options.size() + m_args.size();\n            assert( totalParsers < 512 );\n            // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do\n            ParserInfo parseInfos[512];\n\n            {\n                size_t i = 0;\n                for (auto const &opt : m_options) parseInfos[i++].parser = &opt;\n                for (auto const &arg : m_args) parseInfos[i++].parser = &arg;\n            }\n\n            m_exeName.set( exeName );\n\n            auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );\n            while( result.value().remainingTokens() ) {\n                bool tokenParsed = false;\n\n                for( size_t i = 0; i < totalParsers; ++i ) {\n                    auto&  parseInfo = parseInfos[i];\n                    if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) {\n                        result = parseInfo.parser->parse(exeName, result.value().remainingTokens());\n                        if (!result)\n                            return result;\n                        if (result.value().type() != ParseResultType::NoMatch) {\n                            tokenParsed = true;\n                            ++parseInfo.count;\n                            break;\n                        }\n                    }\n                }\n\n                if( result.value().type() == ParseResultType::ShortCircuitAll )\n                    return result;\n                if( !tokenParsed )\n                    return InternalParseResult::runtimeError( \"Unrecognised token: \" + result.value().remainingTokens()->token );\n            }\n            // !TBD Check missing required options\n            return result;\n        }\n    };\n\n    template<typename DerivedT>\n    template<typename T>\n    auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser {\n        return Parser() | static_cast<DerivedT const &>( *this ) | other;\n    }\n} // namespace detail\n\n// A Combined parser\nusing detail::Parser;\n\n// A parser for options\nusing detail::Opt;\n\n// A parser for arguments\nusing detail::Arg;\n\n// Wrapper for argc, argv from main()\nusing detail::Args;\n\n// Specifies the name of the executable\nusing detail::ExeName;\n\n// Convenience wrapper for option parser that specifies the help option\nusing detail::Help;\n\n// enum of result types from a parse\nusing detail::ParseResultType;\n\n// Result type for parser operation\nusing detail::ParserResult;\n\n}} // namespace Catch::clara\n\n// end clara.hpp\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n\n// Restore Clara's value for console width, if present\n#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH\n#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH\n#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH\n#endif\n\n// end catch_clara.h\nnamespace Catch {\n\n    clara::Parser makeCommandLineParser( ConfigData& config );\n\n} // end namespace Catch\n\n// end catch_commandline.h\n#include <fstream>\n#include <ctime>\n\nnamespace Catch {\n\n    clara::Parser makeCommandLineParser( ConfigData& config ) {\n\n        using namespace clara;\n\n        auto const setWarning = [&]( std::string const& warning ) {\n                auto warningSet = [&]() {\n                    if( warning == \"NoAssertions\" )\n                        return WarnAbout::NoAssertions;\n\n                    if ( warning == \"NoTests\" )\n                        return WarnAbout::NoTests;\n\n                    return WarnAbout::Nothing;\n                }();\n\n                if (warningSet == WarnAbout::Nothing)\n                    return ParserResult::runtimeError( \"Unrecognised warning: '\" + warning + \"'\" );\n                config.warnings = static_cast<WarnAbout::What>( config.warnings | warningSet );\n                return ParserResult::ok( ParseResultType::Matched );\n            };\n        auto const loadTestNamesFromFile = [&]( std::string const& filename ) {\n                std::ifstream f( filename.c_str() );\n                if( !f.is_open() )\n                    return ParserResult::runtimeError( \"Unable to load input file: '\" + filename + \"'\" );\n\n                std::string line;\n                while( std::getline( f, line ) ) {\n                    line = trim(line);\n                    if( !line.empty() && !startsWith( line, '#' ) ) {\n                        if( !startsWith( line, '\"' ) )\n                            line = '\"' + line + '\"';\n                        config.testsOrTags.push_back( line );\n                        config.testsOrTags.emplace_back( \",\" );\n                    }\n                }\n                //Remove comma in the end\n                if(!config.testsOrTags.empty())\n                    config.testsOrTags.erase( config.testsOrTags.end()-1 );\n\n                return ParserResult::ok( ParseResultType::Matched );\n            };\n        auto const setTestOrder = [&]( std::string const& order ) {\n                if( startsWith( \"declared\", order ) )\n                    config.runOrder = RunTests::InDeclarationOrder;\n                else if( startsWith( \"lexical\", order ) )\n                    config.runOrder = RunTests::InLexicographicalOrder;\n                else if( startsWith( \"random\", order ) )\n                    config.runOrder = RunTests::InRandomOrder;\n                else\n                    return clara::ParserResult::runtimeError( \"Unrecognised ordering: '\" + order + \"'\" );\n                return ParserResult::ok( ParseResultType::Matched );\n            };\n        auto const setRngSeed = [&]( std::string const& seed ) {\n                if( seed != \"time\" )\n                    return clara::detail::convertInto( seed, config.rngSeed );\n                config.rngSeed = static_cast<unsigned int>( std::time(nullptr) );\n                return ParserResult::ok( ParseResultType::Matched );\n            };\n        auto const setColourUsage = [&]( std::string const& useColour ) {\n                    auto mode = toLower( useColour );\n\n                    if( mode == \"yes\" )\n                        config.useColour = UseColour::Yes;\n                    else if( mode == \"no\" )\n                        config.useColour = UseColour::No;\n                    else if( mode == \"auto\" )\n                        config.useColour = UseColour::Auto;\n                    else\n                        return ParserResult::runtimeError( \"colour mode must be one of: auto, yes or no. '\" + useColour + \"' not recognised\" );\n                return ParserResult::ok( ParseResultType::Matched );\n            };\n        auto const setWaitForKeypress = [&]( std::string const& keypress ) {\n                auto keypressLc = toLower( keypress );\n                if (keypressLc == \"never\")\n                    config.waitForKeypress = WaitForKeypress::Never;\n                else if( keypressLc == \"start\" )\n                    config.waitForKeypress = WaitForKeypress::BeforeStart;\n                else if( keypressLc == \"exit\" )\n                    config.waitForKeypress = WaitForKeypress::BeforeExit;\n                else if( keypressLc == \"both\" )\n                    config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;\n                else\n                    return ParserResult::runtimeError( \"keypress argument must be one of: never, start, exit or both. '\" + keypress + \"' not recognised\" );\n            return ParserResult::ok( ParseResultType::Matched );\n            };\n        auto const setVerbosity = [&]( std::string const& verbosity ) {\n            auto lcVerbosity = toLower( verbosity );\n            if( lcVerbosity == \"quiet\" )\n                config.verbosity = Verbosity::Quiet;\n            else if( lcVerbosity == \"normal\" )\n                config.verbosity = Verbosity::Normal;\n            else if( lcVerbosity == \"high\" )\n                config.verbosity = Verbosity::High;\n            else\n                return ParserResult::runtimeError( \"Unrecognised verbosity, '\" + verbosity + \"'\" );\n            return ParserResult::ok( ParseResultType::Matched );\n        };\n        auto const setReporter = [&]( std::string const& reporter ) {\n            IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();\n\n            auto lcReporter = toLower( reporter );\n            auto result = factories.find( lcReporter );\n\n            if( factories.end() != result )\n                config.reporterName = lcReporter;\n            else\n                return ParserResult::runtimeError( \"Unrecognized reporter, '\" + reporter + \"'. Check available with --list-reporters\" );\n            return ParserResult::ok( ParseResultType::Matched );\n        };\n\n        auto cli\n            = ExeName( config.processName )\n            | Help( config.showHelp )\n            | Opt( config.listTests )\n                [\"-l\"][\"--list-tests\"]\n                ( \"list all/matching test cases\" )\n            | Opt( config.listTags )\n                [\"-t\"][\"--list-tags\"]\n                ( \"list all/matching tags\" )\n            | Opt( config.showSuccessfulTests )\n                [\"-s\"][\"--success\"]\n                ( \"include successful tests in output\" )\n            | Opt( config.shouldDebugBreak )\n                [\"-b\"][\"--break\"]\n                ( \"break into debugger on failure\" )\n            | Opt( config.noThrow )\n                [\"-e\"][\"--nothrow\"]\n                ( \"skip exception tests\" )\n            | Opt( config.showInvisibles )\n                [\"-i\"][\"--invisibles\"]\n                ( \"show invisibles (tabs, newlines)\" )\n            | Opt( config.outputFilename, \"filename\" )\n                [\"-o\"][\"--out\"]\n                ( \"output filename\" )\n            | Opt( setReporter, \"name\" )\n                [\"-r\"][\"--reporter\"]\n                ( \"reporter to use (defaults to console)\" )\n            | Opt( config.name, \"name\" )\n                [\"-n\"][\"--name\"]\n                ( \"suite name\" )\n            | Opt( [&]( bool ){ config.abortAfter = 1; } )\n                [\"-a\"][\"--abort\"]\n                ( \"abort at first failure\" )\n            | Opt( [&]( int x ){ config.abortAfter = x; }, \"no. failures\" )\n                [\"-x\"][\"--abortx\"]\n                ( \"abort after x failures\" )\n            | Opt( setWarning, \"warning name\" )\n                [\"-w\"][\"--warn\"]\n                ( \"enable warnings\" )\n            | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, \"yes|no\" )\n                [\"-d\"][\"--durations\"]\n                ( \"show test durations\" )\n            | Opt( config.minDuration, \"seconds\" )\n                [\"-D\"][\"--min-duration\"]\n                ( \"show test durations for tests taking at least the given number of seconds\" )\n            | Opt( loadTestNamesFromFile, \"filename\" )\n                [\"-f\"][\"--input-file\"]\n                ( \"load test names to run from a file\" )\n            | Opt( config.filenamesAsTags )\n                [\"-#\"][\"--filenames-as-tags\"]\n                ( \"adds a tag for the filename\" )\n            | Opt( config.sectionsToRun, \"section name\" )\n                [\"-c\"][\"--section\"]\n                ( \"specify section to run\" )\n            | Opt( setVerbosity, \"quiet|normal|high\" )\n                [\"-v\"][\"--verbosity\"]\n                ( \"set output verbosity\" )\n            | Opt( config.listTestNamesOnly )\n                [\"--list-test-names-only\"]\n                ( \"list all/matching test cases names only\" )\n            | Opt( config.listReporters )\n                [\"--list-reporters\"]\n                ( \"list all reporters\" )\n            | Opt( setTestOrder, \"decl|lex|rand\" )\n                [\"--order\"]\n                ( \"test case order (defaults to decl)\" )\n            | Opt( setRngSeed, \"'time'|number\" )\n                [\"--rng-seed\"]\n                ( \"set a specific seed for random numbers\" )\n            | Opt( setColourUsage, \"yes|no\" )\n                [\"--use-colour\"]\n                ( \"should output be colourised\" )\n            | Opt( config.libIdentify )\n                [\"--libidentify\"]\n                ( \"report name and version according to libidentify standard\" )\n            | Opt( setWaitForKeypress, \"never|start|exit|both\" )\n                [\"--wait-for-keypress\"]\n                ( \"waits for a keypress before exiting\" )\n            | Opt( config.benchmarkSamples, \"samples\" )\n                [\"--benchmark-samples\"]\n                ( \"number of samples to collect (default: 100)\" )\n            | Opt( config.benchmarkResamples, \"resamples\" )\n                [\"--benchmark-resamples\"]\n                ( \"number of resamples for the bootstrap (default: 100000)\" )\n            | Opt( config.benchmarkConfidenceInterval, \"confidence interval\" )\n                [\"--benchmark-confidence-interval\"]\n                ( \"confidence interval for the bootstrap (between 0 and 1, default: 0.95)\" )\n            | Opt( config.benchmarkNoAnalysis )\n                [\"--benchmark-no-analysis\"]\n                ( \"perform only measurements; do not perform any analysis\" )\n            | Opt( config.benchmarkWarmupTime, \"benchmarkWarmupTime\" )\n                [\"--benchmark-warmup-time\"]\n                ( \"amount of time in milliseconds spent on warming up each test (default: 100)\" )\n            | Arg( config.testsOrTags, \"test name|pattern|tags\" )\n                ( \"which test or tests to use\" );\n\n        return cli;\n    }\n\n} // end namespace Catch\n// end catch_commandline.cpp\n// start catch_common.cpp\n\n#include <cstring>\n#include <ostream>\n\nnamespace Catch {\n\n    bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept {\n        return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);\n    }\n    bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept {\n        // We can assume that the same file will usually have the same pointer.\n        // Thus, if the pointers are the same, there is no point in calling the strcmp\n        return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0));\n    }\n\n    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {\n#ifndef __GNUG__\n        os << info.file << '(' << info.line << ')';\n#else\n        os << info.file << ':' << info.line;\n#endif\n        return os;\n    }\n\n    std::string StreamEndStop::operator+() const {\n        return std::string();\n    }\n\n    NonCopyable::NonCopyable() = default;\n    NonCopyable::~NonCopyable() = default;\n\n}\n// end catch_common.cpp\n// start catch_config.cpp\n\nnamespace Catch {\n\n    Config::Config( ConfigData const& data )\n    :   m_data( data ),\n        m_stream( openStream() )\n    {\n        // We need to trim filter specs to avoid trouble with superfluous\n        // whitespace (esp. important for bdd macros, as those are manually\n        // aligned with whitespace).\n\n        for (auto& elem : m_data.testsOrTags) {\n            elem = trim(elem);\n        }\n        for (auto& elem : m_data.sectionsToRun) {\n            elem = trim(elem);\n        }\n\n        TestSpecParser parser(ITagAliasRegistry::get());\n        if (!m_data.testsOrTags.empty()) {\n            m_hasTestFilters = true;\n            for (auto const& testOrTags : m_data.testsOrTags) {\n                parser.parse(testOrTags);\n            }\n        }\n        m_testSpec = parser.testSpec();\n    }\n\n    std::string const& Config::getFilename() const {\n        return m_data.outputFilename ;\n    }\n\n    bool Config::listTests() const          { return m_data.listTests; }\n    bool Config::listTestNamesOnly() const  { return m_data.listTestNamesOnly; }\n    bool Config::listTags() const           { return m_data.listTags; }\n    bool Config::listReporters() const      { return m_data.listReporters; }\n\n    std::string Config::getProcessName() const { return m_data.processName; }\n    std::string const& Config::getReporterName() const { return m_data.reporterName; }\n\n    std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }\n    std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }\n\n    TestSpec const& Config::testSpec() const { return m_testSpec; }\n    bool Config::hasTestFilters() const { return m_hasTestFilters; }\n\n    bool Config::showHelp() const { return m_data.showHelp; }\n\n    // IConfig interface\n    bool Config::allowThrows() const                   { return !m_data.noThrow; }\n    std::ostream& Config::stream() const               { return m_stream->stream(); }\n    std::string Config::name() const                   { return m_data.name.empty() ? m_data.processName : m_data.name; }\n    bool Config::includeSuccessfulResults() const      { return m_data.showSuccessfulTests; }\n    bool Config::warnAboutMissingAssertions() const    { return !!(m_data.warnings & WarnAbout::NoAssertions); }\n    bool Config::warnAboutNoTests() const              { return !!(m_data.warnings & WarnAbout::NoTests); }\n    ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }\n    double Config::minDuration() const                 { return m_data.minDuration; }\n    RunTests::InWhatOrder Config::runOrder() const     { return m_data.runOrder; }\n    unsigned int Config::rngSeed() const               { return m_data.rngSeed; }\n    UseColour::YesOrNo Config::useColour() const       { return m_data.useColour; }\n    bool Config::shouldDebugBreak() const              { return m_data.shouldDebugBreak; }\n    int Config::abortAfter() const                     { return m_data.abortAfter; }\n    bool Config::showInvisibles() const                { return m_data.showInvisibles; }\n    Verbosity Config::verbosity() const                { return m_data.verbosity; }\n\n    bool Config::benchmarkNoAnalysis() const                      { return m_data.benchmarkNoAnalysis; }\n    int Config::benchmarkSamples() const                          { return m_data.benchmarkSamples; }\n    double Config::benchmarkConfidenceInterval() const            { return m_data.benchmarkConfidenceInterval; }\n    unsigned int Config::benchmarkResamples() const               { return m_data.benchmarkResamples; }\n    std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); }\n\n    IStream const* Config::openStream() {\n        return Catch::makeStream(m_data.outputFilename);\n    }\n\n} // end namespace Catch\n// end catch_config.cpp\n// start catch_console_colour.cpp\n\n#if defined(__clang__)\n#    pragma clang diagnostic push\n#    pragma clang diagnostic ignored \"-Wexit-time-destructors\"\n#endif\n\n// start catch_errno_guard.h\n\nnamespace Catch {\n\n    class ErrnoGuard {\n    public:\n        ErrnoGuard();\n        ~ErrnoGuard();\n    private:\n        int m_oldErrno;\n    };\n\n}\n\n// end catch_errno_guard.h\n// start catch_windows_h_proxy.h\n\n\n#if defined(CATCH_PLATFORM_WINDOWS)\n\n#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)\n#  define CATCH_DEFINED_NOMINMAX\n#  define NOMINMAX\n#endif\n#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)\n#  define CATCH_DEFINED_WIN32_LEAN_AND_MEAN\n#  define WIN32_LEAN_AND_MEAN\n#endif\n\n#ifdef __AFXDLL\n#include <AfxWin.h>\n#else\n#include <windows.h>\n#endif\n\n#ifdef CATCH_DEFINED_NOMINMAX\n#  undef NOMINMAX\n#endif\n#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN\n#  undef WIN32_LEAN_AND_MEAN\n#endif\n\n#endif // defined(CATCH_PLATFORM_WINDOWS)\n\n// end catch_windows_h_proxy.h\n#include <sstream>\n\nnamespace Catch {\n    namespace {\n\n        struct IColourImpl {\n            virtual ~IColourImpl() = default;\n            virtual void use( Colour::Code _colourCode ) = 0;\n        };\n\n        struct NoColourImpl : IColourImpl {\n            void use( Colour::Code ) override {}\n\n            static IColourImpl* instance() {\n                static NoColourImpl s_instance;\n                return &s_instance;\n            }\n        };\n\n    } // anon namespace\n} // namespace Catch\n\n#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI )\n#   ifdef CATCH_PLATFORM_WINDOWS\n#       define CATCH_CONFIG_COLOUR_WINDOWS\n#   else\n#       define CATCH_CONFIG_COLOUR_ANSI\n#   endif\n#endif\n\n#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////\n\nnamespace Catch {\nnamespace {\n\n    class Win32ColourImpl : public IColourImpl {\n    public:\n        Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )\n        {\n            CONSOLE_SCREEN_BUFFER_INFO csbiInfo;\n            GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo );\n            originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY );\n            originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );\n        }\n\n        void use( Colour::Code _colourCode ) override {\n            switch( _colourCode ) {\n                case Colour::None:      return setTextAttribute( originalForegroundAttributes );\n                case Colour::White:     return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );\n                case Colour::Red:       return setTextAttribute( FOREGROUND_RED );\n                case Colour::Green:     return setTextAttribute( FOREGROUND_GREEN );\n                case Colour::Blue:      return setTextAttribute( FOREGROUND_BLUE );\n                case Colour::Cyan:      return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );\n                case Colour::Yellow:    return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );\n                case Colour::Grey:      return setTextAttribute( 0 );\n\n                case Colour::LightGrey:     return setTextAttribute( FOREGROUND_INTENSITY );\n                case Colour::BrightRed:     return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );\n                case Colour::BrightGreen:   return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );\n                case Colour::BrightWhite:   return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );\n                case Colour::BrightYellow:  return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN );\n\n                case Colour::Bright: CATCH_INTERNAL_ERROR( \"not a colour\" );\n\n                default:\n                    CATCH_ERROR( \"Unknown colour requested\" );\n            }\n        }\n\n    private:\n        void setTextAttribute( WORD _textAttribute ) {\n            SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes );\n        }\n        HANDLE stdoutHandle;\n        WORD originalForegroundAttributes;\n        WORD originalBackgroundAttributes;\n    };\n\n    IColourImpl* platformColourInstance() {\n        static Win32ColourImpl s_instance;\n\n        IConfigPtr config = getCurrentContext().getConfig();\n        UseColour::YesOrNo colourMode = config\n            ? config->useColour()\n            : UseColour::Auto;\n        if( colourMode == UseColour::Auto )\n            colourMode = UseColour::Yes;\n        return colourMode == UseColour::Yes\n            ? &s_instance\n            : NoColourImpl::instance();\n    }\n\n} // end anon namespace\n} // end namespace Catch\n\n#elif defined( CATCH_CONFIG_COLOUR_ANSI ) //////////////////////////////////////\n\n#include <unistd.h>\n\nnamespace Catch {\nnamespace {\n\n    // use POSIX/ ANSI console terminal codes\n    // Thanks to Adam Strzelecki for original contribution\n    // (http://github.com/nanoant)\n    // https://github.com/philsquared/Catch/pull/131\n    class PosixColourImpl : public IColourImpl {\n    public:\n        void use( Colour::Code _colourCode ) override {\n            switch( _colourCode ) {\n                case Colour::None:\n                case Colour::White:     return setColour( \"[0m\" );\n                case Colour::Red:       return setColour( \"[0;31m\" );\n                case Colour::Green:     return setColour( \"[0;32m\" );\n                case Colour::Blue:      return setColour( \"[0;34m\" );\n                case Colour::Cyan:      return setColour( \"[0;36m\" );\n                case Colour::Yellow:    return setColour( \"[0;33m\" );\n                case Colour::Grey:      return setColour( \"[1;30m\" );\n\n                case Colour::LightGrey:     return setColour( \"[0;37m\" );\n                case Colour::BrightRed:     return setColour( \"[1;31m\" );\n                case Colour::BrightGreen:   return setColour( \"[1;32m\" );\n                case Colour::BrightWhite:   return setColour( \"[1;37m\" );\n                case Colour::BrightYellow:  return setColour( \"[1;33m\" );\n\n                case Colour::Bright: CATCH_INTERNAL_ERROR( \"not a colour\" );\n                default: CATCH_INTERNAL_ERROR( \"Unknown colour requested\" );\n            }\n        }\n        static IColourImpl* instance() {\n            static PosixColourImpl s_instance;\n            return &s_instance;\n        }\n\n    private:\n        void setColour( const char* _escapeCode ) {\n            getCurrentContext().getConfig()->stream()\n                << '\\033' << _escapeCode;\n        }\n    };\n\n    bool useColourOnPlatform() {\n        return\n#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)\n            !isDebuggerActive() &&\n#endif\n#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__))\n            isatty(STDOUT_FILENO)\n#else\n            false\n#endif\n            ;\n    }\n    IColourImpl* platformColourInstance() {\n        ErrnoGuard guard;\n        IConfigPtr config = getCurrentContext().getConfig();\n        UseColour::YesOrNo colourMode = config\n            ? config->useColour()\n            : UseColour::Auto;\n        if( colourMode == UseColour::Auto )\n            colourMode = useColourOnPlatform()\n                ? UseColour::Yes\n                : UseColour::No;\n        return colourMode == UseColour::Yes\n            ? PosixColourImpl::instance()\n            : NoColourImpl::instance();\n    }\n\n} // end anon namespace\n} // end namespace Catch\n\n#else  // not Windows or ANSI ///////////////////////////////////////////////\n\nnamespace Catch {\n\n    static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); }\n\n} // end namespace Catch\n\n#endif // Windows/ ANSI/ None\n\nnamespace Catch {\n\n    Colour::Colour( Code _colourCode ) { use( _colourCode ); }\n    Colour::Colour( Colour&& other ) noexcept {\n        m_moved = other.m_moved;\n        other.m_moved = true;\n    }\n    Colour& Colour::operator=( Colour&& other ) noexcept {\n        m_moved = other.m_moved;\n        other.m_moved  = true;\n        return *this;\n    }\n\n    Colour::~Colour(){ if( !m_moved ) use( None ); }\n\n    void Colour::use( Code _colourCode ) {\n        static IColourImpl* impl = platformColourInstance();\n        // Strictly speaking, this cannot possibly happen.\n        // However, under some conditions it does happen (see #1626),\n        // and this change is small enough that we can let practicality\n        // triumph over purity in this case.\n        if (impl != nullptr) {\n            impl->use( _colourCode );\n        }\n    }\n\n    std::ostream& operator << ( std::ostream& os, Colour const& ) {\n        return os;\n    }\n\n} // end namespace Catch\n\n#if defined(__clang__)\n#    pragma clang diagnostic pop\n#endif\n\n// end catch_console_colour.cpp\n// start catch_context.cpp\n\nnamespace Catch {\n\n    class Context : public IMutableContext, NonCopyable {\n\n    public: // IContext\n        IResultCapture* getResultCapture() override {\n            return m_resultCapture;\n        }\n        IRunner* getRunner() override {\n            return m_runner;\n        }\n\n        IConfigPtr const& getConfig() const override {\n            return m_config;\n        }\n\n        ~Context() override;\n\n    public: // IMutableContext\n        void setResultCapture( IResultCapture* resultCapture ) override {\n            m_resultCapture = resultCapture;\n        }\n        void setRunner( IRunner* runner ) override {\n            m_runner = runner;\n        }\n        void setConfig( IConfigPtr const& config ) override {\n            m_config = config;\n        }\n\n        friend IMutableContext& getCurrentMutableContext();\n\n    private:\n        IConfigPtr m_config;\n        IRunner* m_runner = nullptr;\n        IResultCapture* m_resultCapture = nullptr;\n    };\n\n    IMutableContext *IMutableContext::currentContext = nullptr;\n\n    void IMutableContext::createContext()\n    {\n        currentContext = new Context();\n    }\n\n    void cleanUpContext() {\n        delete IMutableContext::currentContext;\n        IMutableContext::currentContext = nullptr;\n    }\n    IContext::~IContext() = default;\n    IMutableContext::~IMutableContext() = default;\n    Context::~Context() = default;\n\n    SimplePcg32& rng() {\n        static SimplePcg32 s_rng;\n        return s_rng;\n    }\n\n}\n// end catch_context.cpp\n// start catch_debug_console.cpp\n\n// start catch_debug_console.h\n\n#include <string>\n\nnamespace Catch {\n    void writeToDebugConsole( std::string const& text );\n}\n\n// end catch_debug_console.h\n#if defined(CATCH_CONFIG_ANDROID_LOGWRITE)\n#include <android/log.h>\n\n    namespace Catch {\n        void writeToDebugConsole( std::string const& text ) {\n            __android_log_write( ANDROID_LOG_DEBUG, \"Catch\", text.c_str() );\n        }\n    }\n\n#elif defined(CATCH_PLATFORM_WINDOWS)\n\n    namespace Catch {\n        void writeToDebugConsole( std::string const& text ) {\n            ::OutputDebugStringA( text.c_str() );\n        }\n    }\n\n#else\n\n    namespace Catch {\n        void writeToDebugConsole( std::string const& text ) {\n            // !TBD: Need a version for Mac/ XCode and other IDEs\n            Catch::cout() << text;\n        }\n    }\n\n#endif // Platform\n// end catch_debug_console.cpp\n// start catch_debugger.cpp\n\n#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)\n\n#  include <cassert>\n#  include <sys/types.h>\n#  include <unistd.h>\n#  include <cstddef>\n#  include <ostream>\n\n#ifdef __apple_build_version__\n    // These headers will only compile with AppleClang (XCode)\n    // For other compilers (Clang, GCC, ... ) we need to exclude them\n#  include <sys/sysctl.h>\n#endif\n\n    namespace Catch {\n        #ifdef __apple_build_version__\n        // The following function is taken directly from the following technical note:\n        // https://developer.apple.com/library/archive/qa/qa1361/_index.html\n\n        // Returns true if the current process is being debugged (either\n        // running under the debugger or has a debugger attached post facto).\n        bool isDebuggerActive(){\n            int                 mib[4];\n            struct kinfo_proc   info;\n            std::size_t         size;\n\n            // Initialize the flags so that, if sysctl fails for some bizarre\n            // reason, we get a predictable result.\n\n            info.kp_proc.p_flag = 0;\n\n            // Initialize mib, which tells sysctl the info we want, in this case\n            // we're looking for information about a specific process ID.\n\n            mib[0] = CTL_KERN;\n            mib[1] = KERN_PROC;\n            mib[2] = KERN_PROC_PID;\n            mib[3] = getpid();\n\n            // Call sysctl.\n\n            size = sizeof(info);\n            if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) {\n                Catch::cerr() << \"\\n** Call to sysctl failed - unable to determine if debugger is active **\\n\" << std::endl;\n                return false;\n            }\n\n            // We're being debugged if the P_TRACED flag is set.\n\n            return ( (info.kp_proc.p_flag & P_TRACED) != 0 );\n        }\n        #else\n        bool isDebuggerActive() {\n            // We need to find another way to determine this for non-appleclang compilers on macOS\n            return false;\n        }\n        #endif\n    } // namespace Catch\n\n#elif defined(CATCH_PLATFORM_LINUX)\n    #include <fstream>\n    #include <string>\n\n    namespace Catch{\n        // The standard POSIX way of detecting a debugger is to attempt to\n        // ptrace() the process, but this needs to be done from a child and not\n        // this process itself to still allow attaching to this process later\n        // if wanted, so is rather heavy. Under Linux we have the PID of the\n        // \"debugger\" (which doesn't need to be gdb, of course, it could also\n        // be strace, for example) in /proc/$PID/status, so just get it from\n        // there instead.\n        bool isDebuggerActive(){\n            // Libstdc++ has a bug, where std::ifstream sets errno to 0\n            // This way our users can properly assert over errno values\n            ErrnoGuard guard;\n            std::ifstream in(\"/proc/self/status\");\n            for( std::string line; std::getline(in, line); ) {\n                static const int PREFIX_LEN = 11;\n                if( line.compare(0, PREFIX_LEN, \"TracerPid:\\t\") == 0 ) {\n                    // We're traced if the PID is not 0 and no other PID starts\n                    // with 0 digit, so it's enough to check for just a single\n                    // character.\n                    return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';\n                }\n            }\n\n            return false;\n        }\n    } // namespace Catch\n#elif defined(_MSC_VER)\n    extern \"C\" __declspec(dllimport) int __stdcall IsDebuggerPresent();\n    namespace Catch {\n        bool isDebuggerActive() {\n            return IsDebuggerPresent() != 0;\n        }\n    }\n#elif defined(__MINGW32__)\n    extern \"C\" __declspec(dllimport) int __stdcall IsDebuggerPresent();\n    namespace Catch {\n        bool isDebuggerActive() {\n            return IsDebuggerPresent() != 0;\n        }\n    }\n#else\n    namespace Catch {\n       bool isDebuggerActive() { return false; }\n    }\n#endif // Platform\n// end catch_debugger.cpp\n// start catch_decomposer.cpp\n\nnamespace Catch {\n\n    ITransientExpression::~ITransientExpression() = default;\n\n    void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) {\n        if( lhs.size() + rhs.size() < 40 &&\n                lhs.find('\\n') == std::string::npos &&\n                rhs.find('\\n') == std::string::npos )\n            os << lhs << \" \" << op << \" \" << rhs;\n        else\n            os << lhs << \"\\n\" << op << \"\\n\" << rhs;\n    }\n}\n// end catch_decomposer.cpp\n// start catch_enforce.cpp\n\n#include <stdexcept>\n\nnamespace Catch {\n#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)\n    [[noreturn]]\n    void throw_exception(std::exception const& e) {\n        Catch::cerr() << \"Catch will terminate because it needed to throw an exception.\\n\"\n                      << \"The message was: \" << e.what() << '\\n';\n        std::terminate();\n    }\n#endif\n\n    [[noreturn]]\n    void throw_logic_error(std::string const& msg) {\n        throw_exception(std::logic_error(msg));\n    }\n\n    [[noreturn]]\n    void throw_domain_error(std::string const& msg) {\n        throw_exception(std::domain_error(msg));\n    }\n\n    [[noreturn]]\n    void throw_runtime_error(std::string const& msg) {\n        throw_exception(std::runtime_error(msg));\n    }\n\n} // namespace Catch;\n// end catch_enforce.cpp\n// start catch_enum_values_registry.cpp\n// start catch_enum_values_registry.h\n\n#include <vector>\n#include <memory>\n\nnamespace Catch {\n\n    namespace Detail {\n\n        std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values );\n\n        class EnumValuesRegistry : public IMutableEnumValuesRegistry {\n\n            std::vector<std::unique_ptr<EnumInfo>> m_enumInfos;\n\n            EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values) override;\n        };\n\n        std::vector<StringRef> parseEnums( StringRef enums );\n\n    } // Detail\n\n} // Catch\n\n// end catch_enum_values_registry.h\n\n#include <map>\n#include <cassert>\n\nnamespace Catch {\n\n    IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() {}\n\n    namespace Detail {\n\n        namespace {\n            // Extracts the actual name part of an enum instance\n            // In other words, it returns the Blue part of Bikeshed::Colour::Blue\n            StringRef extractInstanceName(StringRef enumInstance) {\n                // Find last occurrence of \":\"\n                size_t name_start = enumInstance.size();\n                while (name_start > 0 && enumInstance[name_start - 1] != ':') {\n                    --name_start;\n                }\n                return enumInstance.substr(name_start, enumInstance.size() - name_start);\n            }\n        }\n\n        std::vector<StringRef> parseEnums( StringRef enums ) {\n            auto enumValues = splitStringRef( enums, ',' );\n            std::vector<StringRef> parsed;\n            parsed.reserve( enumValues.size() );\n            for( auto const& enumValue : enumValues ) {\n                parsed.push_back(trim(extractInstanceName(enumValue)));\n            }\n            return parsed;\n        }\n\n        EnumInfo::~EnumInfo() {}\n\n        StringRef EnumInfo::lookup( int value ) const {\n            for( auto const& valueToName : m_values ) {\n                if( valueToName.first == value )\n                    return valueToName.second;\n            }\n            return \"{** unexpected enum value **}\"_sr;\n        }\n\n        std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {\n            std::unique_ptr<EnumInfo> enumInfo( new EnumInfo );\n            enumInfo->m_name = enumName;\n            enumInfo->m_values.reserve( values.size() );\n\n            const auto valueNames = Catch::Detail::parseEnums( allValueNames );\n            assert( valueNames.size() == values.size() );\n            std::size_t i = 0;\n            for( auto value : values )\n                enumInfo->m_values.emplace_back(value, valueNames[i++]);\n\n            return enumInfo;\n        }\n\n        EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {\n            m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values));\n            return *m_enumInfos.back();\n        }\n\n    } // Detail\n} // Catch\n\n// end catch_enum_values_registry.cpp\n// start catch_errno_guard.cpp\n\n#include <cerrno>\n\nnamespace Catch {\n        ErrnoGuard::ErrnoGuard():m_oldErrno(errno){}\n        ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; }\n}\n// end catch_errno_guard.cpp\n// start catch_exception_translator_registry.cpp\n\n// start catch_exception_translator_registry.h\n\n#include <vector>\n#include <string>\n#include <memory>\n\nnamespace Catch {\n\n    class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {\n    public:\n        ~ExceptionTranslatorRegistry();\n        virtual void registerTranslator( const IExceptionTranslator* translator );\n        std::string translateActiveException() const override;\n        std::string tryTranslators() const;\n\n    private:\n        std::vector<std::unique_ptr<IExceptionTranslator const>> m_translators;\n    };\n}\n\n// end catch_exception_translator_registry.h\n#ifdef __OBJC__\n#import \"Foundation/Foundation.h\"\n#endif\n\nnamespace Catch {\n\n    ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() {\n    }\n\n    void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) {\n        m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) );\n    }\n\n#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)\n    std::string ExceptionTranslatorRegistry::translateActiveException() const {\n        try {\n#ifdef __OBJC__\n            // In Objective-C try objective-c exceptions first\n            @try {\n                return tryTranslators();\n            }\n            @catch (NSException *exception) {\n                return Catch::Detail::stringify( [exception description] );\n            }\n#else\n            // Compiling a mixed mode project with MSVC means that CLR\n            // exceptions will be caught in (...) as well. However, these\n            // do not fill-in std::current_exception and thus lead to crash\n            // when attempting rethrow.\n            // /EHa switch also causes structured exceptions to be caught\n            // here, but they fill-in current_exception properly, so\n            // at worst the output should be a little weird, instead of\n            // causing a crash.\n            if (std::current_exception() == nullptr) {\n                return \"Non C++ exception. Possibly a CLR exception.\";\n            }\n            return tryTranslators();\n#endif\n        }\n        catch( TestFailureException& ) {\n            std::rethrow_exception(std::current_exception());\n        }\n        catch( std::exception& ex ) {\n            return ex.what();\n        }\n        catch( std::string& msg ) {\n            return msg;\n        }\n        catch( const char* msg ) {\n            return msg;\n        }\n        catch(...) {\n            return \"Unknown exception\";\n        }\n    }\n\n    std::string ExceptionTranslatorRegistry::tryTranslators() const {\n        if (m_translators.empty()) {\n            std::rethrow_exception(std::current_exception());\n        } else {\n            return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end());\n        }\n    }\n\n#else // ^^ Exceptions are enabled // Exceptions are disabled vv\n    std::string ExceptionTranslatorRegistry::translateActiveException() const {\n        CATCH_INTERNAL_ERROR(\"Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!\");\n    }\n\n    std::string ExceptionTranslatorRegistry::tryTranslators() const {\n        CATCH_INTERNAL_ERROR(\"Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!\");\n    }\n#endif\n\n}\n// end catch_exception_translator_registry.cpp\n// start catch_fatal_condition.cpp\n\n#include <algorithm>\n\n#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS )\n\nnamespace Catch {\n\n    // If neither SEH nor signal handling is required, the handler impls\n    // do not have to do anything, and can be empty.\n    void FatalConditionHandler::engage_platform() {}\n    void FatalConditionHandler::disengage_platform() {}\n    FatalConditionHandler::FatalConditionHandler() = default;\n    FatalConditionHandler::~FatalConditionHandler() = default;\n\n} // end namespace Catch\n\n#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS\n\n#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS )\n#error \"Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time\"\n#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS\n\n#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )\n\nnamespace {\n    //! Signals fatal error message to the run context\n    void reportFatal( char const * const message ) {\n        Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );\n    }\n\n    //! Minimal size Catch2 needs for its own fatal error handling.\n    //! Picked anecdotally, so it might not be sufficient on all\n    //! platforms, and for all configurations.\n    constexpr std::size_t minStackSizeForErrors = 32 * 1024;\n} // end unnamed namespace\n\n#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS\n\n#if defined( CATCH_CONFIG_WINDOWS_SEH )\n\nnamespace Catch {\n\n    struct SignalDefs { DWORD id; const char* name; };\n\n    // There is no 1-1 mapping between signals and windows exceptions.\n    // Windows can easily distinguish between SO and SigSegV,\n    // but SigInt, SigTerm, etc are handled differently.\n    static SignalDefs signalDefs[] = {\n        { static_cast<DWORD>(EXCEPTION_ILLEGAL_INSTRUCTION),  \"SIGILL - Illegal instruction signal\" },\n        { static_cast<DWORD>(EXCEPTION_STACK_OVERFLOW), \"SIGSEGV - Stack overflow\" },\n        { static_cast<DWORD>(EXCEPTION_ACCESS_VIOLATION), \"SIGSEGV - Segmentation violation signal\" },\n        { static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), \"Divide by zero error\" },\n    };\n\n    static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {\n        for (auto const& def : signalDefs) {\n            if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {\n                reportFatal(def.name);\n            }\n        }\n        // If its not an exception we care about, pass it along.\n        // This stops us from eating debugger breaks etc.\n        return EXCEPTION_CONTINUE_SEARCH;\n    }\n\n    // Since we do not support multiple instantiations, we put these\n    // into global variables and rely on cleaning them up in outlined\n    // constructors/destructors\n    static PVOID exceptionHandlerHandle = nullptr;\n\n    // For MSVC, we reserve part of the stack memory for handling\n    // memory overflow structured exception.\n    FatalConditionHandler::FatalConditionHandler() {\n        ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors);\n        if (!SetThreadStackGuarantee(&guaranteeSize)) {\n            // We do not want to fully error out, because needing\n            // the stack reserve should be rare enough anyway.\n            Catch::cerr()\n                << \"Failed to reserve piece of stack.\"\n                << \" Stack overflows will not be reported successfully.\";\n        }\n    }\n\n    // We do not attempt to unset the stack guarantee, because\n    // Windows does not support lowering the stack size guarantee.\n    FatalConditionHandler::~FatalConditionHandler() = default;\n\n    void FatalConditionHandler::engage_platform() {\n        // Register as first handler in current chain\n        exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);\n        if (!exceptionHandlerHandle) {\n            CATCH_RUNTIME_ERROR(\"Could not register vectored exception handler\");\n        }\n    }\n\n    void FatalConditionHandler::disengage_platform() {\n        if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) {\n            CATCH_RUNTIME_ERROR(\"Could not unregister vectored exception handler\");\n        }\n        exceptionHandlerHandle = nullptr;\n    }\n\n} // end namespace Catch\n\n#endif // CATCH_CONFIG_WINDOWS_SEH\n\n#if defined( CATCH_CONFIG_POSIX_SIGNALS )\n\n#include <signal.h>\n\nnamespace Catch {\n\n    struct SignalDefs {\n        int id;\n        const char* name;\n    };\n\n    static SignalDefs signalDefs[] = {\n        { SIGINT,  \"SIGINT - Terminal interrupt signal\" },\n        { SIGILL,  \"SIGILL - Illegal instruction signal\" },\n        { SIGFPE,  \"SIGFPE - Floating point error signal\" },\n        { SIGSEGV, \"SIGSEGV - Segmentation violation signal\" },\n        { SIGTERM, \"SIGTERM - Termination request signal\" },\n        { SIGABRT, \"SIGABRT - Abort (abnormal termination) signal\" }\n    };\n\n// Older GCCs trigger -Wmissing-field-initializers for T foo = {}\n// which is zero initialization, but not explicit. We want to avoid\n// that.\n#if defined(__GNUC__)\n#    pragma GCC diagnostic push\n#    pragma GCC diagnostic ignored \"-Wmissing-field-initializers\"\n#endif\n\n    static char* altStackMem = nullptr;\n    static std::size_t altStackSize = 0;\n    static stack_t oldSigStack{};\n    static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{};\n\n    static void restorePreviousSignalHandlers() {\n        // We set signal handlers back to the previous ones. Hopefully\n        // nobody overwrote them in the meantime, and doesn't expect\n        // their signal handlers to live past ours given that they\n        // installed them after ours..\n        for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {\n            sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);\n        }\n        // Return the old stack\n        sigaltstack(&oldSigStack, nullptr);\n    }\n\n    static void handleSignal( int sig ) {\n        char const * name = \"<unknown signal>\";\n        for (auto const& def : signalDefs) {\n            if (sig == def.id) {\n                name = def.name;\n                break;\n            }\n        }\n        // We need to restore previous signal handlers and let them do\n        // their thing, so that the users can have the debugger break\n        // when a signal is raised, and so on.\n        restorePreviousSignalHandlers();\n        reportFatal( name );\n        raise( sig );\n    }\n\n    FatalConditionHandler::FatalConditionHandler() {\n        assert(!altStackMem && \"Cannot initialize POSIX signal handler when one already exists\");\n        if (altStackSize == 0) {\n            altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors);\n        }\n        altStackMem = new char[altStackSize]();\n    }\n\n    FatalConditionHandler::~FatalConditionHandler() {\n        delete[] altStackMem;\n        // We signal that another instance can be constructed by zeroing\n        // out the pointer.\n        altStackMem = nullptr;\n    }\n\n    void FatalConditionHandler::engage_platform() {\n        stack_t sigStack;\n        sigStack.ss_sp = altStackMem;\n        sigStack.ss_size = altStackSize;\n        sigStack.ss_flags = 0;\n        sigaltstack(&sigStack, &oldSigStack);\n        struct sigaction sa = { };\n\n        sa.sa_handler = handleSignal;\n        sa.sa_flags = SA_ONSTACK;\n        for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {\n            sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);\n        }\n    }\n\n#if defined(__GNUC__)\n#    pragma GCC diagnostic pop\n#endif\n\n    void FatalConditionHandler::disengage_platform() {\n        restorePreviousSignalHandlers();\n    }\n\n} // end namespace Catch\n\n#endif // CATCH_CONFIG_POSIX_SIGNALS\n// end catch_fatal_condition.cpp\n// start catch_generators.cpp\n\n#include <limits>\n#include <set>\n\nnamespace Catch {\n\nIGeneratorTracker::~IGeneratorTracker() {}\n\nconst char* GeneratorException::what() const noexcept {\n    return m_msg;\n}\n\nnamespace Generators {\n\n    GeneratorUntypedBase::~GeneratorUntypedBase() {}\n\n    auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {\n        return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo );\n    }\n\n} // namespace Generators\n} // namespace Catch\n// end catch_generators.cpp\n// start catch_interfaces_capture.cpp\n\nnamespace Catch {\n    IResultCapture::~IResultCapture() = default;\n}\n// end catch_interfaces_capture.cpp\n// start catch_interfaces_config.cpp\n\nnamespace Catch {\n    IConfig::~IConfig() = default;\n}\n// end catch_interfaces_config.cpp\n// start catch_interfaces_exception.cpp\n\nnamespace Catch {\n    IExceptionTranslator::~IExceptionTranslator() = default;\n    IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default;\n}\n// end catch_interfaces_exception.cpp\n// start catch_interfaces_registry_hub.cpp\n\nnamespace Catch {\n    IRegistryHub::~IRegistryHub() = default;\n    IMutableRegistryHub::~IMutableRegistryHub() = default;\n}\n// end catch_interfaces_registry_hub.cpp\n// start catch_interfaces_reporter.cpp\n\n// start catch_reporter_listening.h\n\nnamespace Catch {\n\n    class ListeningReporter : public IStreamingReporter {\n        using Reporters = std::vector<IStreamingReporterPtr>;\n        Reporters m_listeners;\n        IStreamingReporterPtr m_reporter = nullptr;\n        ReporterPreferences m_preferences;\n\n    public:\n        ListeningReporter();\n\n        void addListener( IStreamingReporterPtr&& listener );\n        void addReporter( IStreamingReporterPtr&& reporter );\n\n    public: // IStreamingReporter\n\n        ReporterPreferences getPreferences() const override;\n\n        void noMatchingTestCases( std::string const& spec ) override;\n\n        void reportInvalidArguments(std::string const&arg) override;\n\n        static std::set<Verbosity> getSupportedVerbosities();\n\n#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\n        void benchmarkPreparing(std::string const& name) override;\n        void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override;\n        void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;\n        void benchmarkFailed(std::string const&) override;\n#endif // CATCH_CONFIG_ENABLE_BENCHMARKING\n\n        void testRunStarting( TestRunInfo const& testRunInfo ) override;\n        void testGroupStarting( GroupInfo const& groupInfo ) override;\n        void testCaseStarting( TestCaseInfo const& testInfo ) override;\n        void sectionStarting( SectionInfo const& sectionInfo ) override;\n        void assertionStarting( AssertionInfo const& assertionInfo ) override;\n\n        // The return value indicates if the messages buffer should be cleared:\n        bool assertionEnded( AssertionStats const& assertionStats ) override;\n        void sectionEnded( SectionStats const& sectionStats ) override;\n        void testCaseEnded( TestCaseStats const& testCaseStats ) override;\n        void testGroupEnded( TestGroupStats const& testGroupStats ) override;\n        void testRunEnded( TestRunStats const& testRunStats ) override;\n\n        void skipTest( TestCaseInfo const& testInfo ) override;\n        bool isMulti() const override;\n\n    };\n\n} // end namespace Catch\n\n// end catch_reporter_listening.h\nnamespace Catch {\n\n    ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig )\n    :   m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}\n\n    ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream )\n    :   m_stream( &_stream ), m_fullConfig( _fullConfig ) {}\n\n    std::ostream& ReporterConfig::stream() const { return *m_stream; }\n    IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; }\n\n    TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {}\n\n    GroupInfo::GroupInfo(  std::string const& _name,\n                           std::size_t _groupIndex,\n                           std::size_t _groupsCount )\n    :   name( _name ),\n        groupIndex( _groupIndex ),\n        groupsCounts( _groupsCount )\n    {}\n\n     AssertionStats::AssertionStats( AssertionResult const& _assertionResult,\n                                     std::vector<MessageInfo> const& _infoMessages,\n                                     Totals const& _totals )\n    :   assertionResult( _assertionResult ),\n        infoMessages( _infoMessages ),\n        totals( _totals )\n    {\n        assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression;\n\n        if( assertionResult.hasMessage() ) {\n            // Copy message into messages list.\n            // !TBD This should have been done earlier, somewhere\n            MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );\n            builder << assertionResult.getMessage();\n            builder.m_info.message = builder.m_stream.str();\n\n            infoMessages.push_back( builder.m_info );\n        }\n    }\n\n     AssertionStats::~AssertionStats() = default;\n\n    SectionStats::SectionStats(  SectionInfo const& _sectionInfo,\n                                 Counts const& _assertions,\n                                 double _durationInSeconds,\n                                 bool _missingAssertions )\n    :   sectionInfo( _sectionInfo ),\n        assertions( _assertions ),\n        durationInSeconds( _durationInSeconds ),\n        missingAssertions( _missingAssertions )\n    {}\n\n    SectionStats::~SectionStats() = default;\n\n    TestCaseStats::TestCaseStats(  TestCaseInfo const& _testInfo,\n                                   Totals const& _totals,\n                                   std::string const& _stdOut,\n                                   std::string const& _stdErr,\n                                   bool _aborting )\n    : testInfo( _testInfo ),\n        totals( _totals ),\n        stdOut( _stdOut ),\n        stdErr( _stdErr ),\n        aborting( _aborting )\n    {}\n\n    TestCaseStats::~TestCaseStats() = default;\n\n    TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo,\n                                    Totals const& _totals,\n                                    bool _aborting )\n    :   groupInfo( _groupInfo ),\n        totals( _totals ),\n        aborting( _aborting )\n    {}\n\n    TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo )\n    :   groupInfo( _groupInfo ),\n        aborting( false )\n    {}\n\n    TestGroupStats::~TestGroupStats() = default;\n\n    TestRunStats::TestRunStats(   TestRunInfo const& _runInfo,\n                    Totals const& _totals,\n                    bool _aborting )\n    :   runInfo( _runInfo ),\n        totals( _totals ),\n        aborting( _aborting )\n    {}\n\n    TestRunStats::~TestRunStats() = default;\n\n    void IStreamingReporter::fatalErrorEncountered( StringRef ) {}\n    bool IStreamingReporter::isMulti() const { return false; }\n\n    IReporterFactory::~IReporterFactory() = default;\n    IReporterRegistry::~IReporterRegistry() = default;\n\n} // end namespace Catch\n// end catch_interfaces_reporter.cpp\n// start catch_interfaces_runner.cpp\n\nnamespace Catch {\n    IRunner::~IRunner() = default;\n}\n// end catch_interfaces_runner.cpp\n// start catch_interfaces_testcase.cpp\n\nnamespace Catch {\n    ITestInvoker::~ITestInvoker() = default;\n    ITestCaseRegistry::~ITestCaseRegistry() = default;\n}\n// end catch_interfaces_testcase.cpp\n// start catch_leak_detector.cpp\n\n#ifdef CATCH_CONFIG_WINDOWS_CRTDBG\n#include <crtdbg.h>\n\nnamespace Catch {\n\n    LeakDetector::LeakDetector() {\n        int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);\n        flag |= _CRTDBG_LEAK_CHECK_DF;\n        flag |= _CRTDBG_ALLOC_MEM_DF;\n        _CrtSetDbgFlag(flag);\n        _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);\n        _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);\n        // Change this to leaking allocation's number to break there\n        _CrtSetBreakAlloc(-1);\n    }\n}\n\n#else\n\n    Catch::LeakDetector::LeakDetector() {}\n\n#endif\n\nCatch::LeakDetector::~LeakDetector() {\n    Catch::cleanUp();\n}\n// end catch_leak_detector.cpp\n// start catch_list.cpp\n\n// start catch_list.h\n\n#include <set>\n\nnamespace Catch {\n\n    std::size_t listTests( Config const& config );\n\n    std::size_t listTestsNamesOnly( Config const& config );\n\n    struct TagInfo {\n        void add( std::string const& spelling );\n        std::string all() const;\n\n        std::set<std::string> spellings;\n        std::size_t count = 0;\n    };\n\n    std::size_t listTags( Config const& config );\n\n    std::size_t listReporters();\n\n    Option<std::size_t> list( std::shared_ptr<Config> const& config );\n\n} // end namespace Catch\n\n// end catch_list.h\n// start catch_text.h\n\nnamespace Catch {\n    using namespace clara::TextFlow;\n}\n\n// end catch_text.h\n#include <limits>\n#include <algorithm>\n#include <iomanip>\n\nnamespace Catch {\n\n    std::size_t listTests( Config const& config ) {\n        TestSpec const& testSpec = config.testSpec();\n        if( config.hasTestFilters() )\n            Catch::cout() << \"Matching test cases:\\n\";\n        else {\n            Catch::cout() << \"All available test cases:\\n\";\n        }\n\n        auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );\n        for( auto const& testCaseInfo : matchedTestCases ) {\n            Colour::Code colour = testCaseInfo.isHidden()\n                ? Colour::SecondaryText\n                : Colour::None;\n            Colour colourGuard( colour );\n\n            Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << \"\\n\";\n            if( config.verbosity() >= Verbosity::High ) {\n                Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl;\n                std::string description = testCaseInfo.description;\n                if( description.empty() )\n                    description = \"(NO DESCRIPTION)\";\n                Catch::cout() << Column( description ).indent(4) << std::endl;\n            }\n            if( !testCaseInfo.tags.empty() )\n                Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << \"\\n\";\n        }\n\n        if( !config.hasTestFilters() )\n            Catch::cout() << pluralise( matchedTestCases.size(), \"test case\" ) << '\\n' << std::endl;\n        else\n            Catch::cout() << pluralise( matchedTestCases.size(), \"matching test case\" ) << '\\n' << std::endl;\n        return matchedTestCases.size();\n    }\n\n    std::size_t listTestsNamesOnly( Config const& config ) {\n        TestSpec const& testSpec = config.testSpec();\n        std::size_t matchedTests = 0;\n        std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );\n        for( auto const& testCaseInfo : matchedTestCases ) {\n            matchedTests++;\n            if( startsWith( testCaseInfo.name, '#' ) )\n               Catch::cout() << '\"' << testCaseInfo.name << '\"';\n            else\n               Catch::cout() << testCaseInfo.name;\n            if ( config.verbosity() >= Verbosity::High )\n                Catch::cout() << \"\\t@\" << testCaseInfo.lineInfo;\n            Catch::cout() << std::endl;\n        }\n        return matchedTests;\n    }\n\n    void TagInfo::add( std::string const& spelling ) {\n        ++count;\n        spellings.insert( spelling );\n    }\n\n    std::string TagInfo::all() const {\n        size_t size = 0;\n        for (auto const& spelling : spellings) {\n            // Add 2 for the brackes\n            size += spelling.size() + 2;\n        }\n\n        std::string out; out.reserve(size);\n        for (auto const& spelling : spellings) {\n            out += '[';\n            out += spelling;\n            out += ']';\n        }\n        return out;\n    }\n\n    std::size_t listTags( Config const& config ) {\n        TestSpec const& testSpec = config.testSpec();\n        if( config.hasTestFilters() )\n            Catch::cout() << \"Tags for matching test cases:\\n\";\n        else {\n            Catch::cout() << \"All available tags:\\n\";\n        }\n\n        std::map<std::string, TagInfo> tagCounts;\n\n        std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );\n        for( auto const& testCase : matchedTestCases ) {\n            for( auto const& tagName : testCase.getTestCaseInfo().tags ) {\n                std::string lcaseTagName = toLower( tagName );\n                auto countIt = tagCounts.find( lcaseTagName );\n                if( countIt == tagCounts.end() )\n                    countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;\n                countIt->second.add( tagName );\n            }\n        }\n\n        for( auto const& tagCount : tagCounts ) {\n            ReusableStringStream rss;\n            rss << \"  \" << std::setw(2) << tagCount.second.count << \"  \";\n            auto str = rss.str();\n            auto wrapper = Column( tagCount.second.all() )\n                                                    .initialIndent( 0 )\n                                                    .indent( str.size() )\n                                                    .width( CATCH_CONFIG_CONSOLE_WIDTH-10 );\n            Catch::cout() << str << wrapper << '\\n';\n        }\n        Catch::cout() << pluralise( tagCounts.size(), \"tag\" ) << '\\n' << std::endl;\n        return tagCounts.size();\n    }\n\n    std::size_t listReporters() {\n        Catch::cout() << \"Available reporters:\\n\";\n        IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();\n        std::size_t maxNameLen = 0;\n        for( auto const& factoryKvp : factories )\n            maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() );\n\n        for( auto const& factoryKvp : factories ) {\n            Catch::cout()\n                    << Column( factoryKvp.first + \":\" )\n                            .indent(2)\n                            .width( 5+maxNameLen )\n                    +  Column( factoryKvp.second->getDescription() )\n                            .initialIndent(0)\n                            .indent(2)\n                            .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 )\n                    << \"\\n\";\n        }\n        Catch::cout() << std::endl;\n        return factories.size();\n    }\n\n    Option<std::size_t> list( std::shared_ptr<Config> const& config ) {\n        Option<std::size_t> listedCount;\n        getCurrentMutableContext().setConfig( config );\n        if( config->listTests() )\n            listedCount = listedCount.valueOr(0) + listTests( *config );\n        if( config->listTestNamesOnly() )\n            listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config );\n        if( config->listTags() )\n            listedCount = listedCount.valueOr(0) + listTags( *config );\n        if( config->listReporters() )\n            listedCount = listedCount.valueOr(0) + listReporters();\n        return listedCount;\n    }\n\n} // end namespace Catch\n// end catch_list.cpp\n// start catch_matchers.cpp\n\nnamespace Catch {\nnamespace Matchers {\n    namespace Impl {\n\n        std::string MatcherUntypedBase::toString() const {\n            if( m_cachedToString.empty() )\n                m_cachedToString = describe();\n            return m_cachedToString;\n        }\n\n        MatcherUntypedBase::~MatcherUntypedBase() = default;\n\n    } // namespace Impl\n} // namespace Matchers\n\nusing namespace Matchers;\nusing Matchers::Impl::MatcherBase;\n\n} // namespace Catch\n// end catch_matchers.cpp\n// start catch_matchers_exception.cpp\n\nnamespace Catch {\nnamespace Matchers {\nnamespace Exception {\n\nbool ExceptionMessageMatcher::match(std::exception const& ex) const {\n    return ex.what() == m_message;\n}\n\nstd::string ExceptionMessageMatcher::describe() const {\n    return \"exception message matches \\\"\" + m_message + \"\\\"\";\n}\n\n}\nException::ExceptionMessageMatcher Message(std::string const& message) {\n    return Exception::ExceptionMessageMatcher(message);\n}\n\n// namespace Exception\n} // namespace Matchers\n} // namespace Catch\n// end catch_matchers_exception.cpp\n// start catch_matchers_floating.cpp\n\n// start catch_polyfills.hpp\n\nnamespace Catch {\n    bool isnan(float f);\n    bool isnan(double d);\n}\n\n// end catch_polyfills.hpp\n// start catch_to_string.hpp\n\n#include <string>\n\nnamespace Catch {\n    template <typename T>\n    std::string to_string(T const& t) {\n#if defined(CATCH_CONFIG_CPP11_TO_STRING)\n        return std::to_string(t);\n#else\n        ReusableStringStream rss;\n        rss << t;\n        return rss.str();\n#endif\n    }\n} // end namespace Catch\n\n// end catch_to_string.hpp\n#include <algorithm>\n#include <cmath>\n#include <cstdlib>\n#include <cstdint>\n#include <cstring>\n#include <sstream>\n#include <type_traits>\n#include <iomanip>\n#include <limits>\n\nnamespace Catch {\nnamespace {\n\n    int32_t convert(float f) {\n        static_assert(sizeof(float) == sizeof(int32_t), \"Important ULP matcher assumption violated\");\n        int32_t i;\n        std::memcpy(&i, &f, sizeof(f));\n        return i;\n    }\n\n    int64_t convert(double d) {\n        static_assert(sizeof(double) == sizeof(int64_t), \"Important ULP matcher assumption violated\");\n        int64_t i;\n        std::memcpy(&i, &d, sizeof(d));\n        return i;\n    }\n\n    template <typename FP>\n    bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) {\n        // Comparison with NaN should always be false.\n        // This way we can rule it out before getting into the ugly details\n        if (Catch::isnan(lhs) || Catch::isnan(rhs)) {\n            return false;\n        }\n\n        auto lc = convert(lhs);\n        auto rc = convert(rhs);\n\n        if ((lc < 0) != (rc < 0)) {\n            // Potentially we can have +0 and -0\n            return lhs == rhs;\n        }\n\n        // static cast as a workaround for IBM XLC\n        auto ulpDiff = std::abs(static_cast<FP>(lc - rc));\n        return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;\n    }\n\n#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)\n\n    float nextafter(float x, float y) {\n        return ::nextafterf(x, y);\n    }\n\n    double nextafter(double x, double y) {\n        return ::nextafter(x, y);\n    }\n\n#endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^\n\ntemplate <typename FP>\nFP step(FP start, FP direction, uint64_t steps) {\n    for (uint64_t i = 0; i < steps; ++i) {\n#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)\n        start = Catch::nextafter(start, direction);\n#else\n        start = std::nextafter(start, direction);\n#endif\n    }\n    return start;\n}\n\n// Performs equivalent check of std::fabs(lhs - rhs) <= margin\n// But without the subtraction to allow for INFINITY in comparison\nbool marginComparison(double lhs, double rhs, double margin) {\n    return (lhs + margin >= rhs) && (rhs + margin >= lhs);\n}\n\ntemplate <typename FloatingPoint>\nvoid write(std::ostream& out, FloatingPoint num) {\n    out << std::scientific\n        << std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1)\n        << num;\n}\n\n} // end anonymous namespace\n\nnamespace Matchers {\nnamespace Floating {\n\n    enum class FloatingPointKind : uint8_t {\n        Float,\n        Double\n    };\n\n    WithinAbsMatcher::WithinAbsMatcher(double target, double margin)\n        :m_target{ target }, m_margin{ margin } {\n        CATCH_ENFORCE(margin >= 0, \"Invalid margin: \" << margin << '.'\n            << \" Margin has to be non-negative.\");\n    }\n\n    // Performs equivalent check of std::fabs(lhs - rhs) <= margin\n    // But without the subtraction to allow for INFINITY in comparison\n    bool WithinAbsMatcher::match(double const& matchee) const {\n        return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee);\n    }\n\n    std::string WithinAbsMatcher::describe() const {\n        return \"is within \" + ::Catch::Detail::stringify(m_margin) + \" of \" + ::Catch::Detail::stringify(m_target);\n    }\n\n    WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType)\n        :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {\n        CATCH_ENFORCE(m_type == FloatingPointKind::Double\n                   || m_ulps < (std::numeric_limits<uint32_t>::max)(),\n            \"Provided ULP is impossibly large for a float comparison.\");\n    }\n\n#if defined(__clang__)\n#pragma clang diagnostic push\n// Clang <3.5 reports on the default branch in the switch below\n#pragma clang diagnostic ignored \"-Wunreachable-code\"\n#endif\n\n    bool WithinUlpsMatcher::match(double const& matchee) const {\n        switch (m_type) {\n        case FloatingPointKind::Float:\n            return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps);\n        case FloatingPointKind::Double:\n            return almostEqualUlps<double>(matchee, m_target, m_ulps);\n        default:\n            CATCH_INTERNAL_ERROR( \"Unknown FloatingPointKind value\" );\n        }\n    }\n\n#if defined(__clang__)\n#pragma clang diagnostic pop\n#endif\n\n    std::string WithinUlpsMatcher::describe() const {\n        std::stringstream ret;\n\n        ret << \"is within \" << m_ulps << \" ULPs of \";\n\n        if (m_type == FloatingPointKind::Float) {\n            write(ret, static_cast<float>(m_target));\n            ret << 'f';\n        } else {\n            write(ret, m_target);\n        }\n\n        ret << \" ([\";\n        if (m_type == FloatingPointKind::Double) {\n            write(ret, step(m_target, static_cast<double>(-INFINITY), m_ulps));\n            ret << \", \";\n            write(ret, step(m_target, static_cast<double>( INFINITY), m_ulps));\n        } else {\n            // We have to cast INFINITY to float because of MinGW, see #1782\n            write(ret, step(static_cast<float>(m_target), static_cast<float>(-INFINITY), m_ulps));\n            ret << \", \";\n            write(ret, step(static_cast<float>(m_target), static_cast<float>( INFINITY), m_ulps));\n        }\n        ret << \"])\";\n\n        return ret.str();\n    }\n\n    WithinRelMatcher::WithinRelMatcher(double target, double epsilon):\n        m_target(target),\n        m_epsilon(epsilon){\n        CATCH_ENFORCE(m_epsilon >= 0., \"Relative comparison with epsilon <  0 does not make sense.\");\n        CATCH_ENFORCE(m_epsilon  < 1., \"Relative comparison with epsilon >= 1 does not make sense.\");\n    }\n\n    bool WithinRelMatcher::match(double const& matchee) const {\n        const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target));\n        return marginComparison(matchee, m_target,\n                                std::isinf(relMargin)? 0 : relMargin);\n    }\n\n    std::string WithinRelMatcher::describe() const {\n        Catch::ReusableStringStream sstr;\n        sstr << \"and \" << m_target << \" are within \" << m_epsilon * 100. << \"% of each other\";\n        return sstr.str();\n    }\n\n}// namespace Floating\n\nFloating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) {\n    return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double);\n}\n\nFloating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) {\n    return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float);\n}\n\nFloating::WithinAbsMatcher WithinAbs(double target, double margin) {\n    return Floating::WithinAbsMatcher(target, margin);\n}\n\nFloating::WithinRelMatcher WithinRel(double target, double eps) {\n    return Floating::WithinRelMatcher(target, eps);\n}\n\nFloating::WithinRelMatcher WithinRel(double target) {\n    return Floating::WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100);\n}\n\nFloating::WithinRelMatcher WithinRel(float target, float eps) {\n    return Floating::WithinRelMatcher(target, eps);\n}\n\nFloating::WithinRelMatcher WithinRel(float target) {\n    return Floating::WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100);\n}\n\n} // namespace Matchers\n} // namespace Catch\n// end catch_matchers_floating.cpp\n// start catch_matchers_generic.cpp\n\nstd::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) {\n    if (desc.empty()) {\n        return \"matches undescribed predicate\";\n    } else {\n        return \"matches predicate: \\\"\" + desc + '\"';\n    }\n}\n// end catch_matchers_generic.cpp\n// start catch_matchers_string.cpp\n\n#include <regex>\n\nnamespace Catch {\nnamespace Matchers {\n\n    namespace StdString {\n\n        CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity )\n        :   m_caseSensitivity( caseSensitivity ),\n            m_str( adjustString( str ) )\n        {}\n        std::string CasedString::adjustString( std::string const& str ) const {\n            return m_caseSensitivity == CaseSensitive::No\n                   ? toLower( str )\n                   : str;\n        }\n        std::string CasedString::caseSensitivitySuffix() const {\n            return m_caseSensitivity == CaseSensitive::No\n                   ? \" (case insensitive)\"\n                   : std::string();\n        }\n\n        StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator )\n        : m_comparator( comparator ),\n          m_operation( operation ) {\n        }\n\n        std::string StringMatcherBase::describe() const {\n            std::string description;\n            description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +\n                                        m_comparator.caseSensitivitySuffix().size());\n            description += m_operation;\n            description += \": \\\"\";\n            description += m_comparator.m_str;\n            description += \"\\\"\";\n            description += m_comparator.caseSensitivitySuffix();\n            return description;\n        }\n\n        EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( \"equals\", comparator ) {}\n\n        bool EqualsMatcher::match( std::string const& source ) const {\n            return m_comparator.adjustString( source ) == m_comparator.m_str;\n        }\n\n        ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( \"contains\", comparator ) {}\n\n        bool ContainsMatcher::match( std::string const& source ) const {\n            return contains( m_comparator.adjustString( source ), m_comparator.m_str );\n        }\n\n        StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( \"starts with\", comparator ) {}\n\n        bool StartsWithMatcher::match( std::string const& source ) const {\n            return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );\n        }\n\n        EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( \"ends with\", comparator ) {}\n\n        bool EndsWithMatcher::match( std::string const& source ) const {\n            return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );\n        }\n\n        RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {}\n\n        bool RegexMatcher::match(std::string const& matchee) const {\n            auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway\n            if (m_caseSensitivity == CaseSensitive::Choice::No) {\n                flags |= std::regex::icase;\n            }\n            auto reg = std::regex(m_regex, flags);\n            return std::regex_match(matchee, reg);\n        }\n\n        std::string RegexMatcher::describe() const {\n            return \"matches \" + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? \" case sensitively\" : \" case insensitively\");\n        }\n\n    } // namespace StdString\n\n    StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) {\n        return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) );\n    }\n    StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) {\n        return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) );\n    }\n    StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {\n        return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) );\n    }\n    StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {\n        return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) );\n    }\n\n    StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) {\n        return StdString::RegexMatcher(regex, caseSensitivity);\n    }\n\n} // namespace Matchers\n} // namespace Catch\n// end catch_matchers_string.cpp\n// start catch_message.cpp\n\n// start catch_uncaught_exceptions.h\n\nnamespace Catch {\n    bool uncaught_exceptions();\n} // end namespace Catch\n\n// end catch_uncaught_exceptions.h\n#include <cassert>\n#include <stack>\n\nnamespace Catch {\n\n    MessageInfo::MessageInfo(   StringRef const& _macroName,\n                                SourceLineInfo const& _lineInfo,\n                                ResultWas::OfType _type )\n    :   macroName( _macroName ),\n        lineInfo( _lineInfo ),\n        type( _type ),\n        sequence( ++globalCount )\n    {}\n\n    bool MessageInfo::operator==( MessageInfo const& other ) const {\n        return sequence == other.sequence;\n    }\n\n    bool MessageInfo::operator<( MessageInfo const& other ) const {\n        return sequence < other.sequence;\n    }\n\n    // This may need protecting if threading support is added\n    unsigned int MessageInfo::globalCount = 0;\n\n    ////////////////////////////////////////////////////////////////////////////\n\n    Catch::MessageBuilder::MessageBuilder( StringRef const& macroName,\n                                           SourceLineInfo const& lineInfo,\n                                           ResultWas::OfType type )\n        :m_info(macroName, lineInfo, type) {}\n\n    ////////////////////////////////////////////////////////////////////////////\n\n    ScopedMessage::ScopedMessage( MessageBuilder const& builder )\n    : m_info( builder.m_info ), m_moved()\n    {\n        m_info.message = builder.m_stream.str();\n        getResultCapture().pushScopedMessage( m_info );\n    }\n\n    ScopedMessage::ScopedMessage( ScopedMessage&& old )\n    : m_info( old.m_info ), m_moved()\n    {\n        old.m_moved = true;\n    }\n\n    ScopedMessage::~ScopedMessage() {\n        if ( !uncaught_exceptions() && !m_moved ){\n            getResultCapture().popScopedMessage(m_info);\n        }\n    }\n\n    Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {\n        auto trimmed = [&] (size_t start, size_t end) {\n            while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {\n                ++start;\n            }\n            while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) {\n                --end;\n            }\n            return names.substr(start, end - start + 1);\n        };\n        auto skipq = [&] (size_t start, char quote) {\n            for (auto i = start + 1; i < names.size() ; ++i) {\n                if (names[i] == quote)\n                    return i;\n                if (names[i] == '\\\\')\n                    ++i;\n            }\n            CATCH_INTERNAL_ERROR(\"CAPTURE parsing encountered unmatched quote\");\n        };\n\n        size_t start = 0;\n        std::stack<char> openings;\n        for (size_t pos = 0; pos < names.size(); ++pos) {\n            char c = names[pos];\n            switch (c) {\n            case '[':\n            case '{':\n            case '(':\n            // It is basically impossible to disambiguate between\n            // comparison and start of template args in this context\n//            case '<':\n                openings.push(c);\n                break;\n            case ']':\n            case '}':\n            case ')':\n//           case '>':\n                openings.pop();\n                break;\n            case '\"':\n            case '\\'':\n                pos = skipq(pos, c);\n                break;\n            case ',':\n                if (start != pos && openings.empty()) {\n                    m_messages.emplace_back(macroName, lineInfo, resultType);\n                    m_messages.back().message = static_cast<std::string>(trimmed(start, pos));\n                    m_messages.back().message += \" := \";\n                    start = pos;\n                }\n            }\n        }\n        assert(openings.empty() && \"Mismatched openings\");\n        m_messages.emplace_back(macroName, lineInfo, resultType);\n        m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1));\n        m_messages.back().message += \" := \";\n    }\n    Capturer::~Capturer() {\n        if ( !uncaught_exceptions() ){\n            assert( m_captured == m_messages.size() );\n            for( size_t i = 0; i < m_captured; ++i  )\n                m_resultCapture.popScopedMessage( m_messages[i] );\n        }\n    }\n\n    void Capturer::captureValue( size_t index, std::string const& value ) {\n        assert( index < m_messages.size() );\n        m_messages[index].message += value;\n        m_resultCapture.pushScopedMessage( m_messages[index] );\n        m_captured++;\n    }\n\n} // end namespace Catch\n// end catch_message.cpp\n// start catch_output_redirect.cpp\n\n// start catch_output_redirect.h\n#ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H\n#define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H\n\n#include <cstdio>\n#include <iosfwd>\n#include <string>\n\nnamespace Catch {\n\n    class RedirectedStream {\n        std::ostream& m_originalStream;\n        std::ostream& m_redirectionStream;\n        std::streambuf* m_prevBuf;\n\n    public:\n        RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream );\n        ~RedirectedStream();\n    };\n\n    class RedirectedStdOut {\n        ReusableStringStream m_rss;\n        RedirectedStream m_cout;\n    public:\n        RedirectedStdOut();\n        auto str() const -> std::string;\n    };\n\n    // StdErr has two constituent streams in C++, std::cerr and std::clog\n    // This means that we need to redirect 2 streams into 1 to keep proper\n    // order of writes\n    class RedirectedStdErr {\n        ReusableStringStream m_rss;\n        RedirectedStream m_cerr;\n        RedirectedStream m_clog;\n    public:\n        RedirectedStdErr();\n        auto str() const -> std::string;\n    };\n\n    class RedirectedStreams {\n    public:\n        RedirectedStreams(RedirectedStreams const&) = delete;\n        RedirectedStreams& operator=(RedirectedStreams const&) = delete;\n        RedirectedStreams(RedirectedStreams&&) = delete;\n        RedirectedStreams& operator=(RedirectedStreams&&) = delete;\n\n        RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr);\n        ~RedirectedStreams();\n    private:\n        std::string& m_redirectedCout;\n        std::string& m_redirectedCerr;\n        RedirectedStdOut m_redirectedStdOut;\n        RedirectedStdErr m_redirectedStdErr;\n    };\n\n#if defined(CATCH_CONFIG_NEW_CAPTURE)\n\n    // Windows's implementation of std::tmpfile is terrible (it tries\n    // to create a file inside system folder, thus requiring elevated\n    // privileges for the binary), so we have to use tmpnam(_s) and\n    // create the file ourselves there.\n    class TempFile {\n    public:\n        TempFile(TempFile const&) = delete;\n        TempFile& operator=(TempFile const&) = delete;\n        TempFile(TempFile&&) = delete;\n        TempFile& operator=(TempFile&&) = delete;\n\n        TempFile();\n        ~TempFile();\n\n        std::FILE* getFile();\n        std::string getContents();\n\n    private:\n        std::FILE* m_file = nullptr;\n    #if defined(_MSC_VER)\n        char m_buffer[L_tmpnam] = { 0 };\n    #endif\n    };\n\n    class OutputRedirect {\n    public:\n        OutputRedirect(OutputRedirect const&) = delete;\n        OutputRedirect& operator=(OutputRedirect const&) = delete;\n        OutputRedirect(OutputRedirect&&) = delete;\n        OutputRedirect& operator=(OutputRedirect&&) = delete;\n\n        OutputRedirect(std::string& stdout_dest, std::string& stderr_dest);\n        ~OutputRedirect();\n\n    private:\n        int m_originalStdout = -1;\n        int m_originalStderr = -1;\n        TempFile m_stdoutFile;\n        TempFile m_stderrFile;\n        std::string& m_stdoutDest;\n        std::string& m_stderrDest;\n    };\n\n#endif\n\n} // end namespace Catch\n\n#endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H\n// end catch_output_redirect.h\n#include <cstdio>\n#include <cstring>\n#include <fstream>\n#include <sstream>\n#include <stdexcept>\n\n#if defined(CATCH_CONFIG_NEW_CAPTURE)\n    #if defined(_MSC_VER)\n    #include <io.h>      //_dup and _dup2\n    #define dup _dup\n    #define dup2 _dup2\n    #define fileno _fileno\n    #else\n    #include <unistd.h>  // dup and dup2\n    #endif\n#endif\n\nnamespace Catch {\n\n    RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream )\n    :   m_originalStream( originalStream ),\n        m_redirectionStream( redirectionStream ),\n        m_prevBuf( m_originalStream.rdbuf() )\n    {\n        m_originalStream.rdbuf( m_redirectionStream.rdbuf() );\n    }\n\n    RedirectedStream::~RedirectedStream() {\n        m_originalStream.rdbuf( m_prevBuf );\n    }\n\n    RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {}\n    auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); }\n\n    RedirectedStdErr::RedirectedStdErr()\n    :   m_cerr( Catch::cerr(), m_rss.get() ),\n        m_clog( Catch::clog(), m_rss.get() )\n    {}\n    auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); }\n\n    RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr)\n    :   m_redirectedCout(redirectedCout),\n        m_redirectedCerr(redirectedCerr)\n    {}\n\n    RedirectedStreams::~RedirectedStreams() {\n        m_redirectedCout += m_redirectedStdOut.str();\n        m_redirectedCerr += m_redirectedStdErr.str();\n    }\n\n#if defined(CATCH_CONFIG_NEW_CAPTURE)\n\n#if defined(_MSC_VER)\n    TempFile::TempFile() {\n        if (tmpnam_s(m_buffer)) {\n            CATCH_RUNTIME_ERROR(\"Could not get a temp filename\");\n        }\n        if (fopen_s(&m_file, m_buffer, \"w+\")) {\n            char buffer[100];\n            if (strerror_s(buffer, errno)) {\n                CATCH_RUNTIME_ERROR(\"Could not translate errno to a string\");\n            }\n            CATCH_RUNTIME_ERROR(\"Could not open the temp file: '\" << m_buffer << \"' because: \" << buffer);\n        }\n    }\n#else\n    TempFile::TempFile() {\n        m_file = std::tmpfile();\n        if (!m_file) {\n            CATCH_RUNTIME_ERROR(\"Could not create a temp file.\");\n        }\n    }\n\n#endif\n\n    TempFile::~TempFile() {\n         // TBD: What to do about errors here?\n         std::fclose(m_file);\n         // We manually create the file on Windows only, on Linux\n         // it will be autodeleted\n#if defined(_MSC_VER)\n         std::remove(m_buffer);\n#endif\n    }\n\n    FILE* TempFile::getFile() {\n        return m_file;\n    }\n\n    std::string TempFile::getContents() {\n        std::stringstream sstr;\n        char buffer[100] = {};\n        std::rewind(m_file);\n        while (std::fgets(buffer, sizeof(buffer), m_file)) {\n            sstr << buffer;\n        }\n        return sstr.str();\n    }\n\n    OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) :\n        m_originalStdout(dup(1)),\n        m_originalStderr(dup(2)),\n        m_stdoutDest(stdout_dest),\n        m_stderrDest(stderr_dest) {\n        dup2(fileno(m_stdoutFile.getFile()), 1);\n        dup2(fileno(m_stderrFile.getFile()), 2);\n    }\n\n    OutputRedirect::~OutputRedirect() {\n        Catch::cout() << std::flush;\n        fflush(stdout);\n        // Since we support overriding these streams, we flush cerr\n        // even though std::cerr is unbuffered\n        Catch::cerr() << std::flush;\n        Catch::clog() << std::flush;\n        fflush(stderr);\n\n        dup2(m_originalStdout, 1);\n        dup2(m_originalStderr, 2);\n\n        m_stdoutDest += m_stdoutFile.getContents();\n        m_stderrDest += m_stderrFile.getContents();\n    }\n\n#endif // CATCH_CONFIG_NEW_CAPTURE\n\n} // namespace Catch\n\n#if defined(CATCH_CONFIG_NEW_CAPTURE)\n    #if defined(_MSC_VER)\n    #undef dup\n    #undef dup2\n    #undef fileno\n    #endif\n#endif\n// end catch_output_redirect.cpp\n// start catch_polyfills.cpp\n\n#include <cmath>\n\nnamespace Catch {\n\n#if !defined(CATCH_CONFIG_POLYFILL_ISNAN)\n    bool isnan(float f) {\n        return std::isnan(f);\n    }\n    bool isnan(double d) {\n        return std::isnan(d);\n    }\n#else\n    // For now we only use this for embarcadero\n    bool isnan(float f) {\n        return std::_isnan(f);\n    }\n    bool isnan(double d) {\n        return std::_isnan(d);\n    }\n#endif\n\n} // end namespace Catch\n// end catch_polyfills.cpp\n// start catch_random_number_generator.cpp\n\nnamespace Catch {\n\nnamespace {\n\n#if defined(_MSC_VER)\n#pragma warning(push)\n#pragma warning(disable:4146) // we negate uint32 during the rotate\n#endif\n        // Safe rotr implementation thanks to John Regehr\n        uint32_t rotate_right(uint32_t val, uint32_t count) {\n            const uint32_t mask = 31;\n            count &= mask;\n            return (val >> count) | (val << (-count & mask));\n        }\n\n#if defined(_MSC_VER)\n#pragma warning(pop)\n#endif\n\n}\n\n    SimplePcg32::SimplePcg32(result_type seed_) {\n        seed(seed_);\n    }\n\n    void SimplePcg32::seed(result_type seed_) {\n        m_state = 0;\n        (*this)();\n        m_state += seed_;\n        (*this)();\n    }\n\n    void SimplePcg32::discard(uint64_t skip) {\n        // We could implement this to run in O(log n) steps, but this\n        // should suffice for our use case.\n        for (uint64_t s = 0; s < skip; ++s) {\n            static_cast<void>((*this)());\n        }\n    }\n\n    SimplePcg32::result_type SimplePcg32::operator()() {\n        // prepare the output value\n        const uint32_t xorshifted = static_cast<uint32_t>(((m_state >> 18u) ^ m_state) >> 27u);\n        const auto output = rotate_right(xorshifted, m_state >> 59u);\n\n        // advance state\n        m_state = m_state * 6364136223846793005ULL + s_inc;\n\n        return output;\n    }\n\n    bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {\n        return lhs.m_state == rhs.m_state;\n    }\n\n    bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {\n        return lhs.m_state != rhs.m_state;\n    }\n}\n// end catch_random_number_generator.cpp\n// start catch_registry_hub.cpp\n\n// start catch_test_case_registry_impl.h\n\n#include <vector>\n#include <set>\n#include <algorithm>\n#include <ios>\n\nnamespace Catch {\n\n    class TestCase;\n    struct IConfig;\n\n    std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases );\n\n    bool isThrowSafe( TestCase const& testCase, IConfig const& config );\n    bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );\n\n    void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions );\n\n    std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );\n    std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );\n\n    class TestRegistry : public ITestCaseRegistry {\n    public:\n        virtual ~TestRegistry() = default;\n\n        virtual void registerTest( TestCase const& testCase );\n\n        std::vector<TestCase> const& getAllTests() const override;\n        std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const override;\n\n    private:\n        std::vector<TestCase> m_functions;\n        mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder;\n        mutable std::vector<TestCase> m_sortedFunctions;\n        std::size_t m_unnamedCount = 0;\n        std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised\n    };\n\n    ///////////////////////////////////////////////////////////////////////////\n\n    class TestInvokerAsFunction : public ITestInvoker {\n        void(*m_testAsFunction)();\n    public:\n        TestInvokerAsFunction( void(*testAsFunction)() ) noexcept;\n\n        void invoke() const override;\n    };\n\n    std::string extractClassName( StringRef const& classOrQualifiedMethodName );\n\n    ///////////////////////////////////////////////////////////////////////////\n\n} // end namespace Catch\n\n// end catch_test_case_registry_impl.h\n// start catch_reporter_registry.h\n\n#include <map>\n\nnamespace Catch {\n\n    class ReporterRegistry : public IReporterRegistry {\n\n    public:\n\n        ~ReporterRegistry() override;\n\n        IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override;\n\n        void registerReporter( std::string const& name, IReporterFactoryPtr const& factory );\n        void registerListener( IReporterFactoryPtr const& factory );\n\n        FactoryMap const& getFactories() const override;\n        Listeners const& getListeners() const override;\n\n    private:\n        FactoryMap m_factories;\n        Listeners m_listeners;\n    };\n}\n\n// end catch_reporter_registry.h\n// start catch_tag_alias_registry.h\n\n// start catch_tag_alias.h\n\n#include <string>\n\nnamespace Catch {\n\n    struct TagAlias {\n        TagAlias(std::string const& _tag, SourceLineInfo _lineInfo);\n\n        std::string tag;\n        SourceLineInfo lineInfo;\n    };\n\n} // end namespace Catch\n\n// end catch_tag_alias.h\n#include <map>\n\nnamespace Catch {\n\n    class TagAliasRegistry : public ITagAliasRegistry {\n    public:\n        ~TagAliasRegistry() override;\n        TagAlias const* find( std::string const& alias ) const override;\n        std::string expandAliases( std::string const& unexpandedTestSpec ) const override;\n        void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo );\n\n    private:\n        std::map<std::string, TagAlias> m_registry;\n    };\n\n} // end namespace Catch\n\n// end catch_tag_alias_registry.h\n// start catch_startup_exception_registry.h\n\n#include <vector>\n#include <exception>\n\nnamespace Catch {\n\n    class StartupExceptionRegistry {\n#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)\n    public:\n        void add(std::exception_ptr const& exception) noexcept;\n        std::vector<std::exception_ptr> const& getExceptions() const noexcept;\n    private:\n        std::vector<std::exception_ptr> m_exceptions;\n#endif\n    };\n\n} // end namespace Catch\n\n// end catch_startup_exception_registry.h\n// start catch_singletons.hpp\n\nnamespace Catch {\n\n    struct ISingleton {\n        virtual ~ISingleton();\n    };\n\n    void addSingleton( ISingleton* singleton );\n    void cleanupSingletons();\n\n    template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT>\n    class Singleton : SingletonImplT, public ISingleton {\n\n        static auto getInternal() -> Singleton* {\n            static Singleton* s_instance = nullptr;\n            if( !s_instance ) {\n                s_instance = new Singleton;\n                addSingleton( s_instance );\n            }\n            return s_instance;\n        }\n\n    public:\n        static auto get() -> InterfaceT const& {\n            return *getInternal();\n        }\n        static auto getMutable() -> MutableInterfaceT& {\n            return *getInternal();\n        }\n    };\n\n} // namespace Catch\n\n// end catch_singletons.hpp\nnamespace Catch {\n\n    namespace {\n\n        class RegistryHub : public IRegistryHub, public IMutableRegistryHub,\n                            private NonCopyable {\n\n        public: // IRegistryHub\n            RegistryHub() = default;\n            IReporterRegistry const& getReporterRegistry() const override {\n                return m_reporterRegistry;\n            }\n            ITestCaseRegistry const& getTestCaseRegistry() const override {\n                return m_testCaseRegistry;\n            }\n            IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override {\n                return m_exceptionTranslatorRegistry;\n            }\n            ITagAliasRegistry const& getTagAliasRegistry() const override {\n                return m_tagAliasRegistry;\n            }\n            StartupExceptionRegistry const& getStartupExceptionRegistry() const override {\n                return m_exceptionRegistry;\n            }\n\n        public: // IMutableRegistryHub\n            void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override {\n                m_reporterRegistry.registerReporter( name, factory );\n            }\n            void registerListener( IReporterFactoryPtr const& factory ) override {\n                m_reporterRegistry.registerListener( factory );\n            }\n            void registerTest( TestCase const& testInfo ) override {\n                m_testCaseRegistry.registerTest( testInfo );\n            }\n            void registerTranslator( const IExceptionTranslator* translator ) override {\n                m_exceptionTranslatorRegistry.registerTranslator( translator );\n            }\n            void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override {\n                m_tagAliasRegistry.add( alias, tag, lineInfo );\n            }\n            void registerStartupException() noexcept override {\n#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)\n                m_exceptionRegistry.add(std::current_exception());\n#else\n                CATCH_INTERNAL_ERROR(\"Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!\");\n#endif\n            }\n            IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {\n                return m_enumValuesRegistry;\n            }\n\n        private:\n            TestRegistry m_testCaseRegistry;\n            ReporterRegistry m_reporterRegistry;\n            ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;\n            TagAliasRegistry m_tagAliasRegistry;\n            StartupExceptionRegistry m_exceptionRegistry;\n            Detail::EnumValuesRegistry m_enumValuesRegistry;\n        };\n    }\n\n    using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>;\n\n    IRegistryHub const& getRegistryHub() {\n        return RegistryHubSingleton::get();\n    }\n    IMutableRegistryHub& getMutableRegistryHub() {\n        return RegistryHubSingleton::getMutable();\n    }\n    void cleanUp() {\n        cleanupSingletons();\n        cleanUpContext();\n    }\n    std::string translateActiveException() {\n        return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();\n    }\n\n} // end namespace Catch\n// end catch_registry_hub.cpp\n// start catch_reporter_registry.cpp\n\nnamespace Catch {\n\n    ReporterRegistry::~ReporterRegistry() = default;\n\n    IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const {\n        auto it =  m_factories.find( name );\n        if( it == m_factories.end() )\n            return nullptr;\n        return it->second->create( ReporterConfig( config ) );\n    }\n\n    void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) {\n        m_factories.emplace(name, factory);\n    }\n    void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) {\n        m_listeners.push_back( factory );\n    }\n\n    IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const {\n        return m_factories;\n    }\n    IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const {\n        return m_listeners;\n    }\n\n}\n// end catch_reporter_registry.cpp\n// start catch_result_type.cpp\n\nnamespace Catch {\n\n    bool isOk( ResultWas::OfType resultType ) {\n        return ( resultType & ResultWas::FailureBit ) == 0;\n    }\n    bool isJustInfo( int flags ) {\n        return flags == ResultWas::Info;\n    }\n\n    ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {\n        return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );\n    }\n\n    bool shouldContinueOnFailure( int flags )    { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }\n    bool shouldSuppressFailure( int flags )      { return ( flags & ResultDisposition::SuppressFail ) != 0; }\n\n} // end namespace Catch\n// end catch_result_type.cpp\n// start catch_run_context.cpp\n\n#include <cassert>\n#include <algorithm>\n#include <sstream>\n\nnamespace Catch {\n\n    namespace Generators {\n        struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {\n            GeneratorBasePtr m_generator;\n\n            GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )\n            :   TrackerBase( nameAndLocation, ctx, parent )\n            {}\n            ~GeneratorTracker();\n\n            static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) {\n                std::shared_ptr<GeneratorTracker> tracker;\n\n                ITracker& currentTracker = ctx.currentTracker();\n                // Under specific circumstances, the generator we want\n                // to acquire is also the current tracker. If this is\n                // the case, we have to avoid looking through current\n                // tracker's children, and instead return the current\n                // tracker.\n                // A case where this check is important is e.g.\n                //     for (int i = 0; i < 5; ++i) {\n                //         int n = GENERATE(1, 2);\n                //     }\n                //\n                // without it, the code above creates 5 nested generators.\n                if (currentTracker.nameAndLocation() == nameAndLocation) {\n                    auto thisTracker = currentTracker.parent().findChild(nameAndLocation);\n                    assert(thisTracker);\n                    assert(thisTracker->isGeneratorTracker());\n                    tracker = std::static_pointer_cast<GeneratorTracker>(thisTracker);\n                } else if ( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {\n                    assert( childTracker );\n                    assert( childTracker->isGeneratorTracker() );\n                    tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );\n                } else {\n                    tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, &currentTracker );\n                    currentTracker.addChild( tracker );\n                }\n\n                if( !tracker->isComplete() ) {\n                    tracker->open();\n                }\n\n                return *tracker;\n            }\n\n            // TrackerBase interface\n            bool isGeneratorTracker() const override { return true; }\n            auto hasGenerator() const -> bool override {\n                return !!m_generator;\n            }\n            void close() override {\n                TrackerBase::close();\n                // If a generator has a child (it is followed by a section)\n                // and none of its children have started, then we must wait\n                // until later to start consuming its values.\n                // This catches cases where `GENERATE` is placed between two\n                // `SECTION`s.\n                // **The check for m_children.empty cannot be removed**.\n                // doing so would break `GENERATE` _not_ followed by `SECTION`s.\n                const bool should_wait_for_child = [&]() {\n                    // No children -> nobody to wait for\n                    if ( m_children.empty() ) {\n                        return false;\n                    }\n                    // If at least one child started executing, don't wait\n                    if ( std::find_if(\n                             m_children.begin(),\n                             m_children.end(),\n                             []( TestCaseTracking::ITrackerPtr tracker ) {\n                                 return tracker->hasStarted();\n                             } ) != m_children.end() ) {\n                        return false;\n                    }\n\n                    // No children have started. We need to check if they _can_\n                    // start, and thus we should wait for them, or they cannot\n                    // start (due to filters), and we shouldn't wait for them\n                    auto* parent = m_parent;\n                    // This is safe: there is always at least one section\n                    // tracker in a test case tracking tree\n                    while ( !parent->isSectionTracker() ) {\n                        parent = &( parent->parent() );\n                    }\n                    assert( parent &&\n                            \"Missing root (test case) level section\" );\n\n                    auto const& parentSection =\n                        static_cast<SectionTracker&>( *parent );\n                    auto const& filters = parentSection.getFilters();\n                    // No filters -> no restrictions on running sections\n                    if ( filters.empty() ) {\n                        return true;\n                    }\n\n                    for ( auto const& child : m_children ) {\n                        if ( child->isSectionTracker() &&\n                             std::find( filters.begin(),\n                                        filters.end(),\n                                        static_cast<SectionTracker&>( *child )\n                                            .trimmedName() ) !=\n                                 filters.end() ) {\n                            return true;\n                        }\n                    }\n                    return false;\n                }();\n\n                // This check is a bit tricky, because m_generator->next()\n                // has a side-effect, where it consumes generator's current\n                // value, but we do not want to invoke the side-effect if\n                // this generator is still waiting for any child to start.\n                if ( should_wait_for_child ||\n                     ( m_runState == CompletedSuccessfully &&\n                       m_generator->next() ) ) {\n                    m_children.clear();\n                    m_runState = Executing;\n                }\n            }\n\n            // IGeneratorTracker interface\n            auto getGenerator() const -> GeneratorBasePtr const& override {\n                return m_generator;\n            }\n            void setGenerator( GeneratorBasePtr&& generator ) override {\n                m_generator = std::move( generator );\n            }\n        };\n        GeneratorTracker::~GeneratorTracker() {}\n    }\n\n    RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter)\n    :   m_runInfo(_config->name()),\n        m_context(getCurrentMutableContext()),\n        m_config(_config),\n        m_reporter(std::move(reporter)),\n        m_lastAssertionInfo{ StringRef(), SourceLineInfo(\"\",0), StringRef(), ResultDisposition::Normal },\n        m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions )\n    {\n        m_context.setRunner(this);\n        m_context.setConfig(m_config);\n        m_context.setResultCapture(this);\n        m_reporter->testRunStarting(m_runInfo);\n    }\n\n    RunContext::~RunContext() {\n        m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));\n    }\n\n    void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) {\n        m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount));\n    }\n\n    void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) {\n        m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting()));\n    }\n\n    Totals RunContext::runTest(TestCase const& testCase) {\n        Totals prevTotals = m_totals;\n\n        std::string redirectedCout;\n        std::string redirectedCerr;\n\n        auto const& testInfo = testCase.getTestCaseInfo();\n\n        m_reporter->testCaseStarting(testInfo);\n\n        m_activeTestCase = &testCase;\n\n        ITracker& rootTracker = m_trackerContext.startRun();\n        assert(rootTracker.isSectionTracker());\n        static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun());\n        do {\n            m_trackerContext.startCycle();\n            m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo));\n            runCurrentTest(redirectedCout, redirectedCerr);\n        } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());\n\n        Totals deltaTotals = m_totals.delta(prevTotals);\n        if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) {\n            deltaTotals.assertions.failed++;\n            deltaTotals.testCases.passed--;\n            deltaTotals.testCases.failed++;\n        }\n        m_totals.testCases += deltaTotals.testCases;\n        m_reporter->testCaseEnded(TestCaseStats(testInfo,\n                                  deltaTotals,\n                                  redirectedCout,\n                                  redirectedCerr,\n                                  aborting()));\n\n        m_activeTestCase = nullptr;\n        m_testCaseTracker = nullptr;\n\n        return deltaTotals;\n    }\n\n    IConfigPtr RunContext::config() const {\n        return m_config;\n    }\n\n    IStreamingReporter& RunContext::reporter() const {\n        return *m_reporter;\n    }\n\n    void RunContext::assertionEnded(AssertionResult const & result) {\n        if (result.getResultType() == ResultWas::Ok) {\n            m_totals.assertions.passed++;\n            m_lastAssertionPassed = true;\n        } else if (!result.isOk()) {\n            m_lastAssertionPassed = false;\n            if( m_activeTestCase->getTestCaseInfo().okToFail() )\n                m_totals.assertions.failedButOk++;\n            else\n                m_totals.assertions.failed++;\n        }\n        else {\n            m_lastAssertionPassed = true;\n        }\n\n        // We have no use for the return value (whether messages should be cleared), because messages were made scoped\n        // and should be let to clear themselves out.\n        static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));\n\n        if (result.getResultType() != ResultWas::Warning)\n            m_messageScopes.clear();\n\n        // Reset working state\n        resetAssertionInfo();\n        m_lastResult = result;\n    }\n    void RunContext::resetAssertionInfo() {\n        m_lastAssertionInfo.macroName = StringRef();\n        m_lastAssertionInfo.capturedExpression = \"{Unknown expression after the reported line}\"_sr;\n    }\n\n    bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) {\n        ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo));\n        if (!sectionTracker.isOpen())\n            return false;\n        m_activeSections.push_back(&sectionTracker);\n\n        m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;\n\n        m_reporter->sectionStarting(sectionInfo);\n\n        assertions = m_totals.assertions;\n\n        return true;\n    }\n    auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {\n        using namespace Generators;\n        GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext,\n                                                              TestCaseTracking::NameAndLocation( static_cast<std::string>(generatorName), lineInfo ) );\n        m_lastAssertionInfo.lineInfo = lineInfo;\n        return tracker;\n    }\n\n    bool RunContext::testForMissingAssertions(Counts& assertions) {\n        if (assertions.total() != 0)\n            return false;\n        if (!m_config->warnAboutMissingAssertions())\n            return false;\n        if (m_trackerContext.currentTracker().hasChildren())\n            return false;\n        m_totals.assertions.failed++;\n        assertions.failed++;\n        return true;\n    }\n\n    void RunContext::sectionEnded(SectionEndInfo const & endInfo) {\n        Counts assertions = m_totals.assertions - endInfo.prevAssertions;\n        bool missingAssertions = testForMissingAssertions(assertions);\n\n        if (!m_activeSections.empty()) {\n            m_activeSections.back()->close();\n            m_activeSections.pop_back();\n        }\n\n        m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));\n        m_messages.clear();\n        m_messageScopes.clear();\n    }\n\n    void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) {\n        if (m_unfinishedSections.empty())\n            m_activeSections.back()->fail();\n        else\n            m_activeSections.back()->close();\n        m_activeSections.pop_back();\n\n        m_unfinishedSections.push_back(endInfo);\n    }\n\n#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\n    void RunContext::benchmarkPreparing(std::string const& name) {\n        m_reporter->benchmarkPreparing(name);\n    }\n    void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {\n        m_reporter->benchmarkStarting( info );\n    }\n    void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) {\n        m_reporter->benchmarkEnded( stats );\n    }\n    void RunContext::benchmarkFailed(std::string const & error) {\n        m_reporter->benchmarkFailed(error);\n    }\n#endif // CATCH_CONFIG_ENABLE_BENCHMARKING\n\n    void RunContext::pushScopedMessage(MessageInfo const & message) {\n        m_messages.push_back(message);\n    }\n\n    void RunContext::popScopedMessage(MessageInfo const & message) {\n        m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());\n    }\n\n    void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) {\n        m_messageScopes.emplace_back( builder );\n    }\n\n    std::string RunContext::getCurrentTestName() const {\n        return m_activeTestCase\n            ? m_activeTestCase->getTestCaseInfo().name\n            : std::string();\n    }\n\n    const AssertionResult * RunContext::getLastResult() const {\n        return &(*m_lastResult);\n    }\n\n    void RunContext::exceptionEarlyReported() {\n        m_shouldReportUnexpected = false;\n    }\n\n    void RunContext::handleFatalErrorCondition( StringRef message ) {\n        // First notify reporter that bad things happened\n        m_reporter->fatalErrorEncountered(message);\n\n        // Don't rebuild the result -- the stringification itself can cause more fatal errors\n        // Instead, fake a result data.\n        AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );\n        tempResult.message = static_cast<std::string>(message);\n        AssertionResult result(m_lastAssertionInfo, tempResult);\n\n        assertionEnded(result);\n\n        handleUnfinishedSections();\n\n        // Recreate section for test case (as we will lose the one that was in scope)\n        auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();\n        SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);\n\n        Counts assertions;\n        assertions.failed = 1;\n        SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false);\n        m_reporter->sectionEnded(testCaseSectionStats);\n\n        auto const& testInfo = m_activeTestCase->getTestCaseInfo();\n\n        Totals deltaTotals;\n        deltaTotals.testCases.failed = 1;\n        deltaTotals.assertions.failed = 1;\n        m_reporter->testCaseEnded(TestCaseStats(testInfo,\n                                  deltaTotals,\n                                  std::string(),\n                                  std::string(),\n                                  false));\n        m_totals.testCases.failed++;\n        testGroupEnded(std::string(), m_totals, 1, 1);\n        m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));\n    }\n\n    bool RunContext::lastAssertionPassed() {\n         return m_lastAssertionPassed;\n    }\n\n    void RunContext::assertionPassed() {\n        m_lastAssertionPassed = true;\n        ++m_totals.assertions.passed;\n        resetAssertionInfo();\n        m_messageScopes.clear();\n    }\n\n    bool RunContext::aborting() const {\n        return m_totals.assertions.failed >= static_cast<std::size_t>(m_config->abortAfter());\n    }\n\n    void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) {\n        auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();\n        SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);\n        m_reporter->sectionStarting(testCaseSection);\n        Counts prevAssertions = m_totals.assertions;\n        double duration = 0;\n        m_shouldReportUnexpected = true;\n        m_lastAssertionInfo = { \"TEST_CASE\"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal };\n\n        seedRng(*m_config);\n\n        Timer timer;\n        CATCH_TRY {\n            if (m_reporter->getPreferences().shouldRedirectStdOut) {\n#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)\n                RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr);\n\n                timer.start();\n                invokeActiveTestCase();\n#else\n                OutputRedirect r(redirectedCout, redirectedCerr);\n                timer.start();\n                invokeActiveTestCase();\n#endif\n            } else {\n                timer.start();\n                invokeActiveTestCase();\n            }\n            duration = timer.getElapsedSeconds();\n        } CATCH_CATCH_ANON (TestFailureException&) {\n            // This just means the test was aborted due to failure\n        } CATCH_CATCH_ALL {\n            // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions\n            // are reported without translation at the point of origin.\n            if( m_shouldReportUnexpected ) {\n                AssertionReaction dummyReaction;\n                handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction );\n            }\n        }\n        Counts assertions = m_totals.assertions - prevAssertions;\n        bool missingAssertions = testForMissingAssertions(assertions);\n\n        m_testCaseTracker->close();\n        handleUnfinishedSections();\n        m_messages.clear();\n        m_messageScopes.clear();\n\n        SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);\n        m_reporter->sectionEnded(testCaseSectionStats);\n    }\n\n    void RunContext::invokeActiveTestCase() {\n        FatalConditionHandlerGuard _(&m_fatalConditionhandler);\n        m_activeTestCase->invoke();\n    }\n\n    void RunContext::handleUnfinishedSections() {\n        // If sections ended prematurely due to an exception we stored their\n        // infos here so we can tear them down outside the unwind process.\n        for (auto it = m_unfinishedSections.rbegin(),\n             itEnd = m_unfinishedSections.rend();\n             it != itEnd;\n             ++it)\n            sectionEnded(*it);\n        m_unfinishedSections.clear();\n    }\n\n    void RunContext::handleExpr(\n        AssertionInfo const& info,\n        ITransientExpression const& expr,\n        AssertionReaction& reaction\n    ) {\n        m_reporter->assertionStarting( info );\n\n        bool negated = isFalseTest( info.resultDisposition );\n        bool result = expr.getResult() != negated;\n\n        if( result ) {\n            if (!m_includeSuccessfulResults) {\n                assertionPassed();\n            }\n            else {\n                reportExpr(info, ResultWas::Ok, &expr, negated);\n            }\n        }\n        else {\n            reportExpr(info, ResultWas::ExpressionFailed, &expr, negated );\n            populateReaction( reaction );\n        }\n    }\n    void RunContext::reportExpr(\n            AssertionInfo const &info,\n            ResultWas::OfType resultType,\n            ITransientExpression const *expr,\n            bool negated ) {\n\n        m_lastAssertionInfo = info;\n        AssertionResultData data( resultType, LazyExpression( negated ) );\n\n        AssertionResult assertionResult{ info, data };\n        assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;\n\n        assertionEnded( assertionResult );\n    }\n\n    void RunContext::handleMessage(\n            AssertionInfo const& info,\n            ResultWas::OfType resultType,\n            StringRef const& message,\n            AssertionReaction& reaction\n    ) {\n        m_reporter->assertionStarting( info );\n\n        m_lastAssertionInfo = info;\n\n        AssertionResultData data( resultType, LazyExpression( false ) );\n        data.message = static_cast<std::string>(message);\n        AssertionResult assertionResult{ m_lastAssertionInfo, data };\n        assertionEnded( assertionResult );\n        if( !assertionResult.isOk() )\n            populateReaction( reaction );\n    }\n    void RunContext::handleUnexpectedExceptionNotThrown(\n            AssertionInfo const& info,\n            AssertionReaction& reaction\n    ) {\n        handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction);\n    }\n\n    void RunContext::handleUnexpectedInflightException(\n            AssertionInfo const& info,\n            std::string const& message,\n            AssertionReaction& reaction\n    ) {\n        m_lastAssertionInfo = info;\n\n        AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );\n        data.message = message;\n        AssertionResult assertionResult{ info, data };\n        assertionEnded( assertionResult );\n        populateReaction( reaction );\n    }\n\n    void RunContext::populateReaction( AssertionReaction& reaction ) {\n        reaction.shouldDebugBreak = m_config->shouldDebugBreak();\n        reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal);\n    }\n\n    void RunContext::handleIncomplete(\n            AssertionInfo const& info\n    ) {\n        m_lastAssertionInfo = info;\n\n        AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );\n        data.message = \"Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE\";\n        AssertionResult assertionResult{ info, data };\n        assertionEnded( assertionResult );\n    }\n    void RunContext::handleNonExpr(\n            AssertionInfo const &info,\n            ResultWas::OfType resultType,\n            AssertionReaction &reaction\n    ) {\n        m_lastAssertionInfo = info;\n\n        AssertionResultData data( resultType, LazyExpression( false ) );\n        AssertionResult assertionResult{ info, data };\n        assertionEnded( assertionResult );\n\n        if( !assertionResult.isOk() )\n            populateReaction( reaction );\n    }\n\n    IResultCapture& getResultCapture() {\n        if (auto* capture = getCurrentContext().getResultCapture())\n            return *capture;\n        else\n            CATCH_INTERNAL_ERROR(\"No result capture instance\");\n    }\n\n    void seedRng(IConfig const& config) {\n        if (config.rngSeed() != 0) {\n            std::srand(config.rngSeed());\n            rng().seed(config.rngSeed());\n        }\n    }\n\n    unsigned int rngSeed() {\n        return getCurrentContext().getConfig()->rngSeed();\n    }\n\n}\n// end catch_run_context.cpp\n// start catch_section.cpp\n\nnamespace Catch {\n\n    Section::Section( SectionInfo const& info )\n    :   m_info( info ),\n        m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) )\n    {\n        m_timer.start();\n    }\n\n    Section::~Section() {\n        if( m_sectionIncluded ) {\n            SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() };\n            if( uncaught_exceptions() )\n                getResultCapture().sectionEndedEarly( endInfo );\n            else\n                getResultCapture().sectionEnded( endInfo );\n        }\n    }\n\n    // This indicates whether the section should be executed or not\n    Section::operator bool() const {\n        return m_sectionIncluded;\n    }\n\n} // end namespace Catch\n// end catch_section.cpp\n// start catch_section_info.cpp\n\nnamespace Catch {\n\n    SectionInfo::SectionInfo\n        (   SourceLineInfo const& _lineInfo,\n            std::string const& _name )\n    :   name( _name ),\n        lineInfo( _lineInfo )\n    {}\n\n} // end namespace Catch\n// end catch_section_info.cpp\n// start catch_session.cpp\n\n// start catch_session.h\n\n#include <memory>\n\nnamespace Catch {\n\n    class Session : NonCopyable {\n    public:\n\n        Session();\n        ~Session() override;\n\n        void showHelp() const;\n        void libIdentify();\n\n        int applyCommandLine( int argc, char const * const * argv );\n    #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)\n        int applyCommandLine( int argc, wchar_t const * const * argv );\n    #endif\n\n        void useConfigData( ConfigData const& configData );\n\n        template<typename CharT>\n        int run(int argc, CharT const * const argv[]) {\n            if (m_startupExceptions)\n                return 1;\n            int returnCode = applyCommandLine(argc, argv);\n            if (returnCode == 0)\n                returnCode = run();\n            return returnCode;\n        }\n\n        int run();\n\n        clara::Parser const& cli() const;\n        void cli( clara::Parser const& newParser );\n        ConfigData& configData();\n        Config& config();\n    private:\n        int runInternal();\n\n        clara::Parser m_cli;\n        ConfigData m_configData;\n        std::shared_ptr<Config> m_config;\n        bool m_startupExceptions = false;\n    };\n\n} // end namespace Catch\n\n// end catch_session.h\n// start catch_version.h\n\n#include <iosfwd>\n\nnamespace Catch {\n\n    // Versioning information\n    struct Version {\n        Version( Version const& ) = delete;\n        Version& operator=( Version const& ) = delete;\n        Version(    unsigned int _majorVersion,\n                    unsigned int _minorVersion,\n                    unsigned int _patchNumber,\n                    char const * const _branchName,\n                    unsigned int _buildNumber );\n\n        unsigned int const majorVersion;\n        unsigned int const minorVersion;\n        unsigned int const patchNumber;\n\n        // buildNumber is only used if branchName is not null\n        char const * const branchName;\n        unsigned int const buildNumber;\n\n        friend std::ostream& operator << ( std::ostream& os, Version const& version );\n    };\n\n    Version const& libraryVersion();\n}\n\n// end catch_version.h\n#include <cstdlib>\n#include <iomanip>\n#include <set>\n#include <iterator>\n\nnamespace Catch {\n\n    namespace {\n        const int MaxExitCode = 255;\n\n        IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) {\n            auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config);\n            CATCH_ENFORCE(reporter, \"No reporter registered with name: '\" << reporterName << \"'\");\n\n            return reporter;\n        }\n\n        IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) {\n            if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) {\n                return createReporter(config->getReporterName(), config);\n            }\n\n            // On older platforms, returning std::unique_ptr<ListeningReporter>\n            // when the return type is std::unique_ptr<IStreamingReporter>\n            // doesn't compile without a std::move call. However, this causes\n            // a warning on newer platforms. Thus, we have to work around\n            // it a bit and downcast the pointer manually.\n            auto ret = std::unique_ptr<IStreamingReporter>(new ListeningReporter);\n            auto& multi = static_cast<ListeningReporter&>(*ret);\n            auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();\n            for (auto const& listener : listeners) {\n                multi.addListener(listener->create(Catch::ReporterConfig(config)));\n            }\n            multi.addReporter(createReporter(config->getReporterName(), config));\n            return ret;\n        }\n\n        class TestGroup {\n        public:\n            explicit TestGroup(std::shared_ptr<Config> const& config)\n            : m_config{config}\n            , m_context{config, makeReporter(config)}\n            {\n                auto const& allTestCases = getAllTestCasesSorted(*m_config);\n                m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config);\n                auto const& invalidArgs = m_config->testSpec().getInvalidArgs();\n\n                if (m_matches.empty() && invalidArgs.empty()) {\n                    for (auto const& test : allTestCases)\n                        if (!test.isHidden())\n                            m_tests.emplace(&test);\n                } else {\n                    for (auto const& match : m_matches)\n                        m_tests.insert(match.tests.begin(), match.tests.end());\n                }\n            }\n\n            Totals execute() {\n                auto const& invalidArgs = m_config->testSpec().getInvalidArgs();\n                Totals totals;\n                m_context.testGroupStarting(m_config->name(), 1, 1);\n                for (auto const& testCase : m_tests) {\n                    if (!m_context.aborting())\n                        totals += m_context.runTest(*testCase);\n                    else\n                        m_context.reporter().skipTest(*testCase);\n                }\n\n                for (auto const& match : m_matches) {\n                    if (match.tests.empty()) {\n                        m_context.reporter().noMatchingTestCases(match.name);\n                        totals.error = -1;\n                    }\n                }\n\n                if (!invalidArgs.empty()) {\n                    for (auto const& invalidArg: invalidArgs)\n                         m_context.reporter().reportInvalidArguments(invalidArg);\n                }\n\n                m_context.testGroupEnded(m_config->name(), totals, 1, 1);\n                return totals;\n            }\n\n        private:\n            using Tests = std::set<TestCase const*>;\n\n            std::shared_ptr<Config> m_config;\n            RunContext m_context;\n            Tests m_tests;\n            TestSpec::Matches m_matches;\n        };\n\n        void applyFilenamesAsTags(Catch::IConfig const& config) {\n            auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config));\n            for (auto& testCase : tests) {\n                auto tags = testCase.tags;\n\n                std::string filename = testCase.lineInfo.file;\n                auto lastSlash = filename.find_last_of(\"\\\\/\");\n                if (lastSlash != std::string::npos) {\n                    filename.erase(0, lastSlash);\n                    filename[0] = '#';\n                }\n                else\n                {\n                    filename.insert(0, \"#\");\n                }\n\n                auto lastDot = filename.find_last_of('.');\n                if (lastDot != std::string::npos) {\n                    filename.erase(lastDot);\n                }\n\n                tags.push_back(std::move(filename));\n                setTags(testCase, tags);\n            }\n        }\n\n    } // anon namespace\n\n    Session::Session() {\n        static bool alreadyInstantiated = false;\n        if( alreadyInstantiated ) {\n            CATCH_TRY { CATCH_INTERNAL_ERROR( \"Only one instance of Catch::Session can ever be used\" ); }\n            CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); }\n        }\n\n        // There cannot be exceptions at startup in no-exception mode.\n#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)\n        const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();\n        if ( !exceptions.empty() ) {\n            config();\n            getCurrentMutableContext().setConfig(m_config);\n\n            m_startupExceptions = true;\n            Colour colourGuard( Colour::Red );\n            Catch::cerr() << \"Errors occurred during startup!\" << '\\n';\n            // iterate over all exceptions and notify user\n            for ( const auto& ex_ptr : exceptions ) {\n                try {\n                    std::rethrow_exception(ex_ptr);\n                } catch ( std::exception const& ex ) {\n                    Catch::cerr() << Column( ex.what() ).indent(2) << '\\n';\n                }\n            }\n        }\n#endif\n\n        alreadyInstantiated = true;\n        m_cli = makeCommandLineParser( m_configData );\n    }\n    Session::~Session() {\n        Catch::cleanUp();\n    }\n\n    void Session::showHelp() const {\n        Catch::cout()\n                << \"\\nCatch v\" << libraryVersion() << \"\\n\"\n                << m_cli << std::endl\n                << \"For more detailed usage please see the project docs\\n\" << std::endl;\n    }\n    void Session::libIdentify() {\n        Catch::cout()\n                << std::left << std::setw(16) << \"description: \" << \"A Catch2 test executable\\n\"\n                << std::left << std::setw(16) << \"category: \" << \"testframework\\n\"\n                << std::left << std::setw(16) << \"framework: \" << \"Catch Test\\n\"\n                << std::left << std::setw(16) << \"version: \" << libraryVersion() << std::endl;\n    }\n\n    int Session::applyCommandLine( int argc, char const * const * argv ) {\n        if( m_startupExceptions )\n            return 1;\n\n        auto result = m_cli.parse( clara::Args( argc, argv ) );\n        if( !result ) {\n            config();\n            getCurrentMutableContext().setConfig(m_config);\n            Catch::cerr()\n                << Colour( Colour::Red )\n                << \"\\nError(s) in input:\\n\"\n                << Column( result.errorMessage() ).indent( 2 )\n                << \"\\n\\n\";\n            Catch::cerr() << \"Run with -? for usage\\n\" << std::endl;\n            return MaxExitCode;\n        }\n\n        if( m_configData.showHelp )\n            showHelp();\n        if( m_configData.libIdentify )\n            libIdentify();\n        m_config.reset();\n        return 0;\n    }\n\n#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)\n    int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {\n\n        char **utf8Argv = new char *[ argc ];\n\n        for ( int i = 0; i < argc; ++i ) {\n            int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr );\n\n            utf8Argv[ i ] = new char[ bufSize ];\n\n            WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr );\n        }\n\n        int returnCode = applyCommandLine( argc, utf8Argv );\n\n        for ( int i = 0; i < argc; ++i )\n            delete [] utf8Argv[ i ];\n\n        delete [] utf8Argv;\n\n        return returnCode;\n    }\n#endif\n\n    void Session::useConfigData( ConfigData const& configData ) {\n        m_configData = configData;\n        m_config.reset();\n    }\n\n    int Session::run() {\n        if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {\n            Catch::cout() << \"...waiting for enter/ return before starting\" << std::endl;\n            static_cast<void>(std::getchar());\n        }\n        int exitCode = runInternal();\n        if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {\n            Catch::cout() << \"...waiting for enter/ return before exiting, with code: \" << exitCode << std::endl;\n            static_cast<void>(std::getchar());\n        }\n        return exitCode;\n    }\n\n    clara::Parser const& Session::cli() const {\n        return m_cli;\n    }\n    void Session::cli( clara::Parser const& newParser ) {\n        m_cli = newParser;\n    }\n    ConfigData& Session::configData() {\n        return m_configData;\n    }\n    Config& Session::config() {\n        if( !m_config )\n            m_config = std::make_shared<Config>( m_configData );\n        return *m_config;\n    }\n\n    int Session::runInternal() {\n        if( m_startupExceptions )\n            return 1;\n\n        if (m_configData.showHelp || m_configData.libIdentify) {\n            return 0;\n        }\n\n        CATCH_TRY {\n            config(); // Force config to be constructed\n\n            seedRng( *m_config );\n\n            if( m_configData.filenamesAsTags )\n                applyFilenamesAsTags( *m_config );\n\n            // Handle list request\n            if( Option<std::size_t> listed = list( m_config ) )\n                return static_cast<int>( *listed );\n\n            TestGroup tests { m_config };\n            auto const totals = tests.execute();\n\n            if( m_config->warnAboutNoTests() && totals.error == -1 )\n                return 2;\n\n            // Note that on unices only the lower 8 bits are usually used, clamping\n            // the return value to 255 prevents false negative when some multiple\n            // of 256 tests has failed\n            return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed)));\n        }\n#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)\n        catch( std::exception& ex ) {\n            Catch::cerr() << ex.what() << std::endl;\n            return MaxExitCode;\n        }\n#endif\n    }\n\n} // end namespace Catch\n// end catch_session.cpp\n// start catch_singletons.cpp\n\n#include <vector>\n\nnamespace Catch {\n\n    namespace {\n        static auto getSingletons() -> std::vector<ISingleton*>*& {\n            static std::vector<ISingleton*>* g_singletons = nullptr;\n            if( !g_singletons )\n                g_singletons = new std::vector<ISingleton*>();\n            return g_singletons;\n        }\n    }\n\n    ISingleton::~ISingleton() {}\n\n    void addSingleton(ISingleton* singleton ) {\n        getSingletons()->push_back( singleton );\n    }\n    void cleanupSingletons() {\n        auto& singletons = getSingletons();\n        for( auto singleton : *singletons )\n            delete singleton;\n        delete singletons;\n        singletons = nullptr;\n    }\n\n} // namespace Catch\n// end catch_singletons.cpp\n// start catch_startup_exception_registry.cpp\n\n#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)\nnamespace Catch {\nvoid StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {\n        CATCH_TRY {\n            m_exceptions.push_back(exception);\n        } CATCH_CATCH_ALL {\n            // If we run out of memory during start-up there's really not a lot more we can do about it\n            std::terminate();\n        }\n    }\n\n    std::vector<std::exception_ptr> const& StartupExceptionRegistry::getExceptions() const noexcept {\n        return m_exceptions;\n    }\n\n} // end namespace Catch\n#endif\n// end catch_startup_exception_registry.cpp\n// start catch_stream.cpp\n\n#include <cstdio>\n#include <iostream>\n#include <fstream>\n#include <sstream>\n#include <vector>\n#include <memory>\n\nnamespace Catch {\n\n    Catch::IStream::~IStream() = default;\n\n    namespace Detail { namespace {\n        template<typename WriterF, std::size_t bufferSize=256>\n        class StreamBufImpl : public std::streambuf {\n            char data[bufferSize];\n            WriterF m_writer;\n\n        public:\n            StreamBufImpl() {\n                setp( data, data + sizeof(data) );\n            }\n\n            ~StreamBufImpl() noexcept {\n                StreamBufImpl::sync();\n            }\n\n        private:\n            int overflow( int c ) override {\n                sync();\n\n                if( c != EOF ) {\n                    if( pbase() == epptr() )\n                        m_writer( std::string( 1, static_cast<char>( c ) ) );\n                    else\n                        sputc( static_cast<char>( c ) );\n                }\n                return 0;\n            }\n\n            int sync() override {\n                if( pbase() != pptr() ) {\n                    m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );\n                    setp( pbase(), epptr() );\n                }\n                return 0;\n            }\n        };\n\n        ///////////////////////////////////////////////////////////////////////////\n\n        struct OutputDebugWriter {\n\n            void operator()( std::string const&str ) {\n                writeToDebugConsole( str );\n            }\n        };\n\n        ///////////////////////////////////////////////////////////////////////////\n\n        class FileStream : public IStream {\n            mutable std::ofstream m_ofs;\n        public:\n            FileStream( StringRef filename ) {\n                m_ofs.open( filename.c_str() );\n                CATCH_ENFORCE( !m_ofs.fail(), \"Unable to open file: '\" << filename << \"'\" );\n            }\n            ~FileStream() override = default;\n        public: // IStream\n            std::ostream& stream() const override {\n                return m_ofs;\n            }\n        };\n\n        ///////////////////////////////////////////////////////////////////////////\n\n        class CoutStream : public IStream {\n            mutable std::ostream m_os;\n        public:\n            // Store the streambuf from cout up-front because\n            // cout may get redirected when running tests\n            CoutStream() : m_os( Catch::cout().rdbuf() ) {}\n            ~CoutStream() override = default;\n\n        public: // IStream\n            std::ostream& stream() const override { return m_os; }\n        };\n\n        ///////////////////////////////////////////////////////////////////////////\n\n        class DebugOutStream : public IStream {\n            std::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf;\n            mutable std::ostream m_os;\n        public:\n            DebugOutStream()\n            :   m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ),\n                m_os( m_streamBuf.get() )\n            {}\n\n            ~DebugOutStream() override = default;\n\n        public: // IStream\n            std::ostream& stream() const override { return m_os; }\n        };\n\n    }} // namespace anon::detail\n\n    ///////////////////////////////////////////////////////////////////////////\n\n    auto makeStream( StringRef const &filename ) -> IStream const* {\n        if( filename.empty() )\n            return new Detail::CoutStream();\n        else if( filename[0] == '%' ) {\n            if( filename == \"%debug\" )\n                return new Detail::DebugOutStream();\n            else\n                CATCH_ERROR( \"Unrecognised stream: '\" << filename << \"'\" );\n        }\n        else\n            return new Detail::FileStream( filename );\n    }\n\n    // This class encapsulates the idea of a pool of ostringstreams that can be reused.\n    struct StringStreams {\n        std::vector<std::unique_ptr<std::ostringstream>> m_streams;\n        std::vector<std::size_t> m_unused;\n        std::ostringstream m_referenceStream; // Used for copy state/ flags from\n\n        auto add() -> std::size_t {\n            if( m_unused.empty() ) {\n                m_streams.push_back( std::unique_ptr<std::ostringstream>( new std::ostringstream ) );\n                return m_streams.size()-1;\n            }\n            else {\n                auto index = m_unused.back();\n                m_unused.pop_back();\n                return index;\n            }\n        }\n\n        void release( std::size_t index ) {\n            m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state\n            m_unused.push_back(index);\n        }\n    };\n\n    ReusableStringStream::ReusableStringStream()\n    :   m_index( Singleton<StringStreams>::getMutable().add() ),\n        m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() )\n    {}\n\n    ReusableStringStream::~ReusableStringStream() {\n        static_cast<std::ostringstream*>( m_oss )->str(\"\");\n        m_oss->clear();\n        Singleton<StringStreams>::getMutable().release( m_index );\n    }\n\n    auto ReusableStringStream::str() const -> std::string {\n        return static_cast<std::ostringstream*>( m_oss )->str();\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n\n#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions\n    std::ostream& cout() { return std::cout; }\n    std::ostream& cerr() { return std::cerr; }\n    std::ostream& clog() { return std::clog; }\n#endif\n}\n// end catch_stream.cpp\n// start catch_string_manip.cpp\n\n#include <algorithm>\n#include <ostream>\n#include <cstring>\n#include <cctype>\n#include <vector>\n\nnamespace Catch {\n\n    namespace {\n        char toLowerCh(char c) {\n            return static_cast<char>( std::tolower( static_cast<unsigned char>(c) ) );\n        }\n    }\n\n    bool startsWith( std::string const& s, std::string const& prefix ) {\n        return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());\n    }\n    bool startsWith( std::string const& s, char prefix ) {\n        return !s.empty() && s[0] == prefix;\n    }\n    bool endsWith( std::string const& s, std::string const& suffix ) {\n        return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());\n    }\n    bool endsWith( std::string const& s, char suffix ) {\n        return !s.empty() && s[s.size()-1] == suffix;\n    }\n    bool contains( std::string const& s, std::string const& infix ) {\n        return s.find( infix ) != std::string::npos;\n    }\n    void toLowerInPlace( std::string& s ) {\n        std::transform( s.begin(), s.end(), s.begin(), toLowerCh );\n    }\n    std::string toLower( std::string const& s ) {\n        std::string lc = s;\n        toLowerInPlace( lc );\n        return lc;\n    }\n    std::string trim( std::string const& str ) {\n        static char const* whitespaceChars = \"\\n\\r\\t \";\n        std::string::size_type start = str.find_first_not_of( whitespaceChars );\n        std::string::size_type end = str.find_last_not_of( whitespaceChars );\n\n        return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();\n    }\n\n    StringRef trim(StringRef ref) {\n        const auto is_ws = [](char c) {\n            return c == ' ' || c == '\\t' || c == '\\n' || c == '\\r';\n        };\n        size_t real_begin = 0;\n        while (real_begin < ref.size() && is_ws(ref[real_begin])) { ++real_begin; }\n        size_t real_end = ref.size();\n        while (real_end > real_begin && is_ws(ref[real_end - 1])) { --real_end; }\n\n        return ref.substr(real_begin, real_end - real_begin);\n    }\n\n    bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {\n        bool replaced = false;\n        std::size_t i = str.find( replaceThis );\n        while( i != std::string::npos ) {\n            replaced = true;\n            str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() );\n            if( i < str.size()-withThis.size() )\n                i = str.find( replaceThis, i+withThis.size() );\n            else\n                i = std::string::npos;\n        }\n        return replaced;\n    }\n\n    std::vector<StringRef> splitStringRef( StringRef str, char delimiter ) {\n        std::vector<StringRef> subStrings;\n        std::size_t start = 0;\n        for(std::size_t pos = 0; pos < str.size(); ++pos ) {\n            if( str[pos] == delimiter ) {\n                if( pos - start > 1 )\n                    subStrings.push_back( str.substr( start, pos-start ) );\n                start = pos+1;\n            }\n        }\n        if( start < str.size() )\n            subStrings.push_back( str.substr( start, str.size()-start ) );\n        return subStrings;\n    }\n\n    pluralise::pluralise( std::size_t count, std::string const& label )\n    :   m_count( count ),\n        m_label( label )\n    {}\n\n    std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {\n        os << pluraliser.m_count << ' ' << pluraliser.m_label;\n        if( pluraliser.m_count != 1 )\n            os << 's';\n        return os;\n    }\n\n}\n// end catch_string_manip.cpp\n// start catch_stringref.cpp\n\n#include <algorithm>\n#include <ostream>\n#include <cstring>\n#include <cstdint>\n\nnamespace Catch {\n    StringRef::StringRef( char const* rawChars ) noexcept\n    : StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) )\n    {}\n\n    auto StringRef::c_str() const -> char const* {\n        CATCH_ENFORCE(isNullTerminated(), \"Called StringRef::c_str() on a non-null-terminated instance\");\n        return m_start;\n    }\n    auto StringRef::data() const noexcept -> char const* {\n        return m_start;\n    }\n\n    auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef {\n        if (start < m_size) {\n            return StringRef(m_start + start, (std::min)(m_size - start, size));\n        } else {\n            return StringRef();\n        }\n    }\n    auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool {\n        return m_size == other.m_size\n            && (std::memcmp( m_start, other.m_start, m_size ) == 0);\n    }\n\n    auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& {\n        return os.write(str.data(), str.size());\n    }\n\n    auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& {\n        lhs.append(rhs.data(), rhs.size());\n        return lhs;\n    }\n\n} // namespace Catch\n// end catch_stringref.cpp\n// start catch_tag_alias.cpp\n\nnamespace Catch {\n    TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {}\n}\n// end catch_tag_alias.cpp\n// start catch_tag_alias_autoregistrar.cpp\n\nnamespace Catch {\n\n    RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) {\n        CATCH_TRY {\n            getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo);\n        } CATCH_CATCH_ALL {\n            // Do not throw when constructing global objects, instead register the exception to be processed later\n            getMutableRegistryHub().registerStartupException();\n        }\n    }\n\n}\n// end catch_tag_alias_autoregistrar.cpp\n// start catch_tag_alias_registry.cpp\n\n#include <sstream>\n\nnamespace Catch {\n\n    TagAliasRegistry::~TagAliasRegistry() {}\n\n    TagAlias const* TagAliasRegistry::find( std::string const& alias ) const {\n        auto it = m_registry.find( alias );\n        if( it != m_registry.end() )\n            return &(it->second);\n        else\n            return nullptr;\n    }\n\n    std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {\n        std::string expandedTestSpec = unexpandedTestSpec;\n        for( auto const& registryKvp : m_registry ) {\n            std::size_t pos = expandedTestSpec.find( registryKvp.first );\n            if( pos != std::string::npos ) {\n                expandedTestSpec =  expandedTestSpec.substr( 0, pos ) +\n                                    registryKvp.second.tag +\n                                    expandedTestSpec.substr( pos + registryKvp.first.size() );\n            }\n        }\n        return expandedTestSpec;\n    }\n\n    void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) {\n        CATCH_ENFORCE( startsWith(alias, \"[@\") && endsWith(alias, ']'),\n                      \"error: tag alias, '\" << alias << \"' is not of the form [@alias name].\\n\" << lineInfo );\n\n        CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second,\n                      \"error: tag alias, '\" << alias << \"' already registered.\\n\"\n                      << \"\\tFirst seen at: \" << find(alias)->lineInfo << \"\\n\"\n                      << \"\\tRedefined at: \" << lineInfo );\n    }\n\n    ITagAliasRegistry::~ITagAliasRegistry() {}\n\n    ITagAliasRegistry const& ITagAliasRegistry::get() {\n        return getRegistryHub().getTagAliasRegistry();\n    }\n\n} // end namespace Catch\n// end catch_tag_alias_registry.cpp\n// start catch_test_case_info.cpp\n\n#include <cctype>\n#include <exception>\n#include <algorithm>\n#include <sstream>\n\nnamespace Catch {\n\n    namespace {\n        TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {\n            if( startsWith( tag, '.' ) ||\n                tag == \"!hide\" )\n                return TestCaseInfo::IsHidden;\n            else if( tag == \"!throws\" )\n                return TestCaseInfo::Throws;\n            else if( tag == \"!shouldfail\" )\n                return TestCaseInfo::ShouldFail;\n            else if( tag == \"!mayfail\" )\n                return TestCaseInfo::MayFail;\n            else if( tag == \"!nonportable\" )\n                return TestCaseInfo::NonPortable;\n            else if( tag == \"!benchmark\" )\n                return static_cast<TestCaseInfo::SpecialProperties>( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden );\n            else\n                return TestCaseInfo::None;\n        }\n        bool isReservedTag( std::string const& tag ) {\n            return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast<unsigned char>(tag[0]) );\n        }\n        void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {\n            CATCH_ENFORCE( !isReservedTag(tag),\n                          \"Tag name: [\" << tag << \"] is not allowed.\\n\"\n                          << \"Tag names starting with non alphanumeric characters are reserved\\n\"\n                          << _lineInfo );\n        }\n    }\n\n    TestCase makeTestCase(  ITestInvoker* _testCase,\n                            std::string const& _className,\n                            NameAndTags const& nameAndTags,\n                            SourceLineInfo const& _lineInfo )\n    {\n        bool isHidden = false;\n\n        // Parse out tags\n        std::vector<std::string> tags;\n        std::string desc, tag;\n        bool inTag = false;\n        for (char c : nameAndTags.tags) {\n            if( !inTag ) {\n                if( c == '[' )\n                    inTag = true;\n                else\n                    desc += c;\n            }\n            else {\n                if( c == ']' ) {\n                    TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag );\n                    if( ( prop & TestCaseInfo::IsHidden ) != 0 )\n                        isHidden = true;\n                    else if( prop == TestCaseInfo::None )\n                        enforceNotReservedTag( tag, _lineInfo );\n\n                    // Merged hide tags like `[.approvals]` should be added as\n                    // `[.][approvals]`. The `[.]` is added at later point, so\n                    // we only strip the prefix\n                    if (startsWith(tag, '.') && tag.size() > 1) {\n                        tag.erase(0, 1);\n                    }\n                    tags.push_back( tag );\n                    tag.clear();\n                    inTag = false;\n                }\n                else\n                    tag += c;\n            }\n        }\n        if( isHidden ) {\n            // Add all \"hidden\" tags to make them behave identically\n            tags.insert( tags.end(), { \".\", \"!hide\" } );\n        }\n\n        TestCaseInfo info( static_cast<std::string>(nameAndTags.name), _className, desc, tags, _lineInfo );\n        return TestCase( _testCase, std::move(info) );\n    }\n\n    void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ) {\n        std::sort(begin(tags), end(tags));\n        tags.erase(std::unique(begin(tags), end(tags)), end(tags));\n        testCaseInfo.lcaseTags.clear();\n\n        for( auto const& tag : tags ) {\n            std::string lcaseTag = toLower( tag );\n            testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) );\n            testCaseInfo.lcaseTags.push_back( lcaseTag );\n        }\n        testCaseInfo.tags = std::move(tags);\n    }\n\n    TestCaseInfo::TestCaseInfo( std::string const& _name,\n                                std::string const& _className,\n                                std::string const& _description,\n                                std::vector<std::string> const& _tags,\n                                SourceLineInfo const& _lineInfo )\n    :   name( _name ),\n        className( _className ),\n        description( _description ),\n        lineInfo( _lineInfo ),\n        properties( None )\n    {\n        setTags( *this, _tags );\n    }\n\n    bool TestCaseInfo::isHidden() const {\n        return ( properties & IsHidden ) != 0;\n    }\n    bool TestCaseInfo::throws() const {\n        return ( properties & Throws ) != 0;\n    }\n    bool TestCaseInfo::okToFail() const {\n        return ( properties & (ShouldFail | MayFail ) ) != 0;\n    }\n    bool TestCaseInfo::expectedToFail() const {\n        return ( properties & (ShouldFail ) ) != 0;\n    }\n\n    std::string TestCaseInfo::tagsAsString() const {\n        std::string ret;\n        // '[' and ']' per tag\n        std::size_t full_size = 2 * tags.size();\n        for (const auto& tag : tags) {\n            full_size += tag.size();\n        }\n        ret.reserve(full_size);\n        for (const auto& tag : tags) {\n            ret.push_back('[');\n            ret.append(tag);\n            ret.push_back(']');\n        }\n\n        return ret;\n    }\n\n    TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {}\n\n    TestCase TestCase::withName( std::string const& _newName ) const {\n        TestCase other( *this );\n        other.name = _newName;\n        return other;\n    }\n\n    void TestCase::invoke() const {\n        test->invoke();\n    }\n\n    bool TestCase::operator == ( TestCase const& other ) const {\n        return  test.get() == other.test.get() &&\n                name == other.name &&\n                className == other.className;\n    }\n\n    bool TestCase::operator < ( TestCase const& other ) const {\n        return name < other.name;\n    }\n\n    TestCaseInfo const& TestCase::getTestCaseInfo() const\n    {\n        return *this;\n    }\n\n} // end namespace Catch\n// end catch_test_case_info.cpp\n// start catch_test_case_registry_impl.cpp\n\n#include <algorithm>\n#include <sstream>\n\nnamespace Catch {\n\n    namespace {\n        struct TestHasher {\n            using hash_t = uint64_t;\n\n            explicit TestHasher( hash_t hashSuffix ):\n                m_hashSuffix{ hashSuffix } {}\n\n            uint32_t operator()( TestCase const& t ) const {\n                // FNV-1a hash with multiplication fold.\n                const hash_t prime = 1099511628211u;\n                hash_t hash = 14695981039346656037u;\n                for ( const char c : t.name ) {\n                    hash ^= c;\n                    hash *= prime;\n                }\n                hash ^= m_hashSuffix;\n                hash *= prime;\n                const uint32_t low{ static_cast<uint32_t>( hash ) };\n                const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) };\n                return low * high;\n            }\n\n        private:\n            hash_t m_hashSuffix;\n        };\n    } // end unnamed namespace\n\n    std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {\n        switch( config.runOrder() ) {\n            case RunTests::InDeclarationOrder:\n                // already in declaration order\n                break;\n\n            case RunTests::InLexicographicalOrder: {\n                std::vector<TestCase> sorted = unsortedTestCases;\n                std::sort( sorted.begin(), sorted.end() );\n                return sorted;\n            }\n\n            case RunTests::InRandomOrder: {\n                seedRng( config );\n                TestHasher h{ config.rngSeed() };\n\n                using hashedTest = std::pair<TestHasher::hash_t, TestCase const*>;\n                std::vector<hashedTest> indexed_tests;\n                indexed_tests.reserve( unsortedTestCases.size() );\n\n                for (auto const& testCase : unsortedTestCases) {\n                    indexed_tests.emplace_back(h(testCase), &testCase);\n                }\n\n                std::sort(indexed_tests.begin(), indexed_tests.end(),\n                          [](hashedTest const& lhs, hashedTest const& rhs) {\n                          if (lhs.first == rhs.first) {\n                              return lhs.second->name < rhs.second->name;\n                          }\n                          return lhs.first < rhs.first;\n                });\n\n                std::vector<TestCase> sorted;\n                sorted.reserve( indexed_tests.size() );\n\n                for (auto const& hashed : indexed_tests) {\n                    sorted.emplace_back(*hashed.second);\n                }\n\n                return sorted;\n            }\n        }\n        return unsortedTestCases;\n    }\n\n    bool isThrowSafe( TestCase const& testCase, IConfig const& config ) {\n        return !testCase.throws() || config.allowThrows();\n    }\n\n    bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {\n        return testSpec.matches( testCase ) && isThrowSafe( testCase, config );\n    }\n\n    void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {\n        std::set<TestCase> seenFunctions;\n        for( auto const& function : functions ) {\n            auto prev = seenFunctions.insert( function );\n            CATCH_ENFORCE( prev.second,\n                    \"error: TEST_CASE( \\\"\" << function.name << \"\\\" ) already defined.\\n\"\n                    << \"\\tFirst seen at \" << prev.first->getTestCaseInfo().lineInfo << \"\\n\"\n                    << \"\\tRedefined at \" << function.getTestCaseInfo().lineInfo );\n        }\n    }\n\n    std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) {\n        std::vector<TestCase> filtered;\n        filtered.reserve( testCases.size() );\n        for (auto const& testCase : testCases) {\n            if ((!testSpec.hasFilters() && !testCase.isHidden()) ||\n                (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) {\n                filtered.push_back(testCase);\n            }\n        }\n        return filtered;\n    }\n    std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) {\n        return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );\n    }\n\n    void TestRegistry::registerTest( TestCase const& testCase ) {\n        std::string name = testCase.getTestCaseInfo().name;\n        if( name.empty() ) {\n            ReusableStringStream rss;\n            rss << \"Anonymous test case \" << ++m_unnamedCount;\n            return registerTest( testCase.withName( rss.str() ) );\n        }\n        m_functions.push_back( testCase );\n    }\n\n    std::vector<TestCase> const& TestRegistry::getAllTests() const {\n        return m_functions;\n    }\n    std::vector<TestCase> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const {\n        if( m_sortedFunctions.empty() )\n            enforceNoDuplicateTestCases( m_functions );\n\n        if(  m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {\n            m_sortedFunctions = sortTests( config, m_functions );\n            m_currentSortOrder = config.runOrder();\n        }\n        return m_sortedFunctions;\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n    TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {}\n\n    void TestInvokerAsFunction::invoke() const {\n        m_testAsFunction();\n    }\n\n    std::string extractClassName( StringRef const& classOrQualifiedMethodName ) {\n        std::string className(classOrQualifiedMethodName);\n        if( startsWith( className, '&' ) )\n        {\n            std::size_t lastColons = className.rfind( \"::\" );\n            std::size_t penultimateColons = className.rfind( \"::\", lastColons-1 );\n            if( penultimateColons == std::string::npos )\n                penultimateColons = 1;\n            className = className.substr( penultimateColons, lastColons-penultimateColons );\n        }\n        return className;\n    }\n\n} // end namespace Catch\n// end catch_test_case_registry_impl.cpp\n// start catch_test_case_tracker.cpp\n\n#include <algorithm>\n#include <cassert>\n#include <stdexcept>\n#include <memory>\n#include <sstream>\n\n#if defined(__clang__)\n#    pragma clang diagnostic push\n#    pragma clang diagnostic ignored \"-Wexit-time-destructors\"\n#endif\n\nnamespace Catch {\nnamespace TestCaseTracking {\n\n    NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location )\n    :   name( _name ),\n        location( _location )\n    {}\n\n    ITracker::~ITracker() = default;\n\n    ITracker& TrackerContext::startRun() {\n        m_rootTracker = std::make_shared<SectionTracker>( NameAndLocation( \"{root}\", CATCH_INTERNAL_LINEINFO ), *this, nullptr );\n        m_currentTracker = nullptr;\n        m_runState = Executing;\n        return *m_rootTracker;\n    }\n\n    void TrackerContext::endRun() {\n        m_rootTracker.reset();\n        m_currentTracker = nullptr;\n        m_runState = NotStarted;\n    }\n\n    void TrackerContext::startCycle() {\n        m_currentTracker = m_rootTracker.get();\n        m_runState = Executing;\n    }\n    void TrackerContext::completeCycle() {\n        m_runState = CompletedCycle;\n    }\n\n    bool TrackerContext::completedCycle() const {\n        return m_runState == CompletedCycle;\n    }\n    ITracker& TrackerContext::currentTracker() {\n        return *m_currentTracker;\n    }\n    void TrackerContext::setCurrentTracker( ITracker* tracker ) {\n        m_currentTracker = tracker;\n    }\n\n    TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ):\n        ITracker(nameAndLocation),\n        m_ctx( ctx ),\n        m_parent( parent )\n    {}\n\n    bool TrackerBase::isComplete() const {\n        return m_runState == CompletedSuccessfully || m_runState == Failed;\n    }\n    bool TrackerBase::isSuccessfullyCompleted() const {\n        return m_runState == CompletedSuccessfully;\n    }\n    bool TrackerBase::isOpen() const {\n        return m_runState != NotStarted && !isComplete();\n    }\n    bool TrackerBase::hasChildren() const {\n        return !m_children.empty();\n    }\n\n    void TrackerBase::addChild( ITrackerPtr const& child ) {\n        m_children.push_back( child );\n    }\n\n    ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) {\n        auto it = std::find_if( m_children.begin(), m_children.end(),\n            [&nameAndLocation]( ITrackerPtr const& tracker ){\n                return\n                    tracker->nameAndLocation().location == nameAndLocation.location &&\n                    tracker->nameAndLocation().name == nameAndLocation.name;\n            } );\n        return( it != m_children.end() )\n            ? *it\n            : nullptr;\n    }\n    ITracker& TrackerBase::parent() {\n        assert( m_parent ); // Should always be non-null except for root\n        return *m_parent;\n    }\n\n    void TrackerBase::openChild() {\n        if( m_runState != ExecutingChildren ) {\n            m_runState = ExecutingChildren;\n            if( m_parent )\n                m_parent->openChild();\n        }\n    }\n\n    bool TrackerBase::isSectionTracker() const { return false; }\n    bool TrackerBase::isGeneratorTracker() const { return false; }\n\n    void TrackerBase::open() {\n        m_runState = Executing;\n        moveToThis();\n        if( m_parent )\n            m_parent->openChild();\n    }\n\n    void TrackerBase::close() {\n\n        // Close any still open children (e.g. generators)\n        while( &m_ctx.currentTracker() != this )\n            m_ctx.currentTracker().close();\n\n        switch( m_runState ) {\n            case NeedsAnotherRun:\n                break;\n\n            case Executing:\n                m_runState = CompletedSuccessfully;\n                break;\n            case ExecutingChildren:\n                if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) )\n                    m_runState = CompletedSuccessfully;\n                break;\n\n            case NotStarted:\n            case CompletedSuccessfully:\n            case Failed:\n                CATCH_INTERNAL_ERROR( \"Illogical state: \" << m_runState );\n\n            default:\n                CATCH_INTERNAL_ERROR( \"Unknown state: \" << m_runState );\n        }\n        moveToParent();\n        m_ctx.completeCycle();\n    }\n    void TrackerBase::fail() {\n        m_runState = Failed;\n        if( m_parent )\n            m_parent->markAsNeedingAnotherRun();\n        moveToParent();\n        m_ctx.completeCycle();\n    }\n    void TrackerBase::markAsNeedingAnotherRun() {\n        m_runState = NeedsAnotherRun;\n    }\n\n    void TrackerBase::moveToParent() {\n        assert( m_parent );\n        m_ctx.setCurrentTracker( m_parent );\n    }\n    void TrackerBase::moveToThis() {\n        m_ctx.setCurrentTracker( this );\n    }\n\n    SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )\n    :   TrackerBase( nameAndLocation, ctx, parent ),\n        m_trimmed_name(trim(nameAndLocation.name))\n    {\n        if( parent ) {\n            while( !parent->isSectionTracker() )\n                parent = &parent->parent();\n\n            SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );\n            addNextFilters( parentSection.m_filters );\n        }\n    }\n\n    bool SectionTracker::isComplete() const {\n        bool complete = true;\n\n        if (m_filters.empty()\n            || m_filters[0] == \"\"\n            || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {\n            complete = TrackerBase::isComplete();\n        }\n        return complete;\n    }\n\n    bool SectionTracker::isSectionTracker() const { return true; }\n\n    SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {\n        std::shared_ptr<SectionTracker> section;\n\n        ITracker& currentTracker = ctx.currentTracker();\n        if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {\n            assert( childTracker );\n            assert( childTracker->isSectionTracker() );\n            section = std::static_pointer_cast<SectionTracker>( childTracker );\n        }\n        else {\n            section = std::make_shared<SectionTracker>( nameAndLocation, ctx, &currentTracker );\n            currentTracker.addChild( section );\n        }\n        if( !ctx.completedCycle() )\n            section->tryOpen();\n        return *section;\n    }\n\n    void SectionTracker::tryOpen() {\n        if( !isComplete() )\n            open();\n    }\n\n    void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {\n        if( !filters.empty() ) {\n            m_filters.reserve( m_filters.size() + filters.size() + 2 );\n            m_filters.emplace_back(\"\"); // Root - should never be consulted\n            m_filters.emplace_back(\"\"); // Test Case - not a section filter\n            m_filters.insert( m_filters.end(), filters.begin(), filters.end() );\n        }\n    }\n    void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) {\n        if( filters.size() > 1 )\n            m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );\n    }\n\n    std::vector<std::string> const& SectionTracker::getFilters() const {\n        return m_filters;\n    }\n\n    std::string const& SectionTracker::trimmedName() const {\n        return m_trimmed_name;\n    }\n\n} // namespace TestCaseTracking\n\nusing TestCaseTracking::ITracker;\nusing TestCaseTracking::TrackerContext;\nusing TestCaseTracking::SectionTracker;\n\n} // namespace Catch\n\n#if defined(__clang__)\n#    pragma clang diagnostic pop\n#endif\n// end catch_test_case_tracker.cpp\n// start catch_test_registry.cpp\n\nnamespace Catch {\n\n    auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* {\n        return new(std::nothrow) TestInvokerAsFunction( testAsFunction );\n    }\n\n    NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {}\n\n    AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept {\n        CATCH_TRY {\n            getMutableRegistryHub()\n                    .registerTest(\n                        makeTestCase(\n                            invoker,\n                            extractClassName( classOrMethod ),\n                            nameAndTags,\n                            lineInfo));\n        } CATCH_CATCH_ALL {\n            // Do not throw when constructing global objects, instead register the exception to be processed later\n            getMutableRegistryHub().registerStartupException();\n        }\n    }\n\n    AutoReg::~AutoReg() = default;\n}\n// end catch_test_registry.cpp\n// start catch_test_spec.cpp\n\n#include <algorithm>\n#include <string>\n#include <vector>\n#include <memory>\n\nnamespace Catch {\n\n    TestSpec::Pattern::Pattern( std::string const& name )\n    : m_name( name )\n    {}\n\n    TestSpec::Pattern::~Pattern() = default;\n\n    std::string const& TestSpec::Pattern::name() const {\n        return m_name;\n    }\n\n    TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString )\n    : Pattern( filterString )\n    , m_wildcardPattern( toLower( name ), CaseSensitive::No )\n    {}\n\n    bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {\n        return m_wildcardPattern.matches( testCase.name );\n    }\n\n    TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )\n    : Pattern( filterString )\n    , m_tag( toLower( tag ) )\n    {}\n\n    bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {\n        return std::find(begin(testCase.lcaseTags),\n                         end(testCase.lcaseTags),\n                         m_tag) != end(testCase.lcaseTags);\n    }\n\n    TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern )\n    : Pattern( underlyingPattern->name() )\n    , m_underlyingPattern( underlyingPattern )\n    {}\n\n    bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const {\n        return !m_underlyingPattern->matches( testCase );\n    }\n\n    bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {\n        return std::all_of( m_patterns.begin(), m_patterns.end(), [&]( PatternPtr const& p ){ return p->matches( testCase ); } );\n    }\n\n    std::string TestSpec::Filter::name() const {\n        std::string name;\n        for( auto const& p : m_patterns )\n            name += p->name();\n        return name;\n    }\n\n    bool TestSpec::hasFilters() const {\n        return !m_filters.empty();\n    }\n\n    bool TestSpec::matches( TestCaseInfo const& testCase ) const {\n        return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } );\n    }\n\n    TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const\n    {\n        Matches matches( m_filters.size() );\n        std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){\n            std::vector<TestCase const*> currentMatches;\n            for( auto const& test : testCases )\n                if( isThrowSafe( test, config ) && filter.matches( test ) )\n                    currentMatches.emplace_back( &test );\n            return FilterMatch{ filter.name(), currentMatches };\n        } );\n        return matches;\n    }\n\n    const TestSpec::vectorStrings& TestSpec::getInvalidArgs() const{\n        return  (m_invalidArgs);\n    }\n\n}\n// end catch_test_spec.cpp\n// start catch_test_spec_parser.cpp\n\nnamespace Catch {\n\n    TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}\n\n    TestSpecParser& TestSpecParser::parse( std::string const& arg ) {\n        m_mode = None;\n        m_exclusion = false;\n        m_arg = m_tagAliases->expandAliases( arg );\n        m_escapeChars.clear();\n        m_substring.reserve(m_arg.size());\n        m_patternName.reserve(m_arg.size());\n        m_realPatternPos = 0;\n\n        for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )\n          //if visitChar fails\n           if( !visitChar( m_arg[m_pos] ) ){\n               m_testSpec.m_invalidArgs.push_back(arg);\n               break;\n           }\n        endMode();\n        return *this;\n    }\n    TestSpec TestSpecParser::testSpec() {\n        addFilter();\n        return m_testSpec;\n    }\n    bool TestSpecParser::visitChar( char c ) {\n        if( (m_mode != EscapedName) && (c == '\\\\') ) {\n            escape();\n            addCharToPattern(c);\n            return true;\n        }else if((m_mode != EscapedName) && (c == ',') )  {\n            return separate();\n        }\n\n        switch( m_mode ) {\n        case None:\n            if( processNoneChar( c ) )\n                return true;\n            break;\n        case Name:\n            processNameChar( c );\n            break;\n        case EscapedName:\n            endMode();\n            addCharToPattern(c);\n            return true;\n        default:\n        case Tag:\n        case QuotedName:\n            if( processOtherChar( c ) )\n                return true;\n            break;\n        }\n\n        m_substring += c;\n        if( !isControlChar( c ) ) {\n            m_patternName += c;\n            m_realPatternPos++;\n        }\n        return true;\n    }\n    // Two of the processing methods return true to signal the caller to return\n    // without adding the given character to the current pattern strings\n    bool TestSpecParser::processNoneChar( char c ) {\n        switch( c ) {\n        case ' ':\n            return true;\n        case '~':\n            m_exclusion = true;\n            return false;\n        case '[':\n            startNewMode( Tag );\n            return false;\n        case '\"':\n            startNewMode( QuotedName );\n            return false;\n        default:\n            startNewMode( Name );\n            return false;\n        }\n    }\n    void TestSpecParser::processNameChar( char c ) {\n        if( c == '[' ) {\n            if( m_substring == \"exclude:\" )\n                m_exclusion = true;\n            else\n                endMode();\n            startNewMode( Tag );\n        }\n    }\n    bool TestSpecParser::processOtherChar( char c ) {\n        if( !isControlChar( c ) )\n            return false;\n        m_substring += c;\n        endMode();\n        return true;\n    }\n    void TestSpecParser::startNewMode( Mode mode ) {\n        m_mode = mode;\n    }\n    void TestSpecParser::endMode() {\n        switch( m_mode ) {\n        case Name:\n        case QuotedName:\n            return addNamePattern();\n        case Tag:\n            return addTagPattern();\n        case EscapedName:\n            revertBackToLastMode();\n            return;\n        case None:\n        default:\n            return startNewMode( None );\n        }\n    }\n    void TestSpecParser::escape() {\n        saveLastMode();\n        m_mode = EscapedName;\n        m_escapeChars.push_back(m_realPatternPos);\n    }\n    bool TestSpecParser::isControlChar( char c ) const {\n        switch( m_mode ) {\n            default:\n                return false;\n            case None:\n                return c == '~';\n            case Name:\n                return c == '[';\n            case EscapedName:\n                return true;\n            case QuotedName:\n                return c == '\"';\n            case Tag:\n                return c == '[' || c == ']';\n        }\n    }\n\n    void TestSpecParser::addFilter() {\n        if( !m_currentFilter.m_patterns.empty() ) {\n            m_testSpec.m_filters.push_back( m_currentFilter );\n            m_currentFilter = TestSpec::Filter();\n        }\n    }\n\n    void TestSpecParser::saveLastMode() {\n      lastMode = m_mode;\n    }\n\n    void TestSpecParser::revertBackToLastMode() {\n      m_mode = lastMode;\n    }\n\n    bool TestSpecParser::separate() {\n      if( (m_mode==QuotedName) || (m_mode==Tag) ){\n         //invalid argument, signal failure to previous scope.\n         m_mode = None;\n         m_pos = m_arg.size();\n         m_substring.clear();\n         m_patternName.clear();\n         m_realPatternPos = 0;\n         return false;\n      }\n      endMode();\n      addFilter();\n      return true; //success\n    }\n\n    std::string TestSpecParser::preprocessPattern() {\n        std::string token = m_patternName;\n        for (std::size_t i = 0; i < m_escapeChars.size(); ++i)\n            token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1);\n        m_escapeChars.clear();\n        if (startsWith(token, \"exclude:\")) {\n            m_exclusion = true;\n            token = token.substr(8);\n        }\n\n        m_patternName.clear();\n        m_realPatternPos = 0;\n\n        return token;\n    }\n\n    void TestSpecParser::addNamePattern() {\n        auto token = preprocessPattern();\n\n        if (!token.empty()) {\n            TestSpec::PatternPtr pattern = std::make_shared<TestSpec::NamePattern>(token, m_substring);\n            if (m_exclusion)\n                pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);\n            m_currentFilter.m_patterns.push_back(pattern);\n        }\n        m_substring.clear();\n        m_exclusion = false;\n        m_mode = None;\n    }\n\n    void TestSpecParser::addTagPattern() {\n        auto token = preprocessPattern();\n\n        if (!token.empty()) {\n            // If the tag pattern is the \"hide and tag\" shorthand (e.g. [.foo])\n            // we have to create a separate hide tag and shorten the real one\n            if (token.size() > 1 && token[0] == '.') {\n                token.erase(token.begin());\n                TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(\".\", m_substring);\n                if (m_exclusion) {\n                    pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);\n                }\n                m_currentFilter.m_patterns.push_back(pattern);\n            }\n\n            TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(token, m_substring);\n\n            if (m_exclusion) {\n                pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern);\n            }\n            m_currentFilter.m_patterns.push_back(pattern);\n        }\n        m_substring.clear();\n        m_exclusion = false;\n        m_mode = None;\n    }\n\n    TestSpec parseTestSpec( std::string const& arg ) {\n        return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();\n    }\n\n} // namespace Catch\n// end catch_test_spec_parser.cpp\n// start catch_timer.cpp\n\n#include <chrono>\n\nstatic const uint64_t nanosecondsInSecond = 1000000000;\n\nnamespace Catch {\n\n    auto getCurrentNanosecondsSinceEpoch() -> uint64_t {\n        return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();\n    }\n\n    namespace {\n        auto estimateClockResolution() -> uint64_t {\n            uint64_t sum = 0;\n            static const uint64_t iterations = 1000000;\n\n            auto startTime = getCurrentNanosecondsSinceEpoch();\n\n            for( std::size_t i = 0; i < iterations; ++i ) {\n\n                uint64_t ticks;\n                uint64_t baseTicks = getCurrentNanosecondsSinceEpoch();\n                do {\n                    ticks = getCurrentNanosecondsSinceEpoch();\n                } while( ticks == baseTicks );\n\n                auto delta = ticks - baseTicks;\n                sum += delta;\n\n                // If we have been calibrating for over 3 seconds -- the clock\n                // is terrible and we should move on.\n                // TBD: How to signal that the measured resolution is probably wrong?\n                if (ticks > startTime + 3 * nanosecondsInSecond) {\n                    return sum / ( i + 1u );\n                }\n            }\n\n            // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers\n            // - and potentially do more iterations if there's a high variance.\n            return sum/iterations;\n        }\n    }\n    auto getEstimatedClockResolution() -> uint64_t {\n        static auto s_resolution = estimateClockResolution();\n        return s_resolution;\n    }\n\n    void Timer::start() {\n       m_nanoseconds = getCurrentNanosecondsSinceEpoch();\n    }\n    auto Timer::getElapsedNanoseconds() const -> uint64_t {\n        return getCurrentNanosecondsSinceEpoch() - m_nanoseconds;\n    }\n    auto Timer::getElapsedMicroseconds() const -> uint64_t {\n        return getElapsedNanoseconds()/1000;\n    }\n    auto Timer::getElapsedMilliseconds() const -> unsigned int {\n        return static_cast<unsigned int>(getElapsedMicroseconds()/1000);\n    }\n    auto Timer::getElapsedSeconds() const -> double {\n        return getElapsedMicroseconds()/1000000.0;\n    }\n\n} // namespace Catch\n// end catch_timer.cpp\n// start catch_tostring.cpp\n\n#if defined(__clang__)\n#    pragma clang diagnostic push\n#    pragma clang diagnostic ignored \"-Wexit-time-destructors\"\n#    pragma clang diagnostic ignored \"-Wglobal-constructors\"\n#endif\n\n// Enable specific decls locally\n#if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)\n#define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER\n#endif\n\n#include <cmath>\n#include <iomanip>\n\nnamespace Catch {\n\nnamespace Detail {\n\n    const std::string unprintableString = \"{?}\";\n\n    namespace {\n        const int hexThreshold = 255;\n\n        struct Endianness {\n            enum Arch { Big, Little };\n\n            static Arch which() {\n                int one = 1;\n                // If the lowest byte we read is non-zero, we can assume\n                // that little endian format is used.\n                auto value = *reinterpret_cast<char*>(&one);\n                return value ? Little : Big;\n            }\n        };\n    }\n\n    std::string rawMemoryToString( const void *object, std::size_t size ) {\n        // Reverse order for little endian architectures\n        int i = 0, end = static_cast<int>( size ), inc = 1;\n        if( Endianness::which() == Endianness::Little ) {\n            i = end-1;\n            end = inc = -1;\n        }\n\n        unsigned char const *bytes = static_cast<unsigned char const *>(object);\n        ReusableStringStream rss;\n        rss << \"0x\" << std::setfill('0') << std::hex;\n        for( ; i != end; i += inc )\n             rss << std::setw(2) << static_cast<unsigned>(bytes[i]);\n       return rss.str();\n    }\n}\n\ntemplate<typename T>\nstd::string fpToString( T value, int precision ) {\n    if (Catch::isnan(value)) {\n        return \"nan\";\n    }\n\n    ReusableStringStream rss;\n    rss << std::setprecision( precision )\n        << std::fixed\n        << value;\n    std::string d = rss.str();\n    std::size_t i = d.find_last_not_of( '0' );\n    if( i != std::string::npos && i != d.size()-1 ) {\n        if( d[i] == '.' )\n            i++;\n        d = d.substr( 0, i+1 );\n    }\n    return d;\n}\n\n//// ======================================================= ////\n//\n//   Out-of-line defs for full specialization of StringMaker\n//\n//// ======================================================= ////\n\nstd::string StringMaker<std::string>::convert(const std::string& str) {\n    if (!getCurrentContext().getConfig()->showInvisibles()) {\n        return '\"' + str + '\"';\n    }\n\n    std::string s(\"\\\"\");\n    for (char c : str) {\n        switch (c) {\n        case '\\n':\n            s.append(\"\\\\n\");\n            break;\n        case '\\t':\n            s.append(\"\\\\t\");\n            break;\n        default:\n            s.push_back(c);\n            break;\n        }\n    }\n    s.append(\"\\\"\");\n    return s;\n}\n\n#ifdef CATCH_CONFIG_CPP17_STRING_VIEW\nstd::string StringMaker<std::string_view>::convert(std::string_view str) {\n    return ::Catch::Detail::stringify(std::string{ str });\n}\n#endif\n\nstd::string StringMaker<char const*>::convert(char const* str) {\n    if (str) {\n        return ::Catch::Detail::stringify(std::string{ str });\n    } else {\n        return{ \"{null string}\" };\n    }\n}\nstd::string StringMaker<char*>::convert(char* str) {\n    if (str) {\n        return ::Catch::Detail::stringify(std::string{ str });\n    } else {\n        return{ \"{null string}\" };\n    }\n}\n\n#ifdef CATCH_CONFIG_WCHAR\nstd::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {\n    std::string s;\n    s.reserve(wstr.size());\n    for (auto c : wstr) {\n        s += (c <= 0xff) ? static_cast<char>(c) : '?';\n    }\n    return ::Catch::Detail::stringify(s);\n}\n\n# ifdef CATCH_CONFIG_CPP17_STRING_VIEW\nstd::string StringMaker<std::wstring_view>::convert(std::wstring_view str) {\n    return StringMaker<std::wstring>::convert(std::wstring(str));\n}\n# endif\n\nstd::string StringMaker<wchar_t const*>::convert(wchar_t const * str) {\n    if (str) {\n        return ::Catch::Detail::stringify(std::wstring{ str });\n    } else {\n        return{ \"{null string}\" };\n    }\n}\nstd::string StringMaker<wchar_t *>::convert(wchar_t * str) {\n    if (str) {\n        return ::Catch::Detail::stringify(std::wstring{ str });\n    } else {\n        return{ \"{null string}\" };\n    }\n}\n#endif\n\n#if defined(CATCH_CONFIG_CPP17_BYTE)\n#include <cstddef>\nstd::string StringMaker<std::byte>::convert(std::byte value) {\n    return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value));\n}\n#endif // defined(CATCH_CONFIG_CPP17_BYTE)\n\nstd::string StringMaker<int>::convert(int value) {\n    return ::Catch::Detail::stringify(static_cast<long long>(value));\n}\nstd::string StringMaker<long>::convert(long value) {\n    return ::Catch::Detail::stringify(static_cast<long long>(value));\n}\nstd::string StringMaker<long long>::convert(long long value) {\n    ReusableStringStream rss;\n    rss << value;\n    if (value > Detail::hexThreshold) {\n        rss << \" (0x\" << std::hex << value << ')';\n    }\n    return rss.str();\n}\n\nstd::string StringMaker<unsigned int>::convert(unsigned int value) {\n    return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));\n}\nstd::string StringMaker<unsigned long>::convert(unsigned long value) {\n    return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));\n}\nstd::string StringMaker<unsigned long long>::convert(unsigned long long value) {\n    ReusableStringStream rss;\n    rss << value;\n    if (value > Detail::hexThreshold) {\n        rss << \" (0x\" << std::hex << value << ')';\n    }\n    return rss.str();\n}\n\nstd::string StringMaker<bool>::convert(bool b) {\n    return b ? \"true\" : \"false\";\n}\n\nstd::string StringMaker<signed char>::convert(signed char value) {\n    if (value == '\\r') {\n        return \"'\\\\r'\";\n    } else if (value == '\\f') {\n        return \"'\\\\f'\";\n    } else if (value == '\\n') {\n        return \"'\\\\n'\";\n    } else if (value == '\\t') {\n        return \"'\\\\t'\";\n    } else if ('\\0' <= value && value < ' ') {\n        return ::Catch::Detail::stringify(static_cast<unsigned int>(value));\n    } else {\n        char chstr[] = \"' '\";\n        chstr[1] = value;\n        return chstr;\n    }\n}\nstd::string StringMaker<char>::convert(char c) {\n    return ::Catch::Detail::stringify(static_cast<signed char>(c));\n}\nstd::string StringMaker<unsigned char>::convert(unsigned char c) {\n    return ::Catch::Detail::stringify(static_cast<char>(c));\n}\n\nstd::string StringMaker<std::nullptr_t>::convert(std::nullptr_t) {\n    return \"nullptr\";\n}\n\nint StringMaker<float>::precision = 5;\n\nstd::string StringMaker<float>::convert(float value) {\n    return fpToString(value, precision) + 'f';\n}\n\nint StringMaker<double>::precision = 10;\n\nstd::string StringMaker<double>::convert(double value) {\n    return fpToString(value, precision);\n}\n\nstd::string ratio_string<std::atto>::symbol() { return \"a\"; }\nstd::string ratio_string<std::femto>::symbol() { return \"f\"; }\nstd::string ratio_string<std::pico>::symbol() { return \"p\"; }\nstd::string ratio_string<std::nano>::symbol() { return \"n\"; }\nstd::string ratio_string<std::micro>::symbol() { return \"u\"; }\nstd::string ratio_string<std::milli>::symbol() { return \"m\"; }\n\n} // end namespace Catch\n\n#if defined(__clang__)\n#    pragma clang diagnostic pop\n#endif\n\n// end catch_tostring.cpp\n// start catch_totals.cpp\n\nnamespace Catch {\n\n    Counts Counts::operator - ( Counts const& other ) const {\n        Counts diff;\n        diff.passed = passed - other.passed;\n        diff.failed = failed - other.failed;\n        diff.failedButOk = failedButOk - other.failedButOk;\n        return diff;\n    }\n\n    Counts& Counts::operator += ( Counts const& other ) {\n        passed += other.passed;\n        failed += other.failed;\n        failedButOk += other.failedButOk;\n        return *this;\n    }\n\n    std::size_t Counts::total() const {\n        return passed + failed + failedButOk;\n    }\n    bool Counts::allPassed() const {\n        return failed == 0 && failedButOk == 0;\n    }\n    bool Counts::allOk() const {\n        return failed == 0;\n    }\n\n    Totals Totals::operator - ( Totals const& other ) const {\n        Totals diff;\n        diff.assertions = assertions - other.assertions;\n        diff.testCases = testCases - other.testCases;\n        return diff;\n    }\n\n    Totals& Totals::operator += ( Totals const& other ) {\n        assertions += other.assertions;\n        testCases += other.testCases;\n        return *this;\n    }\n\n    Totals Totals::delta( Totals const& prevTotals ) const {\n        Totals diff = *this - prevTotals;\n        if( diff.assertions.failed > 0 )\n            ++diff.testCases.failed;\n        else if( diff.assertions.failedButOk > 0 )\n            ++diff.testCases.failedButOk;\n        else\n            ++diff.testCases.passed;\n        return diff;\n    }\n\n}\n// end catch_totals.cpp\n// start catch_uncaught_exceptions.cpp\n\n// start catch_config_uncaught_exceptions.hpp\n\n//              Copyright Catch2 Authors\n// Distributed under the Boost Software License, Version 1.0.\n//   (See accompanying file LICENSE_1_0.txt or copy at\n//        https://www.boost.org/LICENSE_1_0.txt)\n\n// SPDX-License-Identifier: BSL-1.0\n\n#ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP\n#define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP\n\n#if defined(_MSC_VER)\n#  if _MSC_VER >= 1900 // Visual Studio 2015 or newer\n#    define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS\n#  endif\n#endif\n\n#include <exception>\n\n#if defined(__cpp_lib_uncaught_exceptions) \\\n    && !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)\n\n#  define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS\n#endif // __cpp_lib_uncaught_exceptions\n\n#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) \\\n    && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) \\\n    && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)\n\n#  define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS\n#endif\n\n#endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP\n// end catch_config_uncaught_exceptions.hpp\n#include <exception>\n\nnamespace Catch {\n    bool uncaught_exceptions() {\n#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)\n        return false;\n#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)\n        return std::uncaught_exceptions() > 0;\n#else\n        return std::uncaught_exception();\n#endif\n  }\n} // end namespace Catch\n// end catch_uncaught_exceptions.cpp\n// start catch_version.cpp\n\n#include <ostream>\n\nnamespace Catch {\n\n    Version::Version\n        (   unsigned int _majorVersion,\n            unsigned int _minorVersion,\n            unsigned int _patchNumber,\n            char const * const _branchName,\n            unsigned int _buildNumber )\n    :   majorVersion( _majorVersion ),\n        minorVersion( _minorVersion ),\n        patchNumber( _patchNumber ),\n        branchName( _branchName ),\n        buildNumber( _buildNumber )\n    {}\n\n    std::ostream& operator << ( std::ostream& os, Version const& version ) {\n        os  << version.majorVersion << '.'\n            << version.minorVersion << '.'\n            << version.patchNumber;\n        // branchName is never null -> 0th char is \\0 if it is empty\n        if (version.branchName[0]) {\n            os << '-' << version.branchName\n               << '.' << version.buildNumber;\n        }\n        return os;\n    }\n\n    Version const& libraryVersion() {\n        static Version version( 2, 13, 9, \"\", 0 );\n        return version;\n    }\n\n}\n// end catch_version.cpp\n// start catch_wildcard_pattern.cpp\n\nnamespace Catch {\n\n    WildcardPattern::WildcardPattern( std::string const& pattern,\n                                      CaseSensitive::Choice caseSensitivity )\n    :   m_caseSensitivity( caseSensitivity ),\n        m_pattern( normaliseString( pattern ) )\n    {\n        if( startsWith( m_pattern, '*' ) ) {\n            m_pattern = m_pattern.substr( 1 );\n            m_wildcard = WildcardAtStart;\n        }\n        if( endsWith( m_pattern, '*' ) ) {\n            m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );\n            m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );\n        }\n    }\n\n    bool WildcardPattern::matches( std::string const& str ) const {\n        switch( m_wildcard ) {\n            case NoWildcard:\n                return m_pattern == normaliseString( str );\n            case WildcardAtStart:\n                return endsWith( normaliseString( str ), m_pattern );\n            case WildcardAtEnd:\n                return startsWith( normaliseString( str ), m_pattern );\n            case WildcardAtBothEnds:\n                return contains( normaliseString( str ), m_pattern );\n            default:\n                CATCH_INTERNAL_ERROR( \"Unknown enum\" );\n        }\n    }\n\n    std::string WildcardPattern::normaliseString( std::string const& str ) const {\n        return trim( m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str );\n    }\n}\n// end catch_wildcard_pattern.cpp\n// start catch_xmlwriter.cpp\n\n#include <iomanip>\n#include <type_traits>\n\nnamespace Catch {\n\nnamespace {\n\n    size_t trailingBytes(unsigned char c) {\n        if ((c & 0xE0) == 0xC0) {\n            return 2;\n        }\n        if ((c & 0xF0) == 0xE0) {\n            return 3;\n        }\n        if ((c & 0xF8) == 0xF0) {\n            return 4;\n        }\n        CATCH_INTERNAL_ERROR(\"Invalid multibyte utf-8 start byte encountered\");\n    }\n\n    uint32_t headerValue(unsigned char c) {\n        if ((c & 0xE0) == 0xC0) {\n            return c & 0x1F;\n        }\n        if ((c & 0xF0) == 0xE0) {\n            return c & 0x0F;\n        }\n        if ((c & 0xF8) == 0xF0) {\n            return c & 0x07;\n        }\n        CATCH_INTERNAL_ERROR(\"Invalid multibyte utf-8 start byte encountered\");\n    }\n\n    void hexEscapeChar(std::ostream& os, unsigned char c) {\n        std::ios_base::fmtflags f(os.flags());\n        os << \"\\\\x\"\n            << std::uppercase << std::hex << std::setfill('0') << std::setw(2)\n            << static_cast<int>(c);\n        os.flags(f);\n    }\n\n    bool shouldNewline(XmlFormatting fmt) {\n        return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Newline));\n    }\n\n    bool shouldIndent(XmlFormatting fmt) {\n        return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Indent));\n    }\n\n} // anonymous namespace\n\n    XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs) {\n        return static_cast<XmlFormatting>(\n            static_cast<std::underlying_type<XmlFormatting>::type>(lhs) |\n            static_cast<std::underlying_type<XmlFormatting>::type>(rhs)\n        );\n    }\n\n    XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs) {\n        return static_cast<XmlFormatting>(\n            static_cast<std::underlying_type<XmlFormatting>::type>(lhs) &\n            static_cast<std::underlying_type<XmlFormatting>::type>(rhs)\n        );\n    }\n\n    XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )\n    :   m_str( str ),\n        m_forWhat( forWhat )\n    {}\n\n    void XmlEncode::encodeTo( std::ostream& os ) const {\n        // Apostrophe escaping not necessary if we always use \" to write attributes\n        // (see: http://www.w3.org/TR/xml/#syntax)\n\n        for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {\n            unsigned char c = m_str[idx];\n            switch (c) {\n            case '<':   os << \"&lt;\"; break;\n            case '&':   os << \"&amp;\"; break;\n\n            case '>':\n                // See: http://www.w3.org/TR/xml/#syntax\n                if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']')\n                    os << \"&gt;\";\n                else\n                    os << c;\n                break;\n\n            case '\\\"':\n                if (m_forWhat == ForAttributes)\n                    os << \"&quot;\";\n                else\n                    os << c;\n                break;\n\n            default:\n                // Check for control characters and invalid utf-8\n\n                // Escape control characters in standard ascii\n                // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0\n                if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) {\n                    hexEscapeChar(os, c);\n                    break;\n                }\n\n                // Plain ASCII: Write it to stream\n                if (c < 0x7F) {\n                    os << c;\n                    break;\n                }\n\n                // UTF-8 territory\n                // Check if the encoding is valid and if it is not, hex escape bytes.\n                // Important: We do not check the exact decoded values for validity, only the encoding format\n                // First check that this bytes is a valid lead byte:\n                // This means that it is not encoded as 1111 1XXX\n                // Or as 10XX XXXX\n                if (c <  0xC0 ||\n                    c >= 0xF8) {\n                    hexEscapeChar(os, c);\n                    break;\n                }\n\n                auto encBytes = trailingBytes(c);\n                // Are there enough bytes left to avoid accessing out-of-bounds memory?\n                if (idx + encBytes - 1 >= m_str.size()) {\n                    hexEscapeChar(os, c);\n                    break;\n                }\n                // The header is valid, check data\n                // The next encBytes bytes must together be a valid utf-8\n                // This means: bitpattern 10XX XXXX and the extracted value is sane (ish)\n                bool valid = true;\n                uint32_t value = headerValue(c);\n                for (std::size_t n = 1; n < encBytes; ++n) {\n                    unsigned char nc = m_str[idx + n];\n                    valid &= ((nc & 0xC0) == 0x80);\n                    value = (value << 6) | (nc & 0x3F);\n                }\n\n                if (\n                    // Wrong bit pattern of following bytes\n                    (!valid) ||\n                    // Overlong encodings\n                    (value < 0x80) ||\n                    (0x80 <= value && value < 0x800   && encBytes > 2) ||\n                    (0x800 < value && value < 0x10000 && encBytes > 3) ||\n                    // Encoded value out of range\n                    (value >= 0x110000)\n                    ) {\n                    hexEscapeChar(os, c);\n                    break;\n                }\n\n                // If we got here, this is in fact a valid(ish) utf-8 sequence\n                for (std::size_t n = 0; n < encBytes; ++n) {\n                    os << m_str[idx + n];\n                }\n                idx += encBytes - 1;\n                break;\n            }\n        }\n    }\n\n    std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {\n        xmlEncode.encodeTo( os );\n        return os;\n    }\n\n    XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting fmt )\n    :   m_writer( writer ),\n        m_fmt(fmt)\n    {}\n\n    XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept\n    :   m_writer( other.m_writer ),\n        m_fmt(other.m_fmt)\n    {\n        other.m_writer = nullptr;\n        other.m_fmt = XmlFormatting::None;\n    }\n    XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept {\n        if ( m_writer ) {\n            m_writer->endElement();\n        }\n        m_writer = other.m_writer;\n        other.m_writer = nullptr;\n        m_fmt = other.m_fmt;\n        other.m_fmt = XmlFormatting::None;\n        return *this;\n    }\n\n    XmlWriter::ScopedElement::~ScopedElement() {\n        if (m_writer) {\n            m_writer->endElement(m_fmt);\n        }\n    }\n\n    XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, XmlFormatting fmt ) {\n        m_writer->writeText( text, fmt );\n        return *this;\n    }\n\n    XmlWriter::XmlWriter( std::ostream& os ) : m_os( os )\n    {\n        writeDeclaration();\n    }\n\n    XmlWriter::~XmlWriter() {\n        while (!m_tags.empty()) {\n            endElement();\n        }\n        newlineIfNecessary();\n    }\n\n    XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) {\n        ensureTagClosed();\n        newlineIfNecessary();\n        if (shouldIndent(fmt)) {\n            m_os << m_indent;\n            m_indent += \"  \";\n        }\n        m_os << '<' << name;\n        m_tags.push_back( name );\n        m_tagIsOpen = true;\n        applyFormatting(fmt);\n        return *this;\n    }\n\n    XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) {\n        ScopedElement scoped( this, fmt );\n        startElement( name, fmt );\n        return scoped;\n    }\n\n    XmlWriter& XmlWriter::endElement(XmlFormatting fmt) {\n        m_indent = m_indent.substr(0, m_indent.size() - 2);\n\n        if( m_tagIsOpen ) {\n            m_os << \"/>\";\n            m_tagIsOpen = false;\n        } else {\n            newlineIfNecessary();\n            if (shouldIndent(fmt)) {\n                m_os << m_indent;\n            }\n            m_os << \"</\" << m_tags.back() << \">\";\n        }\n        m_os << std::flush;\n        applyFormatting(fmt);\n        m_tags.pop_back();\n        return *this;\n    }\n\n    XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) {\n        if( !name.empty() && !attribute.empty() )\n            m_os << ' ' << name << \"=\\\"\" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '\"';\n        return *this;\n    }\n\n    XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) {\n        m_os << ' ' << name << \"=\\\"\" << ( attribute ? \"true\" : \"false\" ) << '\"';\n        return *this;\n    }\n\n    XmlWriter& XmlWriter::writeText( std::string const& text, XmlFormatting fmt) {\n        if( !text.empty() ){\n            bool tagWasOpen = m_tagIsOpen;\n            ensureTagClosed();\n            if (tagWasOpen && shouldIndent(fmt)) {\n                m_os << m_indent;\n            }\n            m_os << XmlEncode( text );\n            applyFormatting(fmt);\n        }\n        return *this;\n    }\n\n    XmlWriter& XmlWriter::writeComment( std::string const& text, XmlFormatting fmt) {\n        ensureTagClosed();\n        if (shouldIndent(fmt)) {\n            m_os << m_indent;\n        }\n        m_os << \"<!--\" << text << \"-->\";\n        applyFormatting(fmt);\n        return *this;\n    }\n\n    void XmlWriter::writeStylesheetRef( std::string const& url ) {\n        m_os << \"<?xml-stylesheet type=\\\"text/xsl\\\" href=\\\"\" << url << \"\\\"?>\\n\";\n    }\n\n    XmlWriter& XmlWriter::writeBlankLine() {\n        ensureTagClosed();\n        m_os << '\\n';\n        return *this;\n    }\n\n    void XmlWriter::ensureTagClosed() {\n        if( m_tagIsOpen ) {\n            m_os << '>' << std::flush;\n            newlineIfNecessary();\n            m_tagIsOpen = false;\n        }\n    }\n\n    void XmlWriter::applyFormatting(XmlFormatting fmt) {\n        m_needsNewline = shouldNewline(fmt);\n    }\n\n    void XmlWriter::writeDeclaration() {\n        m_os << \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n\";\n    }\n\n    void XmlWriter::newlineIfNecessary() {\n        if( m_needsNewline ) {\n            m_os << std::endl;\n            m_needsNewline = false;\n        }\n    }\n}\n// end catch_xmlwriter.cpp\n// start catch_reporter_bases.cpp\n\n#include <cstring>\n#include <cfloat>\n#include <cstdio>\n#include <cassert>\n#include <memory>\n\nnamespace Catch {\n    void prepareExpandedExpression(AssertionResult& result) {\n        result.getExpandedExpression();\n    }\n\n    // Because formatting using c++ streams is stateful, drop down to C is required\n    // Alternatively we could use stringstream, but its performance is... not good.\n    std::string getFormattedDuration( double duration ) {\n        // Max exponent + 1 is required to represent the whole part\n        // + 1 for decimal point\n        // + 3 for the 3 decimal places\n        // + 1 for null terminator\n        const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;\n        char buffer[maxDoubleSize];\n\n        // Save previous errno, to prevent sprintf from overwriting it\n        ErrnoGuard guard;\n#ifdef _MSC_VER\n        sprintf_s(buffer, \"%.3f\", duration);\n#else\n        std::sprintf(buffer, \"%.3f\", duration);\n#endif\n        return std::string(buffer);\n    }\n\n    bool shouldShowDuration( IConfig const& config, double duration ) {\n        if ( config.showDurations() == ShowDurations::Always ) {\n            return true;\n        }\n        if ( config.showDurations() == ShowDurations::Never ) {\n            return false;\n        }\n        const double min = config.minDuration();\n        return min >= 0 && duration >= min;\n    }\n\n    std::string serializeFilters( std::vector<std::string> const& container ) {\n        ReusableStringStream oss;\n        bool first = true;\n        for (auto&& filter : container)\n        {\n            if (!first)\n                oss << ' ';\n            else\n                first = false;\n\n            oss << filter;\n        }\n        return oss.str();\n    }\n\n    TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config)\n        :StreamingReporterBase(_config) {}\n\n    std::set<Verbosity> TestEventListenerBase::getSupportedVerbosities() {\n        return { Verbosity::Quiet, Verbosity::Normal, Verbosity::High };\n    }\n\n    void TestEventListenerBase::assertionStarting(AssertionInfo const &) {}\n\n    bool TestEventListenerBase::assertionEnded(AssertionStats const &) {\n        return false;\n    }\n\n} // end namespace Catch\n// end catch_reporter_bases.cpp\n// start catch_reporter_compact.cpp\n\nnamespace {\n\n#ifdef CATCH_PLATFORM_MAC\n    const char* failedString() { return \"FAILED\"; }\n    const char* passedString() { return \"PASSED\"; }\n#else\n    const char* failedString() { return \"failed\"; }\n    const char* passedString() { return \"passed\"; }\n#endif\n\n    // Colour::LightGrey\n    Catch::Colour::Code dimColour() { return Catch::Colour::FileName; }\n\n    std::string bothOrAll( std::size_t count ) {\n        return count == 1 ? std::string() :\n               count == 2 ? \"both \" : \"all \" ;\n    }\n\n} // anon namespace\n\nnamespace Catch {\nnamespace {\n// Colour, message variants:\n// - white: No tests ran.\n// -   red: Failed [both/all] N test cases, failed [both/all] M assertions.\n// - white: Passed [both/all] N test cases (no assertions).\n// -   red: Failed N tests cases, failed M assertions.\n// - green: Passed [both/all] N tests cases with M assertions.\nvoid printTotals(std::ostream& out, const Totals& totals) {\n    if (totals.testCases.total() == 0) {\n        out << \"No tests ran.\";\n    } else if (totals.testCases.failed == totals.testCases.total()) {\n        Colour colour(Colour::ResultError);\n        const std::string qualify_assertions_failed =\n            totals.assertions.failed == totals.assertions.total() ?\n            bothOrAll(totals.assertions.failed) : std::string();\n        out <<\n            \"Failed \" << bothOrAll(totals.testCases.failed)\n            << pluralise(totals.testCases.failed, \"test case\") << \", \"\n            \"failed \" << qualify_assertions_failed <<\n            pluralise(totals.assertions.failed, \"assertion\") << '.';\n    } else if (totals.assertions.total() == 0) {\n        out <<\n            \"Passed \" << bothOrAll(totals.testCases.total())\n            << pluralise(totals.testCases.total(), \"test case\")\n            << \" (no assertions).\";\n    } else if (totals.assertions.failed) {\n        Colour colour(Colour::ResultError);\n        out <<\n            \"Failed \" << pluralise(totals.testCases.failed, \"test case\") << \", \"\n            \"failed \" << pluralise(totals.assertions.failed, \"assertion\") << '.';\n    } else {\n        Colour colour(Colour::ResultSuccess);\n        out <<\n            \"Passed \" << bothOrAll(totals.testCases.passed)\n            << pluralise(totals.testCases.passed, \"test case\") <<\n            \" with \" << pluralise(totals.assertions.passed, \"assertion\") << '.';\n    }\n}\n\n// Implementation of CompactReporter formatting\nclass AssertionPrinter {\npublic:\n    AssertionPrinter& operator= (AssertionPrinter const&) = delete;\n    AssertionPrinter(AssertionPrinter const&) = delete;\n    AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)\n        : stream(_stream)\n        , result(_stats.assertionResult)\n        , messages(_stats.infoMessages)\n        , itMessage(_stats.infoMessages.begin())\n        , printInfoMessages(_printInfoMessages) {}\n\n    void print() {\n        printSourceInfo();\n\n        itMessage = messages.begin();\n\n        switch (result.getResultType()) {\n        case ResultWas::Ok:\n            printResultType(Colour::ResultSuccess, passedString());\n            printOriginalExpression();\n            printReconstructedExpression();\n            if (!result.hasExpression())\n                printRemainingMessages(Colour::None);\n            else\n                printRemainingMessages();\n            break;\n        case ResultWas::ExpressionFailed:\n            if (result.isOk())\n                printResultType(Colour::ResultSuccess, failedString() + std::string(\" - but was ok\"));\n            else\n                printResultType(Colour::Error, failedString());\n            printOriginalExpression();\n            printReconstructedExpression();\n            printRemainingMessages();\n            break;\n        case ResultWas::ThrewException:\n            printResultType(Colour::Error, failedString());\n            printIssue(\"unexpected exception with message:\");\n            printMessage();\n            printExpressionWas();\n            printRemainingMessages();\n            break;\n        case ResultWas::FatalErrorCondition:\n            printResultType(Colour::Error, failedString());\n            printIssue(\"fatal error condition with message:\");\n            printMessage();\n            printExpressionWas();\n            printRemainingMessages();\n            break;\n        case ResultWas::DidntThrowException:\n            printResultType(Colour::Error, failedString());\n            printIssue(\"expected exception, got none\");\n            printExpressionWas();\n            printRemainingMessages();\n            break;\n        case ResultWas::Info:\n            printResultType(Colour::None, \"info\");\n            printMessage();\n            printRemainingMessages();\n            break;\n        case ResultWas::Warning:\n            printResultType(Colour::None, \"warning\");\n            printMessage();\n            printRemainingMessages();\n            break;\n        case ResultWas::ExplicitFailure:\n            printResultType(Colour::Error, failedString());\n            printIssue(\"explicitly\");\n            printRemainingMessages(Colour::None);\n            break;\n            // These cases are here to prevent compiler warnings\n        case ResultWas::Unknown:\n        case ResultWas::FailureBit:\n        case ResultWas::Exception:\n            printResultType(Colour::Error, \"** internal error **\");\n            break;\n        }\n    }\n\nprivate:\n    void printSourceInfo() const {\n        Colour colourGuard(Colour::FileName);\n        stream << result.getSourceInfo() << ':';\n    }\n\n    void printResultType(Colour::Code colour, std::string const& passOrFail) const {\n        if (!passOrFail.empty()) {\n            {\n                Colour colourGuard(colour);\n                stream << ' ' << passOrFail;\n            }\n            stream << ':';\n        }\n    }\n\n    void printIssue(std::string const& issue) const {\n        stream << ' ' << issue;\n    }\n\n    void printExpressionWas() {\n        if (result.hasExpression()) {\n            stream << ';';\n            {\n                Colour colour(dimColour());\n                stream << \" expression was:\";\n            }\n            printOriginalExpression();\n        }\n    }\n\n    void printOriginalExpression() const {\n        if (result.hasExpression()) {\n            stream << ' ' << result.getExpression();\n        }\n    }\n\n    void printReconstructedExpression() const {\n        if (result.hasExpandedExpression()) {\n            {\n                Colour colour(dimColour());\n                stream << \" for: \";\n            }\n            stream << result.getExpandedExpression();\n        }\n    }\n\n    void printMessage() {\n        if (itMessage != messages.end()) {\n            stream << \" '\" << itMessage->message << '\\'';\n            ++itMessage;\n        }\n    }\n\n    void printRemainingMessages(Colour::Code colour = dimColour()) {\n        if (itMessage == messages.end())\n            return;\n\n        const auto itEnd = messages.cend();\n        const auto N = static_cast<std::size_t>(std::distance(itMessage, itEnd));\n\n        {\n            Colour colourGuard(colour);\n            stream << \" with \" << pluralise(N, \"message\") << ':';\n        }\n\n        while (itMessage != itEnd) {\n            // If this assertion is a warning ignore any INFO messages\n            if (printInfoMessages || itMessage->type != ResultWas::Info) {\n                printMessage();\n                if (itMessage != itEnd) {\n                    Colour colourGuard(dimColour());\n                    stream << \" and\";\n                }\n                continue;\n            }\n            ++itMessage;\n        }\n    }\n\nprivate:\n    std::ostream& stream;\n    AssertionResult const& result;\n    std::vector<MessageInfo> messages;\n    std::vector<MessageInfo>::const_iterator itMessage;\n    bool printInfoMessages;\n};\n\n} // anon namespace\n\n        std::string CompactReporter::getDescription() {\n            return \"Reports test results on a single line, suitable for IDEs\";\n        }\n\n        void CompactReporter::noMatchingTestCases( std::string const& spec ) {\n            stream << \"No test cases matched '\" << spec << '\\'' << std::endl;\n        }\n\n        void CompactReporter::assertionStarting( AssertionInfo const& ) {}\n\n        bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) {\n            AssertionResult const& result = _assertionStats.assertionResult;\n\n            bool printInfoMessages = true;\n\n            // Drop out if result was successful and we're not printing those\n            if( !m_config->includeSuccessfulResults() && result.isOk() ) {\n                if( result.getResultType() != ResultWas::Warning )\n                    return false;\n                printInfoMessages = false;\n            }\n\n            AssertionPrinter printer( stream, _assertionStats, printInfoMessages );\n            printer.print();\n\n            stream << std::endl;\n            return true;\n        }\n\n        void CompactReporter::sectionEnded(SectionStats const& _sectionStats) {\n            double dur = _sectionStats.durationInSeconds;\n            if ( shouldShowDuration( *m_config, dur ) ) {\n                stream << getFormattedDuration( dur ) << \" s: \" << _sectionStats.sectionInfo.name << std::endl;\n            }\n        }\n\n        void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) {\n            printTotals( stream, _testRunStats.totals );\n            stream << '\\n' << std::endl;\n            StreamingReporterBase::testRunEnded( _testRunStats );\n        }\n\n        CompactReporter::~CompactReporter() {}\n\n    CATCH_REGISTER_REPORTER( \"compact\", CompactReporter )\n\n} // end namespace Catch\n// end catch_reporter_compact.cpp\n// start catch_reporter_console.cpp\n\n#include <cfloat>\n#include <cstdio>\n\n#if defined(_MSC_VER)\n#pragma warning(push)\n#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch\n // Note that 4062 (not all labels are handled and default is missing) is enabled\n#endif\n\n#if defined(__clang__)\n#  pragma clang diagnostic push\n// For simplicity, benchmarking-only helpers are always enabled\n#  pragma clang diagnostic ignored \"-Wunused-function\"\n#endif\n\nnamespace Catch {\n\nnamespace {\n\n// Formatter impl for ConsoleReporter\nclass ConsoleAssertionPrinter {\npublic:\n    ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete;\n    ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete;\n    ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)\n        : stream(_stream),\n        stats(_stats),\n        result(_stats.assertionResult),\n        colour(Colour::None),\n        message(result.getMessage()),\n        messages(_stats.infoMessages),\n        printInfoMessages(_printInfoMessages) {\n        switch (result.getResultType()) {\n        case ResultWas::Ok:\n            colour = Colour::Success;\n            passOrFail = \"PASSED\";\n            //if( result.hasMessage() )\n            if (_stats.infoMessages.size() == 1)\n                messageLabel = \"with message\";\n            if (_stats.infoMessages.size() > 1)\n                messageLabel = \"with messages\";\n            break;\n        case ResultWas::ExpressionFailed:\n            if (result.isOk()) {\n                colour = Colour::Success;\n                passOrFail = \"FAILED - but was ok\";\n            } else {\n                colour = Colour::Error;\n                passOrFail = \"FAILED\";\n            }\n            if (_stats.infoMessages.size() == 1)\n                messageLabel = \"with message\";\n            if (_stats.infoMessages.size() > 1)\n                messageLabel = \"with messages\";\n            break;\n        case ResultWas::ThrewException:\n            colour = Colour::Error;\n            passOrFail = \"FAILED\";\n            messageLabel = \"due to unexpected exception with \";\n            if (_stats.infoMessages.size() == 1)\n                messageLabel += \"message\";\n            if (_stats.infoMessages.size() > 1)\n                messageLabel += \"messages\";\n            break;\n        case ResultWas::FatalErrorCondition:\n            colour = Colour::Error;\n            passOrFail = \"FAILED\";\n            messageLabel = \"due to a fatal error condition\";\n            break;\n        case ResultWas::DidntThrowException:\n            colour = Colour::Error;\n            passOrFail = \"FAILED\";\n            messageLabel = \"because no exception was thrown where one was expected\";\n            break;\n        case ResultWas::Info:\n            messageLabel = \"info\";\n            break;\n        case ResultWas::Warning:\n            messageLabel = \"warning\";\n            break;\n        case ResultWas::ExplicitFailure:\n            passOrFail = \"FAILED\";\n            colour = Colour::Error;\n            if (_stats.infoMessages.size() == 1)\n                messageLabel = \"explicitly with message\";\n            if (_stats.infoMessages.size() > 1)\n                messageLabel = \"explicitly with messages\";\n            break;\n            // These cases are here to prevent compiler warnings\n        case ResultWas::Unknown:\n        case ResultWas::FailureBit:\n        case ResultWas::Exception:\n            passOrFail = \"** internal error **\";\n            colour = Colour::Error;\n            break;\n        }\n    }\n\n    void print() const {\n        printSourceInfo();\n        if (stats.totals.assertions.total() > 0) {\n            printResultType();\n            printOriginalExpression();\n            printReconstructedExpression();\n        } else {\n            stream << '\\n';\n        }\n        printMessage();\n    }\n\nprivate:\n    void printResultType() const {\n        if (!passOrFail.empty()) {\n            Colour colourGuard(colour);\n            stream << passOrFail << \":\\n\";\n        }\n    }\n    void printOriginalExpression() const {\n        if (result.hasExpression()) {\n            Colour colourGuard(Colour::OriginalExpression);\n            stream << \"  \";\n            stream << result.getExpressionInMacro();\n            stream << '\\n';\n        }\n    }\n    void printReconstructedExpression() const {\n        if (result.hasExpandedExpression()) {\n            stream << \"with expansion:\\n\";\n            Colour colourGuard(Colour::ReconstructedExpression);\n            stream << Column(result.getExpandedExpression()).indent(2) << '\\n';\n        }\n    }\n    void printMessage() const {\n        if (!messageLabel.empty())\n            stream << messageLabel << ':' << '\\n';\n        for (auto const& msg : messages) {\n            // If this assertion is a warning ignore any INFO messages\n            if (printInfoMessages || msg.type != ResultWas::Info)\n                stream << Column(msg.message).indent(2) << '\\n';\n        }\n    }\n    void printSourceInfo() const {\n        Colour colourGuard(Colour::FileName);\n        stream << result.getSourceInfo() << \": \";\n    }\n\n    std::ostream& stream;\n    AssertionStats const& stats;\n    AssertionResult const& result;\n    Colour::Code colour;\n    std::string passOrFail;\n    std::string messageLabel;\n    std::string message;\n    std::vector<MessageInfo> messages;\n    bool printInfoMessages;\n};\n\nstd::size_t makeRatio(std::size_t number, std::size_t total) {\n    std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0;\n    return (ratio == 0 && number > 0) ? 1 : ratio;\n}\n\nstd::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) {\n    if (i > j && i > k)\n        return i;\n    else if (j > k)\n        return j;\n    else\n        return k;\n}\n\nstruct ColumnInfo {\n    enum Justification { Left, Right };\n    std::string name;\n    int width;\n    Justification justification;\n};\nstruct ColumnBreak {};\nstruct RowBreak {};\n\nclass Duration {\n    enum class Unit {\n        Auto,\n        Nanoseconds,\n        Microseconds,\n        Milliseconds,\n        Seconds,\n        Minutes\n    };\n    static const uint64_t s_nanosecondsInAMicrosecond = 1000;\n    static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond;\n    static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;\n    static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;\n\n    double m_inNanoseconds;\n    Unit m_units;\n\npublic:\n    explicit Duration(double inNanoseconds, Unit units = Unit::Auto)\n        : m_inNanoseconds(inNanoseconds),\n        m_units(units) {\n        if (m_units == Unit::Auto) {\n            if (m_inNanoseconds < s_nanosecondsInAMicrosecond)\n                m_units = Unit::Nanoseconds;\n            else if (m_inNanoseconds < s_nanosecondsInAMillisecond)\n                m_units = Unit::Microseconds;\n            else if (m_inNanoseconds < s_nanosecondsInASecond)\n                m_units = Unit::Milliseconds;\n            else if (m_inNanoseconds < s_nanosecondsInAMinute)\n                m_units = Unit::Seconds;\n            else\n                m_units = Unit::Minutes;\n        }\n\n    }\n\n    auto value() const -> double {\n        switch (m_units) {\n        case Unit::Microseconds:\n            return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMicrosecond);\n        case Unit::Milliseconds:\n            return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMillisecond);\n        case Unit::Seconds:\n            return m_inNanoseconds / static_cast<double>(s_nanosecondsInASecond);\n        case Unit::Minutes:\n            return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute);\n        default:\n            return m_inNanoseconds;\n        }\n    }\n    auto unitsAsString() const -> std::string {\n        switch (m_units) {\n        case Unit::Nanoseconds:\n            return \"ns\";\n        case Unit::Microseconds:\n            return \"us\";\n        case Unit::Milliseconds:\n            return \"ms\";\n        case Unit::Seconds:\n            return \"s\";\n        case Unit::Minutes:\n            return \"m\";\n        default:\n            return \"** internal error **\";\n        }\n\n    }\n    friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {\n        return os << duration.value() << ' ' << duration.unitsAsString();\n    }\n};\n} // end anon namespace\n\nclass TablePrinter {\n    std::ostream& m_os;\n    std::vector<ColumnInfo> m_columnInfos;\n    std::ostringstream m_oss;\n    int m_currentColumn = -1;\n    bool m_isOpen = false;\n\npublic:\n    TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos )\n    :   m_os( os ),\n        m_columnInfos( std::move( columnInfos ) ) {}\n\n    auto columnInfos() const -> std::vector<ColumnInfo> const& {\n        return m_columnInfos;\n    }\n\n    void open() {\n        if (!m_isOpen) {\n            m_isOpen = true;\n            *this << RowBreak();\n\n\t\t\tColumns headerCols;\n\t\t\tSpacer spacer(2);\n\t\t\tfor (auto const& info : m_columnInfos) {\n\t\t\t\theaderCols += Column(info.name).width(static_cast<std::size_t>(info.width - 2));\n\t\t\t\theaderCols += spacer;\n\t\t\t}\n\t\t\tm_os << headerCols << '\\n';\n\n            m_os << Catch::getLineOfChars<'-'>() << '\\n';\n        }\n    }\n    void close() {\n        if (m_isOpen) {\n            *this << RowBreak();\n            m_os << std::endl;\n            m_isOpen = false;\n        }\n    }\n\n    template<typename T>\n    friend TablePrinter& operator << (TablePrinter& tp, T const& value) {\n        tp.m_oss << value;\n        return tp;\n    }\n\n    friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) {\n        auto colStr = tp.m_oss.str();\n        const auto strSize = colStr.size();\n        tp.m_oss.str(\"\");\n        tp.open();\n        if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) {\n            tp.m_currentColumn = -1;\n            tp.m_os << '\\n';\n        }\n        tp.m_currentColumn++;\n\n        auto colInfo = tp.m_columnInfos[tp.m_currentColumn];\n        auto padding = (strSize + 1 < static_cast<std::size_t>(colInfo.width))\n            ? std::string(colInfo.width - (strSize + 1), ' ')\n            : std::string();\n        if (colInfo.justification == ColumnInfo::Left)\n            tp.m_os << colStr << padding << ' ';\n        else\n            tp.m_os << padding << colStr << ' ';\n        return tp;\n    }\n\n    friend TablePrinter& operator << (TablePrinter& tp, RowBreak) {\n        if (tp.m_currentColumn > 0) {\n            tp.m_os << '\\n';\n            tp.m_currentColumn = -1;\n        }\n        return tp;\n    }\n};\n\nConsoleReporter::ConsoleReporter(ReporterConfig const& config)\n    : StreamingReporterBase(config),\n    m_tablePrinter(new TablePrinter(config.stream(),\n        [&config]() -> std::vector<ColumnInfo> {\n        if (config.fullConfig()->benchmarkNoAnalysis())\n        {\n            return{\n                { \"benchmark name\", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left },\n                { \"     samples\", 14, ColumnInfo::Right },\n                { \"  iterations\", 14, ColumnInfo::Right },\n                { \"        mean\", 14, ColumnInfo::Right }\n            };\n        }\n        else\n        {\n            return{\n                { \"benchmark name\", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left },\n                { \"samples      mean       std dev\", 14, ColumnInfo::Right },\n                { \"iterations   low mean   low std dev\", 14, ColumnInfo::Right },\n                { \"estimated    high mean  high std dev\", 14, ColumnInfo::Right }\n            };\n        }\n    }())) {}\nConsoleReporter::~ConsoleReporter() = default;\n\nstd::string ConsoleReporter::getDescription() {\n    return \"Reports test results as plain lines of text\";\n}\n\nvoid ConsoleReporter::noMatchingTestCases(std::string const& spec) {\n    stream << \"No test cases matched '\" << spec << '\\'' << std::endl;\n}\n\nvoid ConsoleReporter::reportInvalidArguments(std::string const&arg){\n    stream << \"Invalid Filter: \" << arg << std::endl;\n}\n\nvoid ConsoleReporter::assertionStarting(AssertionInfo const&) {}\n\nbool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {\n    AssertionResult const& result = _assertionStats.assertionResult;\n\n    bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();\n\n    // Drop out if result was successful but we're not printing them.\n    if (!includeResults && result.getResultType() != ResultWas::Warning)\n        return false;\n\n    lazyPrint();\n\n    ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults);\n    printer.print();\n    stream << std::endl;\n    return true;\n}\n\nvoid ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) {\n    m_tablePrinter->close();\n    m_headerPrinted = false;\n    StreamingReporterBase::sectionStarting(_sectionInfo);\n}\nvoid ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {\n    m_tablePrinter->close();\n    if (_sectionStats.missingAssertions) {\n        lazyPrint();\n        Colour colour(Colour::ResultError);\n        if (m_sectionStack.size() > 1)\n            stream << \"\\nNo assertions in section\";\n        else\n            stream << \"\\nNo assertions in test case\";\n        stream << \" '\" << _sectionStats.sectionInfo.name << \"'\\n\" << std::endl;\n    }\n    double dur = _sectionStats.durationInSeconds;\n    if (shouldShowDuration(*m_config, dur)) {\n        stream << getFormattedDuration(dur) << \" s: \" << _sectionStats.sectionInfo.name << std::endl;\n    }\n    if (m_headerPrinted) {\n        m_headerPrinted = false;\n    }\n    StreamingReporterBase::sectionEnded(_sectionStats);\n}\n\n#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\nvoid ConsoleReporter::benchmarkPreparing(std::string const& name) {\n\tlazyPrintWithoutClosingBenchmarkTable();\n\n\tauto nameCol = Column(name).width(static_cast<std::size_t>(m_tablePrinter->columnInfos()[0].width - 2));\n\n\tbool firstLine = true;\n\tfor (auto line : nameCol) {\n\t\tif (!firstLine)\n\t\t\t(*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();\n\t\telse\n\t\t\tfirstLine = false;\n\n\t\t(*m_tablePrinter) << line << ColumnBreak();\n\t}\n}\n\nvoid ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {\n    (*m_tablePrinter) << info.samples << ColumnBreak()\n        << info.iterations << ColumnBreak();\n    if (!m_config->benchmarkNoAnalysis())\n        (*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak();\n}\nvoid ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) {\n    if (m_config->benchmarkNoAnalysis())\n    {\n        (*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak();\n    }\n    else\n    {\n        (*m_tablePrinter) << ColumnBreak()\n            << Duration(stats.mean.point.count()) << ColumnBreak()\n            << Duration(stats.mean.lower_bound.count()) << ColumnBreak()\n            << Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak()\n            << Duration(stats.standardDeviation.point.count()) << ColumnBreak()\n            << Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak()\n            << Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak();\n    }\n}\n\nvoid ConsoleReporter::benchmarkFailed(std::string const& error) {\n\tColour colour(Colour::Red);\n    (*m_tablePrinter)\n        << \"Benchmark failed (\" << error << ')'\n        << ColumnBreak() << RowBreak();\n}\n#endif // CATCH_CONFIG_ENABLE_BENCHMARKING\n\nvoid ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {\n    m_tablePrinter->close();\n    StreamingReporterBase::testCaseEnded(_testCaseStats);\n    m_headerPrinted = false;\n}\nvoid ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) {\n    if (currentGroupInfo.used) {\n        printSummaryDivider();\n        stream << \"Summary for group '\" << _testGroupStats.groupInfo.name << \"':\\n\";\n        printTotals(_testGroupStats.totals);\n        stream << '\\n' << std::endl;\n    }\n    StreamingReporterBase::testGroupEnded(_testGroupStats);\n}\nvoid ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) {\n    printTotalsDivider(_testRunStats.totals);\n    printTotals(_testRunStats.totals);\n    stream << std::endl;\n    StreamingReporterBase::testRunEnded(_testRunStats);\n}\nvoid ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) {\n    StreamingReporterBase::testRunStarting(_testInfo);\n    printTestFilters();\n}\n\nvoid ConsoleReporter::lazyPrint() {\n\n    m_tablePrinter->close();\n    lazyPrintWithoutClosingBenchmarkTable();\n}\n\nvoid ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() {\n\n    if (!currentTestRunInfo.used)\n        lazyPrintRunInfo();\n    if (!currentGroupInfo.used)\n        lazyPrintGroupInfo();\n\n    if (!m_headerPrinted) {\n        printTestCaseAndSectionHeader();\n        m_headerPrinted = true;\n    }\n}\nvoid ConsoleReporter::lazyPrintRunInfo() {\n    stream << '\\n' << getLineOfChars<'~'>() << '\\n';\n    Colour colour(Colour::SecondaryText);\n    stream << currentTestRunInfo->name\n        << \" is a Catch v\" << libraryVersion() << \" host application.\\n\"\n        << \"Run with -? for options\\n\\n\";\n\n    if (m_config->rngSeed() != 0)\n        stream << \"Randomness seeded to: \" << m_config->rngSeed() << \"\\n\\n\";\n\n    currentTestRunInfo.used = true;\n}\nvoid ConsoleReporter::lazyPrintGroupInfo() {\n    if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) {\n        printClosedHeader(\"Group: \" + currentGroupInfo->name);\n        currentGroupInfo.used = true;\n    }\n}\nvoid ConsoleReporter::printTestCaseAndSectionHeader() {\n    assert(!m_sectionStack.empty());\n    printOpenHeader(currentTestCaseInfo->name);\n\n    if (m_sectionStack.size() > 1) {\n        Colour colourGuard(Colour::Headers);\n\n        auto\n            it = m_sectionStack.begin() + 1, // Skip first section (test case)\n            itEnd = m_sectionStack.end();\n        for (; it != itEnd; ++it)\n            printHeaderString(it->name, 2);\n    }\n\n    SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;\n\n    stream << getLineOfChars<'-'>() << '\\n';\n    Colour colourGuard(Colour::FileName);\n    stream << lineInfo << '\\n';\n    stream << getLineOfChars<'.'>() << '\\n' << std::endl;\n}\n\nvoid ConsoleReporter::printClosedHeader(std::string const& _name) {\n    printOpenHeader(_name);\n    stream << getLineOfChars<'.'>() << '\\n';\n}\nvoid ConsoleReporter::printOpenHeader(std::string const& _name) {\n    stream << getLineOfChars<'-'>() << '\\n';\n    {\n        Colour colourGuard(Colour::Headers);\n        printHeaderString(_name);\n    }\n}\n\n// if string has a : in first line will set indent to follow it on\n// subsequent lines\nvoid ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) {\n    std::size_t i = _string.find(\": \");\n    if (i != std::string::npos)\n        i += 2;\n    else\n        i = 0;\n    stream << Column(_string).indent(indent + i).initialIndent(indent) << '\\n';\n}\n\nstruct SummaryColumn {\n\n    SummaryColumn( std::string _label, Colour::Code _colour )\n    :   label( std::move( _label ) ),\n        colour( _colour ) {}\n    SummaryColumn addRow( std::size_t count ) {\n        ReusableStringStream rss;\n        rss << count;\n        std::string row = rss.str();\n        for (auto& oldRow : rows) {\n            while (oldRow.size() < row.size())\n                oldRow = ' ' + oldRow;\n            while (oldRow.size() > row.size())\n                row = ' ' + row;\n        }\n        rows.push_back(row);\n        return *this;\n    }\n\n    std::string label;\n    Colour::Code colour;\n    std::vector<std::string> rows;\n\n};\n\nvoid ConsoleReporter::printTotals( Totals const& totals ) {\n    if (totals.testCases.total() == 0) {\n        stream << Colour(Colour::Warning) << \"No tests ran\\n\";\n    } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) {\n        stream << Colour(Colour::ResultSuccess) << \"All tests passed\";\n        stream << \" (\"\n            << pluralise(totals.assertions.passed, \"assertion\") << \" in \"\n            << pluralise(totals.testCases.passed, \"test case\") << ')'\n            << '\\n';\n    } else {\n\n        std::vector<SummaryColumn> columns;\n        columns.push_back(SummaryColumn(\"\", Colour::None)\n                          .addRow(totals.testCases.total())\n                          .addRow(totals.assertions.total()));\n        columns.push_back(SummaryColumn(\"passed\", Colour::Success)\n                          .addRow(totals.testCases.passed)\n                          .addRow(totals.assertions.passed));\n        columns.push_back(SummaryColumn(\"failed\", Colour::ResultError)\n                          .addRow(totals.testCases.failed)\n                          .addRow(totals.assertions.failed));\n        columns.push_back(SummaryColumn(\"failed as expected\", Colour::ResultExpectedFailure)\n                          .addRow(totals.testCases.failedButOk)\n                          .addRow(totals.assertions.failedButOk));\n\n        printSummaryRow(\"test cases\", columns, 0);\n        printSummaryRow(\"assertions\", columns, 1);\n    }\n}\nvoid ConsoleReporter::printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row) {\n    for (auto col : cols) {\n        std::string value = col.rows[row];\n        if (col.label.empty()) {\n            stream << label << \": \";\n            if (value != \"0\")\n                stream << value;\n            else\n                stream << Colour(Colour::Warning) << \"- none -\";\n        } else if (value != \"0\") {\n            stream << Colour(Colour::LightGrey) << \" | \";\n            stream << Colour(col.colour)\n                << value << ' ' << col.label;\n        }\n    }\n    stream << '\\n';\n}\n\nvoid ConsoleReporter::printTotalsDivider(Totals const& totals) {\n    if (totals.testCases.total() > 0) {\n        std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());\n        std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());\n        std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total());\n        while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1)\n            findMax(failedRatio, failedButOkRatio, passedRatio)++;\n        while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1)\n            findMax(failedRatio, failedButOkRatio, passedRatio)--;\n\n        stream << Colour(Colour::Error) << std::string(failedRatio, '=');\n        stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '=');\n        if (totals.testCases.allPassed())\n            stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '=');\n        else\n            stream << Colour(Colour::Success) << std::string(passedRatio, '=');\n    } else {\n        stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '=');\n    }\n    stream << '\\n';\n}\nvoid ConsoleReporter::printSummaryDivider() {\n    stream << getLineOfChars<'-'>() << '\\n';\n}\n\nvoid ConsoleReporter::printTestFilters() {\n    if (m_config->testSpec().hasFilters()) {\n        Colour guard(Colour::BrightYellow);\n        stream << \"Filters: \" << serializeFilters(m_config->getTestsOrTags()) << '\\n';\n    }\n}\n\nCATCH_REGISTER_REPORTER(\"console\", ConsoleReporter)\n\n} // end namespace Catch\n\n#if defined(_MSC_VER)\n#pragma warning(pop)\n#endif\n\n#if defined(__clang__)\n#  pragma clang diagnostic pop\n#endif\n// end catch_reporter_console.cpp\n// start catch_reporter_junit.cpp\n\n#include <cassert>\n#include <sstream>\n#include <ctime>\n#include <algorithm>\n#include <iomanip>\n\nnamespace Catch {\n\n    namespace {\n        std::string getCurrentTimestamp() {\n            // Beware, this is not reentrant because of backward compatibility issues\n            // Also, UTC only, again because of backward compatibility (%z is C++11)\n            time_t rawtime;\n            std::time(&rawtime);\n            auto const timeStampSize = sizeof(\"2017-01-16T17:06:45Z\");\n\n#ifdef _MSC_VER\n            std::tm timeInfo = {};\n            gmtime_s(&timeInfo, &rawtime);\n#else\n            std::tm* timeInfo;\n            timeInfo = std::gmtime(&rawtime);\n#endif\n\n            char timeStamp[timeStampSize];\n            const char * const fmt = \"%Y-%m-%dT%H:%M:%SZ\";\n\n#ifdef _MSC_VER\n            std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);\n#else\n            std::strftime(timeStamp, timeStampSize, fmt, timeInfo);\n#endif\n            return std::string(timeStamp, timeStampSize-1);\n        }\n\n        std::string fileNameTag(const std::vector<std::string> &tags) {\n            auto it = std::find_if(begin(tags),\n                                   end(tags),\n                                   [] (std::string const& tag) {return tag.front() == '#'; });\n            if (it != tags.end())\n                return it->substr(1);\n            return std::string();\n        }\n\n        // Formats the duration in seconds to 3 decimal places.\n        // This is done because some genius defined Maven Surefire schema\n        // in a way that only accepts 3 decimal places, and tools like\n        // Jenkins use that schema for validation JUnit reporter output.\n        std::string formatDuration( double seconds ) {\n            ReusableStringStream rss;\n            rss << std::fixed << std::setprecision( 3 ) << seconds;\n            return rss.str();\n        }\n\n    } // anonymous namespace\n\n    JunitReporter::JunitReporter( ReporterConfig const& _config )\n        :   CumulativeReporterBase( _config ),\n            xml( _config.stream() )\n        {\n            m_reporterPrefs.shouldRedirectStdOut = true;\n            m_reporterPrefs.shouldReportAllAssertions = true;\n        }\n\n    JunitReporter::~JunitReporter() {}\n\n    std::string JunitReporter::getDescription() {\n        return \"Reports test results in an XML format that looks like Ant's junitreport target\";\n    }\n\n    void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {}\n\n    void JunitReporter::testRunStarting( TestRunInfo const& runInfo )  {\n        CumulativeReporterBase::testRunStarting( runInfo );\n        xml.startElement( \"testsuites\" );\n    }\n\n    void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) {\n        suiteTimer.start();\n        stdOutForSuite.clear();\n        stdErrForSuite.clear();\n        unexpectedExceptions = 0;\n        CumulativeReporterBase::testGroupStarting( groupInfo );\n    }\n\n    void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) {\n        m_okToFail = testCaseInfo.okToFail();\n    }\n\n    bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) {\n        if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail )\n            unexpectedExceptions++;\n        return CumulativeReporterBase::assertionEnded( assertionStats );\n    }\n\n    void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {\n        stdOutForSuite += testCaseStats.stdOut;\n        stdErrForSuite += testCaseStats.stdErr;\n        CumulativeReporterBase::testCaseEnded( testCaseStats );\n    }\n\n    void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {\n        double suiteTime = suiteTimer.getElapsedSeconds();\n        CumulativeReporterBase::testGroupEnded( testGroupStats );\n        writeGroup( *m_testGroups.back(), suiteTime );\n    }\n\n    void JunitReporter::testRunEndedCumulative() {\n        xml.endElement();\n    }\n\n    void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) {\n        XmlWriter::ScopedElement e = xml.scopedElement( \"testsuite\" );\n\n        TestGroupStats const& stats = groupNode.value;\n        xml.writeAttribute( \"name\", stats.groupInfo.name );\n        xml.writeAttribute( \"errors\", unexpectedExceptions );\n        xml.writeAttribute( \"failures\", stats.totals.assertions.failed-unexpectedExceptions );\n        xml.writeAttribute( \"tests\", stats.totals.assertions.total() );\n        xml.writeAttribute( \"hostname\", \"tbd\" ); // !TBD\n        if( m_config->showDurations() == ShowDurations::Never )\n            xml.writeAttribute( \"time\", \"\" );\n        else\n            xml.writeAttribute( \"time\", formatDuration( suiteTime ) );\n        xml.writeAttribute( \"timestamp\", getCurrentTimestamp() );\n\n        // Write properties if there are any\n        if (m_config->hasTestFilters() || m_config->rngSeed() != 0) {\n            auto properties = xml.scopedElement(\"properties\");\n            if (m_config->hasTestFilters()) {\n                xml.scopedElement(\"property\")\n                    .writeAttribute(\"name\", \"filters\")\n                    .writeAttribute(\"value\", serializeFilters(m_config->getTestsOrTags()));\n            }\n            if (m_config->rngSeed() != 0) {\n                xml.scopedElement(\"property\")\n                    .writeAttribute(\"name\", \"random-seed\")\n                    .writeAttribute(\"value\", m_config->rngSeed());\n            }\n        }\n\n        // Write test cases\n        for( auto const& child : groupNode.children )\n            writeTestCase( *child );\n\n        xml.scopedElement( \"system-out\" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline );\n        xml.scopedElement( \"system-err\" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline );\n    }\n\n    void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) {\n        TestCaseStats const& stats = testCaseNode.value;\n\n        // All test cases have exactly one section - which represents the\n        // test case itself. That section may have 0-n nested sections\n        assert( testCaseNode.children.size() == 1 );\n        SectionNode const& rootSection = *testCaseNode.children.front();\n\n        std::string className = stats.testInfo.className;\n\n        if( className.empty() ) {\n            className = fileNameTag(stats.testInfo.tags);\n            if ( className.empty() )\n                className = \"global\";\n        }\n\n        if ( !m_config->name().empty() )\n            className = m_config->name() + \".\" + className;\n\n        writeSection( className, \"\", rootSection, stats.testInfo.okToFail() );\n    }\n\n    void JunitReporter::writeSection( std::string const& className,\n                                      std::string const& rootName,\n                                      SectionNode const& sectionNode,\n                                      bool testOkToFail) {\n        std::string name = trim( sectionNode.stats.sectionInfo.name );\n        if( !rootName.empty() )\n            name = rootName + '/' + name;\n\n        if( !sectionNode.assertions.empty() ||\n            !sectionNode.stdOut.empty() ||\n            !sectionNode.stdErr.empty() ) {\n            XmlWriter::ScopedElement e = xml.scopedElement( \"testcase\" );\n            if( className.empty() ) {\n                xml.writeAttribute( \"classname\", name );\n                xml.writeAttribute( \"name\", \"root\" );\n            }\n            else {\n                xml.writeAttribute( \"classname\", className );\n                xml.writeAttribute( \"name\", name );\n            }\n            xml.writeAttribute( \"time\", formatDuration( sectionNode.stats.durationInSeconds ) );\n            // This is not ideal, but it should be enough to mimic gtest's\n            // junit output.\n            // Ideally the JUnit reporter would also handle `skipTest`\n            // events and write those out appropriately.\n            xml.writeAttribute( \"status\", \"run\" );\n\n            if (sectionNode.stats.assertions.failedButOk) {\n                xml.scopedElement(\"skipped\")\n                    .writeAttribute(\"message\", \"TEST_CASE tagged with !mayfail\");\n            }\n\n            writeAssertions( sectionNode );\n\n            if( !sectionNode.stdOut.empty() )\n                xml.scopedElement( \"system-out\" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline );\n            if( !sectionNode.stdErr.empty() )\n                xml.scopedElement( \"system-err\" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline );\n        }\n        for( auto const& childNode : sectionNode.childSections )\n            if( className.empty() )\n                writeSection( name, \"\", *childNode, testOkToFail );\n            else\n                writeSection( className, name, *childNode, testOkToFail );\n    }\n\n    void JunitReporter::writeAssertions( SectionNode const& sectionNode ) {\n        for( auto const& assertion : sectionNode.assertions )\n            writeAssertion( assertion );\n    }\n\n    void JunitReporter::writeAssertion( AssertionStats const& stats ) {\n        AssertionResult const& result = stats.assertionResult;\n        if( !result.isOk() ) {\n            std::string elementName;\n            switch( result.getResultType() ) {\n                case ResultWas::ThrewException:\n                case ResultWas::FatalErrorCondition:\n                    elementName = \"error\";\n                    break;\n                case ResultWas::ExplicitFailure:\n                case ResultWas::ExpressionFailed:\n                case ResultWas::DidntThrowException:\n                    elementName = \"failure\";\n                    break;\n\n                // We should never see these here:\n                case ResultWas::Info:\n                case ResultWas::Warning:\n                case ResultWas::Ok:\n                case ResultWas::Unknown:\n                case ResultWas::FailureBit:\n                case ResultWas::Exception:\n                    elementName = \"internalError\";\n                    break;\n            }\n\n            XmlWriter::ScopedElement e = xml.scopedElement( elementName );\n\n            xml.writeAttribute( \"message\", result.getExpression() );\n            xml.writeAttribute( \"type\", result.getTestMacroName() );\n\n            ReusableStringStream rss;\n            if (stats.totals.assertions.total() > 0) {\n                rss << \"FAILED\" << \":\\n\";\n                if (result.hasExpression()) {\n                    rss << \"  \";\n                    rss << result.getExpressionInMacro();\n                    rss << '\\n';\n                }\n                if (result.hasExpandedExpression()) {\n                    rss << \"with expansion:\\n\";\n                    rss << Column(result.getExpandedExpression()).indent(2) << '\\n';\n                }\n            } else {\n                rss << '\\n';\n            }\n\n            if( !result.getMessage().empty() )\n                rss << result.getMessage() << '\\n';\n            for( auto const& msg : stats.infoMessages )\n                if( msg.type == ResultWas::Info )\n                    rss << msg.message << '\\n';\n\n            rss << \"at \" << result.getSourceInfo();\n            xml.writeText( rss.str(), XmlFormatting::Newline );\n        }\n    }\n\n    CATCH_REGISTER_REPORTER( \"junit\", JunitReporter )\n\n} // end namespace Catch\n// end catch_reporter_junit.cpp\n// start catch_reporter_listening.cpp\n\n#include <cassert>\n\nnamespace Catch {\n\n    ListeningReporter::ListeningReporter() {\n        // We will assume that listeners will always want all assertions\n        m_preferences.shouldReportAllAssertions = true;\n    }\n\n    void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) {\n        m_listeners.push_back( std::move( listener ) );\n    }\n\n    void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) {\n        assert(!m_reporter && \"Listening reporter can wrap only 1 real reporter\");\n        m_reporter = std::move( reporter );\n        m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut;\n    }\n\n    ReporterPreferences ListeningReporter::getPreferences() const {\n        return m_preferences;\n    }\n\n    std::set<Verbosity> ListeningReporter::getSupportedVerbosities() {\n        return std::set<Verbosity>{ };\n    }\n\n    void ListeningReporter::noMatchingTestCases( std::string const& spec ) {\n        for ( auto const& listener : m_listeners ) {\n            listener->noMatchingTestCases( spec );\n        }\n        m_reporter->noMatchingTestCases( spec );\n    }\n\n    void ListeningReporter::reportInvalidArguments(std::string const&arg){\n        for ( auto const& listener : m_listeners ) {\n            listener->reportInvalidArguments( arg );\n        }\n        m_reporter->reportInvalidArguments( arg );\n    }\n\n#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\n    void ListeningReporter::benchmarkPreparing( std::string const& name ) {\n\t\tfor (auto const& listener : m_listeners) {\n\t\t\tlistener->benchmarkPreparing(name);\n\t\t}\n\t\tm_reporter->benchmarkPreparing(name);\n\t}\n    void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {\n        for ( auto const& listener : m_listeners ) {\n            listener->benchmarkStarting( benchmarkInfo );\n        }\n        m_reporter->benchmarkStarting( benchmarkInfo );\n    }\n    void ListeningReporter::benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) {\n        for ( auto const& listener : m_listeners ) {\n            listener->benchmarkEnded( benchmarkStats );\n        }\n        m_reporter->benchmarkEnded( benchmarkStats );\n    }\n\n\tvoid ListeningReporter::benchmarkFailed( std::string const& error ) {\n\t\tfor (auto const& listener : m_listeners) {\n\t\t\tlistener->benchmarkFailed(error);\n\t\t}\n\t\tm_reporter->benchmarkFailed(error);\n\t}\n#endif // CATCH_CONFIG_ENABLE_BENCHMARKING\n\n    void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) {\n        for ( auto const& listener : m_listeners ) {\n            listener->testRunStarting( testRunInfo );\n        }\n        m_reporter->testRunStarting( testRunInfo );\n    }\n\n    void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) {\n        for ( auto const& listener : m_listeners ) {\n            listener->testGroupStarting( groupInfo );\n        }\n        m_reporter->testGroupStarting( groupInfo );\n    }\n\n    void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) {\n        for ( auto const& listener : m_listeners ) {\n            listener->testCaseStarting( testInfo );\n        }\n        m_reporter->testCaseStarting( testInfo );\n    }\n\n    void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) {\n        for ( auto const& listener : m_listeners ) {\n            listener->sectionStarting( sectionInfo );\n        }\n        m_reporter->sectionStarting( sectionInfo );\n    }\n\n    void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) {\n        for ( auto const& listener : m_listeners ) {\n            listener->assertionStarting( assertionInfo );\n        }\n        m_reporter->assertionStarting( assertionInfo );\n    }\n\n    // The return value indicates if the messages buffer should be cleared:\n    bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) {\n        for( auto const& listener : m_listeners ) {\n            static_cast<void>( listener->assertionEnded( assertionStats ) );\n        }\n        return m_reporter->assertionEnded( assertionStats );\n    }\n\n    void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) {\n        for ( auto const& listener : m_listeners ) {\n            listener->sectionEnded( sectionStats );\n        }\n        m_reporter->sectionEnded( sectionStats );\n    }\n\n    void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {\n        for ( auto const& listener : m_listeners ) {\n            listener->testCaseEnded( testCaseStats );\n        }\n        m_reporter->testCaseEnded( testCaseStats );\n    }\n\n    void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {\n        for ( auto const& listener : m_listeners ) {\n            listener->testGroupEnded( testGroupStats );\n        }\n        m_reporter->testGroupEnded( testGroupStats );\n    }\n\n    void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) {\n        for ( auto const& listener : m_listeners ) {\n            listener->testRunEnded( testRunStats );\n        }\n        m_reporter->testRunEnded( testRunStats );\n    }\n\n    void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) {\n        for ( auto const& listener : m_listeners ) {\n            listener->skipTest( testInfo );\n        }\n        m_reporter->skipTest( testInfo );\n    }\n\n    bool ListeningReporter::isMulti() const {\n        return true;\n    }\n\n} // end namespace Catch\n// end catch_reporter_listening.cpp\n// start catch_reporter_xml.cpp\n\n#if defined(_MSC_VER)\n#pragma warning(push)\n#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch\n                              // Note that 4062 (not all labels are handled\n                              // and default is missing) is enabled\n#endif\n\nnamespace Catch {\n    XmlReporter::XmlReporter( ReporterConfig const& _config )\n    :   StreamingReporterBase( _config ),\n        m_xml(_config.stream())\n    {\n        m_reporterPrefs.shouldRedirectStdOut = true;\n        m_reporterPrefs.shouldReportAllAssertions = true;\n    }\n\n    XmlReporter::~XmlReporter() = default;\n\n    std::string XmlReporter::getDescription() {\n        return \"Reports test results as an XML document\";\n    }\n\n    std::string XmlReporter::getStylesheetRef() const {\n        return std::string();\n    }\n\n    void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) {\n        m_xml\n            .writeAttribute( \"filename\", sourceInfo.file )\n            .writeAttribute( \"line\", sourceInfo.line );\n    }\n\n    void XmlReporter::noMatchingTestCases( std::string const& s ) {\n        StreamingReporterBase::noMatchingTestCases( s );\n    }\n\n    void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) {\n        StreamingReporterBase::testRunStarting( testInfo );\n        std::string stylesheetRef = getStylesheetRef();\n        if( !stylesheetRef.empty() )\n            m_xml.writeStylesheetRef( stylesheetRef );\n        m_xml.startElement( \"Catch\" );\n        if( !m_config->name().empty() )\n            m_xml.writeAttribute( \"name\", m_config->name() );\n        if (m_config->testSpec().hasFilters())\n            m_xml.writeAttribute( \"filters\", serializeFilters( m_config->getTestsOrTags() ) );\n        if( m_config->rngSeed() != 0 )\n            m_xml.scopedElement( \"Randomness\" )\n                .writeAttribute( \"seed\", m_config->rngSeed() );\n    }\n\n    void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) {\n        StreamingReporterBase::testGroupStarting( groupInfo );\n        m_xml.startElement( \"Group\" )\n            .writeAttribute( \"name\", groupInfo.name );\n    }\n\n    void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) {\n        StreamingReporterBase::testCaseStarting(testInfo);\n        m_xml.startElement( \"TestCase\" )\n            .writeAttribute( \"name\", trim( testInfo.name ) )\n            .writeAttribute( \"description\", testInfo.description )\n            .writeAttribute( \"tags\", testInfo.tagsAsString() );\n\n        writeSourceInfo( testInfo.lineInfo );\n\n        if ( m_config->showDurations() == ShowDurations::Always )\n            m_testCaseTimer.start();\n        m_xml.ensureTagClosed();\n    }\n\n    void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) {\n        StreamingReporterBase::sectionStarting( sectionInfo );\n        if( m_sectionDepth++ > 0 ) {\n            m_xml.startElement( \"Section\" )\n                .writeAttribute( \"name\", trim( sectionInfo.name ) );\n            writeSourceInfo( sectionInfo.lineInfo );\n            m_xml.ensureTagClosed();\n        }\n    }\n\n    void XmlReporter::assertionStarting( AssertionInfo const& ) { }\n\n    bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) {\n\n        AssertionResult const& result = assertionStats.assertionResult;\n\n        bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();\n\n        if( includeResults || result.getResultType() == ResultWas::Warning ) {\n            // Print any info messages in <Info> tags.\n            for( auto const& msg : assertionStats.infoMessages ) {\n                if( msg.type == ResultWas::Info && includeResults ) {\n                    m_xml.scopedElement( \"Info\" )\n                            .writeText( msg.message );\n                } else if ( msg.type == ResultWas::Warning ) {\n                    m_xml.scopedElement( \"Warning\" )\n                            .writeText( msg.message );\n                }\n            }\n        }\n\n        // Drop out if result was successful but we're not printing them.\n        if( !includeResults && result.getResultType() != ResultWas::Warning )\n            return true;\n\n        // Print the expression if there is one.\n        if( result.hasExpression() ) {\n            m_xml.startElement( \"Expression\" )\n                .writeAttribute( \"success\", result.succeeded() )\n                .writeAttribute( \"type\", result.getTestMacroName() );\n\n            writeSourceInfo( result.getSourceInfo() );\n\n            m_xml.scopedElement( \"Original\" )\n                .writeText( result.getExpression() );\n            m_xml.scopedElement( \"Expanded\" )\n                .writeText( result.getExpandedExpression() );\n        }\n\n        // And... Print a result applicable to each result type.\n        switch( result.getResultType() ) {\n            case ResultWas::ThrewException:\n                m_xml.startElement( \"Exception\" );\n                writeSourceInfo( result.getSourceInfo() );\n                m_xml.writeText( result.getMessage() );\n                m_xml.endElement();\n                break;\n            case ResultWas::FatalErrorCondition:\n                m_xml.startElement( \"FatalErrorCondition\" );\n                writeSourceInfo( result.getSourceInfo() );\n                m_xml.writeText( result.getMessage() );\n                m_xml.endElement();\n                break;\n            case ResultWas::Info:\n                m_xml.scopedElement( \"Info\" )\n                    .writeText( result.getMessage() );\n                break;\n            case ResultWas::Warning:\n                // Warning will already have been written\n                break;\n            case ResultWas::ExplicitFailure:\n                m_xml.startElement( \"Failure\" );\n                writeSourceInfo( result.getSourceInfo() );\n                m_xml.writeText( result.getMessage() );\n                m_xml.endElement();\n                break;\n            default:\n                break;\n        }\n\n        if( result.hasExpression() )\n            m_xml.endElement();\n\n        return true;\n    }\n\n    void XmlReporter::sectionEnded( SectionStats const& sectionStats ) {\n        StreamingReporterBase::sectionEnded( sectionStats );\n        if( --m_sectionDepth > 0 ) {\n            XmlWriter::ScopedElement e = m_xml.scopedElement( \"OverallResults\" );\n            e.writeAttribute( \"successes\", sectionStats.assertions.passed );\n            e.writeAttribute( \"failures\", sectionStats.assertions.failed );\n            e.writeAttribute( \"expectedFailures\", sectionStats.assertions.failedButOk );\n\n            if ( m_config->showDurations() == ShowDurations::Always )\n                e.writeAttribute( \"durationInSeconds\", sectionStats.durationInSeconds );\n\n            m_xml.endElement();\n        }\n    }\n\n    void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {\n        StreamingReporterBase::testCaseEnded( testCaseStats );\n        XmlWriter::ScopedElement e = m_xml.scopedElement( \"OverallResult\" );\n        e.writeAttribute( \"success\", testCaseStats.totals.assertions.allOk() );\n\n        if ( m_config->showDurations() == ShowDurations::Always )\n            e.writeAttribute( \"durationInSeconds\", m_testCaseTimer.getElapsedSeconds() );\n\n        if( !testCaseStats.stdOut.empty() )\n            m_xml.scopedElement( \"StdOut\" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline );\n        if( !testCaseStats.stdErr.empty() )\n            m_xml.scopedElement( \"StdErr\" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline );\n\n        m_xml.endElement();\n    }\n\n    void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {\n        StreamingReporterBase::testGroupEnded( testGroupStats );\n        // TODO: Check testGroupStats.aborting and act accordingly.\n        m_xml.scopedElement( \"OverallResults\" )\n            .writeAttribute( \"successes\", testGroupStats.totals.assertions.passed )\n            .writeAttribute( \"failures\", testGroupStats.totals.assertions.failed )\n            .writeAttribute( \"expectedFailures\", testGroupStats.totals.assertions.failedButOk );\n        m_xml.scopedElement( \"OverallResultsCases\")\n            .writeAttribute( \"successes\", testGroupStats.totals.testCases.passed )\n            .writeAttribute( \"failures\", testGroupStats.totals.testCases.failed )\n            .writeAttribute( \"expectedFailures\", testGroupStats.totals.testCases.failedButOk );\n        m_xml.endElement();\n    }\n\n    void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) {\n        StreamingReporterBase::testRunEnded( testRunStats );\n        m_xml.scopedElement( \"OverallResults\" )\n            .writeAttribute( \"successes\", testRunStats.totals.assertions.passed )\n            .writeAttribute( \"failures\", testRunStats.totals.assertions.failed )\n            .writeAttribute( \"expectedFailures\", testRunStats.totals.assertions.failedButOk );\n        m_xml.scopedElement( \"OverallResultsCases\")\n            .writeAttribute( \"successes\", testRunStats.totals.testCases.passed )\n            .writeAttribute( \"failures\", testRunStats.totals.testCases.failed )\n            .writeAttribute( \"expectedFailures\", testRunStats.totals.testCases.failedButOk );\n        m_xml.endElement();\n    }\n\n#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\n    void XmlReporter::benchmarkPreparing(std::string const& name) {\n        m_xml.startElement(\"BenchmarkResults\")\n            .writeAttribute(\"name\", name);\n    }\n\n    void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) {\n        m_xml.writeAttribute(\"samples\", info.samples)\n            .writeAttribute(\"resamples\", info.resamples)\n            .writeAttribute(\"iterations\", info.iterations)\n            .writeAttribute(\"clockResolution\", info.clockResolution)\n            .writeAttribute(\"estimatedDuration\", info.estimatedDuration)\n            .writeComment(\"All values in nano seconds\");\n    }\n\n    void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) {\n        m_xml.startElement(\"mean\")\n            .writeAttribute(\"value\", benchmarkStats.mean.point.count())\n            .writeAttribute(\"lowerBound\", benchmarkStats.mean.lower_bound.count())\n            .writeAttribute(\"upperBound\", benchmarkStats.mean.upper_bound.count())\n            .writeAttribute(\"ci\", benchmarkStats.mean.confidence_interval);\n        m_xml.endElement();\n        m_xml.startElement(\"standardDeviation\")\n            .writeAttribute(\"value\", benchmarkStats.standardDeviation.point.count())\n            .writeAttribute(\"lowerBound\", benchmarkStats.standardDeviation.lower_bound.count())\n            .writeAttribute(\"upperBound\", benchmarkStats.standardDeviation.upper_bound.count())\n            .writeAttribute(\"ci\", benchmarkStats.standardDeviation.confidence_interval);\n        m_xml.endElement();\n        m_xml.startElement(\"outliers\")\n            .writeAttribute(\"variance\", benchmarkStats.outlierVariance)\n            .writeAttribute(\"lowMild\", benchmarkStats.outliers.low_mild)\n            .writeAttribute(\"lowSevere\", benchmarkStats.outliers.low_severe)\n            .writeAttribute(\"highMild\", benchmarkStats.outliers.high_mild)\n            .writeAttribute(\"highSevere\", benchmarkStats.outliers.high_severe);\n        m_xml.endElement();\n        m_xml.endElement();\n    }\n\n    void XmlReporter::benchmarkFailed(std::string const &error) {\n        m_xml.scopedElement(\"failed\").\n            writeAttribute(\"message\", error);\n        m_xml.endElement();\n    }\n#endif // CATCH_CONFIG_ENABLE_BENCHMARKING\n\n    CATCH_REGISTER_REPORTER( \"xml\", XmlReporter )\n\n} // end namespace Catch\n\n#if defined(_MSC_VER)\n#pragma warning(pop)\n#endif\n// end catch_reporter_xml.cpp\n\nnamespace Catch {\n    LeakDetector leakDetector;\n}\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n\n// end catch_impl.hpp\n#endif\n\n#ifdef CATCH_CONFIG_MAIN\n// start catch_default_main.hpp\n\n#ifndef __OBJC__\n\n#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)\n// Standard C/C++ Win32 Unicode wmain entry point\nextern \"C\" int wmain (int argc, wchar_t * argv[], wchar_t * []) {\n#else\n// Standard C/C++ main entry point\nint main (int argc, char * argv[]) {\n#endif\n\n    return Catch::Session().run( argc, argv );\n}\n\n#else // __OBJC__\n\n// Objective-C entry point\nint main (int argc, char * const argv[]) {\n#if !CATCH_ARC_ENABLED\n    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];\n#endif\n\n    Catch::registerTestMethods();\n    int result = Catch::Session().run( argc, (char**)argv );\n\n#if !CATCH_ARC_ENABLED\n    [pool drain];\n#endif\n\n    return result;\n}\n\n#endif // __OBJC__\n\n// end catch_default_main.hpp\n#endif\n\n#if !defined(CATCH_CONFIG_IMPL_ONLY)\n\n#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED\n#  undef CLARA_CONFIG_MAIN\n#endif\n\n#if !defined(CATCH_CONFIG_DISABLE)\n//////\n// If this config identifier is defined then all CATCH macros are prefixed with CATCH_\n#ifdef CATCH_CONFIG_PREFIX_ALL\n\n#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( \"CATCH_REQUIRE\", Catch::ResultDisposition::Normal, __VA_ARGS__ )\n#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( \"CATCH_REQUIRE_FALSE\", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )\n\n#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( \"CATCH_REQUIRE_THROWS\", Catch::ResultDisposition::Normal, __VA_ARGS__ )\n#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( \"CATCH_REQUIRE_THROWS_AS\", exceptionType, Catch::ResultDisposition::Normal, expr )\n#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( \"CATCH_REQUIRE_THROWS_WITH\", Catch::ResultDisposition::Normal, matcher, expr )\n#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)\n#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( \"CATCH_REQUIRE_THROWS_MATCHES\", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )\n#endif// CATCH_CONFIG_DISABLE_MATCHERS\n#define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( \"CATCH_REQUIRE_NOTHROW\", Catch::ResultDisposition::Normal, __VA_ARGS__ )\n\n#define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( \"CATCH_CHECK\", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )\n#define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( \"CATCH_CHECK_FALSE\", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )\n#define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( \"CATCH_CHECKED_IF\", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )\n#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( \"CATCH_CHECKED_ELSE\", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )\n#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( \"CATCH_CHECK_NOFAIL\", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )\n\n#define CATCH_CHECK_THROWS( ... )  INTERNAL_CATCH_THROWS( \"CATCH_CHECK_THROWS\", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )\n#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( \"CATCH_CHECK_THROWS_AS\", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )\n#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( \"CATCH_CHECK_THROWS_WITH\", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )\n#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)\n#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( \"CATCH_CHECK_THROWS_MATCHES\", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )\n#endif // CATCH_CONFIG_DISABLE_MATCHERS\n#define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( \"CATCH_CHECK_NOTHROW\", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )\n\n#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)\n#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( \"CATCH_CHECK_THAT\", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )\n\n#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( \"CATCH_REQUIRE_THAT\", matcher, Catch::ResultDisposition::Normal, arg )\n#endif // CATCH_CONFIG_DISABLE_MATCHERS\n\n#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( \"CATCH_INFO\", msg )\n#define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( \"CATCH_UNSCOPED_INFO\", msg )\n#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( \"CATCH_WARN\", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )\n#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), \"CATCH_CAPTURE\",__VA_ARGS__ )\n\n#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )\n#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )\n#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )\n#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )\n#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )\n#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )\n#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( \"CATCH_FAIL\", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )\n#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( \"CATCH_FAIL_CHECK\", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )\n#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( \"CATCH_SUCCEED\", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )\n\n#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()\n\n#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )\n#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )\n#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )\n#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )\n#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )\n#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )\n#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )\n#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )\n#else\n#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )\n#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )\n#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )\n#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )\n#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )\n#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )\n#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )\n#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )\n#endif\n\n#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)\n#define CATCH_STATIC_REQUIRE( ... )       static_assert(   __VA_ARGS__ ,      #__VA_ARGS__ );     CATCH_SUCCEED( #__VA_ARGS__ )\n#define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), \"!(\" #__VA_ARGS__ \")\" ); CATCH_SUCCEED( #__VA_ARGS__ )\n#else\n#define CATCH_STATIC_REQUIRE( ... )       CATCH_REQUIRE( __VA_ARGS__ )\n#define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ )\n#endif\n\n// \"BDD-style\" convenience wrappers\n#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( \"Scenario: \" __VA_ARGS__ )\n#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, \"Scenario: \" __VA_ARGS__ )\n#define CATCH_GIVEN( desc )     INTERNAL_CATCH_DYNAMIC_SECTION( \"    Given: \" << desc )\n#define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( \"And given: \" << desc )\n#define CATCH_WHEN( desc )      INTERNAL_CATCH_DYNAMIC_SECTION( \"     When: \" << desc )\n#define CATCH_AND_WHEN( desc )  INTERNAL_CATCH_DYNAMIC_SECTION( \" And when: \" << desc )\n#define CATCH_THEN( desc )      INTERNAL_CATCH_DYNAMIC_SECTION( \"     Then: \" << desc )\n#define CATCH_AND_THEN( desc )  INTERNAL_CATCH_DYNAMIC_SECTION( \"      And: \" << desc )\n\n#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\n#define CATCH_BENCHMARK(...) \\\n    INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))\n#define CATCH_BENCHMARK_ADVANCED(name) \\\n    INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name)\n#endif // CATCH_CONFIG_ENABLE_BENCHMARKING\n\n// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required\n#else\n\n#define REQUIRE( ... ) INTERNAL_CATCH_TEST( \"REQUIRE\", Catch::ResultDisposition::Normal, __VA_ARGS__  )\n#define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( \"REQUIRE_FALSE\", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )\n\n#define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( \"REQUIRE_THROWS\", Catch::ResultDisposition::Normal, __VA_ARGS__ )\n#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( \"REQUIRE_THROWS_AS\", exceptionType, Catch::ResultDisposition::Normal, expr )\n#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( \"REQUIRE_THROWS_WITH\", Catch::ResultDisposition::Normal, matcher, expr )\n#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)\n#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( \"REQUIRE_THROWS_MATCHES\", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )\n#endif // CATCH_CONFIG_DISABLE_MATCHERS\n#define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( \"REQUIRE_NOTHROW\", Catch::ResultDisposition::Normal, __VA_ARGS__ )\n\n#define CHECK( ... ) INTERNAL_CATCH_TEST( \"CHECK\", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )\n#define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( \"CHECK_FALSE\", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )\n#define CHECKED_IF( ... ) INTERNAL_CATCH_IF( \"CHECKED_IF\", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )\n#define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( \"CHECKED_ELSE\", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )\n#define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( \"CHECK_NOFAIL\", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )\n\n#define CHECK_THROWS( ... )  INTERNAL_CATCH_THROWS( \"CHECK_THROWS\", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )\n#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( \"CHECK_THROWS_AS\", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )\n#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( \"CHECK_THROWS_WITH\", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )\n#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)\n#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( \"CHECK_THROWS_MATCHES\", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )\n#endif // CATCH_CONFIG_DISABLE_MATCHERS\n#define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( \"CHECK_NOTHROW\", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )\n\n#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)\n#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( \"CHECK_THAT\", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )\n\n#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( \"REQUIRE_THAT\", matcher, Catch::ResultDisposition::Normal, arg )\n#endif // CATCH_CONFIG_DISABLE_MATCHERS\n\n#define INFO( msg ) INTERNAL_CATCH_INFO( \"INFO\", msg )\n#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( \"UNSCOPED_INFO\", msg )\n#define WARN( msg ) INTERNAL_CATCH_MSG( \"WARN\", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )\n#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), \"CAPTURE\",__VA_ARGS__ )\n\n#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )\n#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )\n#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )\n#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )\n#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )\n#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )\n#define FAIL( ... ) INTERNAL_CATCH_MSG( \"FAIL\", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )\n#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( \"FAIL_CHECK\", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )\n#define SUCCEED( ... ) INTERNAL_CATCH_MSG( \"SUCCEED\", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )\n#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()\n\n#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )\n#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )\n#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )\n#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )\n#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )\n#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )\n#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )\n#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )\n#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)\n#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )\n#else\n#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )\n#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )\n#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )\n#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )\n#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )\n#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )\n#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )\n#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )\n#define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )\n#define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )\n#endif\n\n#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)\n#define STATIC_REQUIRE( ... )       static_assert(   __VA_ARGS__,  #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )\n#define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), \"!(\" #__VA_ARGS__ \")\" ); SUCCEED( \"!(\" #__VA_ARGS__ \")\" )\n#else\n#define STATIC_REQUIRE( ... )       REQUIRE( __VA_ARGS__ )\n#define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ )\n#endif\n\n#endif\n\n#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )\n\n// \"BDD-style\" convenience wrappers\n#define SCENARIO( ... ) TEST_CASE( \"Scenario: \" __VA_ARGS__ )\n#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, \"Scenario: \" __VA_ARGS__ )\n\n#define GIVEN( desc )     INTERNAL_CATCH_DYNAMIC_SECTION( \"    Given: \" << desc )\n#define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( \"And given: \" << desc )\n#define WHEN( desc )      INTERNAL_CATCH_DYNAMIC_SECTION( \"     When: \" << desc )\n#define AND_WHEN( desc )  INTERNAL_CATCH_DYNAMIC_SECTION( \" And when: \" << desc )\n#define THEN( desc )      INTERNAL_CATCH_DYNAMIC_SECTION( \"     Then: \" << desc )\n#define AND_THEN( desc )  INTERNAL_CATCH_DYNAMIC_SECTION( \"      And: \" << desc )\n\n#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)\n#define BENCHMARK(...) \\\n    INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))\n#define BENCHMARK_ADVANCED(name) \\\n    INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name)\n#endif // CATCH_CONFIG_ENABLE_BENCHMARKING\n\nusing Catch::Detail::Approx;\n\n#else // CATCH_CONFIG_DISABLE\n\n//////\n// If this config identifier is defined then all CATCH macros are prefixed with CATCH_\n#ifdef CATCH_CONFIG_PREFIX_ALL\n\n#define CATCH_REQUIRE( ... )        (void)(0)\n#define CATCH_REQUIRE_FALSE( ... )  (void)(0)\n\n#define CATCH_REQUIRE_THROWS( ... ) (void)(0)\n#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)\n#define CATCH_REQUIRE_THROWS_WITH( expr, matcher )     (void)(0)\n#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)\n#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)\n#endif// CATCH_CONFIG_DISABLE_MATCHERS\n#define CATCH_REQUIRE_NOTHROW( ... ) (void)(0)\n\n#define CATCH_CHECK( ... )         (void)(0)\n#define CATCH_CHECK_FALSE( ... )   (void)(0)\n#define CATCH_CHECKED_IF( ... )    if (__VA_ARGS__)\n#define CATCH_CHECKED_ELSE( ... )  if (!(__VA_ARGS__))\n#define CATCH_CHECK_NOFAIL( ... )  (void)(0)\n\n#define CATCH_CHECK_THROWS( ... )  (void)(0)\n#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0)\n#define CATCH_CHECK_THROWS_WITH( expr, matcher )     (void)(0)\n#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)\n#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)\n#endif // CATCH_CONFIG_DISABLE_MATCHERS\n#define CATCH_CHECK_NOTHROW( ... ) (void)(0)\n\n#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)\n#define CATCH_CHECK_THAT( arg, matcher )   (void)(0)\n\n#define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0)\n#endif // CATCH_CONFIG_DISABLE_MATCHERS\n\n#define CATCH_INFO( msg )          (void)(0)\n#define CATCH_UNSCOPED_INFO( msg ) (void)(0)\n#define CATCH_WARN( msg )          (void)(0)\n#define CATCH_CAPTURE( msg )       (void)(0)\n\n#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))\n#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))\n#define CATCH_METHOD_AS_TEST_CASE( method, ... )\n#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)\n#define CATCH_SECTION( ... )\n#define CATCH_DYNAMIC_SECTION( ... )\n#define CATCH_FAIL( ... ) (void)(0)\n#define CATCH_FAIL_CHECK( ... ) (void)(0)\n#define CATCH_SUCCEED( ... ) (void)(0)\n\n#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))\n\n#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)\n#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)\n#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)\n#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )\n#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )\n#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )\n#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )\n#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )\n#else\n#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )\n#define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )\n#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )\n#define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )\n#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )\n#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )\n#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )\n#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )\n#endif\n\n// \"BDD-style\" convenience wrappers\n#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))\n#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className )\n#define CATCH_GIVEN( desc )\n#define CATCH_AND_GIVEN( desc )\n#define CATCH_WHEN( desc )\n#define CATCH_AND_WHEN( desc )\n#define CATCH_THEN( desc )\n#define CATCH_AND_THEN( desc )\n\n#define CATCH_STATIC_REQUIRE( ... )       (void)(0)\n#define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0)\n\n// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required\n#else\n\n#define REQUIRE( ... )       (void)(0)\n#define REQUIRE_FALSE( ... ) (void)(0)\n\n#define REQUIRE_THROWS( ... ) (void)(0)\n#define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)\n#define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)\n#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)\n#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)\n#endif // CATCH_CONFIG_DISABLE_MATCHERS\n#define REQUIRE_NOTHROW( ... ) (void)(0)\n\n#define CHECK( ... ) (void)(0)\n#define CHECK_FALSE( ... ) (void)(0)\n#define CHECKED_IF( ... ) if (__VA_ARGS__)\n#define CHECKED_ELSE( ... ) if (!(__VA_ARGS__))\n#define CHECK_NOFAIL( ... ) (void)(0)\n\n#define CHECK_THROWS( ... )  (void)(0)\n#define CHECK_THROWS_AS( expr, exceptionType ) (void)(0)\n#define CHECK_THROWS_WITH( expr, matcher ) (void)(0)\n#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)\n#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)\n#endif // CATCH_CONFIG_DISABLE_MATCHERS\n#define CHECK_NOTHROW( ... ) (void)(0)\n\n#if !defined(CATCH_CONFIG_DISABLE_MATCHERS)\n#define CHECK_THAT( arg, matcher ) (void)(0)\n\n#define REQUIRE_THAT( arg, matcher ) (void)(0)\n#endif // CATCH_CONFIG_DISABLE_MATCHERS\n\n#define INFO( msg ) (void)(0)\n#define UNSCOPED_INFO( msg ) (void)(0)\n#define WARN( msg ) (void)(0)\n#define CAPTURE( ... ) (void)(0)\n\n#define TEST_CASE( ... )  INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))\n#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))\n#define METHOD_AS_TEST_CASE( method, ... )\n#define REGISTER_TEST_CASE( Function, ... ) (void)(0)\n#define SECTION( ... )\n#define DYNAMIC_SECTION( ... )\n#define FAIL( ... ) (void)(0)\n#define FAIL_CHECK( ... ) (void)(0)\n#define SUCCEED( ... ) (void)(0)\n#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))\n\n#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR\n#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)\n#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)\n#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)\n#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )\n#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )\n#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )\n#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )\n#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )\n#else\n#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )\n#define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )\n#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )\n#define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )\n#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )\n#define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )\n#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )\n#define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )\n#endif\n\n#define STATIC_REQUIRE( ... )       (void)(0)\n#define STATIC_REQUIRE_FALSE( ... ) (void)(0)\n\n#endif\n\n#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )\n\n// \"BDD-style\" convenience wrappers\n#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ) )\n#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className )\n\n#define GIVEN( desc )\n#define AND_GIVEN( desc )\n#define WHEN( desc )\n#define AND_WHEN( desc )\n#define THEN( desc )\n#define AND_THEN( desc )\n\nusing Catch::Detail::Approx;\n\n#endif\n\n#endif // ! CATCH_CONFIG_IMPL_ONLY\n\n// start catch_reenable_warnings.h\n\n\n#ifdef __clang__\n#    ifdef __ICC // icpc defines the __clang__ macro\n#        pragma warning(pop)\n#    else\n#        pragma clang diagnostic pop\n#    endif\n#elif defined __GNUC__\n#    pragma GCC diagnostic pop\n#endif\n\n// end catch_reenable_warnings.h\n// end catch.hpp\n#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED\n\n"
  },
  {
    "path": "tests/cmd-args.py",
    "content": "#!/usr/bin/env python3\n\nfrom os import listdir, access, X_OK\nfrom subprocess import DEVNULL, PIPE, Popen\nfrom shutil import which\n\nfailed = False\nno_dot = which('dot') is None\n\ndef is_exe(f):\n    return access(f, X_OK)\n\nfor f in filter(lambda x: x.startswith('llvm') and is_exe(x), listdir()):\n    # skip wrapper scripts if 'dot' is missing as they depend on it\n    if no_dot and f in ('llvmdda-dump', 'llvmdg-show'):\n        print(f\"{f}\\u001b[33m SKIP (needs 'dot')\\u001b[0m\")\n        continue\n    print(f, end='')\n    p = Popen(['./' + f, '--version'], stdout=DEVNULL, stderr=PIPE)\n    out = p.communicate()[1].decode()\n\n    if p.returncode == 0:\n        print(\"\\u001b[32m OK\\u001b[0m\")\n        continue\n\n    failed = True\n    print(\"\\u001b[31m NOK\\u001b[0m\")\n    print(out)\n\nexit(failed)\n"
  },
  {
    "path": "tests/disjunctive-intervals-map-test.cpp",
    "content": "#include <catch2/catch.hpp>\n\n#include <random>\n#include <sstream>\n#include <vector>\n\n#undef NDEBUG\n\n#include \"dg/ADT/DisjunctiveIntervalMap.h\"\n#include \"dg/Offset.h\"\n\nusing namespace dg;\nusing dg::ADT::DisjunctiveIntervalMap;\n\nstatic std::ostream &\noperator<<(std::ostream &os, const std::vector<std::tuple<int, int, int>> &v) {\n    os << \"{\";\n    for (const auto &tup : v) {\n        os << \"{ \";\n        os << std::get<0>(tup) << \"-\";\n        os << std::get<1>(tup) << \": \";\n        os << std::get<2>(tup);\n        os << \" }, \";\n    }\n    os << \"}\";\n    return os;\n}\n\ntemplate <typename ValueT, typename IntervalValueT>\nclass DisjunctiveIntervalMapMatcher\n        : public Catch::MatcherBase<\n                  DisjunctiveIntervalMap<ValueT, IntervalValueT>> {\n    std::vector<std::tuple<IntervalValueT, IntervalValueT, ValueT>> structure;\n\n  public:\n    DisjunctiveIntervalMapMatcher(\n            std::vector<std::tuple<IntervalValueT, IntervalValueT, ValueT>> s)\n            : structure(std::move(s)) {}\n\n    bool match(const DisjunctiveIntervalMap<ValueT, IntervalValueT> &M)\n            const override {\n        if (M.size() != structure.size()) {\n            return false;\n        }\n\n        size_t i = 0;\n        for (const auto &pair : M) {\n            const auto &interval = pair.first;\n            const auto &values = pair.second;\n\n            if (interval.start != std::get<0>(structure[i])) {\n                return false;\n            }\n\n            if (interval.end != std::get<1>(structure[i])) {\n                return false;\n            }\n\n            if (values.find(std::get<2>(structure[i])) == values.end()) {\n                return false;\n            }\n\n            ++i;\n        }\n        return true;\n    }\n\n    std::string describe() const override {\n        std::ostringstream ss;\n        ss << \"has the structure: \" << structure;\n        return ss.str();\n    }\n};\n\nstatic inline DisjunctiveIntervalMapMatcher<int, int>\nHasStructure(std::initializer_list<std::tuple<int, int, int>> structure) {\n    return DisjunctiveIntervalMapMatcher<int, int>(structure);\n}\n\nTEST_CASE(\"Querying empty set\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    REQUIRE(M.empty());\n}\n\nTEST_CASE(\"Add same\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    M.add(0, 2, 1);\n    REQUIRE(M.size() == 1);\n    REQUIRE(M.overlaps(0, 0));\n    REQUIRE(M.overlaps(0, 1));\n    REQUIRE(M.overlaps(0, 2));\n    REQUIRE(M.overlaps(1, 1));\n    REQUIRE(M.overlaps(1, 2));\n    REQUIRE(M.overlaps(2, 2));\n    REQUIRE(M.overlapsFull(0, 0));\n    REQUIRE(M.overlapsFull(0, 1));\n    REQUIRE(M.overlapsFull(0, 2));\n    REQUIRE(M.overlapsFull(1, 1));\n    REQUIRE(M.overlapsFull(1, 2));\n    REQUIRE(M.overlapsFull(2, 2));\n    REQUIRE(M.overlapsFull(0, 2));\n\n    REQUIRE(M.overlaps(0, 3));\n    REQUIRE(M.overlaps(1, 3));\n    REQUIRE(M.overlaps(2, 3));\n    REQUIRE(!M.overlaps(3, 3));\n    REQUIRE(!M.overlapsFull(0, 3));\n    REQUIRE(!M.overlapsFull(1, 3));\n    REQUIRE(!M.overlapsFull(2, 3));\n    REQUIRE(!M.overlapsFull(3, 3));\n\n    REQUIRE(!M.overlapsFull(0, 10));\n    M.add(0, 2, 1);\n    REQUIRE(M.size() == 1);\n}\n\nTEST_CASE(\"Add non-overlapping\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    M.add(0, 2, 1);\n    REQUIRE(M.size() == 1);\n    REQUIRE(!M.overlaps(3, 4));\n    M.add(3, 4, 2);\n    REQUIRE(M.size() == 2);\n}\n\nTEST_CASE(\"Add non-overlapping3\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    M.add(3, 4, 2);\n    REQUIRE(M.size() == 1);\n    REQUIRE(M.overlaps(3, 4));\n    REQUIRE(!M.overlaps(0, 2));\n    M.add(0, 2, 1);\n    REQUIRE(M.size() == 2);\n}\n\nTEST_CASE(\"Add non-overlapping1\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    M.add(0, 10, 1);\n    REQUIRE(M.size() == 1);\n    REQUIRE(M.overlaps(3, 4));\n    REQUIRE(M.overlaps(0, 0));\n    REQUIRE(M.overlaps(0, 1));\n    REQUIRE(M.overlaps(10, 10));\n    REQUIRE(M.overlaps(7, 15));\n    REQUIRE(M.overlaps(0, 100));\n    REQUIRE(M.overlapsFull(3, 4));\n    REQUIRE(M.overlapsFull(0, 0));\n    REQUIRE(M.overlapsFull(0, 1));\n    REQUIRE(M.overlapsFull(10, 10));\n    REQUIRE(!M.overlapsFull(0, 100));\n    REQUIRE(!M.overlaps(11, 11));\n    REQUIRE(!M.overlaps(11, 99));\n\n    M.add(100, 101, 2);\n    REQUIRE(M.size() == 2);\n}\n\nTEST_CASE(\"Add overlapping0\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    M.add(0, 2, 1);\n    REQUIRE(M.size() == 1);\n    REQUIRE(M.overlaps(2, 3));\n    M.add(2, 3, 2);\n    REQUIRE(M.size() == 3);\n}\n\nTEST_CASE(\"Add overlapping0com\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    M.add(2, 3, 2);\n    REQUIRE(M.size() == 1);\n    REQUIRE(M.overlaps(0, 2));\n    M.add(0, 2, 1);\n    REQUIRE(M.size() == 3);\n}\n\nTEST_CASE(\"Add overlapping\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    M.add(0, 2, 1);\n    REQUIRE(M.size() == 1);\n    REQUIRE(M.overlaps(0, 4));\n    REQUIRE(M.overlapsFull(0, 2));\n    REQUIRE(!M.overlapsFull(0, 4));\n    M.add(0, 4, 2);\n    REQUIRE(M.size() == 2);\n}\n\nTEST_CASE(\"Add overlappingCom\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    M.add(0, 4, 2);\n    REQUIRE(M.size() == 1);\n    REQUIRE(M.overlaps(0, 2));\n    REQUIRE(M.overlapsFull(0, 2));\n    M.add(0, 2, 1);\n    REQUIRE(M.size() == 2);\n}\n\nTEST_CASE(\"Add overlapping1\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    M.add(1, 3, 1);\n    REQUIRE(M.size() == 1);\n    M.add(2, 5, 2);\n    REQUIRE(M.size() == 3);\n}\n\nTEST_CASE(\"Add overlapping2\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    M.add(2, 5, 1);\n    REQUIRE(M.size() == 1);\n    M.add(1, 3, 2);\n    REQUIRE(M.size() == 3);\n}\n\nTEST_CASE(\"Add overlapping3\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    M.add(1, 2, 1);\n    REQUIRE(M.size() == 1);\n    M.add(0, 4, 2);\n    REQUIRE(M.size() == 3);\n}\n\nTEST_CASE(\"Add overlapping3com\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    M.add(0, 4, 2);\n    REQUIRE(M.size() == 1);\n    M.add(1, 2, 1);\n    REQUIRE(M.size() == 3);\n}\n\nTEST_CASE(\"Add overlapping5\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    M.add(0, 4, 1);\n    REQUIRE(M.size() == 1);\n    M.add(2, 4, 2);\n    REQUIRE(M.size() == 2);\n}\n\nTEST_CASE(\"Add overlapping5com\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    M.add(2, 4, 2);\n    REQUIRE(M.size() == 1);\n    M.add(0, 4, 1);\n    REQUIRE(M.size() == 2);\n}\n\nTEST_CASE(\"Add overlapping4\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    M.add(0, 0, 0);\n    REQUIRE(M.size() == 1);\n    M.add(1, 1, 1);\n    REQUIRE(M.size() == 2);\n    M.add(3, 3, 2);\n    REQUIRE(M.size() == 3);\n\n    REQUIRE(M.overlapsFull(0, 0));\n    REQUIRE(M.overlapsFull(0, 1));\n    REQUIRE(!M.overlapsFull(0, 2));\n    REQUIRE(!M.overlapsFull(2, 3));\n    REQUIRE(M.overlapsFull(3, 3));\n    REQUIRE(!M.overlapsFull(3, 5));\n    REQUIRE(M.overlaps(3, 5));\n\n    M.add(5, 5, 3);\n    REQUIRE(M.size() == 4);\n\n    REQUIRE(M.overlaps(3, 5));\n    REQUIRE(M.overlaps(5, 5));\n    REQUIRE(M.overlapsFull(5, 5));\n\n    bool changed = M.add(5, 5, 3);\n    REQUIRE(changed == false);\n    REQUIRE(M.size() == 4);\n\n    M.add(0, 10, 4);\n    REQUIRE(M.size() == 7);\n\n    REQUIRE(M.overlapsFull(0, 0));\n    REQUIRE(M.overlapsFull(0, 1));\n    REQUIRE(M.overlapsFull(0, 2));\n    REQUIRE(M.overlapsFull(2, 3));\n    REQUIRE(M.overlapsFull(3, 3));\n    REQUIRE(M.overlapsFull(3, 5));\n    REQUIRE(M.overlapsFull(0, 5));\n    REQUIRE(M.overlapsFull(0, 10));\n    REQUIRE(!M.overlapsFull(0, 11));\n\n    for (int i = 1; i < 11; ++i)\n        REQUIRE(!M.overlapsFull(i, 11));\n\n    for (int i = 0; i < 11; ++i)\n        for (int j = i; j < 11; ++j)\n            REQUIRE(M.overlapsFull(i, j));\n}\n\nTEST_CASE(\"Add overlappingX\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    M.add(0, 4, 1);\n    M.add(1, 1, 2);\n    M.add(3, 5, 3);\n    REQUIRE(M.size() == 5);\n\n    REQUIRE(M.overlaps(0, 0));\n    REQUIRE(M.overlaps(0, 10));\n    REQUIRE(M.overlaps(0, 6));\n    REQUIRE(M.overlaps(1, 5));\n\n    REQUIRE(M.overlapsFull(0, 5));\n    REQUIRE(!M.overlapsFull(0, 6));\n    REQUIRE(M.overlapsFull(1, 5));\n\n    using IntervalT = decltype(M)::IntervalT;\n    std::vector<IntervalT> results = {\n            IntervalT(0, 0), IntervalT(1, 1), IntervalT(2, 2),\n            IntervalT(3, 4), IntervalT(5, 5),\n    };\n\n    int i = 0;\n    for (auto &I : M) {\n        REQUIRE(I.first == results[i++]);\n    }\n}\n\nTEST_CASE(\"OverlappsNegative\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int, int> M;\n    M.add(0, 2, 0);\n    REQUIRE(M.overlaps(-1, 5));\n    REQUIRE(M.overlaps(-1, 0));\n    REQUIRE(M.overlaps(-1, 1));\n    REQUIRE(!M.overlaps(-1, -1));\n    REQUIRE(!M.overlaps(-4, -1));\n    REQUIRE(M.overlaps(-4, 10));\n    REQUIRE(!M.overlapsFull(-4, 10));\n    REQUIRE(!M.overlapsFull(-1, 0));\n    REQUIRE(!M.overlapsFull(-1, 1));\n}\n\nTEST_CASE(\"OverlappsNegative2\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int, int> M;\n    M.add(-2, 2, 0);\n    REQUIRE(M.overlaps(-1, 5));\n    REQUIRE(M.overlaps(-1, 0));\n    REQUIRE(M.overlaps(-1, 1));\n    REQUIRE(M.overlaps(-1, -1));\n    REQUIRE(M.overlaps(-4, -1));\n    REQUIRE(M.overlaps(-4, 10));\n    REQUIRE(!M.overlapsFull(-4, 10));\n    REQUIRE(M.overlapsFull(-1, 0));\n    REQUIRE(M.overlapsFull(-1, 1));\n    REQUIRE(M.overlapsFull(-2, 2));\n    REQUIRE(!M.overlapsFull(-2, 3));\n    REQUIRE(!M.overlapsFull(-3, 2));\n}\n\nTEST_CASE(\"OverlappsRandom\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int, int> M;\n    M.add(0, 10, 0);\n    REQUIRE(M.size() == 1);\n\n    std::default_random_engine generator;\n    std::uniform_int_distribution<int> distribution(-100, 100);\n\n    for (int i = 0; i < 1000; ++i) {\n        auto start = distribution(generator);\n        auto end = distribution(generator);\n\n        if (end < start)\n            std::swap(end, start);\n\n        assert(start <= end);\n        if (start >= 0 && start <= 10) {\n            REQUIRE(M.overlaps(start, start));\n            REQUIRE(M.overlapsFull(start, start));\n\n            REQUIRE(M.overlaps(start, end));\n            if (end <= 10)\n                REQUIRE(M.overlapsFull(start, end));\n        } else {\n            REQUIRE(!M.overlaps(start, start));\n            REQUIRE(!M.overlapsFull(start, start));\n\n            if (end >= 0 && end <= 10) {\n                REQUIRE(M.overlaps(start, end));\n                REQUIRE(!M.overlapsFull(start, end));\n            } else {\n                if (start > 10 || end < 0) {\n                    REQUIRE(!M.overlaps(start, end));\n                    REQUIRE(!M.overlapsFull(start, end));\n                } else {\n                    REQUIRE(M.overlaps(start, end));\n                    REQUIRE(!M.overlapsFull(start, end));\n                }\n            }\n        }\n    }\n}\n\nTEST_CASE(\"OverlapsEmptyNonemptyinterval\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int, int> M;\n    REQUIRE_FALSE(M.overlapsFull(0, 10));\n    REQUIRE_FALSE(M.overlapsFull(10, 10));\n}\n\nTEST_CASE(\"Split\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int, int> M;\n\n    // add 0-4\n    M.update(0, 4, 1);\n\n    // now add intervals such that their union is 0-4\n    M.update(0, 1, 2);\n    M.update(1, 2, 3);\n    M.update(2, 2, 4);\n    M.update(3, 4, 5);\n\n    /*\n     * The map should now contain:\n     * [0,0] -> 2\n     * [1,1] -> 3\n     * [2,2] -> 4\n     * [3,4] -> 5\n     */\n    REQUIRE_THAT(\n            M,\n            HasStructure({std::make_tuple(0, 0, 2), std::make_tuple(1, 1, 3),\n                          std::make_tuple(2, 2, 4), std::make_tuple(3, 4, 5)}));\n}\n\nTEST_CASE(\"Split2\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int, int> M;\n\n    // add 0-4\n    M.update(0, 4, 1);\n\n    // now add intervals such that their union is 0-4\n    M.update(0, 1, 2);\n    M.update(1, 2, 3);\n    M.update(2, 3, 4);\n    M.update(3, 4, 5);\n\n    /*\n     * The map should now contain:\n     * [0,0] -> 2\n     * [1,1] -> 3\n     * [2,2] -> 4\n     * [3,3] -> 5\n     * [4,4] -> 5\n     */\n    REQUIRE_THAT(\n            M, HasStructure({std::make_tuple(0, 0, 2), std::make_tuple(1, 1, 3),\n                             std::make_tuple(2, 2, 4), std::make_tuple(3, 3, 5),\n                             std::make_tuple(4, 4, 5)}));\n}\n\nTEST_CASE(\"Uncovered 1\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    using IntT = decltype(M)::IntervalT;\n\n    auto ret = M.uncovered(2, 5);\n    REQUIRE(ret.size() == 1);\n    REQUIRE(ret[0] == IntT{2, 5});\n\n    M.update(0, 5, 0);\n\n    ret = M.uncovered(2, 5);\n    REQUIRE(ret.empty());\n\n    ret = M.uncovered(0, 5);\n    REQUIRE(ret.empty());\n\n    ret = M.uncovered(3, 4);\n    REQUIRE(ret.empty());\n\n    ret = M.uncovered(5, 5);\n    REQUIRE(ret.empty());\n\n    ret = M.uncovered(1, 1);\n    REQUIRE(ret.empty());\n\n    ret = M.uncovered(0, 0);\n    REQUIRE(ret.empty());\n\n    ret = M.uncovered(6, 6);\n    REQUIRE(ret.size() == 1);\n    REQUIRE(ret[0] == IntT{6, 6});\n\n    ret = M.uncovered(6, 10);\n    REQUIRE(ret.size() == 1);\n    REQUIRE(ret[0] == IntT{6, 10});\n}\n\nTEST_CASE(\"Uncovered 2\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    using IntT = decltype(M)::IntervalT;\n\n    M.update(2, 5, 0);\n\n    auto ret = M.uncovered(0, 5);\n    REQUIRE(ret.size() == 1);\n    REQUIRE(ret[0] == IntT{0, 1});\n\n    ret = M.uncovered(0, 10);\n    REQUIRE(ret.size() == 2);\n    REQUIRE(ret[0] == IntT{0, 1});\n    REQUIRE(ret[1] == IntT{6, 10});\n}\n\nTEST_CASE(\"Uncovered 3\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    using IntT = decltype(M)::IntervalT;\n\n    M.update(0, 0, 0);\n    M.update(2, 2, 0);\n    M.update(4, 4, 0);\n    M.update(6, 6, 0);\n\n    auto ret = M.uncovered(0, 7);\n    REQUIRE(ret.size() == 4);\n    REQUIRE(ret[0] == IntT{1, 1});\n    REQUIRE(ret[1] == IntT{3, 3});\n    REQUIRE(ret[2] == IntT{5, 5});\n    REQUIRE(ret[3] == IntT{7, 7});\n\n    ret = M.uncovered(0, 10);\n    REQUIRE(ret.size() == 4);\n    REQUIRE(ret[0] == IntT{1, 1});\n    REQUIRE(ret[1] == IntT{3, 3});\n    REQUIRE(ret[2] == IntT{5, 5});\n    REQUIRE(ret[3] == IntT{7, 10});\n}\n\nTEST_CASE(\"Uncovered 4\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    using IntT = decltype(M)::IntervalT;\n\n    M.update(1, 1, 0);\n    M.update(3, 3, 0);\n    M.update(5, 5, 0);\n    M.update(7, 7, 0);\n\n    auto ret = M.uncovered(0, 7);\n    REQUIRE(ret.size() == 4);\n    REQUIRE(ret[0] == IntT{0, 0});\n    REQUIRE(ret[1] == IntT{2, 2});\n    REQUIRE(ret[2] == IntT{4, 4});\n    REQUIRE(ret[3] == IntT{6, 6});\n\n    ret = M.uncovered(0, 8);\n    REQUIRE(ret.size() == 5);\n    REQUIRE(ret[0] == IntT{0, 0});\n    REQUIRE(ret[1] == IntT{2, 2});\n    REQUIRE(ret[2] == IntT{4, 4});\n    REQUIRE(ret[3] == IntT{6, 6});\n    REQUIRE(ret[4] == IntT{8, 8});\n\n    ret = M.uncovered(0, 80);\n    REQUIRE(ret.size() == 5);\n    REQUIRE(ret[0] == IntT{0, 0});\n    REQUIRE(ret[1] == IntT{2, 2});\n    REQUIRE(ret[2] == IntT{4, 4});\n    REQUIRE(ret[3] == IntT{6, 6});\n    REQUIRE(ret[4] == IntT{8, 80});\n}\n\nTEST_CASE(\"Uncovered - regression 1\", \"DisjunctiveIntervalMap\") {\n    DisjunctiveIntervalMap<int> M;\n    using IntT = decltype(M)::IntervalT;\n\n    M.update(0, 3, 0);\n\n    auto ret = M.uncovered(1, 100000);\n    REQUIRE(ret.size() == 1);\n    REQUIRE(ret[0] == IntT{4, 100000});\n\n    ret = M.uncovered(0, 3);\n    REQUIRE(ret.empty());\n}\n"
  },
  {
    "path": "tests/fuzzing/CMakeLists.txt",
    "content": "# --------------------------------------------------\n# use sanitizers in fuzzing tests\n# --------------------------------------------------\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -fsanitize=address,undefined,fuzzer\")\n\n# --------------------------------------------------\n# fuzzing tests\n# --------------------------------------------------\nadd_executable(numbers-set1 numbers-set1.cpp)\nadd_dependencies(check numbers-set1)\nadd_test(numbers-set1-fuzzing numbers-set1\n    ${CMAKE_CURRENT_SOURCE_DIR}/regressions/numbers-set1 -runs=100000)\n\nadd_executable(bitvector1 bitvector1.cpp)\nadd_dependencies(check bitvector1)\nadd_test(bitvector1-fuzzing bitvector1 -runs=100000)\n\nadd_executable(disjunctive-map1 disjunctive-map1.cpp)\nadd_dependencies(check disjunctive-map1)\nadd_test(disjunctive-map1-fuzzing disjunctive-map1\n    ${CMAKE_CURRENT_SOURCE_DIR}/regressions/disjunctive-map1 -runs=20000)\n"
  },
  {
    "path": "tests/fuzzing/bitvector1.cpp",
    "content": "#undef NDEBUG\n\n#include <cassert>\n#include <cstdint>\n#include <set>\n\n#include \"dg/ADT/Bitvector.h\"\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n    std::set<uint64_t> S;\n    dg::ADT::SparseBitvector B;\n\n    const auto elems = size / sizeof(uint64_t);\n    const uint64_t *numbers = reinterpret_cast<const uint64_t *>(data);\n    for (unsigned i = 0; i < elems; ++i) {\n        B.set(numbers[i]);\n        S.insert(numbers[i]);\n    }\n\n    for (auto x : S)\n        assert(B.get(x));\n\n    for (unsigned int i = 0; i < elems; ++i) {\n        if (S.count(i) > 0)\n            assert(B.get(i));\n        else\n            assert(!B.get(i));\n    }\n\n    for (auto x : S)\n        assert(B.unset(x));\n\n    for (auto x : S)\n        assert(!B.get(x));\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/fuzzing/disjunctive-map1.cpp",
    "content": "#undef NDEBUG\n\n#include <cassert>\n#include <cstdint>\n\n#ifdef DUMP\n#include <cstdio>\n#endif\n\n#include \"dg/ADT/DisjunctiveIntervalMap.h\"\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n    dg::ADT::DisjunctiveIntervalMap<int, int> M;\n\n    const auto elems = size / sizeof(int);\n    if (elems == 0)\n        return 0;\n\n    const int *numbers = reinterpret_cast<const int *>(data);\n    for (unsigned i = 0; i < elems - 1; i += 2) {\n        int a = numbers[i], b = numbers[i + 1];\n        if (a > b)\n            std::swap(a, b);\n        assert(a <= b);\n#ifdef DUMP\n        printf(\"Adding [%d, %d]\\n\", a, b);\n        fflush(stdout);\n#endif\n        M.add(a, b, 0);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/fuzzing/numbers-set1.cpp",
    "content": "#undef NDEBUG\n\n#include <cassert>\n#include <cstdint>\n#include <set>\n\n#include \"dg/ADT/NumberSet.h\"\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n    std::set<uint64_t> S;\n    dg::ADT::BitvectorNumberSet B;\n\n    const auto elems = size / sizeof(uint64_t);\n    const uint64_t *numbers = reinterpret_cast<const uint64_t *>(data);\n    for (unsigned i = 0; i < elems; ++i) {\n        B.add(numbers[i]);\n        S.insert(numbers[i]);\n    }\n\n    for (auto x : S)\n        assert(B.has(x));\n\n    for (unsigned int i = 0; i < elems; ++i) {\n        if (S.count(i) > 0)\n            assert(B.has(i));\n        else\n            assert(!B.has(i));\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/llvm-dg-test.cpp",
    "content": "#include <catch2/catch.hpp>\n\n#include \"dg/DFS.h\"\n#include \"dg/llvm/LLVMDependenceGraph.h\"\n\nTEST_CASE(\"reference counting test\", \"LLVM DG\") {\n    using namespace dg;\n\n    LLVMDependenceGraph d;\n    LLVMDependenceGraph s;\n\n    int rc;\n    rc = s.ref();\n    REQUIRE(rc == 2);\n    rc = s.unref();\n    REQUIRE(rc == 1);\n\n    s.ref();\n    rc = s.ref();\n    REQUIRE(rc == 3);\n    s.unref();\n    rc = s.unref();\n    REQUIRE(rc == 1);\n\n    // addSubgraph increases refcount\n    LLVMNode n1(nullptr), n2(nullptr);\n    n1.addSubgraph(&s);\n    n2.addSubgraph(&s);\n\n    // we do not have a getter for refcounts, so just\n    // inc and dec the counter to get the current value\n    s.ref();\n    rc = s.unref();\n    REQUIRE(rc == 3);\n\n    // set entry blocks, otherwise the constructor will call assert\n    LLVMBBlock *entryBB1 = new LLVMBBlock(&n1);\n    LLVMBBlock *entryBB2 = new LLVMBBlock(&n2);\n\n    d.setEntryBB(entryBB1);\n    s.setEntryBB(entryBB2);\n\n    delete entryBB1;\n    delete entryBB2;\n}\n"
  },
  {
    "path": "tests/nodes-walk-test.cpp",
    "content": "#include <catch2/catch.hpp>\n\n#include <dg/ADT/Queue.h>\n#include <dg/NodesWalk.h>\n#include <set>\n\nusing namespace dg;\n\nstruct Node {\n    std::vector<Node *> _successors;\n    const std::vector<Node *> &successors() const { return _successors; }\n    void addSuccessor(Node *s) { _successors.push_back(s); }\n};\n\nTEST_CASE(\"NodesWalk1\", \"NodesWalk\") {\n    Node A, B, C, D;\n\n    A.addSuccessor(&B);\n    B.addSuccessor(&C);\n    C.addSuccessor(&D);\n\n    NodesWalk<Node, dg::ADT::QueueLIFO<Node *>> walk;\n\n    std::set<Node *> nodes;\n    walk.run(&A, [&nodes](Node *n) {\n        bool ret = nodes.insert(n).second;\n        REQUIRE(ret);\n    });\n\n    REQUIRE(nodes.count(&A) > 0);\n    REQUIRE(nodes.count(&B) > 0);\n    REQUIRE(nodes.count(&C) > 0);\n    REQUIRE(nodes.count(&D) > 0);\n}\n\nTEST_CASE(\"NodesWalk-branch\", \"NodesWalk\") {\n    Node A, B, C, D;\n\n    A.addSuccessor(&B);\n    A.addSuccessor(&C);\n    B.addSuccessor(&D);\n    C.addSuccessor(&D);\n\n    NodesWalk<Node, dg::ADT::QueueLIFO<Node *>> walk;\n\n    std::set<Node *> nodes;\n    walk.run(&A, [&nodes](Node *n) {\n        bool ret = nodes.insert(n).second;\n        REQUIRE(ret);\n    });\n\n    REQUIRE(nodes.count(&A) > 0);\n    REQUIRE(nodes.count(&B) > 0);\n    REQUIRE(nodes.count(&C) > 0);\n    REQUIRE(nodes.count(&D) > 0);\n}\n\nTEST_CASE(\"NodesWalk-cycle\", \"NodesWalk\") {\n    Node A, B, C, D;\n\n    A.addSuccessor(&B);\n    A.addSuccessor(&C);\n    B.addSuccessor(&D);\n    C.addSuccessor(&D);\n    D.addSuccessor(&A);\n\n    NodesWalk<Node, dg::ADT::QueueLIFO<Node *>> walk;\n\n    std::set<Node *> nodes;\n    walk.run(&A, [&nodes](Node *n) {\n        bool ret = nodes.insert(n).second;\n        REQUIRE(ret);\n    });\n\n    REQUIRE(nodes.count(&A) > 0);\n    REQUIRE(nodes.count(&B) > 0);\n    REQUIRE(nodes.count(&C) > 0);\n    REQUIRE(nodes.count(&D) > 0);\n}\n\nTEST_CASE(\"NodesWalk-cycle2\", \"NodesWalk\") {\n    Node pA, A, B, C, D;\n\n    pA.addSuccessor(&A);\n    A.addSuccessor(&B);\n    A.addSuccessor(&C);\n    B.addSuccessor(&D);\n    C.addSuccessor(&D);\n    D.addSuccessor(&A);\n\n    NodesWalk<Node, dg::ADT::QueueLIFO<Node *>> walk;\n\n    std::set<Node *> nodes;\n    walk.run(&pA, [&nodes](Node *n) {\n        bool ret = nodes.insert(n).second;\n        REQUIRE(ret);\n    });\n\n    REQUIRE(nodes.count(&pA) > 0);\n    REQUIRE(nodes.count(&A) > 0);\n    REQUIRE(nodes.count(&B) > 0);\n    REQUIRE(nodes.count(&C) > 0);\n    REQUIRE(nodes.count(&D) > 0);\n}\n\nTEST_CASE(\"NodesWalk-disconnected\", \"NodesWalk\") {\n    Node A, B, C, D;\n\n    A.addSuccessor(&B);\n    A.addSuccessor(&C);\n    D.addSuccessor(&A);\n\n    NodesWalk<Node, dg::ADT::QueueLIFO<Node *>> walk;\n\n    std::set<Node *> nodes;\n    walk.run(&A, [&nodes](Node *n) {\n        bool ret = nodes.insert(n).second;\n        REQUIRE(ret);\n    });\n\n    REQUIRE(nodes.count(&A) > 0);\n    REQUIRE(nodes.count(&B) > 0);\n    REQUIRE(nodes.count(&C) > 0);\n    REQUIRE(nodes.count(&D) == 0);\n}\n\nTEST_CASE(\"NodesWalk-disconnected2\", \"NodesWalk\") {\n    Node A, B, C, D;\n\n    B.addSuccessor(&D);\n    C.addSuccessor(&D);\n    D.addSuccessor(&A);\n\n    NodesWalk<Node, dg::ADT::QueueLIFO<Node *>> walk;\n\n    std::set<Node *> nodes;\n    walk.run(&A, [&nodes](Node *n) {\n        bool ret = nodes.insert(n).second;\n        REQUIRE(ret);\n    });\n\n    REQUIRE(nodes.count(&A) > 0);\n    REQUIRE(nodes.count(&B) == 0);\n    REQUIRE(nodes.count(&C) == 0);\n    REQUIRE(nodes.count(&D) == 0);\n}\n\n#include <dg/BFS.h>\n\nTEST_CASE(\"BFS-sanity\", \"BFS\") {\n    Node A, B, C, D;\n\n    A.addSuccessor(&B);\n    B.addSuccessor(&C);\n    C.addSuccessor(&D);\n\n    BFS<Node> bfs;\n\n    std::set<Node *> nodes;\n    bfs.run(&A, [&nodes](Node *n) {\n        bool ret = nodes.insert(n).second;\n        REQUIRE(ret);\n    });\n\n    REQUIRE(nodes.count(&A) > 0);\n    REQUIRE(nodes.count(&B) > 0);\n    REQUIRE(nodes.count(&C) > 0);\n    REQUIRE(nodes.count(&D) > 0);\n}\n\nTEST_CASE(\"BFS-order\", \"BFS\") {\n    Node A, B, C, D, E;\n\n    A.addSuccessor(&B);\n    A.addSuccessor(&C);\n    B.addSuccessor(&D);\n    D.addSuccessor(&E);\n\n    BFS<Node> bfs;\n\n    std::vector<Node *> nodes;\n    bfs.run(&A, [&nodes](Node *n) { nodes.push_back(n); });\n\n    // here we know that the successors are processed\n    // from left-to-right\n    REQUIRE(nodes == decltype(nodes){&A, &B, &C, &D, &E});\n}\n\nTEST_CASE(\"BFS-order2\", \"BFS\") {\n    Node A, B, C, D, E, F;\n\n    A.addSuccessor(&B);\n    A.addSuccessor(&C);\n    B.addSuccessor(&D);\n    B.addSuccessor(&F);\n    C.addSuccessor(&E);\n\n    BFS<Node> bfs;\n\n    std::vector<Node *> nodes;\n    bfs.run(&A, [&nodes](Node *n) { nodes.push_back(n); });\n\n    // here we know that the successors are processed\n    // from left-to-right\n    REQUIRE(nodes == decltype(nodes){&A, &B, &C, &D, &F, &E});\n}\n\nTEST_CASE(\"BFS-order3\", \"BFS\") {\n    Node A, B, C, D, E, F;\n\n    A.addSuccessor(&B);\n    A.addSuccessor(&C);\n    B.addSuccessor(&D);\n    B.addSuccessor(&F);\n    D.addSuccessor(&E);\n\n    BFS<Node> bfs;\n\n    std::vector<Node *> nodes;\n    bfs.run(&A, [&nodes](Node *n) { nodes.push_back(n); });\n\n    // here we know that the successors are processed\n    // from left-to-right\n    REQUIRE(nodes == decltype(nodes){&A, &B, &C, &D, &F, &E});\n}\n\n#include <dg/DFS.h>\n\nTEST_CASE(\"DFS1\", \"DFS\") {\n    Node A, B, C, D;\n\n    A.addSuccessor(&B);\n    B.addSuccessor(&C);\n    C.addSuccessor(&D);\n\n    DFS<Node> dfs;\n\n    std::set<Node *> nodes;\n    dfs.run(&A, [&nodes](Node *n) {\n        bool ret = nodes.insert(n).second;\n        REQUIRE(ret);\n    });\n\n    REQUIRE(nodes.count(&A) > 0);\n    REQUIRE(nodes.count(&B) > 0);\n    REQUIRE(nodes.count(&C) > 0);\n    REQUIRE(nodes.count(&D) > 0);\n}\n\nTEST_CASE(\"DFS-order\", \"DFS\") {\n    Node A, B, C, D, E;\n\n    A.addSuccessor(&B);\n    A.addSuccessor(&C);\n    B.addSuccessor(&D);\n    D.addSuccessor(&E);\n\n    DFS<Node> dfs;\n\n    std::vector<Node *> nodes;\n    dfs.run(&A, [&nodes](Node *n) { nodes.push_back(n); });\n\n    // here we know that the successors are processed\n    // from right-to-left\n    REQUIRE(nodes == decltype(nodes){&A, &C, &B, &D, &E});\n}\n\nTEST_CASE(\"DFS-order2\", \"DFS\") {\n    Node A, B, C, D, E, F;\n\n    A.addSuccessor(&B);\n    A.addSuccessor(&C);\n    B.addSuccessor(&D);\n    B.addSuccessor(&F);\n    D.addSuccessor(&E);\n\n    DFS<Node> dfs;\n\n    std::vector<Node *> nodes;\n    dfs.run(&A, [&nodes](Node *n) { nodes.push_back(n); });\n\n    // here we know that the successors are processed\n    // from right-to-left\n    REQUIRE(nodes == decltype(nodes){&A, &C, &B, &F, &D, &E});\n}\n\nTEST_CASE(\"DFS-order3\", \"DFS\") {\n    Node A, B, C, D, E, F, G;\n\n    A.addSuccessor(&B);\n    A.addSuccessor(&C);\n    B.addSuccessor(&D);\n    B.addSuccessor(&F);\n    D.addSuccessor(&E);\n    F.addSuccessor(&G);\n\n    DFS<Node> dfs;\n\n    std::vector<Node *> nodes;\n    dfs.run(&A, [&nodes](Node *n) { nodes.push_back(n); });\n\n    // here we know that the successors are processed\n    // from right-to-left\n    REQUIRE(nodes == decltype(nodes){&A, &C, &B, &F, &G, &D, &E});\n}\n"
  },
  {
    "path": "tests/numbers-set-test.cpp",
    "content": "#include <catch2/catch.hpp>\n\n#include <set>\n\n#include \"dg/ADT/NumberSet.h\"\n\nusing namespace dg::ADT;\n\nTEST_CASE(\"Querying empty set\", \"BitvectorNumberSet\") {\n    BitvectorNumberSet B;\n    REQUIRE(B.empty());\n    REQUIRE(B.empty());\n}\n\nTEST_CASE(\"Add few elements\", \"BitvectorNumberSet\") {\n    BitvectorNumberSet B;\n    REQUIRE(B.add(0));\n    REQUIRE(B.add(1));\n    REQUIRE(B.add(10));\n\n    REQUIRE(B.size() == 3);\n    REQUIRE(B.has(0));\n    REQUIRE(B.has(1));\n    REQUIRE(B.has(10));\n\n    REQUIRE(!B.has(3));\n    REQUIRE(!B.has(2));\n    REQUIRE(!B.has(100));\n}\n\nTEST_CASE(\"Add big elements\", \"BitvectorNumberSet\") {\n    BitvectorNumberSet B;\n    REQUIRE(B.add(100));\n    REQUIRE(B.add(100000));\n    REQUIRE(B.add(100000000));\n\n    REQUIRE(B.size() == 3);\n    REQUIRE(B.has(100));\n    REQUIRE(B.has(100000));\n    REQUIRE(B.has(100000000));\n\n    REQUIRE(!B.has(3));\n    REQUIRE(!B.has(2));\n    REQUIRE(!B.has(1000));\n}\n\nTEST_CASE(\"Querying empty small set\", \"SmallNumberSet\") {\n    SmallNumberSet B;\n    REQUIRE(B.empty());\n    REQUIRE(B.empty());\n}\n\nTEST_CASE(\"Add few elements (small-set)\", \"SmallNumberSet\") {\n    SmallNumberSet B;\n\n    REQUIRE(B.add(0));\n    REQUIRE(B.add(1));\n    REQUIRE(B.add(10));\n\n    REQUIRE(B.size() == 3);\n    REQUIRE(B.has(0));\n    REQUIRE(B.has(1));\n    REQUIRE(B.has(10));\n\n    REQUIRE(!B.has(3));\n    REQUIRE(!B.has(2));\n    REQUIRE(!B.has(100));\n}\n\nTEST_CASE(\"Add big elements (small-set)\", \"SmallNumberSet\") {\n    SmallNumberSet B;\n    REQUIRE(B.add(100));\n    REQUIRE(B.add(100000));\n    REQUIRE(B.add(100000000));\n\n    REQUIRE(B.size() == 3);\n    REQUIRE(B.has(100));\n    REQUIRE(B.has(100000));\n    REQUIRE(B.has(100000000));\n\n    REQUIRE(!B.has(3));\n    REQUIRE(!B.has(2));\n    REQUIRE(!B.has(1000));\n}\n\nTEST_CASE(\"Iterate few elements\", \"SmallNumberSet\") {\n    BitvectorNumberSet B;\n    std::set<uint64_t> S;\n\n    REQUIRE(B.add(0));\n    REQUIRE(B.add(1));\n    REQUIRE(B.add(10));\n    S.insert({0, 1, 10});\n\n    REQUIRE(B.size() == 3);\n    for (auto x : B) {\n        REQUIRE(S.count(x) > 0);\n    }\n}\n\nTEST_CASE(\"Iterate big elements\", \"SmallNumberSet\") {\n    BitvectorNumberSet B;\n    std::set<uint64_t> S;\n\n    S.insert({100, 100000, 1000000000000000});\n    for (auto x : S)\n        REQUIRE(B.add(x));\n\n    REQUIRE(B.size() == 3);\n    for (auto x : B) {\n        REQUIRE(S.count(x) > 0);\n    }\n}\n\nTEST_CASE(\"Iterate mixed elements\", \"SmallNumberSet\") {\n    BitvectorNumberSet B;\n    std::set<uint64_t> S;\n\n    S.insert({0, 1, 10, 63, 64, 100, 100000, 1000000000000000});\n    for (auto x : S)\n        REQUIRE(B.add(x));\n\n    REQUIRE(B.size() == S.size());\n    for (auto x : B) {\n        REQUIRE(S.count(x) > 0);\n    }\n\n    for (auto x : S)\n        REQUIRE(B.has(x));\n}\n"
  },
  {
    "path": "tests/points-to-set-test.cpp",
    "content": "#include <catch2/catch.hpp>\n\n#include \"dg/PointerAnalysis/PSNode.h\"\n#include \"dg/PointerAnalysis/Pointer.h\"\n#include \"dg/PointerAnalysis/PointerGraph.h\"\n\nusing namespace dg::pta;\n\ntemplate <typename PTSetT>\nvoid queryingEmptySet() {\n    PTSetT B;\n    REQUIRE(B.empty());\n    REQUIRE(B.empty());\n}\n\ntemplate <typename PTSetT>\nvoid addAnElement() {\n    PTSetT B;\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    B.add(Pointer(A, 0));\n    REQUIRE(*(B.begin()) == Pointer(A, 0));\n}\n\ntemplate <typename PTSetT>\nvoid addFewElements() {\n    PTSetT S;\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    REQUIRE(S.add(Pointer(A, 0)) == true);\n    REQUIRE(S.add(Pointer(A, 20)) == true);\n    REQUIRE(S.add(Pointer(A, 120)) == true);\n    REQUIRE(S.add(Pointer(A, 1240)) == true);\n    REQUIRE(S.add(Pointer(A, 235235)) == true);\n    REQUIRE(S.add(Pointer(A, 22332435235)) == true);\n    for (const auto &ptr : S)\n        REQUIRE(ptr.target == A);\n    REQUIRE(S.size() == 6);\n}\n\ntemplate <typename PTSetT>\nvoid addFewElements2() {\n    PTSetT S;\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    REQUIRE(S.add(Pointer(A, 0)) == true);\n    REQUIRE(S.add(Pointer(A, 20)) == true);\n    REQUIRE(S.add(Pointer(A, 120)) == true);\n    REQUIRE(S.add(Pointer(A, 1240)) == true);\n    REQUIRE(S.add(Pointer(A, 235235)) == true);\n    REQUIRE(S.add(Pointer(A, 22332435235)) == true);\n    for (const auto &ptr : S)\n        REQUIRE((ptr.target == A || ptr.target == B));\n\n    REQUIRE(S.size() == 6);\n\n    REQUIRE(S.add(Pointer(A, 0)) == false);\n    REQUIRE(S.add(Pointer(A, 20)) == false);\n    REQUIRE(S.add(Pointer(A, 120)) == false);\n    REQUIRE(S.add(Pointer(A, 1240)) == false);\n    REQUIRE(S.add(Pointer(A, 235235)) == false);\n    REQUIRE(S.add(Pointer(A, 22332435235)) == false);\n\n    REQUIRE(S.size() == 6);\n}\n\ntemplate <typename PTSetT>\nvoid mergePointsToSets() {\n    PTSetT S1;\n    PTSetT S2;\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n\n    REQUIRE(S1.add({A, 0}));\n    REQUIRE(S2.add({B, 0}));\n\n    // union (merge) operation\n    REQUIRE(S1.add(S2));\n    REQUIRE(S1.has({A, 0}));\n    REQUIRE(S1.has({B, 0}));\n    REQUIRE(S1.size() == 2);\n}\n\ntemplate <typename PTSetT>\nvoid removeElement() {\n    PTSetT S;\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n\n    REQUIRE(S.add({A, 0}) == true);\n    REQUIRE(S.size() == 1);\n    REQUIRE(S.remove({A, 0}) == true);\n    REQUIRE(S.remove({A, 1}) == false);\n    REQUIRE(S.empty());\n}\n\ntemplate <typename PTSetT>\nvoid removeFewElements() {\n    PTSetT S;\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n\n    REQUIRE(S.add(Pointer(A, 0)) == true);\n    REQUIRE(S.add(Pointer(A, 16)) == true);\n    REQUIRE(S.add(Pointer(A, 120)) == true);\n    REQUIRE(S.add(Pointer(B, 1240)) == true);\n    REQUIRE(S.add(Pointer(B, 235235)) == true);\n    REQUIRE(S.add(Pointer(B, 22332435235)) == true);\n    REQUIRE(S.remove({A, 0}) == true);\n    REQUIRE(S.remove({A, 120}) == true);\n    REQUIRE(S.remove({B, 22332435235}) == true);\n    REQUIRE(S.size() == 3);\n}\n\ntemplate <typename PTSetT>\nvoid removeAnyTest() {\n    PTSetT S;\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n\n    REQUIRE(S.add(Pointer(A, 0)) == true);\n    REQUIRE(S.add(Pointer(A, 16)) == true);\n    REQUIRE(S.add(Pointer(A, 120)) == true);\n    REQUIRE(S.add(Pointer(B, 1240)) == true);\n    REQUIRE(S.add(Pointer(B, 235235)) == true);\n    REQUIRE(S.add(Pointer(B, 22332435235)) == true);\n    REQUIRE(S.removeAny(A) == true);\n    REQUIRE(S.removeAny(A) == false);\n    REQUIRE(S.size() == 3);\n    REQUIRE(S.removeAny(B) == true);\n    REQUIRE(S.empty());\n    REQUIRE(S.removeAny(B) == false);\n}\n\ntemplate <typename PTSetT>\nvoid pointsToTest() {\n    PTSetT S;\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    S.add(Pointer(A, 0));\n    REQUIRE(S.pointsTo(Pointer(A, 0)) == true);\n    REQUIRE(S.mayPointTo(Pointer(A, 0)) == true);\n    REQUIRE(S.mustPointTo(Pointer(A, 0)) == true);\n    S.add(Pointer(A, 8));\n    S.add(Pointer(A, 64));\n    S.add(Pointer(B, 123));\n    REQUIRE(S.pointsTo(Pointer(A, 0)) == true);\n    REQUIRE(S.mayPointTo(Pointer(A, 0)) == true);\n    REQUIRE(S.mustPointTo(Pointer(A, 0)) == false);\n    REQUIRE(S.pointsTo(Pointer(A, 64)) == true);\n    REQUIRE(S.mayPointTo(Pointer(A, 64)) == true);\n    REQUIRE(S.mustPointTo(Pointer(A, 64)) == false);\n    REQUIRE(S.pointsTo(Pointer(B, 123)) == true);\n    REQUIRE(S.mayPointTo(Pointer(B, 123)) == true);\n    REQUIRE(S.mustPointTo(Pointer(B, 123)) == false);\n    REQUIRE(S.mayPointTo(Pointer(A, 10000)) == false);\n    REQUIRE(S.mustPointTo(Pointer(A, 10000)) == false);\n    REQUIRE(S.pointsTo(Pointer(A, 10000)) == false);\n    S.add(Pointer(A, dg::Offset::UNKNOWN));\n    REQUIRE(S.pointsTo(Pointer(A, 0)) == false);\n    REQUIRE(S.mayPointTo(Pointer(A, 0)) == true);\n    REQUIRE(S.mustPointTo(Pointer(A, 0)) == false);\n}\n\ntemplate <typename PTSetT>\nvoid testAlignedOverflowBehavior() { // only works for aligned PTSets using\n                                     // overflow Set\n    PTSetT S;\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    REQUIRE(S.getMultiplier() > 1);\n    REQUIRE(S.add(Pointer(A, 0)) == true);\n    REQUIRE(S.size() == 1);\n    REQUIRE(S.overflowSetSize() == 0);\n    REQUIRE(S.add(Pointer(A, S.getMultiplier())) == true);\n    REQUIRE(S.size() == 2);\n    REQUIRE(S.overflowSetSize() == 0);\n    REQUIRE(S.add(Pointer(A, 2 * S.getMultiplier() + 1)) == true);\n    REQUIRE(S.size() == 3);\n    REQUIRE(S.overflowSetSize() == 1);\n    REQUIRE(S.add(Pointer(A, 2 * S.getMultiplier())) == true);\n    REQUIRE(S.size() == 4);\n    REQUIRE(S.overflowSetSize() == 1);\n    REQUIRE(S.add(Pointer(A, 11 * S.getMultiplier() + 1)) == true);\n    REQUIRE(S.size() == 5);\n    REQUIRE(S.overflowSetSize() == 2);\n    REQUIRE(S.add(Pointer(B, dg::Offset::UNKNOWN)) == true);\n    REQUIRE(S.size() == 6);\n    REQUIRE(S.overflowSetSize() == 2);\n    REQUIRE(S.remove(Pointer(A, 11 * S.getMultiplier() + 1)) == true);\n    REQUIRE(S.size() == 5);\n    REQUIRE(S.overflowSetSize() == 1);\n    REQUIRE(S.remove(Pointer(A, 2 * S.getMultiplier())) == true);\n    REQUIRE(S.size() == 4);\n    REQUIRE(S.overflowSetSize() == 1);\n    REQUIRE(S.add(Pointer(A, dg::Offset::UNKNOWN)) == true);\n    REQUIRE(S.size() == 2);\n    REQUIRE(S.overflowSetSize() == 0);\n    REQUIRE(S.removeAny(B) == true);\n    REQUIRE(S.size() == 1);\n    REQUIRE(S.overflowSetSize() == 0);\n}\n\ntemplate <typename PTSetT>\nvoid testSmallOverflowBehavior() { // only works for SmallOffsetsPTSet\n    PTSetT S;\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    REQUIRE(S.add(Pointer(A, 0)) == true);\n    REQUIRE(S.size() == 1);\n    REQUIRE(S.overflowSetSize() == 0);\n    REQUIRE(S.add(Pointer(A, 21)) == true);\n    REQUIRE(S.size() == 2);\n    REQUIRE(S.overflowSetSize() == 0);\n    REQUIRE(S.add(Pointer(A, 63)) == true);\n    REQUIRE(S.size() == 3);\n    REQUIRE(S.overflowSetSize() == 1);\n    REQUIRE(S.add(Pointer(A, 62)) == true);\n    REQUIRE(S.size() == 4);\n    REQUIRE(S.overflowSetSize() == 1);\n    REQUIRE(S.add(Pointer(A, 1287)) == true);\n    REQUIRE(S.size() == 5);\n    REQUIRE(S.overflowSetSize() == 2);\n    REQUIRE(S.add(Pointer(B, dg::Offset::UNKNOWN)) == true);\n    REQUIRE(S.size() == 6);\n    REQUIRE(S.overflowSetSize() == 2);\n    REQUIRE(S.remove(Pointer(A, 63)) == true);\n    REQUIRE(S.size() == 5);\n    REQUIRE(S.overflowSetSize() == 1);\n    REQUIRE(S.remove(Pointer(A, 62)) == true);\n    REQUIRE(S.size() == 4);\n    REQUIRE(S.overflowSetSize() == 1);\n    REQUIRE(S.add(Pointer(A, dg::Offset::UNKNOWN)) == true);\n    REQUIRE(S.size() == 2);\n    REQUIRE(S.overflowSetSize() == 0);\n    REQUIRE(S.removeAny(B) == true);\n    REQUIRE(S.size() == 1);\n    REQUIRE(S.overflowSetSize() == 0);\n}\n\nTEST_CASE(\"Querying empty set\", \"PointsToSet\") {\n    queryingEmptySet<OffsetsSetPointsToSet>();\n    queryingEmptySet<SimplePointsToSet>();\n    queryingEmptySet<SeparateOffsetsPointsToSet>();\n    queryingEmptySet<PointerIdPointsToSet>();\n    queryingEmptySet<SmallOffsetsPointsToSet>();\n    queryingEmptySet<AlignedSmallOffsetsPointsToSet>();\n    queryingEmptySet<AlignedPointerIdPointsToSet>();\n}\n\nTEST_CASE(\"Add an element\", \"PointsToSet\") {\n    addAnElement<OffsetsSetPointsToSet>();\n    addAnElement<SimplePointsToSet>();\n    addAnElement<SeparateOffsetsPointsToSet>();\n    addAnElement<PointerIdPointsToSet>();\n    addAnElement<SmallOffsetsPointsToSet>();\n    addAnElement<AlignedSmallOffsetsPointsToSet>();\n    addAnElement<AlignedPointerIdPointsToSet>();\n}\n\nTEST_CASE(\"Add few elements\", \"PointsToSet\") {\n    addFewElements<OffsetsSetPointsToSet>();\n    addFewElements<SimplePointsToSet>();\n    addFewElements<SeparateOffsetsPointsToSet>();\n    addFewElements<PointerIdPointsToSet>();\n    addFewElements<SmallOffsetsPointsToSet>();\n    addFewElements<AlignedSmallOffsetsPointsToSet>();\n    addFewElements<AlignedPointerIdPointsToSet>();\n}\n\nTEST_CASE(\"Add few elements 2\", \"PointsToSet\") {\n    addFewElements2<OffsetsSetPointsToSet>();\n    addFewElements2<SimplePointsToSet>();\n    addFewElements2<SeparateOffsetsPointsToSet>();\n    addFewElements2<PointerIdPointsToSet>();\n    addFewElements2<SmallOffsetsPointsToSet>();\n    addFewElements2<AlignedSmallOffsetsPointsToSet>();\n    addFewElements2<AlignedPointerIdPointsToSet>();\n}\n\nTEST_CASE(\"Merge points-to sets\", \"PointsToSet\") {\n    mergePointsToSets<OffsetsSetPointsToSet>();\n    mergePointsToSets<SimplePointsToSet>();\n    mergePointsToSets<SeparateOffsetsPointsToSet>();\n    mergePointsToSets<PointerIdPointsToSet>();\n    mergePointsToSets<SmallOffsetsPointsToSet>();\n    mergePointsToSets<AlignedSmallOffsetsPointsToSet>();\n    mergePointsToSets<AlignedPointerIdPointsToSet>();\n}\n\nTEST_CASE(\"Remove element\",\n          \"PointsToSet\") { // SeparateOffsetsPointsToSet has different remove\n                           // behavior, it isn't tested here\n    removeElement<OffsetsSetPointsToSet>();\n    removeElement<SimplePointsToSet>();\n    removeElement<PointerIdPointsToSet>();\n    removeElement<SmallOffsetsPointsToSet>();\n    removeElement<AlignedSmallOffsetsPointsToSet>();\n    removeElement<AlignedPointerIdPointsToSet>();\n}\n\nTEST_CASE(\"Remove few elements\",\n          \"PointsToSet\") { // SeparateOffsetsPointsToSet has different remove\n                           // behavior, it isn't tested here\n    removeFewElements<OffsetsSetPointsToSet>();\n    removeFewElements<SimplePointsToSet>();\n    removeFewElements<PointerIdPointsToSet>();\n    removeFewElements<SmallOffsetsPointsToSet>();\n    removeFewElements<AlignedSmallOffsetsPointsToSet>();\n    removeFewElements<AlignedPointerIdPointsToSet>();\n}\n\nTEST_CASE(\"Remove all elements pointing to a target\",\n          \"PointsToSet\") { // SeparateOffsetsPointsToSet has different behavior,\n                           // it isn't tested here\n    removeAnyTest<OffsetsSetPointsToSet>();\n    removeAnyTest<SimplePointsToSet>();\n    removeAnyTest<PointerIdPointsToSet>();\n    removeAnyTest<SmallOffsetsPointsToSet>();\n    removeAnyTest<AlignedSmallOffsetsPointsToSet>();\n    removeAnyTest<AlignedPointerIdPointsToSet>();\n}\n\nTEST_CASE(\"Test various points-to functions\", \"PointsToSet\") {\n    pointsToTest<OffsetsSetPointsToSet>();\n    pointsToTest<SimplePointsToSet>();\n    pointsToTest<SeparateOffsetsPointsToSet>();\n    pointsToTest<PointerIdPointsToSet>();\n    pointsToTest<SmallOffsetsPointsToSet>();\n    pointsToTest<AlignedSmallOffsetsPointsToSet>();\n    pointsToTest<AlignedPointerIdPointsToSet>();\n}\n\nTEST_CASE(\"Test small overflow set behavior\", \"PointsToSet\") {\n    testSmallOverflowBehavior<SmallOffsetsPointsToSet>();\n}\n\nTEST_CASE(\"Test aligned overflow set behavior\", \"PointsToSet\") {\n    testAlignedOverflowBehavior<AlignedSmallOffsetsPointsToSet>();\n    testAlignedOverflowBehavior<AlignedPointerIdPointsToSet>();\n}\n"
  },
  {
    "path": "tests/points-to-test.cpp",
    "content": "#include <catch2/catch.hpp>\n\n#include \"dg/PointerAnalysis/PointerAnalysisFI.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFS.h\"\n#include \"dg/PointerAnalysis/PointerGraph.h\"\n\nusing namespace dg::pta;\nusing dg::Offset;\n\ntemplate <typename PTStoT>\nvoid store_load() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    PSNode *S = PS.create<PSNodeType::STORE>(A, B);\n    PSNode *L = PS.create<PSNodeType::LOAD>(B);\n\n    A->addSuccessor(B);\n    B->addSuccessor(S);\n    S->addSuccessor(L);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L->doesPointsTo(A));\n}\n\ntemplate <typename PTStoT>\nvoid store_load2() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    PSNode *C = PS.create<PSNodeType::ALLOC>();\n    PSNode *S1 = PS.create<PSNodeType::STORE>(A, B);\n    PSNode *S2 = PS.create<PSNodeType::STORE>(C, B);\n    PSNode *L1 = PS.create<PSNodeType::LOAD>(B);\n    PSNode *L2 = PS.create<PSNodeType::LOAD>(B);\n    PSNode *L3 = PS.create<PSNodeType::LOAD>(B);\n\n    /*\n     *        A\n     *        |\n     *        B\n     *        |\n     *        C\n     *      /   \\\n     *     S1    S2\n     *     |      |\n     *     L1    L2\n     *       \\  /\n     *        L3\n     */\n    A->addSuccessor(B);\n    B->addSuccessor(C);\n    C->addSuccessor(S1);\n    C->addSuccessor(S2);\n    S1->addSuccessor(L1);\n    S2->addSuccessor(L2);\n    L1->addSuccessor(L3);\n    L2->addSuccessor(L3);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L1->doesPointsTo(A));\n    REQUIRE(L2->doesPointsTo(C));\n    REQUIRE(L3->doesPointsTo(A));\n    REQUIRE(L3->doesPointsTo(C));\n}\n\ntemplate <typename PTStoT>\nvoid store_load3() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    PSNode *C = PS.create<PSNodeType::ALLOC>();\n    PSNode *S1 = PS.create<PSNodeType::STORE>(A, B);\n    PSNode *L1 = PS.create<PSNodeType::LOAD>(B);\n    PSNode *S2 = PS.create<PSNodeType::STORE>(C, B);\n    PSNode *L2 = PS.create<PSNodeType::LOAD>(B);\n\n    A->addSuccessor(B);\n    B->addSuccessor(C);\n    C->addSuccessor(S1);\n    S1->addSuccessor(L1);\n    L1->addSuccessor(S2);\n    S2->addSuccessor(L2);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L1->doesPointsTo(A));\n    REQUIRE(L2->doesPointsTo(C));\n}\n\ntemplate <typename PTStoT>\nvoid store_load4() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    A->setSize(8);\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    PSNode *C = PS.create<PSNodeType::ALLOC>();\n    PSNode *GEP = PS.create<PSNodeType::GEP>(A, 4);\n    PSNode *S1 = PS.create<PSNodeType::STORE>(GEP, B);\n    PSNode *L1 = PS.create<PSNodeType::LOAD>(B);\n    PSNode *S2 = PS.create<PSNodeType::STORE>(C, B);\n    PSNode *L2 = PS.create<PSNodeType::LOAD>(B);\n\n    A->addSuccessor(B);\n    B->addSuccessor(C);\n    C->addSuccessor(GEP);\n    GEP->addSuccessor(S1);\n    S1->addSuccessor(L1);\n    L1->addSuccessor(S2);\n    S2->addSuccessor(L2);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L1->doesPointsTo(A, 4));\n    REQUIRE(L2->doesPointsTo(C));\n}\n\ntemplate <typename PTStoT>\nvoid store_load5() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    A->setSize(8);\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    B->setSize(16);\n    PSNode *C = PS.create<PSNodeType::ALLOC>();\n    PSNode *GEP1 = PS.create<PSNodeType::GEP>(A, 4);\n    PSNode *GEP2 = PS.create<PSNodeType::GEP>(B, 8);\n    PSNode *S1 = PS.create<PSNodeType::STORE>(GEP1, GEP2);\n    PSNode *GEP3 = PS.create<PSNodeType::GEP>(B, 8);\n    PSNode *L1 = PS.create<PSNodeType::LOAD>(GEP3);\n    PSNode *S2 = PS.create<PSNodeType::STORE>(C, B);\n    PSNode *L2 = PS.create<PSNodeType::LOAD>(B);\n\n    A->addSuccessor(B);\n    B->addSuccessor(C);\n    C->addSuccessor(GEP1);\n    GEP1->addSuccessor(GEP2);\n    GEP2->addSuccessor(S1);\n    S1->addSuccessor(GEP3);\n    GEP3->addSuccessor(L1);\n    L1->addSuccessor(S2);\n    S2->addSuccessor(L2);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L1->doesPointsTo(A, 4));\n    REQUIRE(L2->doesPointsTo(C));\n}\n\ntemplate <typename PTStoT>\nvoid gep1() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    // we must set size, so that GEP won't\n    // make the offset UNKNOWN\n    A->setSize(8);\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    PSNode *GEP1 = PS.create<PSNodeType::GEP>(A, 4);\n    PSNode *S = PS.create<PSNodeType::STORE>(B, GEP1);\n    PSNode *GEP2 = PS.create<PSNodeType::GEP>(A, 4);\n    PSNode *L = PS.create<PSNodeType::LOAD>(GEP2);\n\n    A->addSuccessor(B);\n    B->addSuccessor(GEP1);\n    GEP1->addSuccessor(S);\n    S->addSuccessor(GEP2);\n    GEP2->addSuccessor(L);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(GEP1->doesPointsTo(A, 4));\n    REQUIRE(GEP2->doesPointsTo(A, 4));\n    REQUIRE(L->doesPointsTo(B));\n}\n\ntemplate <typename PTStoT>\nvoid gep2() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    A->setSize(16);\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    PSNode *GEP1 = PS.create<PSNodeType::GEP>(A, 4);\n    PSNode *GEP2 = PS.create<PSNodeType::GEP>(GEP1, 4);\n    PSNode *S = PS.create<PSNodeType::STORE>(B, GEP2);\n    PSNode *GEP3 = PS.create<PSNodeType::GEP>(A, 8);\n    PSNode *L = PS.create<PSNodeType::LOAD>(GEP3);\n\n    A->addSuccessor(B);\n    B->addSuccessor(GEP1);\n    GEP1->addSuccessor(GEP2);\n    GEP2->addSuccessor(S);\n    S->addSuccessor(GEP3);\n    GEP3->addSuccessor(L);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(GEP1->doesPointsTo(A, 4));\n    REQUIRE(L->doesPointsTo(B));\n}\n\ntemplate <typename PTStoT>\nvoid gep3() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    PSNode *ARRAY = PS.create<PSNodeType::ALLOC>();\n    ARRAY->setSize(40);\n    PSNode *GEP1 = PS.create<PSNodeType::GEP>(ARRAY, 0);\n    PSNode *GEP2 = PS.create<PSNodeType::GEP>(ARRAY, 4);\n    PSNode *S1 = PS.create<PSNodeType::STORE>(A, GEP1);\n    PSNode *S2 = PS.create<PSNodeType::STORE>(B, GEP2);\n    PSNode *GEP3 = PS.create<PSNodeType::GEP>(ARRAY, 0);\n    PSNode *GEP4 = PS.create<PSNodeType::GEP>(ARRAY, 4);\n    PSNode *L1 = PS.create<PSNodeType::LOAD>(GEP3);\n    PSNode *L2 = PS.create<PSNodeType::LOAD>(GEP4);\n\n    A->addSuccessor(B);\n    B->addSuccessor(ARRAY);\n    ARRAY->addSuccessor(GEP1);\n    GEP1->addSuccessor(GEP2);\n    GEP2->addSuccessor(S1);\n    S1->addSuccessor(S2);\n    S2->addSuccessor(GEP3);\n    GEP3->addSuccessor(GEP4);\n    GEP4->addSuccessor(L1);\n    L1->addSuccessor(L2);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L1->doesPointsTo(A));\n    REQUIRE(L2->doesPointsTo(B));\n}\n\ntemplate <typename PTStoT>\nvoid gep4() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    PSNodeAlloc *ARRAY = PSNodeAlloc::get(PS.create<PSNodeType::ALLOC>());\n    ARRAY->setSize(40);\n    PSNode *GEP1 = PS.create<PSNodeType::GEP>(ARRAY, 0);\n    PSNode *GEP2 = PS.create<PSNodeType::GEP>(ARRAY, 4);\n    PSNode *S1 = PS.create<PSNodeType::STORE>(A, GEP1);\n    PSNode *S2 = PS.create<PSNodeType::STORE>(B, GEP2);\n    PSNode *GEP3 = PS.create<PSNodeType::GEP>(ARRAY, 0);\n    PSNode *GEP4 = PS.create<PSNodeType::GEP>(ARRAY, 4);\n    PSNode *L1 = PS.create<PSNodeType::LOAD>(GEP3);\n    PSNode *L2 = PS.create<PSNodeType::LOAD>(GEP4);\n\n    A->addSuccessor(B);\n    B->addSuccessor(ARRAY);\n    ARRAY->addSuccessor(GEP1);\n    ARRAY->addSuccessor(GEP2);\n\n    GEP1->addSuccessor(S1);\n    S1->addSuccessor(GEP3);\n\n    GEP2->addSuccessor(S2);\n    S2->addSuccessor(GEP3);\n\n    GEP3->addSuccessor(GEP4);\n    GEP4->addSuccessor(L1);\n    L1->addSuccessor(L2);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L1->doesPointsTo(A));\n    REQUIRE(L2->doesPointsTo(B));\n}\n\ntemplate <typename PTStoT>\nvoid gep5() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    PSNode *ARRAY = PS.create<PSNodeType::ALLOC>();\n    ARRAY->setSize(20);\n    PSNode *GEP1 = PS.create<PSNodeType::GEP>(ARRAY, 0);\n    PSNode *GEP2 = PS.create<PSNodeType::GEP>(ARRAY, 4);\n    PSNode *S1 = PS.create<PSNodeType::STORE>(A, GEP1);\n    PSNode *S2 = PS.create<PSNodeType::STORE>(B, GEP2);\n    PSNode *GEP3 = PS.create<PSNodeType::GEP>(ARRAY, 0);\n    PSNode *GEP4 = PS.create<PSNodeType::GEP>(ARRAY, 4);\n    PSNode *L1 = PS.create<PSNodeType::LOAD>(GEP3);\n    PSNode *L2 = PS.create<PSNodeType::LOAD>(GEP4);\n    PSNode *GEP5 = PS.create<PSNodeType::GEP>(ARRAY, 0);\n    PSNode *S3 = PS.create<PSNodeType::STORE>(B, GEP5);\n    PSNode *L3 = PS.create<PSNodeType::LOAD>(GEP5);\n\n    A->addSuccessor(B);\n    B->addSuccessor(ARRAY);\n    ARRAY->addSuccessor(GEP1);\n    ARRAY->addSuccessor(GEP2);\n\n    GEP1->addSuccessor(S1);\n    S1->addSuccessor(GEP3);\n\n    GEP2->addSuccessor(S2);\n    S2->addSuccessor(GEP5);\n    GEP5->addSuccessor(S3);\n    S3->addSuccessor(L3);\n    L3->addSuccessor(GEP3);\n\n    GEP3->addSuccessor(GEP4);\n    GEP4->addSuccessor(L1);\n    L1->addSuccessor(L2);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L1->doesPointsTo(A));\n    REQUIRE(L1->doesPointsTo(B));\n    REQUIRE(L2->doesPointsTo(B));\n    REQUIRE(L3->doesPointsTo(B));\n}\n\ntemplate <typename PTStoT>\nvoid nulltest() {\n    PointerGraph PS;\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    PSNode *S = PS.create<PSNodeType::STORE>(NULLPTR, B);\n    PSNode *L = PS.create<PSNodeType::LOAD>(B);\n\n    B->addSuccessor(S);\n    S->addSuccessor(L);\n\n    auto *subg = PS.createSubgraph(B);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L->doesPointsTo(NULLPTR));\n}\n\ntemplate <typename PTStoT>\nvoid constant_store() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    B->setSize(16);\n    PSNode *C = PS.create<PSNodeType::CONSTANT>(B, 4);\n    PSNode *S = PS.create<PSNodeType::STORE>(A, C);\n    PSNode *GEP = PS.create<PSNodeType::GEP>(B, 4);\n    PSNode *L = PS.create<PSNodeType::LOAD>(GEP);\n\n    A->addSuccessor(B);\n    B->addSuccessor(S);\n    S->addSuccessor(GEP);\n    GEP->addSuccessor(L);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L->doesPointsTo(A));\n}\n\ntemplate <typename PTStoT>\nvoid load_from_zeroed() {\n    PointerGraph PS;\n    PSNodeAlloc *B = PSNodeAlloc::get(PS.create<PSNodeType::ALLOC>());\n    B->setZeroInitialized();\n    PSNode *L = PS.create<PSNodeType::LOAD>(B);\n\n    B->addSuccessor(L);\n\n    auto *subg = PS.createSubgraph(B);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L->doesPointsTo(NULLPTR));\n}\n\ntemplate <typename PTStoT>\nvoid load_from_unknown_offset() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    B->setSize(20);\n    PSNode *GEP = PS.create<PSNodeType::GEP>(B, Offset::UNKNOWN);\n    PSNode *S = PS.create<PSNodeType::STORE>(A, GEP);\n    PSNode *GEP2 = PS.create<PSNodeType::GEP>(B, 4);\n    PSNode *L = PS.create<PSNodeType::LOAD>(GEP2); // load from B + 4\n\n    A->addSuccessor(B);\n    B->addSuccessor(GEP);\n    GEP->addSuccessor(S);\n    S->addSuccessor(GEP2);\n    GEP2->addSuccessor(L);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    // B points to A + 0 at unknown offset,\n    // so load from B + 4 should be A + 0\n    REQUIRE(L->doesPointsTo(A));\n}\n\ntemplate <typename PTStoT>\nvoid load_from_unknown_offset2() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    B->setSize(20);\n    PSNode *GEP = PS.create<PSNodeType::GEP>(B, 4);\n    PSNode *S = PS.create<PSNodeType::STORE>(A, GEP);\n    PSNode *GEP2 = PS.create<PSNodeType::GEP>(B, Offset::UNKNOWN);\n    PSNode *L =\n            PS.create<PSNodeType::LOAD>(GEP2); // load from B + Offset::UNKNOWN\n\n    A->addSuccessor(B);\n    B->addSuccessor(GEP);\n    GEP->addSuccessor(S);\n    S->addSuccessor(GEP2);\n    GEP2->addSuccessor(L);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    // B points to A + 0 at offset 4,\n    // so load from B + UNKNOWN should be A + 0\n    REQUIRE(L->doesPointsTo(A));\n}\n\ntemplate <typename PTStoT>\nvoid load_from_unknown_offset3() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    PSNode *B = PS.create<PSNodeType::ALLOC>();\n    B->setSize(20);\n    PSNode *GEP = PS.create<PSNodeType::GEP>(B, Offset::UNKNOWN);\n    PSNode *S = PS.create<PSNodeType::STORE>(A, GEP);\n    PSNode *GEP2 = PS.create<PSNodeType::GEP>(B, Offset::UNKNOWN);\n    PSNode *L = PS.create<PSNodeType::LOAD>(GEP2);\n\n    A->addSuccessor(B);\n    B->addSuccessor(GEP);\n    GEP->addSuccessor(S);\n    S->addSuccessor(GEP2);\n    GEP2->addSuccessor(L);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L->doesPointsTo(A));\n}\n\ntemplate <typename PTStoT>\nvoid memcpy_test() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    A->setSize(20);\n    PSNode *SRC = PS.create<PSNodeType::ALLOC>();\n    SRC->setSize(16);\n    PSNode *DEST = PS.create<PSNodeType::ALLOC>();\n    DEST->setSize(16);\n\n    /* initialize SRC, so that\n     * it will point to A + 3 and A + 12\n     * at offsets 4 and 8 */\n    PSNode *GEP1 = PS.create<PSNodeType::GEP>(A, 3);\n    PSNode *GEP2 = PS.create<PSNodeType::GEP>(A, 12);\n    PSNode *G1 = PS.create<PSNodeType::GEP>(SRC, 4);\n    PSNode *G2 = PS.create<PSNodeType::GEP>(SRC, 8);\n    PSNode *S1 = PS.create<PSNodeType::STORE>(GEP1, G1);\n    PSNode *S2 = PS.create<PSNodeType::STORE>(GEP2, G2);\n\n    /* copy the memory,\n     * after this node dest should point to\n     * A + 3 and A + 12 at offsets 4 and 8 */\n    PSNode *CPY = PS.create<PSNodeType::MEMCPY>(\n            SRC, DEST, Offset::UNKNOWN /* len = all */);\n\n    /* load from the dest memory */\n    PSNode *G3 = PS.create<PSNodeType::GEP>(DEST, 4);\n    PSNode *G4 = PS.create<PSNodeType::GEP>(DEST, 8);\n    PSNode *L1 = PS.create<PSNodeType::LOAD>(G3);\n    PSNode *L2 = PS.create<PSNodeType::LOAD>(G4);\n\n    A->addSuccessor(SRC);\n    SRC->addSuccessor(DEST);\n    DEST->addSuccessor(GEP1);\n    GEP1->addSuccessor(GEP2);\n    GEP2->addSuccessor(G1);\n    G1->addSuccessor(G2);\n    G2->addSuccessor(S1);\n    S1->addSuccessor(S2);\n    S2->addSuccessor(CPY);\n    CPY->addSuccessor(G3);\n    G3->addSuccessor(G4);\n    G4->addSuccessor(L1);\n    L1->addSuccessor(L2);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L1->doesPointsTo(A, 3));\n    REQUIRE(L2->doesPointsTo(A, 12));\n}\n\ntemplate <typename PTStoT>\nvoid memcpy_test2() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    A->setSize(20);\n    PSNode *SRC = PS.create<PSNodeType::ALLOC>();\n    SRC->setSize(16);\n    PSNode *DEST = PS.create<PSNodeType::ALLOC>();\n    DEST->setSize(16);\n\n    /* initialize SRC, so that\n     * it will point to A + 3 and A + 12\n     * at offsets 4 and 8 */\n    PSNode *GEP1 = PS.create<PSNodeType::GEP>(A, 3);\n    PSNode *GEP2 = PS.create<PSNodeType::GEP>(A, 12);\n    PSNode *G1 = PS.create<PSNodeType::GEP>(SRC, 4);\n    PSNode *G2 = PS.create<PSNodeType::GEP>(SRC, 8);\n    PSNode *S1 = PS.create<PSNodeType::STORE>(GEP1, G1);\n    PSNode *S2 = PS.create<PSNodeType::STORE>(GEP2, G2);\n\n    /* copy first 8 bytes from the memory,\n     * after this node dest should point to\n     * A + 3 at offset 4  = PS.create<8 is 9th byte,\n     * so it should not be included) */\n    PSNode *CPY = PS.create<PSNodeType::MEMCPY>(SRC, DEST, 8 /* len*/);\n\n    /* load from the dest memory */\n    PSNode *G3 = PS.create<PSNodeType::GEP>(DEST, 4);\n    PSNode *G4 = PS.create<PSNodeType::GEP>(DEST, 8);\n    PSNode *L1 = PS.create<PSNodeType::LOAD>(G3);\n    PSNode *L2 = PS.create<PSNodeType::LOAD>(G4);\n\n    A->addSuccessor(SRC);\n    SRC->addSuccessor(DEST);\n    DEST->addSuccessor(GEP1);\n    GEP1->addSuccessor(GEP2);\n    GEP2->addSuccessor(G1);\n    G1->addSuccessor(G2);\n    G2->addSuccessor(S1);\n    S1->addSuccessor(S2);\n    S2->addSuccessor(CPY);\n    CPY->addSuccessor(G3);\n    G3->addSuccessor(G4);\n    G4->addSuccessor(L1);\n    L1->addSuccessor(L2);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L1->doesPointsTo(A, 3));\n    REQUIRE(L2->pointsTo.empty());\n}\n\ntemplate <typename PTStoT>\nvoid memcpy_test3() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    A->setSize(20);\n    PSNode *SRC = PS.create<PSNodeType::ALLOC>();\n    SRC->setSize(16);\n    PSNode *DEST = PS.create<PSNodeType::ALLOC>();\n    DEST->setSize(16);\n\n    /* initialize SRC, so that\n     * it will point to A + 3 and A + 12\n     * at offsets 4 and 8 */\n    PSNode *GEP1 = PS.create<PSNodeType::GEP>(A, 3);\n    PSNode *GEP2 = PS.create<PSNodeType::GEP>(A, 12);\n    PSNode *G1 = PS.create<PSNodeType::GEP>(SRC, 4);\n    PSNode *G2 = PS.create<PSNodeType::GEP>(SRC, 8);\n    PSNode *S1 = PS.create<PSNodeType::STORE>(GEP1, G1);\n    PSNode *S2 = PS.create<PSNodeType::STORE>(GEP2, G2);\n\n    /* copy memory from 8 bytes and further\n     * after this node dest should point to\n     * A + 12 at offset 0 */\n    PSNode *CPY =\n            PS.create<PSNodeType::MEMCPY>(G2, DEST, Offset::UNKNOWN /* len*/);\n\n    /* load from the dest memory */\n    PSNode *G3 = PS.create<PSNodeType::GEP>(DEST, 4);\n    PSNode *G4 = PS.create<PSNodeType::GEP>(DEST, 0);\n    PSNode *L1 = PS.create<PSNodeType::LOAD>(G3);\n    PSNode *L2 = PS.create<PSNodeType::LOAD>(G4);\n\n    A->addSuccessor(SRC);\n    SRC->addSuccessor(DEST);\n    DEST->addSuccessor(GEP1);\n    GEP1->addSuccessor(GEP2);\n    GEP2->addSuccessor(G1);\n    G1->addSuccessor(G2);\n    G2->addSuccessor(S1);\n    S1->addSuccessor(S2);\n    S2->addSuccessor(CPY);\n    CPY->addSuccessor(G3);\n    G3->addSuccessor(G4);\n    G4->addSuccessor(L1);\n    L1->addSuccessor(L2);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L2->doesPointsTo(A, 12));\n    REQUIRE(L1->pointsTo.empty());\n}\n\ntemplate <typename PTStoT>\nvoid memcpy_test4() {\n    PointerGraph PS;\n    PSNodeAlloc *A = PSNodeAlloc::get(PS.create<PSNodeType::ALLOC>());\n    A->setSize(20);\n    PSNodeAlloc *SRC = PSNodeAlloc::get(PS.create<PSNodeType::ALLOC>());\n    SRC->setSize(16);\n    SRC->setZeroInitialized();\n    PSNode *DEST = PS.create<PSNodeType::ALLOC>();\n    DEST->setSize(16);\n\n    /* initialize SRC, so that it will point to A + 3 at offset 4 */\n    PSNode *GEP1 = PS.create<PSNodeType::GEP>(A, 3);\n    PSNode *G1 = PS.create<PSNodeType::GEP>(SRC, 4);\n    PSNode *S1 = PS.create<PSNodeType::STORE>(GEP1, G1);\n\n    /* copy memory from 8 bytes and further after this node dest should\n     * point to NULL */\n    PSNode *G3 = PS.create<PSNodeType::GEP>(SRC, 8);\n    PSNode *CPY =\n            PS.create<PSNodeType::MEMCPY>(G3, DEST, Offset::UNKNOWN /* len*/);\n\n    /* load from the dest memory */\n    PSNode *G4 = PS.create<PSNodeType::GEP>(DEST, 0);\n    PSNode *L1 = PS.create<PSNodeType::LOAD>(G3);\n    PSNode *L2 = PS.create<PSNodeType::LOAD>(G4);\n\n    A->addSuccessor(SRC);\n    SRC->addSuccessor(DEST);\n    DEST->addSuccessor(GEP1);\n    GEP1->addSuccessor(G1);\n    G1->addSuccessor(S1);\n    S1->addSuccessor(G3);\n    G3->addSuccessor(CPY);\n    CPY->addSuccessor(G4);\n    G4->addSuccessor(L1);\n    L1->addSuccessor(L2);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L1->doesPointsTo(NULLPTR));\n    REQUIRE(L2->doesPointsTo(NULLPTR));\n}\n\ntemplate <typename PTStoT>\nvoid memcpy_test5() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    A->setSize(20);\n    PSNode *SRC = PS.create<PSNodeType::ALLOC>();\n    SRC->setSize(16);\n    PSNode *DEST = PS.create<PSNodeType::ALLOC>();\n    DEST->setSize(16);\n\n    PSNode *GEP1 = PS.create<PSNodeType::GEP>(A, 3);\n    PSNode *G1 = PS.create<PSNodeType::GEP>(SRC, 4);\n    PSNode *S1 = PS.create<PSNodeType::STORE>(GEP1, G1);\n\n    // copy the only pointer to dest + 0\n    PSNode *CPY = PS.create<PSNodeType::MEMCPY>(G1, DEST, 1);\n\n    /* load from the dest memory */\n    PSNode *G3 = PS.create<PSNodeType::GEP>(DEST, 0);\n    PSNode *L1 = PS.create<PSNodeType::LOAD>(G3);\n    PSNode *G4 = PS.create<PSNodeType::GEP>(DEST, 1);\n    PSNode *L2 = PS.create<PSNodeType::LOAD>(G4);\n\n    A->addSuccessor(SRC);\n    SRC->addSuccessor(DEST);\n    DEST->addSuccessor(GEP1);\n    GEP1->addSuccessor(G1);\n    G1->addSuccessor(S1);\n    S1->addSuccessor(CPY);\n    CPY->addSuccessor(G3);\n    G3->addSuccessor(L1);\n    L1->addSuccessor(G4);\n    G4->addSuccessor(L2);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L1->doesPointsTo(A, 3));\n    REQUIRE(L2->pointsTo.empty());\n}\n\ntemplate <typename PTStoT>\nvoid memcpy_test6() {\n    PointerGraph PS;\n    PSNode *A = PS.create<PSNodeType::ALLOC>();\n    A->setSize(20);\n    PSNode *SRC = PS.create<PSNodeType::ALLOC>();\n    SRC->setSize(16);\n    PSNode *DEST = PS.create<PSNodeType::ALLOC>();\n    DEST->setSize(16);\n\n    PSNode *GEP1 = PS.create<PSNodeType::GEP>(A, 3);\n    PSNode *G1 = PS.create<PSNodeType::GEP>(SRC, 4);\n    PSNode *S1 = PS.create<PSNodeType::STORE>(GEP1, G1);\n    PSNode *G3 = PS.create<PSNodeType::GEP>(DEST, 5);\n    PSNode *G4 = PS.create<PSNodeType::GEP>(DEST, 1);\n\n    PSNode *CPY = PS.create<PSNodeType::MEMCPY>(SRC, G4, 8);\n\n    /* load from the dest memory */\n    PSNode *L1 = PS.create<PSNodeType::LOAD>(G3);\n\n    A->addSuccessor(SRC);\n    SRC->addSuccessor(DEST);\n    DEST->addSuccessor(GEP1);\n    GEP1->addSuccessor(G1);\n    G1->addSuccessor(S1);\n    S1->addSuccessor(G3);\n    G3->addSuccessor(G4);\n    G4->addSuccessor(CPY);\n    CPY->addSuccessor(L1);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L1->doesPointsTo(A, 3));\n}\n\ntemplate <typename PTStoT>\nvoid memcpy_test7() {\n    PointerGraph PS;\n    PSNodeAlloc *A = PSNodeAlloc::get(PS.create<PSNodeType::ALLOC>());\n    PSNodeAlloc *SRC = PSNodeAlloc::get(PS.create<PSNodeType::ALLOC>());\n    PSNode *DEST = PS.create<PSNodeType::ALLOC>();\n\n    A->setSize(20);\n    SRC->setSize(16);\n    SRC->setZeroInitialized();\n    DEST->setSize(16);\n\n    PSNode *CPY =\n            PS.create<PSNodeType::MEMCPY>(SRC, DEST, Offset::UNKNOWN /* len*/);\n\n    /* load from the dest memory */\n    PSNode *G4 = PS.create<PSNodeType::GEP>(DEST, 0);\n    PSNode *G5 = PS.create<PSNodeType::GEP>(DEST, 4);\n    PSNode *G6 = PS.create<PSNodeType::GEP>(DEST, Offset::UNKNOWN);\n    PSNode *L1 = PS.create<PSNodeType::LOAD>(G4);\n    PSNode *L2 = PS.create<PSNodeType::LOAD>(G5);\n    PSNode *L3 = PS.create<PSNodeType::LOAD>(G6);\n\n    A->addSuccessor(SRC);\n    SRC->addSuccessor(DEST);\n    DEST->addSuccessor(CPY);\n    CPY->addSuccessor(G4);\n    G4->addSuccessor(G5);\n    G5->addSuccessor(G6);\n    G6->addSuccessor(L1);\n    L1->addSuccessor(L2);\n    L2->addSuccessor(L3);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L1->doesPointsTo(NULLPTR));\n    REQUIRE(L2->doesPointsTo(NULLPTR));\n    REQUIRE(L3->doesPointsTo(NULLPTR));\n}\n\ntemplate <typename PTStoT>\nvoid memcpy_test8() {\n    PointerGraph PS;\n    PSNodeAlloc *A = PSNodeAlloc::get(PS.create<PSNodeType::ALLOC>());\n    A->setSize(20);\n    PSNodeAlloc *SRC = PSNodeAlloc::get(PS.create<PSNodeType::ALLOC>());\n    SRC->setSize(16);\n    SRC->setZeroInitialized();\n    PSNode *DEST = PS.create<PSNodeType::ALLOC>();\n    DEST->setSize(16);\n\n    /* initialize SRC, so that it will point to A + 3 at offset 0 */\n    PSNode *GEP1 = PS.create<PSNodeType::GEP>(A, 3);\n    PSNode *S1 = PS.create<PSNodeType::STORE>(GEP1, SRC);\n\n    PSNode *CPY = PS.create<PSNodeType::MEMCPY>(SRC, DEST, 10);\n\n    /* load from the dest memory */\n    PSNode *G1 = PS.create<PSNodeType::GEP>(DEST, 0);\n    PSNode *G3 = PS.create<PSNodeType::GEP>(DEST, 4);\n    PSNode *G4 = PS.create<PSNodeType::GEP>(DEST, 8);\n    PSNode *L1 = PS.create<PSNodeType::LOAD>(G1);\n    PSNode *L2 = PS.create<PSNodeType::LOAD>(G3);\n    PSNode *L3 = PS.create<PSNodeType::LOAD>(G4);\n\n    A->addSuccessor(SRC);\n    SRC->addSuccessor(DEST);\n    DEST->addSuccessor(GEP1);\n    GEP1->addSuccessor(G1);\n    G1->addSuccessor(S1);\n    S1->addSuccessor(G3);\n    G3->addSuccessor(CPY);\n    CPY->addSuccessor(G4);\n    G4->addSuccessor(L1);\n    L1->addSuccessor(L2);\n    L2->addSuccessor(L3);\n\n    auto *subg = PS.createSubgraph(A);\n    PS.setEntry(subg);\n    PTStoT PA(&PS);\n    PA.run();\n\n    REQUIRE(L1->doesPointsTo(A, 3));\n    REQUIRE(L2->doesPointsTo(NULLPTR));\n    REQUIRE(L3->doesPointsTo(NULLPTR));\n}\n\nTEST_CASE(\"Flow insensitive\", \"FI\") {\n    store_load<dg::pta::PointerAnalysisFI>();\n    store_load2<dg::pta::PointerAnalysisFI>();\n    store_load3<dg::pta::PointerAnalysisFI>();\n    store_load4<dg::pta::PointerAnalysisFI>();\n    store_load5<dg::pta::PointerAnalysisFI>();\n    gep1<dg::pta::PointerAnalysisFI>();\n    gep2<dg::pta::PointerAnalysisFI>();\n    gep3<dg::pta::PointerAnalysisFI>();\n    gep4<dg::pta::PointerAnalysisFI>();\n    gep5<dg::pta::PointerAnalysisFI>();\n    nulltest<dg::pta::PointerAnalysisFI>();\n    constant_store<dg::pta::PointerAnalysisFI>();\n    load_from_zeroed<dg::pta::PointerAnalysisFI>();\n    load_from_unknown_offset<dg::pta::PointerAnalysisFI>();\n    load_from_unknown_offset2<dg::pta::PointerAnalysisFI>();\n    load_from_unknown_offset3<dg::pta::PointerAnalysisFI>();\n    memcpy_test<dg::pta::PointerAnalysisFI>();\n    memcpy_test2<dg::pta::PointerAnalysisFI>();\n    memcpy_test3<dg::pta::PointerAnalysisFI>();\n    memcpy_test4<dg::pta::PointerAnalysisFI>();\n    memcpy_test5<dg::pta::PointerAnalysisFI>();\n    memcpy_test6<dg::pta::PointerAnalysisFI>();\n    memcpy_test7<dg::pta::PointerAnalysisFI>();\n    memcpy_test8<dg::pta::PointerAnalysisFI>();\n}\n\nTEST_CASE(\"Flow sensitive\", \"FS\") {\n    store_load<dg::pta::PointerAnalysisFS>();\n    store_load2<dg::pta::PointerAnalysisFS>();\n    store_load3<dg::pta::PointerAnalysisFS>();\n    store_load4<dg::pta::PointerAnalysisFS>();\n    store_load5<dg::pta::PointerAnalysisFS>();\n    gep1<dg::pta::PointerAnalysisFS>();\n    gep2<dg::pta::PointerAnalysisFS>();\n    gep3<dg::pta::PointerAnalysisFS>();\n    gep4<dg::pta::PointerAnalysisFS>();\n    gep5<dg::pta::PointerAnalysisFS>();\n    nulltest<dg::pta::PointerAnalysisFS>();\n    constant_store<dg::pta::PointerAnalysisFS>();\n    load_from_zeroed<dg::pta::PointerAnalysisFS>();\n    load_from_unknown_offset<dg::pta::PointerAnalysisFS>();\n    load_from_unknown_offset2<dg::pta::PointerAnalysisFS>();\n    load_from_unknown_offset3<dg::pta::PointerAnalysisFS>();\n    memcpy_test<dg::pta::PointerAnalysisFS>();\n    memcpy_test2<dg::pta::PointerAnalysisFS>();\n    memcpy_test3<dg::pta::PointerAnalysisFS>();\n    memcpy_test4<dg::pta::PointerAnalysisFS>();\n    memcpy_test5<dg::pta::PointerAnalysisFS>();\n    memcpy_test6<dg::pta::PointerAnalysisFS>();\n    memcpy_test7<dg::pta::PointerAnalysisFS>();\n    memcpy_test8<dg::pta::PointerAnalysisFS>();\n}\n\nTEST_CASE(\"PSNode test\", \"PSNode\") {\n    using namespace dg::pta;\n    PointerGraph PS;\n    PSNode *N1 = PS.create<PSNodeType::ALLOC>();\n    PSNode *N2 = PS.create<PSNodeType::LOAD>(N1);\n\n    N2->addPointsTo(N1, 1);\n    N2->addPointsTo(N1, 2);\n    N2->addPointsTo(N1, 3);\n    REQUIRE(N2->pointsTo.size() == 3);\n    N2->addPointsTo(N1, Offset::UNKNOWN);\n    REQUIRE(N2->pointsTo.size() == 1);\n    REQUIRE(N2->addPointsTo(N1, 3) == false);\n}\n"
  },
  {
    "path": "tests/ptset-benchmark.cpp",
    "content": "#include <random>\n#include <string>\n#include <vector>\n\n#include \"dg/PointerAnalysis/PointsToSet.h\"\n#include \"dg/util/TimeMeasure.h\"\n\nusing namespace dg::pta;\n\nstd::default_random_engine generator;\nstd::uniform_int_distribution<uint64_t> distribution(0,\n                                                     ~static_cast<uint64_t>(0));\n\n#define run(func, msg)                                                         \\\n    do {                                                                       \\\n        std::cout << \"Running \" << (msg) << \"\\n\";                              \\\n        dg::debug::TimeMeasure tm;                                             \\\n        tm.start();                                                            \\\n        for (int i = 0; i < times; ++i)                                        \\\n            func<PointsToSetT>();                                              \\\n        tm.stop();                                                             \\\n        tm.report(\" -- PointsToSet bitvector took\");                           \\\n        tm.start();                                                            \\\n        for (int i = 0; i < times; ++i)                                        \\\n            func<SimplePointsToSet>();                                         \\\n        tm.stop();                                                             \\\n        tm.report(\" -- PointsToSet std::set took\");                            \\\n    } while (0);\n\ntemplate <typename PTSetT>\nvoid test1() {\n    PTSetT S;\n    PSNode *x = reinterpret_cast<PSNode *>(0x1);\n    PSNode *y = reinterpret_cast<PSNode *>(0x2);\n    PSNode *z = reinterpret_cast<PSNode *>(0x3);\n\n    S.add({x, 0});\n    S.add({y, 0});\n    S.add({z, 0});\n}\n\ntemplate <typename PTSetT>\nvoid test2() {\n    PTSetT S;\n    PSNode *x = reinterpret_cast<PSNode *>(0x1);\n\n    S.add({x, 0});\n}\n\ntemplate <typename PTSetT>\nvoid test3() {\n    std::set<size_t> numbers;\n\n    PTSetT S;\n    PSNode *pointers[]{\n            reinterpret_cast<PSNode *>(0x1), reinterpret_cast<PSNode *>(0x2),\n            reinterpret_cast<PSNode *>(0x3), reinterpret_cast<PSNode *>(0x4),\n            reinterpret_cast<PSNode *>(0x5), reinterpret_cast<PSNode *>(0x6),\n            reinterpret_cast<PSNode *>(0x7)};\n\n    for (int i = 0; i < 1000; ++i) {\n        auto x = distribution(generator);\n        S.add(pointers[x % (sizeof(pointers) / sizeof(*pointers))], x);\n    }\n}\n\ntemplate <typename PTSetT>\nvoid test4() {\n    std::set<size_t> numbers;\n\n    PTSetT S;\n    for (int i = 0; i < 1000; ++i) {\n        S.add(reinterpret_cast<PSNode *>(1), i);\n    }\n}\n\ntemplate <typename PTSetT>\nvoid test5() {\n    std::set<size_t> numbers;\n\n    PTSetT S;\n    for (int i = 0; i < 1000; ++i) {\n        S.add(reinterpret_cast<PSNode *>(i), i);\n    }\n}\n\nint main() {\n    int times;\n    times = 100000;\n    run(test1, \"Adding three elements\");\n\n    times = 100000;\n    run(test2, \"Adding same element\");\n\n    times = 10000;\n    run(test3, \"Adding 1000 times 7 pointers with random offsets\");\n\n    times = 10000;\n    run(test4, \"Adding 1000 offsets to a pointer\");\n\n    times = 10000;\n    run(test5, \"Adding 1000 different pointers\");\n}\n"
  },
  {
    "path": "tests/rdmap-test.cpp",
    "content": "#include <catch2/catch.hpp>\n\n#include <cassert>\n#include <random>\n#include <vector>\n\n#undef NDEBUG\n\n#include \"dg/ReachingDefinitions/RDMap.h\"\n#include \"dg/ReachingDefinitions/ReachingDefinitions.h\"\n\nusing namespace dg::analysis;\n\nRWNode A;\nRWNode B;\nRWNode C;\n\nTEST_CASE(\"Querying empty set\", \"DisjunctiveIntervalMap\") {\n    RDMap M;\n    REQUIRE(M.empty());\n}\n\n/*\nTEST_CASE(\"Singleton set\", \"DisjunctiveIntervalMap\") {\n    RDMap M;\n\n    M.add(DefSite(&A, 0, 4), &B);\n    REQUIRE(!M.empty());\n\n    std::set<RWNode *> rd;\n    M.get(&A, 0, 4, rd);\n    REQUIRE(!rd.empty());\n    REQUIRE(*(rd.begin()) == &B);\n\n    // check full overlap\n    for (int i = 0; i < 5; ++i) {\n        for (int j = i; j < 5; ++j) {\n            rd.clear();\n            M.get(&A, i, j - i + 1, rd);\n            REQUIRE(!rd.empty());\n            REQUIRE(*(rd.begin()) == &B);\n        }\n    }\n\n    // check partial overlap\n    for (int i = 0; i < 5; ++i) {\n        rd.clear();\n        M.get(&A, i, 10, rd);\n        REQUIRE(!rd.empty());\n        REQUIRE(*(rd.begin()) == &B);\n    }\n}\n\nTEST_CASE(\"2-elem set\", \"DisjunctiveIntervalMap\") {\n    RDMap M;\n\n    M.add(DefSite(&A, 0, 2), &B);\n    M.add(DefSite(&A, 3, 4), &B);\n    REQUIRE(!M.empty());\n\n    std::set<RWNode *> rd;\n    M.get(&A, 0, 4, rd);\n    REQUIRE(!rd.empty());\n    REQUIRE(*(rd.begin()) == &B);\n\n    // check full overlap\n    for (int i = 0; i < 5; ++i) {\n        for (int j = i; j < 5; ++j) {\n            rd.clear();\n            M.get(&A, i, j - i + 1, rd);\n            REQUIRE(!rd.empty());\n            REQUIRE(*(rd.begin()) == &B);\n        }\n    }\n\n    // check partial overlap\n    for (int i = 0; i < 5; ++i) {\n        rd.clear();\n        M.get(&A, i, 10, rd);\n        REQUIRE(!rd.empty());\n        REQUIRE(*(rd.begin()) == &B);\n    }\n}\n\nTEST_CASE(\"iterator\", \"DisjunctiveIntervalMap\") {\n    RDMap M;\n\n    REQUIRE(M.begin() == M.begin());\n    REQUIRE(M.end() == M.end());\n    REQUIRE(M.begin() == M.end());\n\n    M.add(DefSite(&A, 0, 4), &B);\n    REQUIRE(!M.empty());\n    REQUIRE(M.begin() == M.begin());\n    REQUIRE(M.begin() != M.end());\n    REQUIRE(M.end() == M.end());\n\n    auto it = M.begin();\n    REQUIRE(it == it);\n    REQUIRE(it == M.begin());\n    REQUIRE(it != M.end());\n\n    auto d = *it;\n    REQUIRE(d.first.target == &A);\n    REQUIRE(d.first.offset == 0);\n    REQUIRE(d.first.len == 5);\n    REQUIRE(d.second.size() == 1);\n    REQUIRE(*(d.second.begin()) == &B);\n\n    ++it;\n    REQUIRE(it == M.end());\n    REQUIRE(it != M.begin());\n}\n*/\n"
  },
  {
    "path": "tests/readwritegraph-test.cpp",
    "content": "#include <catch2/catch.hpp>\n\n#include \"dg/ReadWriteGraph/ReadWriteGraph.h\"\n\nusing namespace dg::dda;\n\nTEST_CASE(\"empty ctor\", \"[RWBBlock]\") { RWBBlock block; }\n\nTEST_CASE(\"subgraph ctor\", \"[RWBBlock]\") {\n    RWSubgraph subg;\n    RWBBlock B(&subg);\n    REQUIRE(B.getSubgraph() == &subg);\n}\n\nTEST_CASE(\"split around singleton\", \"[RWBBlock]\") {\n    RWNode A;\n    RWBBlock B;\n    B.append(&A);\n\n    auto blks = B.splitAround(&A);\n    CHECK(blks.first == nullptr);\n    CHECK(blks.second == nullptr);\n}\n\nTEST_CASE(\"split around no prefix\", \"[RWBBlock]\") {\n    RWNode A, B;\n    RWBBlock block;\n    RWBBlock succ;\n    RWBBlock succssucc;\n    block.addSuccessor(&succ);\n    block.append(&A);\n    block.append(&B);\n\n    auto blks = block.splitAround(&A);\n    REQUIRE(blks.first == nullptr);\n    REQUIRE(blks.second != nullptr);\n\n    CHECK(blks.second->size() == 1);\n    CHECK(*blks.second->getNodes().begin() == &B);\n\n    CHECK(block.getSingleSuccessor() == blks.second.get());\n    CHECK(blks.second->getSingleSuccessor() == &succ);\n}\n\nTEST_CASE(\"split around no suffix\", \"[RWBBlock]\") {\n    RWNode A, B;\n    RWBBlock block;\n    RWBBlock succ;\n    block.addSuccessor(&succ);\n    block.append(&A);\n    block.append(&B);\n\n    auto blks = block.splitAround(&B);\n    REQUIRE(blks.first != nullptr);\n    CHECK(blks.second == nullptr);\n\n    CHECK(blks.first->size() == 1);\n    CHECK(*blks.first->getNodes().begin() == &B);\n    CHECK(block.size() == 1);\n    CHECK(*block.getNodes().begin() == &A);\n\n    CHECK(block.getSingleSuccessor() == blks.first.get());\n    CHECK(blks.first->getSingleSuccessor() == &succ);\n}\n\nTEST_CASE(\"split around in middle\", \"[RWBBlock]\") {\n    RWNode A, B, C;\n    RWBBlock block;\n    RWBBlock succ;\n    block.addSuccessor(&succ);\n    block.append(&A);\n    block.append(&B);\n    block.append(&C);\n\n    auto blks = block.splitAround(&B);\n    REQUIRE(blks.first != nullptr);\n    REQUIRE(blks.second != nullptr);\n\n    CHECK(block.size() == 1);\n    CHECK(*block.getNodes().begin() == &A);\n\n    CHECK(blks.first->size() == 1);\n    CHECK(*blks.first->getNodes().begin() == &B);\n\n    CHECK(blks.second->size() == 1);\n    CHECK(*blks.second->getNodes().begin() == &C);\n\n    CHECK(block.getSingleSuccessor() == blks.first.get());\n    CHECK(blks.first->getSingleSuccessor() == blks.second.get());\n    CHECK(blks.second->getSingleSuccessor() == &succ);\n}\n"
  },
  {
    "path": "tests/slicing/CMakeLists.txt",
    "content": "# Debug runner will print output when a test fails\nset(RUNNER \"${CMAKE_CURRENT_LIST_DIR}/test-runner-debug.py\")\n\nadd_test(test1                  ${RUNNER} test1)\nadd_test(test2                  ${RUNNER} test2)\nadd_test(test3                  ${RUNNER} test3)\nadd_test(test4                  ${RUNNER} test4)\nadd_test(test5                  ${RUNNER} test5)\nadd_test(test6                  ${RUNNER} test6)\nadd_test(test7                  ${RUNNER} test7)\nadd_test(test8                  ${RUNNER} test8)\nadd_test(test22                 ${RUNNER} test22)\nadd_test(test222                ${RUNNER} test222)\nadd_test(recursive1             ${RUNNER} recursive1)\nadd_test(recursive2             ${RUNNER} recursive2)\nadd_test(recursive3             ${RUNNER} recursive3)\nadd_test(recursive4             ${RUNNER} recursive4)\nadd_test(recursive5             ${RUNNER} recursive5)\nadd_test(interprocedural1       ${RUNNER} interprocedural1)\nadd_test(interprocedural2       ${RUNNER} interprocedural2)\nadd_test(interprocedural3       ${RUNNER} interprocedural3)\nadd_test(interprocedural4       ${RUNNER} interprocedural4)\nadd_test(interprocedural5       ${RUNNER} interprocedural5)\nadd_test(interprocedural6       ${RUNNER} interprocedural6)\nadd_test(interprocedural7       ${RUNNER} interprocedural7)\nadd_test(interprocedural8       ${RUNNER} interprocedural8)\nadd_test(interprocedural9       ${RUNNER} interprocedural9)\nadd_test(funcptr1               ${RUNNER} funcptr1)\nadd_test(funcptr2               ${RUNNER} funcptr2)\nadd_test(funcptr3               ${RUNNER} funcptr3)\nadd_test(funcptr4               ${RUNNER} funcptr4)\nadd_test(funcptr5               ${RUNNER} funcptr5)\nadd_test(funcptr6               ${RUNNER} funcptr6)\nadd_test(funcptr7               ${RUNNER} funcptr7)\nadd_test(funcptr8               ${RUNNER} funcptr8)\nadd_test(funcptr9               ${RUNNER} funcptr9)\nadd_test(funcptr10              ${RUNNER} funcptr10)\nadd_test(funcptr11              ${RUNNER} funcptr11)\nadd_test(funcptr12              ${RUNNER} funcptr12)\nadd_test(funcptr13              ${RUNNER} funcptr13)\nadd_test(funcptr14              ${RUNNER} funcptr14)\nadd_test(funcptr15              ${RUNNER} funcptr15)\nadd_test(funcptr16              ${RUNNER} funcptr16)\nadd_test(funcptr-regression1    ${RUNNER} funcptr-regression1)\nadd_test(funcarray1             ${RUNNER} funcarray1)\nadd_test(funcarray2             ${RUNNER} funcarray2)\nadd_test(funcarray3             ${RUNNER} funcarray3)\nadd_test(unknownptr1            ${RUNNER} unknownptr1)\nadd_test(unknownptr2            ${RUNNER} unknownptr2)\nadd_test(unknownptr3            ${RUNNER} unknownptr3)\nadd_test(unknownptr4            ${RUNNER} unknownptr4)\nadd_test(unknownptr5            ${RUNNER} unknownptr5)\nadd_test(unknownptr6            ${RUNNER} unknownptr6)\nadd_test(unknownptr7            ${RUNNER} unknownptr7)\nadd_test(unknownptr8            ${RUNNER} unknownptr8)\nadd_test(unknownptr9            ${RUNNER} unknownptr9)\nadd_test(unknownptr10           ${RUNNER} unknownptr10)\nadd_test(unknownptr11           ${RUNNER} unknownptr11)\nadd_test(pointers1              ${RUNNER} pointers1)\nadd_test(pointers2              ${RUNNER} pointers2)\nadd_test(pointers3              ${RUNNER} pointers3)\nadd_test(pointers4              ${RUNNER} pointers4)\nadd_test(pointers5              ${RUNNER} pointers5)\nadd_test(pointers6              ${RUNNER} pointers6)\nadd_test(pointers7              ${RUNNER} pointers7)\nadd_test(ptrarray1              ${RUNNER} ptrarray1)\nadd_test(ptrarray2              ${RUNNER} ptrarray2)\nadd_test(phi1                   ${RUNNER} phi1)\nadd_test(phi2                   ${RUNNER} phi2)\nadd_test(phi3                   ${RUNNER} phi3)\nadd_test(phi4                   ${RUNNER} phi4)\nadd_test(phi1-nophi             ${RUNNER} phi1-nophi)\nadd_test(phi2-nophi             ${RUNNER} phi2-nophi)\nadd_test(phi3-nophi             ${RUNNER} phi3-nophi)\nadd_test(phi4-nophi             ${RUNNER} phi4-nophi)\nadd_test(global1                ${RUNNER} global1)\nadd_test(global2                ${RUNNER} global2)\nadd_test(global3                ${RUNNER} global3)\nadd_test(global4                ${RUNNER} global4)\nadd_test(global5                ${RUNNER} global5)\nadd_test(global6                ${RUNNER} global6)\nadd_test(global7                ${RUNNER} global7)\nadd_test(global8                ${RUNNER} global8)\nadd_test(global9                ${RUNNER} global9)\nadd_test(global10               ${RUNNER} global10)\nadd_test(ptrtoint1              ${RUNNER} ptrtoint1)\nadd_test(ptrtoint2              ${RUNNER} ptrtoint2)\nadd_test(ptrtoint3              ${RUNNER} ptrtoint3)\nadd_test(ptrtoint4              ${RUNNER} ptrtoint4)\nadd_test(ptrtoint5              ${RUNNER} ptrtoint5)\nadd_test(ptrtoint6              ${RUNNER} ptrtoint6)\nadd_test(ptrtoint7              ${RUNNER} ptrtoint7)\nadd_test(llvmmemcpy             ${RUNNER} llvmmemcpy)\nadd_test(llvmmemcpy2            ${RUNNER} llvmmemcpy2)\nadd_test(memset1                ${RUNNER} memset1)\nadd_test(memcpy1                ${RUNNER} memcpy1)\nadd_test(memcpy2                ${RUNNER} memcpy2)\nadd_test(memcpy3                ${RUNNER} memcpy3)\nadd_test(memcpy4                ${RUNNER} memcpy4)\nadd_test(memcpy5                ${RUNNER} memcpy5)\nadd_test(memcpy6                ${RUNNER} memcpy6)\nadd_test(bitcast1               ${RUNNER} bitcast1)\nadd_test(bitcast2               ${RUNNER} bitcast2)\nadd_test(bitcast3               ${RUNNER} bitcast3)\nadd_test(bitcast4               ${RUNNER} bitcast4)\nadd_test(bitcast5               ${RUNNER} bitcast5)\nadd_test(loop1                  ${RUNNER} loop1)\nadd_test(loop2                  ${RUNNER} loop2)\nadd_test(loop3                  ${RUNNER} loop3)\nadd_test(loop4                  ${RUNNER} loop4)\nadd_test(loop5                  ${RUNNER} loop5)\nadd_test(list1                  ${RUNNER} list1)\nadd_test(list2                  ${RUNNER} list2)\nadd_test(list3                  ${RUNNER} list3)\nadd_test(list4                  ${RUNNER} list4)\nadd_test(list5                  ${RUNNER} list5)\nadd_test(list6                  ${RUNNER} list6)\nadd_test(list7                  ${RUNNER} list7)\nadd_test(list8                  ${RUNNER} list8)\nadd_test(list9                  ${RUNNER} list9)\nadd_test(dynalloc1              ${RUNNER} dynalloc1)\nadd_test(dynalloc2              ${RUNNER} dynalloc2)\nadd_test(dynalloc3              ${RUNNER} dynalloc3)\nadd_test(dynalloc4              ${RUNNER} dynalloc4)\nadd_test(dynalloc5              ${RUNNER} dynalloc5)\nadd_test(dynalloc6              ${RUNNER} dynalloc6)\nadd_test(dynalloc7              ${RUNNER} dynalloc7)\nadd_test(realloc1               ${RUNNER} realloc1)\nadd_test(realloc2               ${RUNNER} realloc2)\nadd_test(cyclic-realloc         ${RUNNER} cyclic-realloc)\nadd_test(switch1                ${RUNNER} switch1)\nadd_test(switch2                ${RUNNER} switch2)\nadd_test(vararg1                ${RUNNER} vararg1)\nadd_test(vararg2                ${RUNNER} vararg2)\nadd_test(vararg3                ${RUNNER} vararg3)\nadd_test(vararg4                ${RUNNER} vararg4)\nadd_test(negoffset1             ${RUNNER} negoffset1)\nadd_test(negoffset2             ${RUNNER} negoffset2)\nadd_test(negoffset3             ${RUNNER} negoffset3)\nadd_test(sum1                   ${RUNNER} sum1)\nadd_test(sum2                   ${RUNNER} sum2)\nadd_test(sum3                   ${RUNNER} sum3)\nadd_test(control-regression1    ${RUNNER} control-regression1)\nadd_test(pta_fs_regression1     ${RUNNER} pta_fs_regression1)\nadd_test(pta_fs_regression2     ${RUNNER} pta_fs_regression2)\nadd_test(pta_regression2        ${RUNNER} pta_regression2)\nadd_test(pta_regression3        ${RUNNER} pta_regression3)\nadd_test(alias_of_return        ${RUNNER} alias_of_return)\nadd_test(regression1            ${RUNNER} regression1)\nadd_test(fptoui                 ${RUNNER} fptoui)\nadd_test(malloc-redef           ${RUNNER} malloc-redef)\nadd_test(globalptr1             ${RUNNER} globalptr1)\nadd_test(globalptr2             ${RUNNER} globalptr2)\nadd_test(globalptr3             ${RUNNER} globalptr3)\nadd_test(globalptr4             ${RUNNER} globalptr4)\n# Disabled until we properly support threads again\n# add_test(threads1               ${RUNNER} threads1)\nadd_test(pta-inv-infinite-loop  ${RUNNER} pta-inv-infinite-loop)\nadd_test(undefcall1             ${RUNNER} undefcall1)\nadd_test(undefcall2             ${RUNNER} undefcall2)\nadd_test(unknown-interproc      ${RUNNER} unknown-interproc)\nadd_test(unknown-interproc2     ${RUNNER} unknown-interproc2)\nadd_test(unknown-interproc2-a   ${RUNNER} unknown-interproc2-a)\nadd_test(unknown-interproc3     ${RUNNER} unknown-interproc3)\nadd_test(atomic1                ${RUNNER} atomic1)\nadd_test(atomic2                ${RUNNER} atomic2)\nadd_test(atomic3                ${RUNNER} atomic3)\n\n"
  },
  {
    "path": "tests/slicing/sources/a_ptr.c",
    "content": "int *a_ptr(int **b) { return *b; }\n"
  },
  {
    "path": "tests/slicing/sources/alias_of_return.c",
    "content": "// file ldv-regression/alias_of_return.c_true-unreach-call.i\n// from SV-COMP (revision 9113fca)\n\nint *return_self(int *p) { return p; }\n\nvoid test_assert(int);\n\nint main() {\n    int a = 1, *q;\n    q = return_self(&a);\n    *q = 2;\n\n    test_assert(a == 2);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/atomic1.c",
    "content": "#include <stdatomic.h>\n\nextern void test_assert(int);\n\nint a[10] = {1, 2};\n_Atomic unsigned long p = 0;\n\nint main(void) {\n    atomic_exchange(&p, (unsigned long) &a);\n    int *pp = (int *) p;\n    test_assert(*(pp + 1) == 2);\n}\n"
  },
  {
    "path": "tests/slicing/sources/atomic2.c",
    "content": "#include <stdatomic.h>\n\nextern void test_assert(int);\n\nint a[10] = {1, 2};\n_Atomic unsigned long p = 0;\n\nint main(void) {\n    atomic_exchange(&p, ((unsigned long) &a) + sizeof(int));\n    int *pp = (int *) p;\n    test_assert(*pp == 2);\n}\n"
  },
  {
    "path": "tests/slicing/sources/atomic3.c",
    "content": "#include <stdatomic.h>\n\nextern void test_assert(int);\n\nint a[10] = {1, 2};\n_Atomic unsigned long p = 0;\n\nint main(void) {\n    atomic_exchange(&p, (unsigned long) &a);\n    atomic_fetch_add(&p, sizeof(int));\n    int *pp = (int *) p;\n    test_assert(*pp == 2);\n}\n"
  },
  {
    "path": "tests/slicing/sources/bitcast1.c",
    "content": "/* test accessing bytes in int */\nint main(void) {\n    int a;\n    a = 0;\n    char *byte = (char *) &a;\n    int i;\n    for (i = 0; i < sizeof(int); ++i) {\n        *byte = 0xff;\n        byte++;\n    }\n\n    test_assert(a == ~((int) 0));\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/bitcast2.c",
    "content": "_Static_assert(sizeof(int) == 4, \"This test assumes sizeof(int) == 4\");\n\n/* test accessing bytes in int */\nint main(void) {\n    int a;\n    a = 0;\n    unsigned char *byte = (unsigned char *) &a;\n    byte[0] = 0xab;\n    byte[1] = 0xab;\n    byte[2] = 0xab;\n    byte[3] = 0xab;\n    test_assert(a == 0xabababab);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/bitcast3.c",
    "content": "_Static_assert(sizeof(int) == 4, \"This test assumes sizeof(int) == 4\");\n\nunion BYTE {\n    int i;\n    unsigned char b[4];\n};\n\n/* test accessing bytes in int */\nint main(void) {\n    union BYTE B = {.i = 0};\n    B.b[0] = 0xab;\n    B.b[1] = 0xab;\n    B.b[2] = 0xab;\n    B.b[3] = 0xab;\n    test_assert(B.i == 0xabababab);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/bitcast4.c",
    "content": "#include <stdalign.h>\n\nint main(void) {\n    alignas(alignof(int)) char a[] = \"Hello, world\";\n\n    _Static_assert(sizeof(int) <= sizeof a,\n                   \"This test assumes that sizeof(int) <= sizeof a\");\n\n    int *p = (int *) a;\n    *p = 0;\n\n    test_assert(a[3] == 0);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/bitcast5.c",
    "content": "#include <stdalign.h>\n\nint main(void) {\n    alignas(alignof(int)) char a[] = \"Hello, world\";\n\n    _Static_assert(2 * sizeof(int) <= sizeof a &&\n                           sizeof(int) > 3 * sizeof(char),\n                   \"This test assumes that 2 * sizeof(int) <= sizeof a && \"\n                   \"sizeof(int) > 3 * sizeof(char)\");\n\n    int *p = (int *) a + 1;\n    *p = 0;\n\n    test_assert(a[2] == 'l');\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/bitcast6.c",
    "content": "#include <limits.h>\n\n/* test accessing bytes in int */\nint main(void) {\n    int a = 0;\n    char *byte = (char *) &a;\n\n    int result = 0;\n    for (unsigned i = 0; i < sizeof(int); i++)\n        result |= (byte[i] = 0x1b) << i * CHAR_BIT;\n\n    test_assert(a == result);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/control-regression1.c",
    "content": "int main(void) {\n    int a = 0xdeadbee;\n    int b = 0;\n    int c = 1;\n\n    while (c) {\n        if (b == 0)\n            goto L;\n\n        test_assert(a == 1);\n        if (a == 1) {\n            c = 0;\nL:\n            a = 1;\n            b = 1;\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/cyclic-realloc.c",
    "content": "#include <stdlib.h>\n\nint main(void) {\n    int *p = malloc(4);\n    if (!p)\n        return 0;\n    for (int i = sizeof(int); i < 10; ++i) {\n        p = realloc(p, i);\n        if (!p)\n            return 0;\n        *p = i;\n    }\n    test_assert(*p == 9);\n    free(p);\n}\n"
  },
  {
    "path": "tests/slicing/sources/dynalloc1.c",
    "content": "#include <stdlib.h>\n\nstruct item {\n    int a;\n};\n\nstruct item *alloc() {\n    struct item *i = malloc(sizeof *i);\n    i->a = 13;\n\n    return i;\n}\n\nint main(void) {\n    struct item *i = alloc();\n    test_assert(i->a == 13);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/dynalloc2.c",
    "content": "#include <stdlib.h>\n\nstruct item {\n    int a;\n};\n\nvoid alloc(struct item **i) {\n    (*i) = malloc(sizeof(struct item));\n    (*i)->a = 13;\n}\n\nint main(void) {\n    struct item *i;\n    alloc(&i);\n    test_assert(i->a == 13);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/dynalloc3.c",
    "content": "#include <stdlib.h>\n\nstruct item {\n    int a;\n};\n\nstruct item *alloc() {\n    int size = sizeof(struct item);\n    struct item *i = malloc(size);\n    i->a = 13;\n\n    return i;\n}\n\nint main(void) {\n    struct item *i = alloc();\n    test_assert(i->a == 13);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/dynalloc4.c",
    "content": "#include <stdlib.h>\n\nstruct item {\n    int a;\n};\n\nstruct item *alloc() {\n    struct item *i = calloc(4, sizeof *i);\n    (i + 2)->a = 13;\n\n    return i;\n}\n\nint main(void) {\n    struct item *i = alloc();\n    test_assert((i + 2)->a == 13);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/dynalloc5.c",
    "content": "#include <stdlib.h>\n\nstruct item {\n    int a;\n};\n\n/* use function pointer */\nvoid *(*memalloc)(unsigned long size) = malloc;\nstruct item *alloc() {\n    struct item *i = memalloc(sizeof *i);\n    i->a = 13;\n\n    return i;\n}\n\nint main(void) {\n    struct item *i = alloc();\n    test_assert(i->a == 13);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/dynalloc6.c",
    "content": "#include <stdlib.h>\n\nstruct node {\n    int val;\n    struct node *next;\n    struct node *prev;\n};\n\nstatic struct node *alloc_node(void) {\n    struct node *ptr = malloc(sizeof *ptr);\n    ptr->val = 13;\n    ptr->next = ((void *) 0);\n    ptr->prev = ((void *) 0);\n    return ptr;\n}\nstatic void chain_node(struct node **ppnode) {\n    struct node *node = alloc_node();\n    node->next = *ppnode;\n    *ppnode = node;\n}\nstatic void create_sll(const struct node **pp1) {\n    chain_node((struct node **) pp1);\n}\n\nint main() {\n    const struct node *p1;\n    create_sll(&p1);\n    test_assert(p1->val == 13);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/dynalloc7.c",
    "content": "#include <stdlib.h>\n\nint *foo(void) {\n    int *i = malloc(sizeof *i);\n    return i;\n}\n\nint main(void) {\n    int *a = foo();\n    *a = 3;\n    int *b = foo();\n    *b = 13;\n    test_assert(*a == 3);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/foo.c",
    "content": "extern int *glob;\nvoid foo(void) { *glob = 2; }\n"
  },
  {
    "path": "tests/slicing/sources/fptoui1.c",
    "content": "int main(void) {\n    int a = 42;\n    unsigned long pa = (unsigned long) &a;\n    double da = (double) pa;\n    unsigned long pa1 = (unsigned long) da;\n\n    test_assert(*((int *) pa1) == a);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcarray1.c",
    "content": "int glob;\nvoid setglob(void) { glob = 8; }\n\nvoid (*funcarray[10])(void) = {setglob};\n\nint main(void) {\n    funcarray[0]();\n    test_assert(glob == 8);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcarray2.c",
    "content": "int glob;\nvoid setglob(void) { glob = 8; }\n\nvoid (*funcarray[10])(void) = {setglob};\n\nvoid call(void (**funcarray)(void), int idx) { funcarray[idx](); }\n\nint main(void) {\n    call(funcarray, 0);\n    test_assert(glob == 8);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcarray3.c",
    "content": "int glob;\nvoid setglob(void) { glob = 8; }\n\nvoid setglob2(void) { glob = 13; }\n\nvoid (*funcarray[10])(void) = {setglob, setglob2};\n\nvoid call(void (**funcarray)(void), int idx) { funcarray[idx](); }\n\nint main(void) {\n    call(funcarray, 1);\n    test_assert(glob == 13);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcptr-regression1.c",
    "content": "#include <stdlib.h>\n\nstruct ldv_kref {\n    int refcount;\n};\n\nstruct ldv_kobject {\n    int a;\n    struct ldv_kref kref;\n};\n\nstatic void ldv_kobject_cleanup(struct ldv_kobject *kobj) {\n    test_assert(kobj == 0);\n}\n\nstatic void ldv_kobject_release(struct ldv_kref *kref) {\n    ldv_kobject_cleanup((void *) kref);\n}\n\nstatic void ldv_kref_sub(unsigned int count,\n                         void (*release)(struct ldv_kref *kref)) {\n    release(0);\n}\n\nint main(void) {\n    struct ldv_kobject *kobj;\n\n    ldv_kref_sub(1, ldv_kobject_release);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcptr1.c",
    "content": "void set(int *a) { *a = 8; }\n\n/* basic test */\nint main(void) {\n    void (*s)(int *) = set;\n    int a, b = 1, c = 13;\n    a = b + c;\n    b = 3;\n    c = 5;\n    s(&a);\n\n    test_assert(a == 8);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcptr10.c",
    "content": "#include <stdlib.h>\n\nstruct item {\n    int a;\n};\n\nstruct item *alloc(void) {\n    struct item *i = malloc(sizeof *i);\n    i->a = 8;\n    return i;\n}\n\nstruct item *alloc2(void) {\n    struct item *i = malloc(sizeof *i);\n    i->a = 9;\n    return i;\n}\n\nstruct item *foo(struct item *(*f)(void) ) {\n    return f();\n}\n\n/* test passing function pointers */\nint main(void) {\n    int a = 1;\n    struct item *i;\n    if (a > 0)\n        i = foo(alloc2);\n    else\n        i = foo(alloc);\n\n    test_assert(i->a == 9);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcptr11.c",
    "content": "int *foo(int *a, int *b) { return a; }\n\nint *(*f)(int *, int *) = 0;\n\nint main(void) {\n    int a, b;\n    int *p;\n\n    f = foo;\n    p = f(&a, &b);\n    *p = 7;\n\n    test_assert(a == 7);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcptr12.c",
    "content": "struct callbacks {\n    int *(*reta)(int *, int *);\n    int *(*retb)(int *, int *);\n};\n\nint *foo1(int *a, int *b) { return a; }\n\nint *foo2(int *a, int *b) { return b; }\n\nstruct callbacks cb = {foo1, foo2};\n\nint main(void) {\n    int a, b;\n    int *p;\n    unsigned long fptr = (unsigned long) cb.retb;\n    int *(*f)(int *, int *) = (int *(*) (int *, int *) ) fptr;\n\n    p = f(&a, &b);\n    *p = 7;\n\n    test_assert(b == 7);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcptr13.c",
    "content": "struct m {\n    int a;\n};\n\nextern struct m *get_ptr(struct m *);\n\nint main(void) {\n    struct m real;\n    struct m *(*f)(struct m *) = get_ptr;\n    struct m *m = f(&real);\n    m->a = 13;\n\n    test_assert(real.a == 13);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcptr14.c",
    "content": "#include <stdlib.h>\n#include <string.h>\n\nstatic int mode = 2;\n\nstatic void *zalloc(size_t x) {\n    void *p = malloc(x);\n    memset(p, 0, x);\n    return p;\n}\n\nstatic void *foo(size_t x) {\n    (void) x;\n    static int bar = 0xfeed;\n    return &bar;\n}\n\nstatic void *foo2(size_t x) {\n    (void) x;\n    static int bar = 0xbee;\n    return &bar;\n}\n\nint main(void) {\n    void *(*f)(size_t);\n    if (mode == 0)\n        f = malloc;\n    else if (mode == 1)\n        f = zalloc;\n    else if (mode == 2)\n        f = foo;\n    else\n        f = foo2;\n\n    int *p = f(sizeof(int));\n\n    if (mode == 1) {\n        test_assert(*p == 0);\n    } else if (mode == 2) {\n        test_assert(*p == 0xfeed);\n    } else if (mode > 2) {\n        test_assert(*p == 0xbee);\n    }\n\n    if (mode <= 1)\n        free(p);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcptr15.c",
    "content": "#include <stdlib.h>\n#include <string.h>\n\nstatic int mode = 3;\n\nstatic void *zalloc(size_t x) {\n    void *p = malloc(x);\n    memset(p, 0, x);\n    return p;\n}\n\nstatic void *foo(size_t x) {\n    (void) x;\n    static int bar = 0xfeed;\n    return &bar;\n}\n\nstatic void *foo2(size_t x) {\n    (void) x;\n    static int bar = 0xbee;\n    return &bar;\n}\n\nint main(void) {\n    void *(*f)(size_t);\n    if (mode == 0)\n        f = malloc;\n    else if (mode == 1)\n        f = zalloc;\n    else if (mode == 2)\n        f = foo;\n    else\n        f = foo2;\n\n    int *p = f(sizeof(int));\n\n    if (mode == 1) {\n        test_assert(*p == 0);\n    } else if (mode == 2) {\n        test_assert(*p == 0xfeed);\n    } else if (mode > 2) {\n        test_assert(*p == 0xbee);\n    }\n\n    if (mode <= 1)\n        free(p);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcptr16.c",
    "content": "#include <stdlib.h>\n#include <string.h>\n\nstatic int mode = 1;\n\nstatic void *zalloc(size_t x) {\n    void *p = malloc(x);\n    memset(p, 0, x);\n    return p;\n}\n\nstatic void *foo(size_t x) {\n    (void) x;\n    static int bar = 0xfeed;\n    return &bar;\n}\n\nstatic void *foo2(size_t x) {\n    (void) x;\n    static int bar = 0xbee;\n    return &bar;\n}\n\nint main(void) {\n    void *(*f)(size_t);\n    if (mode == 0)\n        f = malloc;\n    else if (mode == 1)\n        f = zalloc;\n    else if (mode == 2)\n        f = foo;\n    else\n        f = foo2;\n\n    int *p = f(sizeof(int));\n\n    if (mode == 1) {\n        test_assert(*p == 0);\n    } else if (mode == 2) {\n        test_assert(*p == 0xfeed);\n    } else if (mode > 2) {\n        test_assert(*p == 0xbee);\n    }\n\n    if (mode <= 1)\n        free(p);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcptr2.c",
    "content": "void set(int *a) { *a = 8; }\n\n/* globals are initialized by\n * ConstantExpr, so this is different\n * test thatn funcptr1.c */\n\nvoid (*s)(int *) = set;\nint main(void) {\n    int a, b = 0xfe, c = 0xef;\n    a = b + c;\n    b = 3;\n    c = 5;\n    s(&a);\n\n    test_assert(a == 8);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcptr3.c",
    "content": "void set2(int *b) { *b = 13; }\n\nvoid set(int *a) {\n    void (*f)(int *b);\n    f = set2;\n    f(a);\n}\n\nvoid (*s)(int *) = set;\nint main(void) {\n    int a, b = 0xda, c = 0xd1;\n    a = b + c;\n    b = 3;\n    c = 5;\n    s(&a);\n\n    test_assert(a == 13);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcptr4.c",
    "content": "int *set2(int *a, int *b) { return a; }\n\nint *set(int *a) {\n    int *(*f)(int *, int *);\n    f = set2;\n    return f(a, a);\n}\n\nint *(*s)(int *) = set;\nint main(void) {\n    int a, b = 0xbee, c = 0x3;\n    a = b + c;\n    b = 3;\n    c = 5;\n    int *p = s(&a);\n    *p = 13;\n\n    test_assert(a == 13);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcptr5.c",
    "content": "int *set2(int *a, int *b) { return a; }\n\nint *set(int *a) {\n    int *(*f)(int *, int *);\n    f = set2;\n    return f(a, a);\n}\n\nint main(void) {\n    int a, b = 0x71, c = 0x43;\n    int *(*s)(int *) = set;\n    a = b + c;\n    b = 3;\n    c = 5;\n    int *p = s(&a);\n    *p = 13;\n\n    test_assert(a == 13);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcptr6.c",
    "content": "struct callbacks {\n    void (*f1)(int *);\n    void (*f2)(int *);\n};\n\nvoid foo(int *a) { *a = 1; }\n\nvoid foo2(int *c) { *c = 2; }\n\nstatic struct callbacks cb = {.f1 = foo, .f2 = foo2};\n\nint main(void) {\n    int a, b;\n    cb.f1(&a);\n    cb.f2(&b);\n\n    test_assert(a == 1 && b == 2);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcptr7.c",
    "content": "void set(int *a) { *a = 8; }\n\nvoid foo(void (*f)(int *), int *p) { f(p); }\n\n/* test passing function pointers */\nint main(void) {\n    void (*s)(int *) = set;\n    int a, b = 0x235, c = 0xbeef;\n    a = b + c;\n    b = 3;\n    c = 5;\n    foo(set, &a);\n\n    test_assert(a == 8);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcptr8.c",
    "content": "int a;\nvoid set(void) { a = 8; }\n\nvoid foo(void (*f)()) { f(); }\n\n/* test passing function pointers */\nint main(void) {\n    foo(set);\n    test_assert(a == 8);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/funcptr9.c",
    "content": "#include <stdlib.h>\n\nstruct item {\n    int a;\n};\n\nstruct item *alloc(void) {\n    struct item *i = malloc(sizeof *i);\n    i->a = 8;\n    return i;\n}\n\nstruct item *foo(struct item *(*f)(void) ) {\n    return f();\n}\n\n/* test passing function pointers */\nint main(void) {\n    struct item *i = foo(alloc);\n    test_assert(i->a == 8);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/get_int.c",
    "content": "int get_int(int a) { return a; }\n"
  },
  {
    "path": "tests/slicing/sources/get_output.c",
    "content": "#include <stdio.h>\n\nFILE *get_output(void) { return stdout; }\n"
  },
  {
    "path": "tests/slicing/sources/get_ptr.c",
    "content": "struct m;\nstruct m *get_ptr(struct m *m) {\n    return m;\n}\n"
  },
  {
    "path": "tests/slicing/sources/glob_ptr-a.c",
    "content": "int glob;\n\nint *glob_ptr(int *x) {\n    (void) x;\n    return &glob;\n}\n"
  },
  {
    "path": "tests/slicing/sources/glob_ptr.c",
    "content": "extern int glob;\n\nint *glob_ptr(int *x) {\n    (void) x;\n    return &glob;\n}\n"
  },
  {
    "path": "tests/slicing/sources/global-init.c",
    "content": "struct test_type_t {\n    char *type_name;\n    int type;\n    int (*func_p)(struct test_type_t *tttttttt);\n};\n\nextern void test_assert(int);\n\nstatic int a_func(struct test_type_t *tttttttt) {\n    /* The assert should not be sliced away */\n    test_assert(1);\n    return 1;\n}\n\nstatic struct test_type_t test_instance_2 = {\n        .type_name = \"instance 2\",\n        .type = 0,\n        .func_p = a_func,\n};\n\nint main(int argc, char const *argv[]) {\n    struct test_type_t *tt = &test_instance_2;\n    tt->func_p(tt);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/global1.c",
    "content": "int a;\n\nvoid foo() { a = 1; }\n\n/* basic test */\nint main(void) {\n    a = 0;\n    foo();\n\n    test_assert(a == 1);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/global10.c",
    "content": "int glob;\nint *setglob(void) {\n    glob = 23;\n    return &glob;\n}\n\nint *foo(int *(f) (void) ) { return f(); }\n\nint main(void) {\n    int *p = foo(setglob);\n    test_assert(*p == 23);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/global2.c",
    "content": "int a;\n\nvoid foo() { a = 0; }\n\nint main(void) {\n    a = 1;\n    foo();\n\n    test_assert(a == 0);\n    return a;\n}\n"
  },
  {
    "path": "tests/slicing/sources/global3.c",
    "content": "static int a = 0;\n\nvoid foo() { test_assert(a == 1); }\n\nint main(void) {\n    a = 1;\n    foo();\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/global4.c",
    "content": "int a, b, c;\n\nvoid setA(void) { a = 1; }\n\nvoid setB(void) { b = 1; }\n\nvoid setC(void) { c = 1; }\n\nint main(void) {\n    if (b == 0)\n        setB();\n    if (a == 0)\n        setA();\n\n    test_assert(a == 1);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/global5.c",
    "content": "int a, b, c = 1;\n\nvoid setA(void) { a = 1; }\n\nvoid setB(void) { b = 1; }\n\nint check(void) {\n    test_assert(a == 1);\n    return a == 1;\n}\n\nint main(void) {\n    while (c) {\n        if (b == 0)\n            goto L;\n\n        if (check()) {\n            c = 0;\nL:\n            setA();\n            setB();\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/global6.c",
    "content": "static int a, b, c = 1;\n\nvoid setB(void) { b = 1; }\n\nvoid setA(void) {\n    a = 1;\n    setB();\n}\n\nint check(void) {\n    test_assert(a == 1);\n    return a == 1;\n}\n\nint main(void) {\n    while (c) {\n        if (b == 0)\n            goto L;\n\n        if (check()) {\n            c = 0;\n            break;\nL:\n            setA();\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/global7.c",
    "content": "int b;\n\nvoid setB(void) { b = 1; }\n\nvoid setA(void) { setB(); }\n\nint main(void) {\n    setA();\n    test_assert(b == 1);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/global8.c",
    "content": "int b;\n\nvoid setB(void) { b = 1; }\n\nvoid setA(void) { setB(); }\n\nint main(void) {\n    void (*f)(void) = setA;\n    f();\n    test_assert(b == 1);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/global9.c",
    "content": "int glob;\n\nint *setglob(void) {\n    glob = 23;\n    return ((void *) 0);\n}\n\nint *foo(int *(f) (void) ) { return f(); }\n\nint main(void) {\n    int *p = foo(setglob);\n    test_assert(glob == 23);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/globalptr1.c",
    "content": "/*\n * The code taken from #135,\n * author: @thierry-tct  <tctthierry@gmail.com>\n */\n\nint x;\n\nvoid foo(int a) { x = 1; }\n\nvoid foo2(int a) { x = 2; }\n\nstruct T {\n    void (*f)(int c);\n    int c;\n};\n\nint main(void) {\n    int a = 1;\n    struct T tv[] = {{foo, 7}, {foo2, 4}};\n    tv[0].f(a);\n    test_assert(x == 1);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/globalptr2.c",
    "content": "/*\n * The code taken from #135,\n * author: @thierry-tct  <tctthierry@gmail.com>\n */\n\nint x;\n\nvoid foo(int a) { x = 1; }\n\nvoid foo2(int a) { x = a; }\n\nstruct T {\n    void (*f)(int c);\n    int c;\n};\n\nint main(void) {\n    int a = 13;\n    struct T tv[] = {{foo, 7}, {foo2, 4}};\n    tv[1].f(a);\n    test_assert(x == 13);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/globalptr3.c",
    "content": "/*\n * The code taken from #135,\n * author: @thierry-tct  <tctthierry@gmail.com>\n */\n\nint x;\n\nvoid foo(int a) { x = 1; }\n\nvoid foo2(int a) { x = 2; }\n\nstruct T {\n    void (*f)(int c);\n    int c;\n};\n\nint main(void) {\n    int a = 1;\n    struct T tv[] = {{foo, 7}, {foo2, 4}};\n    tv[1].f(a);\n    test_assert(x == 2);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/globalptr4.c",
    "content": "/*\n * The code taken from #135,\n * author: @thierry-tct  <tctthierry@gmail.com>\n */\n\nint x;\n\nvoid foo(int a) { x = 1; }\n\nvoid foo2(int a) { x = a; }\n\nstruct T {\n    void (*f)(int c);\n    int c;\n};\n\nint main(void) {\n    int a = 1;\n    struct T tv[] = {{foo, 7}, {foo2, 4}};\n    tv[1].f(tv[0].c);\n    test_assert(x == 7);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/interprocedural1.c",
    "content": "void set(int *a) { *a = 8; }\n\n/* basic test */\nint main(void) {\n    int a, b, c;\n    a = 0;\n    b = 1;\n    c = 3;\n\n    a = b + c;\n    b = 3;\n    c = 5;\n    set(&a);\n\n    test_assert(a == 8);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/interprocedural2.c",
    "content": "void add2(int *b) {\n    *b += 1;\n    *b += 1;\n}\n\nvoid set(int *a) {\n    *a = 8;\n    add2(a);\n}\n\n/* basic test */\nint main(void) {\n    int a, b, c;\n    a = 0;\n    b = 1;\n    c = 3;\n\n    a = b + c;\n    b = 3;\n    c = 5;\n    set(&a);\n\n    test_assert(a == 10);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/interprocedural3.c",
    "content": "/* check if returning pointer\n * from function works properly */\n\nint *pick(int *a, int *b) { return b; }\n\nint main(void) {\n    int a, b, c;\n    a = 0;\n    b = 1;\n    c = 3;\n\n    int *p = pick(&a, &b);\n    *p = 13;\n\n    test_assert(b == 13);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/interprocedural4.c",
    "content": "void set(int *a) { test_assert(*a == 8); }\n\n/* basic test */\nint main(void) {\n    int a, b, c;\n\n    a = 8;\n    b = 1;\n    c = 3;\n    b = 3;\n    c = 5;\n\n    set(&a);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/interprocedural5.c",
    "content": "void error(void) {\n    /* OK, reached */\n    test_assert(1);\n}\n\nvoid set(int *a) {\n    if (*a == 8)\n        error();\n}\n\n/* basic test */\nint main(void) {\n    int a, b, c;\n    a = 8;\n    b = 1;\n    c = 3;\n    b = 3;\n    c = 5;\n\n    set(&a);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/interprocedural6.c",
    "content": "void foo(int *a) { *(a + 1) = 8; }\n\nint main(void) {\n    int a[2] = {0, 1};\n    foo(a);\n    test_assert(a[1] == 8);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/interprocedural7.c",
    "content": "void foo(int *a) {\n    ++a;\n    *a = 8;\n}\n\nint main(void) {\n    int a[2] = {0, 1};\n    foo(a);\n    test_assert(a[1] == 8);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/interprocedural8-a.c",
    "content": "#include <stdlib.h>\n\nvoid check_and_set(int *p) {\n    test_assert(*p == 0);\n    *p = 1;\n}\n\nint main(void) {\n    int *p = malloc(sizeof(int));\n    *p = 0;\n    // this test_assert will pass\n    check_and_set(p);\n\n    // this test_assert should abort the program\n    check_and_set(p);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/interprocedural8.c",
    "content": "int glob = 0;\n\nvoid check_and_set(void) {\n    test_assert(glob == 0);\n    glob = 1;\n}\n\nint main(void) {\n    // this test_assert will pass\n    check_and_set();\n\n    // this test_assert should abort the program\n    check_and_set();\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/interprocedural8.output",
    "content": "Assertion PASSED\nAssertion FAILED\n"
  },
  {
    "path": "tests/slicing/sources/interprocedural9.c",
    "content": "int glob = 0;\n\nvoid check_and_set(int i) {\n    if (glob == 1) {\n        test_assert(i == 1);\n        glob = 2;\n    } else if (glob == 2) {\n        glob = 0;\n    } else\n        glob = 1;\n}\n\nint main(void) {\n    int i = 0;\n    for (; i < 4; ++i) {\n        // the second test_assert should abort the program\n        check_and_set(i);\n    }\n\n    /* now the glob should be 1, thus this call should\n     * trigger the assert\n    check_and_set(1);\n    */\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/list1.c",
    "content": "#include <stdlib.h>\n\nstruct wl_list;\n\nvoid wl_list_init(struct wl_list *list);\nvoid wl_list_insert(struct wl_list *list, struct wl_list *elm);\nvoid wl_list_remove(struct wl_list *elm);\nint wl_list_length(const struct wl_list *list);\nint wl_list_empty(const struct wl_list *list);\n\nstruct wl_list {\n    struct wl_list *prev;\n    struct wl_list *next;\n};\n\nstruct item {\n    int number;\n    struct wl_list link;\n};\n\nint main(void) {\n    struct wl_list list;\n    wl_list_init(&list);\n\n    struct item *i1 = malloc(sizeof *i1);\n    wl_list_insert(&list, &i1->link);\n\n    test_assert(wl_list_length(&list) == 1);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/list2.c",
    "content": "#include <stdlib.h>\n\nstruct wl_list;\n\nvoid wl_list_init(struct wl_list *list);\nvoid wl_list_insert(struct wl_list *list, struct wl_list *elm);\nvoid wl_list_remove(struct wl_list *elm);\nint wl_list_length(const struct wl_list *list);\nint wl_list_empty(const struct wl_list *list);\n\nstruct wl_list {\n    struct wl_list *prev;\n    struct wl_list *next;\n};\n\nstruct item {\n    int number;\n    struct wl_list link;\n};\n\nint main(void) {\n    struct wl_list list;\n    wl_list_init(&list);\n\n    struct item *i1 = malloc(sizeof *i1);\n    wl_list_insert(&list, &i1->link);\n    i1->number = 8;\n\n    test_assert(list.next == &i1->link);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/list3.c",
    "content": "#include <stddef.h>\n#include <stdlib.h>\n\nstruct wl_list;\n\nvoid wl_list_init(struct wl_list *list);\nvoid wl_list_insert(struct wl_list *list, struct wl_list *elm);\nvoid wl_list_remove(struct wl_list *elm);\nint wl_list_length(const struct wl_list *list);\nint wl_list_empty(const struct wl_list *list);\n\nstruct wl_list {\n    struct wl_list *prev;\n    struct wl_list *next;\n};\n\nstruct item {\n    int number;\n    struct wl_list link;\n};\n\n#define wl_container_of(ptr, sample, member)                                   \\\n    (__typeof__(sample)) ((char *) (ptr) -offsetof(__typeof__(*sample), member))\nint main(void) {\n    struct wl_list list;\n    wl_list_init(&list);\n\n    struct item *i1 = malloc(sizeof *i1);\n    wl_list_insert(&list, &i1->link);\n    i1->number = 8;\n\n    struct item *i = wl_container_of(list.next, i, link);\n    test_assert(i->number == 8);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/list4.c",
    "content": "#include <stdlib.h>\n\nstruct wl_list;\n\nvoid wl_list_init(struct wl_list *list);\nvoid wl_list_insert(struct wl_list *list, struct wl_list *elm);\nvoid wl_list_remove(struct wl_list *elm);\nint wl_list_length(const struct wl_list *list);\nint wl_list_empty(const struct wl_list *list);\n\nstruct wl_list {\n    struct wl_list *prev;\n    struct wl_list *next;\n};\n\nstruct item {\n    int number;\n    struct wl_list link;\n};\n\nint main(void) {\n    struct wl_list list;\n    wl_list_init(&list);\n\n    struct item *i1 = malloc(sizeof *i1);\n    wl_list_insert(&list, &i1->link);\n    wl_list_remove(&i1->link);\n\n    test_assert(wl_list_empty(&list));\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/list5.c",
    "content": "#include <stdlib.h>\n\nstruct wl_list {\n    struct wl_list *prev;\n    struct wl_list *next;\n};\n\nstruct item {\n    int number;\n    struct wl_list link;\n};\n\nint main(void) {\n    struct wl_list list;\n    struct item *i1 = malloc(sizeof *i1);\n\n    // inlined wl_list_init\n    list.prev = &list;\n    list.next = &list;\n\n    // inlined wl_list_insert\n    i1->link.prev = &list;\n    i1->link.next = list.next;\n    list.next = &i1->link;\n    i1->link.next->prev = &i1->link;\n\n    // inlined part of wl_list_remove\n    i1->link.prev->next = i1->link.next;\n    i1->link.next->prev = i1->link.prev;\n\n    test_assert(list.next == list.prev);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/list6.c",
    "content": "#include <stdlib.h>\n\nstruct wl_list {\n    struct wl_list *prev;\n    struct wl_list *next;\n};\n\nstruct item {\n    int number;\n    struct wl_list link;\n};\n\nint main(void) {\n    struct wl_list list;\n    struct item *i1 = malloc(sizeof *i1);\n    i1->link.next = &i1->link;\n    i1->link.next->prev = &list;\n    i1->link.next->prev->next = &list;\n    i1->link.next->prev->next->prev = NULL;\n\n    test_assert(list.prev == NULL);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/list7.c",
    "content": "#include <stdlib.h>\n\nstruct wl_list;\n\nvoid wl_list_init(struct wl_list *list);\nvoid wl_list_insert(struct wl_list *list, struct wl_list *elm);\nvoid wl_list_remove(struct wl_list *elm);\nint wl_list_length(const struct wl_list *list);\nint wl_list_empty(const struct wl_list *list);\n\nstruct wl_list {\n    struct wl_list *prev;\n    struct wl_list *next;\n};\n\nstruct item {\n    int number;\n    struct wl_list link;\n};\n\nint main(void) {\n    struct wl_list list;\n    list.next = &list;\n    list.prev = &list;\n\n    struct item *i1 = malloc(sizeof *i1);\n\n    i1->link.prev = &list;\n    i1->link.next = list.next;\n    list.next = &i1->link;\n    i1->link.next->prev = &i1->link;\n\n    wl_list_remove(&i1->link);\n\n    test_assert(wl_list_empty(&list));\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/list8.c",
    "content": "#include <stdlib.h>\n\ntypedef struct list {\n    int key;\n    struct list *next;\n} mlist;\n\nmlist *head;\n\nvoid insert_list(int k) {\n    mlist *l = (mlist *) malloc(sizeof(mlist));\n    l->key = k;\n\n    head = l;\n}\n\nint main(void) {\n    mlist *temp;\n\n    insert_list(2);\n    test_assert(head->key == 2);\n}\n"
  },
  {
    "path": "tests/slicing/sources/llvmmemcpy.c",
    "content": "typedef struct Stuff {\n    int a;\n    int b;\n} Stuff;\n\nint main() {\n    Stuff good = {1, 2};\n    Stuff bad;\n    bad = good;\n    test_assert(bad.b == 2);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/llvmmemcpy2.c",
    "content": "typedef struct Stuff {\n    void (*f1)(int *);\n    void (*f2)(int *);\n} Stuff;\n\nvoid foo1(int *a) { *a = 1; }\n\nvoid foo2(int *a) { *a = 2; }\n\nint main() {\n    int a = 0;\n    Stuff good = {foo1, foo2};\n    Stuff bad;\n    bad = good;\n    bad.f2(&a);\n    test_assert(a == 2);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/loop1.c",
    "content": "int main(void) {\n    int a = 0, b = 0;\n    while (a < 10) {\n        a += b;\n        b += 1;\n    }\n\n    test_assert(a == 10);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/loop2.c",
    "content": "int main(void) {\n    int a = 0, b = 0;\n    while (a < 10) {\n        a += b;\n        b += 1;\n    }\n\n    test_assert(b == 5);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/loop3.c",
    "content": "int glob = 1;\n\nint main(void) {\n    int a = 0, b = 0;\n    while (a < 10) {\n        a += b;\n        b += 1;\n        test_assert(glob >= 1);\n        glob++;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/loop4.c",
    "content": "int glob = 1;\nint num;\n\nvoid check(int c) {\n    ++num;\n\n    if (num == 5)\n        test_assert(c == 4);\n}\n\nint main(void) {\n    int a = 0, b = 0;\n    while (a < 10) {\n        a += b;\n        check(b);\n        b++;\n    }\n\n    test_assert(num == 5);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/loop5.c",
    "content": "int glob = 1;\nint num;\n\nvoid check(int c) { ++num; }\n\nint main(void) {\n    int a = 0, b = 0;\n    while (a < 10) {\n        if (a++ > 0)\n            // check that we haven't deleted b++ later\n            test_assert(b > 0);\n        b++;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/malloc-redef.c",
    "content": "#include <stddef.h>\n\nint x;\n\nvoid *malloc(size_t i) {\n    if (i == sizeof(int))\n        return &x;\n    else\n        return ((char *) 0);\n}\n\nint main(void) {\n    int *p = malloc(sizeof(int));\n    if (!p)\n        return 1;\n\n    *p = 3;\n    test_assert(x == 3);\n    return 0;\n}\n\n/*\nint main(void) {\n        unsigned n = 0;\n        scanf(\"%d\", &n);\n        int i = 0;\n        int sum = 0;\n        while (++i < n - 3) {}\n        sum += i;\n        write_sum(sum);\n}\n*/\n"
  },
  {
    "path": "tests/slicing/sources/memcpy1.c",
    "content": "#include <string.h>\n\nint main(void) {\n    int a = 0;\n    int *array[10];\n    int *array2[10];\n\n    array[3] = &a;\n    memcpy(array2, array, sizeof(array));\n\n    *array2[3] = 13;\n    test_assert(13 == a);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/memcpy2.c",
    "content": "#include <string.h>\n\nint main(void) {\n    int a = 0;\n    int *array[10];\n    int *array2[10];\n\n    array[3] = &a;\n    /* copy just the one pointer */\n    memcpy(array2 + 3, array + 3, sizeof(int *));\n\n    *array2[3] = 13;\n    test_assert(13 == a);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/memcpy3.c",
    "content": "#include <string.h>\n\nint main(void) {\n    int a = 0;\n    int *array[10];\n    int *array2[10];\n\n    array[3] = &a;\n    /* copy just the one pointer, but\n     * shift the memory by 3 elemnts,\n     * thus array2[0] will contain memory\n     * from array[3] */\n    memcpy(array2, array + 3, sizeof(int *));\n\n    *array2[0] = 13;\n    test_assert(13 == a);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/memcpy4.c",
    "content": "#include <string.h>\n\nstruct S {\n    int *a;\n    int b;\n};\n\nint main(void) {\n    struct S S1, S2;\n    S1.a = &S1.b;\n    memcpy(&S2, &S1, sizeof(S1));\n    *S2.a = 9;\n    test_assert(S1.b == 9);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/memcpy5.c",
    "content": "#include <string.h>\n\nstruct S {\n    int *a;\n    int b;\n};\n\nint main(void) {\n    struct S S1, S2;\n    S1.a = &S1.b;\n    void *ptr = &S1;\n    void *ptr2 = &S2;\n    memcpy(ptr2, ptr, sizeof(S1));\n\n    *S2.a = 9;\n    test_assert(S1.b == 9);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/memcpy6.c",
    "content": "#include <string.h>\n\nint main(void) {\n    int a = 0;\n    int *array[10];\n    int *array2[10];\n    int **p = array;\n    int **q = array2;\n\n    array[3] = &a;\n    memcpy(q, p, sizeof(array));\n\n    *array2[3] = 13;\n    test_assert(13 == a);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/memset1.c",
    "content": "#include <string.h>\n\nint main() {\n    int array[16];\n    memset(array, 0, 16 * sizeof(int));\n\n    for (size_t i = 0; i < 16; ++i)\n        test_assert(array[i] == 0);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/negoffset1.c",
    "content": "int main(void) {\n    int array[10];\n    int *a = array + 1;\n    int *p = a - 1;\n    *p = 0;\n    test_assert(array[0] == 0);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/negoffset2.c",
    "content": "int main(void) {\n    int array[10];\n    int *a = array + 10;\n    int *p = a - 10;\n    *p = 7;\n    test_assert(array[0] == 7);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/negoffset3.c",
    "content": "void *shift(int *mem) { return mem + 20; }\n\nint main(void) {\n    int array[10];\n    int *a = shift(array);\n    int *p = a - 16;\n    *p = 3;\n    test_assert(array[4] == 3);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/phi1.c",
    "content": "/* test phi nodes handling */\nint main(void) {\n    int a = 2, b = 3, c;\n    int *p;\n\n    if (a > b)\n        p = &a;\n    else\n        p = &b;\n\n    *p = 4;\n\n    test_assert(b == 4);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/phi2.c",
    "content": "void set1(int *a) { *a = 1; }\n\nvoid set2(int *a) { *a = 2; }\n\n/* test phi nodes handling */\nint main(void) {\n    int a = 2, b = 3, c;\n    void (*f)(int *);\n\n    if (a > b)\n        f = set1;\n    else\n        f = set2;\n\n    f(&a);\n\n    test_assert(a == 2);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/phi3.c",
    "content": "int main(void) {\n    int a, b, c = 7;\n\n    if (c > 7)\n        a = 7;\n    else\n        a = 8;\n\n    /* this is a regression. Once slicer tried\n     * to remove phi that was created due to this\n     * assignment, it crashed due to dangling reference */\n    b = a;\n    test_assert(c == 7);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/phi4.c",
    "content": "#include <stdint.h>\n\nvoid set1(uintptr_t addr) { *((int *) addr) = 1; }\n\nvoid set2(uintptr_t addr) { *((int *) addr) = 2; }\n\n/* test phi nodes handling */\nint main(void) {\n    int a = 2, b = 3, c;\n    void (*f)(uintptr_t);\n\n    if (a > b)\n        f = set1;\n    else\n        f = set2;\n\n    f((uintptr_t) &a);\n\n    test_assert(a == 2);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/pointers1.c",
    "content": "struct item {\n    int a;\n    int *ptr;\n};\n\nstruct item2 {\n    struct item i;\n    struct item p;\n};\n\nint main(void) {\n    struct item2 I;\n    I.p.a = 4;\n    I.i.ptr = &I.p.a;\n\n    test_assert(*I.i.ptr == 4);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/pointers2.c",
    "content": "#include <stdlib.h>\n\nstruct item {\n    int a;\n    int *ptr;\n};\n\nstruct item2 {\n    struct item i;\n    struct item p;\n};\n\nint main(void) {\n    int n = 10;\n    struct item2 *A = malloc(n * sizeof(struct item2));\n    A[3].p.a = 4;\n    A[5].i.ptr = &A[3].p.a;\n    int *p = &A[3].p.a;\n\n    test_assert(*p == 4);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/pointers3.c",
    "content": "#include <stdlib.h>\n\nstruct item {\n    int a;\n    int *ptr;\n};\n\nstruct item2 {\n    struct item i;\n    struct item p;\n};\n\nint main(void) {\n    int n = 10;\n    struct item2 *A = malloc(n * sizeof(struct item2));\n    A[3].p.a = 4;\n    A[5].i.ptr = &A[3].p.a;\n    /* make the pointer point to unknown offset\n     * for points-to analysis */\n    int idx = 3;\n    int *p = &A[idx].p.a;\n\n    test_assert(*p == 4);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/pointers4.c",
    "content": "#include <stdlib.h>\n\nstruct item {\n    int a;\n    int *ptr;\n};\n\nstruct item2 {\n    struct item i;\n    struct item p;\n};\n\nint main(void) {\n    int n = 10;\n    struct item2 *A = malloc(n * sizeof(struct item2));\n    /* store to variable in A[3] */\n    struct item *i = &A[3].i;\n    i->ptr = &i->a;\n    *i->ptr = 8;\n\n    /* shift to A[3] by incrementing in loop */\n    struct item2 *ptr = A;\n    for (n = 0; n < 3; ++n)\n        ++ptr;\n\n    test_assert(ptr->i.a == 8);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/pointers5.c",
    "content": "#include <string.h>\n\nint main(void) {\n    // enough to keep pointer on 32 and 64 bit\n    char bytes[8];\n    int a = 3;\n    int *p = &a;\n    int *q;\n    memcpy((void *) bytes, &p, sizeof p);\n    memcpy(&q, (void *) bytes, sizeof p);\n    *q = 13;\n\n    test_assert(a == 13);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/pointers6.c",
    "content": "#include <stdalign.h>\n\nint main(void) {\n    int b = 4;\n    alignas(alignof(int **)) char array[100];\n\n    _Static_assert(\n            4 * sizeof(int **) <= sizeof array,\n            \"This test requires that 4 * sizeof(int **) <= sizeof array\");\n\n    int **p = (int **) array + 3;\n    *p = &b;\n\n    p = 0;\n    int *q = *((int **) array + 3);\n    *q = 3;\n\n    test_assert(b == 3);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/pointers7.c",
    "content": "#include <stdalign.h>\n\nint main(void) {\n    int b = 4;\n    int i;\n    alignas(alignof(int **)) char array[100];\n\n    _Static_assert(\n            4 * sizeof(int **) <= sizeof array,\n            \"This test requires that 4 * sizeof(int **) <= sizeof array\");\n\n    int **p = (int **) array + 3;\n    *p = &b;\n\n    int *q;\n    for (i = 0; i < sizeof(array); ++i) {\n        q = *((int **) array + 3);\n        if (q == &b)\n            *q = 3;\n    }\n\n    test_assert(b == 3);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/pta-inv-infinite-loop.c",
    "content": "#include <stddef.h>\n#include <stdlib.h>\n\nstruct list_head {\n    struct list_head *next, *prev;\n};\n\nstruct s {\n    struct list_head h0;\n    char *b;\n    struct list_head h3;\n};\n\nint main() {\n    struct s s;\n    struct list_head *h3 = &s.h3;\n    struct s *ps = (struct s *) ((char *) h3 - offsetof(struct s, h3));\n\n    // let us slice away the error below\n    // (we are testing only the pointer analysis now)\n    test_assert(1);\n\n    if (ps != &s)\n        free(ps);\n\n    ps->b = 0;\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/pta_fs_regression1.c",
    "content": "#include <stdio.h>\n\nint foo() { return 1; }\n\nFILE *get_output(void);\n\nint main(void) {\n    FILE *output = stderr;\n    if (foo())\n        output = get_output();\n\n    test_assert(output == stdout);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/pta_regression2.c",
    "content": "#include <stdlib.h>\n\nint get_int(int);\n\nstruct node {\n    int value;\n};\n\nstruct node *nd;\n\nstatic void insert(int value) {\n    struct node *node = malloc(sizeof *node);\n    node->value = value;\n    nd = node;\n}\n\nstatic void read() {\n    /* wrapping insert in the loop with\n     * no pointers in this function and\n     * call to unknown function get_int()\n     * resulted in incorrectly built PSS */\n    do {\n        insert(23);\n    } while (get_int(0));\n}\n\nint main() {\n    read();\n    test_assert(nd->value == 23);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/ptr-9.c",
    "content": "extern int *glob;\n\nint *ptr() {\n    // return what is in glob\n    return glob;\n}\n"
  },
  {
    "path": "tests/slicing/sources/ptr.c",
    "content": "int *ptr(int *p) { return p; }\n"
  },
  {
    "path": "tests/slicing/sources/ptrarray1.c",
    "content": "int main(void) {\n    int array[10];\n    int *ptrs[10];\n    int i;\n\n    for (i = 1; i < 10; ++i)\n        ptrs[i - 1] = &array[i];\n\n    ptrs[0] = &array[9];\n    *ptrs[0] = 1;\n    array[0] = 2;\n\n    test_assert(array[9] == 1);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/ptrarray2.c",
    "content": "int main(void) {\n    int array[10];\n    int *ptrs[10];\n    int i;\n\n    for (i = 1; i < 11; ++i)\n        ptrs[i - 1] = &array[i % 10];\n\n    ptrs[0] = &array[9];\n    *ptrs[0] = 1;\n    array[0] = 2;\n\n    test_assert(*ptrs[9] == 2);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/ptrtoint1.c",
    "content": "int main(void) {\n    int a;\n    unsigned long iptr = (unsigned long) &a;\n    int *p = (int *) iptr;\n    *p = 8;\n    test_assert(a == 8);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/ptrtoint2.c",
    "content": "void test_assert(int);\n\nint main(void) {\n    int array[10];\n    int *p = &array[0];\n\n    unsigned long ip = ((unsigned long) p);\n    ip += sizeof(int);\n\n    int *q = (int *) ip;\n    *q = 13;\n\n    test_assert(13 == array[1]);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/ptrtoint3.c",
    "content": "unsigned long foo(int *a) { return (unsigned long) a; }\n\nint main(void) {\n    int c;\n    int *p = (void *) foo(&c);\n    *p = 3;\n\n    test_assert(c == 3);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/ptrtoint4.c",
    "content": "void foo(int **a, unsigned long b) { *a = (int *) b; }\n\nint main(void) {\n    int c;\n    int *p;\n    foo(&p, (unsigned long) &c);\n    *p = 3;\n\n    test_assert(c == 3);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/ptrtoint5.c",
    "content": "void foo(unsigned long a, unsigned long b) { *((int **) a) = (int *) b; }\n\nint main(void) {\n    int c;\n    int *p;\n    foo((unsigned long) &p, (unsigned long) &c);\n    *p = 3;\n\n    test_assert(c == 3);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/ptrtoint6.c",
    "content": "#include <stdint.h>\n\nvoid test_assert(int);\n\nvoid set(uintptr_t addr) { *((int *) addr) = 13; }\n\nint main(void) {\n    int a = 0, b = 0;\n    set((uintptr_t) &a);\n    test_assert(a == 13);\n}\n"
  },
  {
    "path": "tests/slicing/sources/ptrtoint7.c",
    "content": "#include <stdlib.h>\n\nvoid set(unsigned long addr) { *((int *) addr) = 13; }\n\nint main(void) {\n    unsigned long addr = (unsigned long) malloc(sizeof(int));\n    set(addr);\n    int *p = (int *) addr;\n    test_assert(*p == 13);\n}\n"
  },
  {
    "path": "tests/slicing/sources/realloc1.c",
    "content": "#include <stdlib.h>\n\nstruct s {\n    int *a;\n    int *b;\n};\n\nint main(void) {\n    int a, b;\n    struct s *s1, *s2;\n\n    s1 = malloc(sizeof *s1);\n    if (!s1)\n        return 1;\n\n    s1->a = &a;\n    s1->b = &b;\n\n    s2 = realloc(s1, sizeof(*s2));\n    if (!s2)\n        return 1;\n\n    *s2->a = 9;\n    test_assert(a == 9);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/realloc2.c",
    "content": "#include <stdlib.h>\n\nstruct s {\n    int *a;\n    int *b;\n};\n\nint main(void) {\n    int a, b;\n    struct s *s1, *s2;\n\n    s1 = malloc(sizeof *s1);\n    if (!s1)\n        return 1;\n\n    s1->a = &a;\n    s1->b = &b;\n\n    s2 = realloc(s1, sizeof(*s2));\n    if (!s2)\n        return 1;\n\n    *s2->b = 9;\n    test_assert(b == 9);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/realloc3.c",
    "content": "/* Written by @thierry-tct <tctthierry@gmail.com>\n * from issue #133\n */\n\n#include <stdlib.h>\n\nint x;\n\nvoid foo(int a) { x = 1; }\n\nvoid foo2(int a) { x = 2; }\n\nstruct T {\n    void (*f)(int c);\n    int c;\n};\n\nint main(void) {\n    int a = 1;\n    struct T *pt = NULL;\n    pt = (struct T *) realloc(pt, sizeof(struct T));\n    pt[0].f = (a == 1 ? foo : foo2);\n    pt[0].f(a);\n    test_assert(x == 1);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/recursive1.c",
    "content": "void set(int *n, int *x) {\n    if (!x) {\n        x = n;\n        set(n, x);\n    } else\n        *x = 13;\n}\n\nint main(void) {\n    int a;\n    set(&a, 0);\n\n    test_assert(a == 13);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/recursive2.c",
    "content": "int **get_elem_rec(int **array, int idx) {\n    if (idx == 0)\n        return array;\n    else\n        return get_elem_rec(array + 1, idx - 1);\n}\n\nint main(void) {\n    int b = 2;\n    int *array[10];\n    array[9] = &b;\n\n    int **p = get_elem_rec(array, 9);\n    **p = 3;\n\n    test_assert(b == 3);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/recursive3.c",
    "content": "int fact(int a) {\n    if (a <= 1)\n        return 1;\n    return a * fact(a - 1);\n}\n\nint main() {\n    int f = fact(3);\n    test_assert(f == 6);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/recursive4.c",
    "content": "int ack(int m, int n) {\n    if (m == 0)\n        return n + 1;\n    else if (m > 0 && n == 0)\n        return ack(m - 1, 1);\n    else\n        return ack(m - 1, ack(m, n - 1));\n}\n\nint main() { test_assert(ack(1, 2) == 4); }\n"
  },
  {
    "path": "tests/slicing/sources/recursive5.c",
    "content": "static int a;\n\nvoid foo(int x) {\n    if (x > 0) {\n        foo(x - 1);\n    } else {\n        a = 5;\n    }\n}\n\nint main(void) {\n    foo(10);\n    test_assert(a == 5);\n}\n"
  },
  {
    "path": "tests/slicing/sources/regression1.c",
    "content": "/* with LLVM compiled with\n * assertions enabled, we hit an assert\n * while deleting the argc; variable,\n * because the entry block that contains\n * the alloca instruction (the definition)\n * is deleted earlier than the block containing\n * the load (the argc; line) */\n\nvoid test_assert(int);\n\nint main(int argc, char *argv[]) {\n    if (argc == 0) {}\n\n    test_assert(1);\n    (void) argc;\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/sum1.c",
    "content": "#define N 4\n\nint sum(int x[N]) {\n    int i;\n    long long ret;\n    ret = 0;\n    for (i = 0; i < N; i++) {\n        ret = ret + x[i];\n    }\n    return ret;\n}\n\nint main(void) {\n    int x[N] = {1, 2, 3, 4};\n    int temp, i, ret, ret2;\n\n    /* sum elements in array */\n    ret = sum(x);\n\n    /* do cyclic shift in array */\n    temp = x[0];\n    for (i = 0; i < N - 1; i++) {\n        x[i] = x[i + 1];\n    }\n    x[N - 1] = temp;\n\n    /* sum them again */\n    ret2 = sum(x);\n\n    /* check that the sums equal*/\n    test_assert(ret == ret2);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/sum2.c",
    "content": "int sum(int x[3]) {\n    long long ret;\n    ret = x[0] + x[1] + x[2];\n    return ret;\n}\n\n/* use concrete offsets, so that\n * we won't have any UNKNOWN_OFFSET */\nint main(void) {\n    int x[3] = {1, 2, 3};\n    int temp, ret, ret2;\n\n    /* sum elements in array */\n    ret = sum(x);\n\n    /* do cyclic shift in array */\n    temp = x[0];\n    x[0] = x[1];\n    x[1] = x[2];\n    x[2] = temp;\n\n    /* sum them again */\n    ret2 = sum(x);\n\n    /* check that the sums equal*/\n    test_assert(ret == ret2);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/sum3.c",
    "content": "#define N 4\n\nint main(void) {\n    int x[N] = {1, 2, 3, 4};\n    int temp, i, ret, ret2;\n\n    /* sum elements in array */\n    ret = 0;\n    for (i = 0; i < N; i++) {\n        ret = ret + x[i];\n    }\n\n    /* do cyclic shift in array */\n    temp = x[0];\n    for (i = 0; i < N - 1; i++) {\n        x[i] = x[i + 1];\n    }\n    x[N - 1] = temp;\n\n    /* sum them again */\n    ret2 = 0;\n    for (i = 0; i < N; i++) {\n        ret2 = ret2 + x[i];\n    }\n\n    /* check that the sums equal*/\n    test_assert(ret == ret2);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/switch1.c",
    "content": "int main(void) {\n    int a = 1;\n    switch (a) {\n    case 1:\n        a = 4;\n        break;\n    case 2:\n        a = 2;\n        break;\n    case 3:\n        a = 3;\n        break;\n    case 4:\n    case 5:\n        a = 8;\n        break;\n    default:\n        a = 3;\n    }\n\n    test_assert(a == 4);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/switch2.c",
    "content": "int main(void) {\n    int a = 1;\n\n    /* OK, this is really ugly, but C supports it */\n    switch (a) {\n        if (a > 0) {\n        case 1:\n            a = 4;\n            break;\n        case 2:\n            a = 2;\n            break;\n        } else {\n        case -3:\n            a = 3;\n            break;\n        case -4:\n            a = 8;\n            break;\n        }\n    default:\n        a = 3;\n    }\n\n    test_assert(a == 4);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/test1.c",
    "content": "/* basic test */\n\nint main(void) {\n    int a, b, c;\n    a = 0;\n    b = 1;\n    c = 3;\n\n    a = b + c;\n    b = 3;\n    c = 5;\n\n    test_assert(a == 4);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/test2.c",
    "content": "/* basic test with pointers */\nint main(void) {\n    int a, b, c;\n    int *p;\n    a = 0;\n    p = &b;\n    *p = 1;\n    p = &c;\n    *p = 3;\n\n    a = b + c;\n    b = 3;\n    c = 5;\n\n    test_assert(a == 4);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/test22.c",
    "content": "#include <stddef.h>\n#include <stdlib.h>\n\ntypedef struct ldv_kref {\n    int refcount;\n} ldv_kref_t;\n\ntypedef struct ldv_kobject {\n    int a;\n    ldv_kref_t kref;\n} ldv_kobject_t;\n\nstatic void ldv_kobject_cleanup(ldv_kobject_t *kobj) {\n    test_assert(kobj->a == 0xdead);\n}\n\nstatic void ldv_kobject_release(ldv_kref_t *kref) {\n    ldv_kobject_t *kobj = ({\n        typeof(((ldv_kobject_t *) 0)->kref) *mptr = kref;\n        (ldv_kobject_t *) ((char *) mptr - offsetof(ldv_kobject_t, kref));\n    });\n    ldv_kobject_cleanup(kobj);\n}\n\nstatic void ldv_kref_sub(ldv_kref_t *kref, unsigned int count,\n                         void (*release)(ldv_kref_t *kref)) {\n    release(kref);\n}\n\nint main(void) {\n    ldv_kobject_t *kobj;\n\n    kobj = malloc(sizeof(*kobj));\n    kobj->a = 0xdead;\n    ldv_kref_sub(&kobj->kref, 1, ldv_kobject_release);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/test222.c",
    "content": "#include <stddef.h>\n#include <stdlib.h>\n\ntypedef struct ldv_kref {\n    int refcount;\n} ldv_kref_t;\n\ntypedef struct ldv_kobject {\n    int a;\n    struct ldv_kref kref;\n} ldv_kobject_t;\n\nstatic void ldv_kobject_cleanup(ldv_kobject_t *kobj) {\n    test_assert(kobj->a == 0xdead);\n}\n\nstatic void ldv_kobject_release(ldv_kref_t *kref) {\n    ldv_kobject_t *kobj = ({\n        typeof(((ldv_kobject_t *) 0)->kref) *mptr = kref;\n        (ldv_kobject_t *) ((char *) mptr - offsetof(ldv_kobject_t, kref));\n    });\n    void (*func)(ldv_kobject_t *) = ldv_kobject_cleanup;\n    func(kobj);\n}\n\nstatic void ldv_kref_sub(ldv_kref_t *kref, unsigned int count,\n                         void (*release)(ldv_kref_t *kref)) {\n    release(kref);\n}\n\n/* derived from test22.c, adds one more indirect call */\nint main(void) {\n    ldv_kobject_t *kobj;\n\n    kobj = malloc(sizeof(*kobj));\n    kobj->a = 0xdead;\n    ldv_kref_sub(&kobj->kref, 1, ldv_kobject_release);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/test3.c",
    "content": "/* basic test with pointers */\nint main(void) {\n    int a, b, c;\n    int *p;\n    a = 0;\n    p = &b;\n    *p = 1;\n    p = &c;\n    *p = 3;\n\n    a = b + c;\n    b = 3;\n    c = 5;\n    p = &a;\n    *p = 9;\n\n    test_assert(a == 9);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/test4.c",
    "content": "int set(int *a, int b) {\n    *a = b;\n    return b;\n}\n\nvoid clear(int *a) { set(a, 0); }\n\n/* basic test */\nint main(void) {\n    int a, b, c;\n    a = 0;\n    b = 1;\n    c = 3;\n\n    a = b + c;\n    b = 3;\n    c = 5;\n\n    clear(&a);\n    set(&a, 11);\n    clear(&a);\n    set(&a, 12);\n    clear(&a);\n    set(&a, 13);\n\n    test_assert(a == 13);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/test5.c",
    "content": "#include <stdlib.h>\n\nint *array;\nvoid set(int a) { array[3] = a; }\n\n/* basic test */\nint main(void) {\n    array = calloc(5, sizeof(int));\n    set(4);\n    test_assert(array[3] == 4);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/test6.c",
    "content": "int array[5];\n\nvoid set(int a) { array[3] = a; }\n\nint main(void) {\n    set(4);\n    test_assert(array[3] == 4);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/test7.c",
    "content": "void set(int **y, int *x) { *y = x; }\n\nint main(void) {\n    int a = 1, b = 2, *p;\n    if (a > b) {\n        set(&p, &b);\n        *p = 3;\n    } else {\n        set(&p, &a);\n        *p = 4;\n    }\n\n    test_assert(a == 4);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/test8.c",
    "content": "void test_assert(int);\n\nint getVal() { return 9; }\n\nint main(void) {\n    int a = getVal();\n    test_assert(a == 9);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/threads1.c",
    "content": "#include <pthread.h>\n\nvoid *foo(void *data) {\n    int *x = data;\n    *x = 7;\n    return x;\n}\n\nvoid *foo2(void *data) {\n    int *x = data;\n    *x = 8;\n    return 0;\n}\n\nint main(void) {\n    int x = 0;\n    void *p;\n    pthread_t t1, t2;\n    pthread_create(&t1, 0, foo, &x);\n    pthread_create(&t2, 0, foo2, &x);\n\n    x = 3;\n\n    pthread_join(t1, &p);\n    pthread_join(t2, 0);\n\n    *((int *) p) = 4;\n\n    test_assert(x == 4);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/undefcall1_true-unreach-call.c",
    "content": "#include <string.h>\n\nint main(void) {\n    int FORWARD = 1;\n    char *a = \"baba\";\n    char *(*f)(const char *s, int c) = strchr;\n    if (FORWARD) {\n        f = strrchr;\n    }\n\n    char *x = f(a, 'b');\n    test_assert(x == a + 2);\n}\n"
  },
  {
    "path": "tests/slicing/sources/undefcall2_true-unreach-call.c",
    "content": "#include <string.h>\n\nint main(void) {\n    int FORWARD = 0;\n    char *a = \"baba\";\n    char *(*f)(const char *s, int c) = strchr;\n    if (FORWARD) {\n        f = strrchr;\n    }\n\n    char *x = f(a, 'b');\n    test_assert(x == a);\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknown-interproc.c",
    "content": "extern void test_assert(int);\nint *ptr(int *);\n\nvoid foo(int *x) {\n    int *p = ptr(x);\n    *p = 3;\n}\n\nint main(void) {\n    int a = 0;\n    foo(&a);\n    test_assert(a == 3);\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknown-interproc2-a.c",
    "content": "#include <stdlib.h>\n\nextern int glob;\n\nint *glob_ptr(int *);\nvoid test_assert(int);\n\nvoid foo(int *x) {\n    int *p = glob_ptr(x); // returns the pointer to glob\n    *p = 3;\n}\n\nint main(void) {\n    int a = 0;\n    foo(&a);\n    test_assert(glob == 3);\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknown-interproc2.c",
    "content": "#include <stdlib.h>\n\nint glob;\n\nint *glob_ptr(int *);\nvoid test_assert(int);\n\nvoid foo(int *x) {\n    int *p = glob_ptr(x); // returns the pointer to glob\n    *p = 3;\n}\n\nint main(void) {\n    int a = 0;\n    foo(&a);\n    test_assert(glob == 3);\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknown-interproc3.c",
    "content": "void test_assert(int);\nint *a_ptr(int **x);\n\nvoid foo(int **x) {\n    int *p = a_ptr(x); // returns pointer to a\n    *p = 3;\n}\n\nint main(void) {\n    int a;\n    int *b = &a;\n    foo(&b);\n    test_assert(a == 3);\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknownptr1.c",
    "content": "int *foo(int *a);\n\nint main(void) {\n    int a, b, c;\n\n    int *p = foo(&a);\n    // the p points to unknown location, so\n    // slicer must not remove *p = 8,\n    // since it may point to a\n    *p = 8;\n\n    test_assert(a == 8);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknownptr10-a.c",
    "content": "void test_assert(int);\nint glob;\nextern int *glob_ptr(int *);\n\nvoid foo2() {\n    int x;\n    test_assert(*glob_ptr(&x) == 3);\n}\n\nint main(void) {\n    int x;\n    *glob_ptr(&x) = 3;\n    foo2();\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknownptr10.c",
    "content": "void test_assert(int);\nextern int *glob_ptr(int *);\nint glob;\n\nvoid foo2() {\n    int x;\n    test_assert(*glob_ptr(&x) == 3);\n}\n\nint main(void) {\n    glob = 3;\n    foo2();\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknownptr11.c",
    "content": "int *glob;\nextern void test_assert(int);\nextern void foo(void);\n\nint main(void) {\n    int a = 0;\n    glob = &a;\n    foo();\n    test_assert(a == 2);\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknownptr2.c",
    "content": "volatile int getidx(void) { return 2; }\n\nint main(void) {\n    int array[5];\n    int idx = getidx();\n    // getidx() returns 2, but slicer\n    // does not know it, so array[idx] is\n    // pointer with unknown offset to array\n    array[idx] = 7;\n\n    test_assert(array[2] == 7);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknownptr3.c",
    "content": "volatile int getidx(void) { return 2; }\n\nint main(void) {\n    int array[5];\n    int idx = getidx();\n\n    // some pointer arithmetic\n    int *p = array;\n    p += idx;\n    ++p;\n\n    *p = 7;\n\n    test_assert(array[3] == 7);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknownptr4.c",
    "content": "struct m {\n    int a;\n};\n\nstruct m *get_ptr(struct m *);\n\nint main(void) {\n    struct m real;\n    struct m *m = get_ptr(&real);\n    m->a = 13;\n\n    test_assert(real.a == 13);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknownptr5.c",
    "content": "struct m {\n    int a;\n};\n\nstruct m *get_ptr(struct m *);\n\nint main(void) {\n    struct m real1, real2;\n    struct m *m = get_ptr(&real1);\n    struct m *n = get_ptr(&real2);\n    real1.a = 0;\n    if (real1.a) {\n        real1.a = 11;\n        real2.a = 12;\n    } else {\n        m->a = 13;\n        n->a = 14;\n    }\n\n    test_assert(real1.a == 13 && real2.a == 14);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknownptr6.c",
    "content": "int a = 3;\n\nextern int *foo();\n\nint main(void) {\n    int *x = foo();\n    a = 2;\n    test_assert(*x == 2);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknownptr7.c",
    "content": "int a = -1;\n\nextern int *foo();\n\nint main(void) {\n    a = 0;\n    a |= 0x1;\n    if (a != 0) {\n        a |= 0x2;\n    } else {\n        a |= 0x4;\n    }\n    int *x = foo();\n    test_assert(*x == 3);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknownptr8.c",
    "content": "int a = -1;\n\nextern int *foo();\n\nint main(void) {\n    a = 0;\n    a |= 0x1;\n    if (a == 0) {\n        a |= 0x4;\n    } else {\n        a |= 0x2;\n    }\n    int *x = foo();\n    test_assert(*x == 3);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknownptr9.c",
    "content": "void test_assert(int);\n\nint *glob;\nint *ptr();\n\nvoid foo1() { *ptr() = 2; }\n\nint main(void) {\n    int a;\n    glob = &a;\n    foo1();\n    test_assert(a == 2);\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknownptrfoo.c",
    "content": "int *foo(int *a) {\n    *a = 8;\n    return a;\n}\n"
  },
  {
    "path": "tests/slicing/sources/unknownptrfoo2.c",
    "content": "extern int a;\n\nint *foo() { return &a; }\n"
  },
  {
    "path": "tests/slicing/sources/vararg1.c",
    "content": "#include <stdarg.h>\n\nvoid setv(int num, ...) {\n    va_list l;\n    int *x;\n\n    (void) num;\n\n    /* in this test we have only one var arg */\n    va_start(l, num);\n    x = va_arg(l, int *);\n    *x = 13;\n    va_end(l);\n}\n\nint main(void) {\n    int a;\n    setv(1, &a);\n    test_assert(a == 13);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/vararg2.c",
    "content": "#include <stdarg.h>\n\nvoid setv(int num, ...) {\n    va_list l;\n    int *x;\n\n    va_start(l, num);\n\n    for (; num > 0; --num) {\n        x = va_arg(l, int *);\n        *x = 13;\n    }\n\n    va_end(l);\n}\n\nint main(void) {\n    int a, b, c;\n    setv(3, &a, &b, &c);\n    test_assert(a == 13);\n\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/vararg3.c",
    "content": "#include <stdarg.h>\n\nvoid setv(int num, ...) {\n    va_list l;\n    void (*f)(void);\n\n    (void) num;\n\n    /* in this test we have only one var arg */\n    va_start(l, num);\n    f = va_arg(l, void *);\n    f();\n    va_end(l);\n}\n\nvoid foo(void) {\n    /* OK, assert reached */\n    test_assert(1);\n}\n\nint main(void) {\n    int a;\n    setv(1, foo);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/vararg4.c",
    "content": "#include <stdarg.h>\n\nvoid setv(int num, ...) {\n    va_list l;\n    void (*f)(int *);\n    int *x;\n\n    (void) num;\n\n    va_start(l, num);\n    f = va_arg(l, void *);\n    x = va_arg(l, int *);\n    f(x);\n    va_end(l);\n}\n\nvoid foo(int *a) { *a = 17; }\n\nint main(void) {\n    int a = 0;\n    setv(1, foo, &a);\n    test_assert(a == 17);\n    return 0;\n}\n"
  },
  {
    "path": "tests/slicing/sources/wl_list.c",
    "content": "/*\n * Copyright © 2008-2011 Kristian Høgsberg\n * Copyright © 2011 Intel Corporation\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice (including the\n * next paragraph) shall be included in all copies or substantial\n * portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n#include <stdlib.h>\n\nstruct wl_list {\n    struct wl_list *prev;\n    struct wl_list *next;\n};\n\nvoid wl_list_init(struct wl_list *list) {\n    list->prev = list;\n    list->next = list;\n}\n\nvoid wl_list_insert(struct wl_list *list, struct wl_list *elm) {\n    elm->prev = list;\n    elm->next = list->next;\n    list->next = elm;\n    elm->next->prev = elm;\n}\n\nvoid wl_list_remove(struct wl_list *elm) {\n    elm->prev->next = elm->next;\n    elm->next->prev = elm->prev;\n    elm->next = NULL;\n    elm->prev = NULL;\n}\n\nint wl_list_length(const struct wl_list *list) {\n    struct wl_list *e;\n    int count;\n\n    count = 0;\n    e = list->next;\n    while (e != list) {\n        e = e->next;\n        count++;\n    }\n\n    return count;\n}\n\nint wl_list_empty(const struct wl_list *list) { return list->next == list; }\n"
  },
  {
    "path": "tests/slicing/test-runner.py",
    "content": "#!/usr/bin/env python3\n\nfrom os import chdir, environ, getcwd\nfrom os.path import abspath, basename, dirname, join\nfrom shutil import rmtree\nfrom subprocess import DEVNULL, PIPE, Popen\nfrom sys import argv, stdout\n\nclang_has_sanitizers = False\ndebug = False\nhave_svf = False\n\n# going to be (possibly) re-set in set_environment()\nDG_TOOLS_DIR = \"../../tools/\"\nTEST_SOURCES_DIR = \"../sources/\"\nLLVM_TOOLS_DIR = \"\"\n\n\ndef parse_cmake_cache(cmakecache):\n    with open(cmakecache, 'r') as f:\n        for line in f:\n            if line.startswith('SVF_DIR'):\n                have_svf = True\n            elif line.startswith('CLANG_HAS_SANITIZERS'):\n                global clang_has_sanitizers\n                clang_has_sanitizers = True\n            elif line.startswith('dg_SOURCE_DIR'):\n                parts = line.split('=')\n                global TEST_SOURCES_DIR\n                TEST_SOURCES_DIR = abspath(join(parts[1].strip(),\n                                                'tests/slicing/sources/'))\n            elif line.startswith('dg_BINARY_DIR'):\n                parts = line.split('=')\n                global DG_TOOLS_DIR\n                DG_TOOLS_DIR = abspath(join(parts[1].strip(), 'tools/'))\n            elif line.startswith('LLVM_TOOLS_DIR'):\n                parts = line.split('=')\n                global LLVM_TOOLS_DIR\n                LLVM_TOOLS_DIR = parts[1].strip()\n\n\nconfigs = {\n#   '-dda': ['rd', 'ssa'],\n    '-pta': ['fi', 'fs', 'inv'],\n    '-cd-alg': ['ntscd', 'classic'],\n}\n\n\ndef command(cmd, env=environ):\n    if debug:\n        print(\"> \" + \"  \".join(cmd), flush=True)\n        p = Popen(cmd, env=env)\n    else:\n        p = Popen(cmd, stdout=DEVNULL, stderr=DEVNULL, env=env)\n    return p.wait()\n\n\ndef command_output(cmd, env=environ):\n    if debug:\n        print(\"> \" + \"  \".join(cmd), flush=True)\n    p = Popen(cmd, stdout=PIPE, stderr=PIPE, env=env)\n    out, err = p.communicate()\n    return out, err, p.poll()\n\n\ndef cleanup():\n    oldpath = getcwd()\n    chdir('..')\n    rmtree(oldpath)\n\n\ndef error(msg):\n    from sys import exit, stderr\n    print(msg, file=stderr)\n    exit(1)\n\n\ndef set_environment():\n    try:\n        parse_cmake_cache(\"../../CMakeCache.txt\")\n    except IOError:\n        # assume in-source build where we want to call\n        # the test-runner.py from everywhere\n        chdir(dirname(argv[0]))\n\n\ndef _getbcname(name):\n    if name[-2:] != '.c':\n        error('Input is not a .c source code')\n\n    return basename(name[:-2]) + '.bc'\n\n\ndef compile(source, output=None, params=[]):\n    if output is None:\n        output = _getbcname(source)\n\n    clang = join(LLVM_TOOLS_DIR, 'clang')\n    test_assert_h = join(TEST_SOURCES_DIR, '..', \"test_assert.h\")\n    ret = command([clang, \"-include\", test_assert_h, \"-emit-llvm\", \"-std=c11\",\n                   \"-fno-strict-aliasing\", \"-c\", source, \"-o\", output]\n                  + params)\n    if ret != 0:\n        error('Failed executing ' + clang)\n\n    return output\n\n\ndef slice(bccode, args):\n    output = bccode + \".sliced\"\n    slicer = join(DG_TOOLS_DIR, \"llvm-slicer\")\n\n    cmd = [slicer, \"-c\", \"test_assert\"] + args + [bccode, \"-o\", output]\n    if command(cmd) != 0:\n        error('Failed executing llvm-slicer')\n\n    return output\n\n\ndef link(bccode, codes, output=None):\n    if output is None:\n        output = bccode + \".linked\"\n\n    llvm_link = join(LLVM_TOOLS_DIR, \"llvm-link\")\n    cmd = [llvm_link, bccode, \"-o\", output] + codes\n\n    if command(cmd) != 0:\n        error('Failed executing ' + llvm_link)\n\n    return output\n\n\ndef opt(bccode, passes, output=None):\n    if output is None:\n        output = bccode + \".opt\"\n\n    opt = join(LLVM_TOOLS_DIR, \"opt\")\n    cmd = [opt, bccode, \"-o\", output] + passes\n\n    if command(cmd) != 0:\n        error('Failed executing ' + opt)\n\n    return output\n\n\ndef check_output(out, err, exitcode, expout):\n    if debug:\n        print(\"--- stdout ---\")\n        print(out.decode())\n        print(\"--- stderr ---\")\n        print(err.decode())\n        print(\"--- exitcode {0} ---\".format(exitcode))\n\n    if exitcode != 0:\n        error(\"Executing the code failed!\")\n\n    lines = [line for line in out.decode().split('\\n') if line]\n    if expout:\n        with open(join(TEST_SOURCES_DIR, expout), 'r') as f:\n            expected = [line for line\n                        in map(lambda s: s.strip(), f.readlines()) if line]\n            if expected != lines:\n                if debug:\n                    print(' -- expected --')\n                    print(expected)\n                    print(' -- got --')\n                    print(lines)\n                error('The output is not as expected')\n\n        print('OK!\\n')\n        return\n\n    # the default expected output\n    passed = False\n    failed = False\n\n    for l in lines:\n        if l == 'Assertion PASSED':\n            passed = True\n        elif l == 'Assertion FAILED':\n            failed = True\n\n    if not passed and not failed:\n        error('Assertion was not called')\n    if not passed or failed:\n        error('Assertion failed!')\n\n    print('OK!\\n')\n\n\ndef execute(bccode, expout=None):\n    lli = join(LLVM_TOOLS_DIR, 'lli')\n    ret = command_output([lli, bccode])\n    check_output(*ret, expout)\n\n\ndef get_variations(rem=list(configs), result=[]):\n    \"\"\" Get all possible variations of the parameters \"\"\"\n    if not rem:\n        return result\n\n    if result == []:\n        result = [[\"{0}={1}\".format(rem[0], c)] for c in configs[rem[0]]]\n    else:\n        tmp = result\n        result = []\n        for c in configs[rem[0]]:\n            result += [x + [\"{0}={1}\".format(rem[0], c)] for x in tmp]\n\n    return get_variations(rem[1:], result)\n\n\ndef _test_enabled(test, setup):\n    for p in test.requiredparams:\n        if p not in setup:\n            return False\n\n    return True\n\n\ndef run_test(test, bccode, optafter, linkafter, args):\n    bccode = slice(bccode, args + test.addparams)\n\n    if optafter:\n        assert False\n\n    if linkafter:\n        bccode = link(bccode, linkafter)\n\n    if test.optafter:\n        bccode = opt(bccode, t.optafter)\n\n    execute(bccode, test.expectedoutput)\n\n\ndef sanity_check(test):\n    \"\"\"Check that the test runs and has the expected output without slicing.\"\"\"\n\n    clang = join(LLVM_TOOLS_DIR, 'clang')\n    cmd = [clang, join(TEST_SOURCES_DIR, t.source),\n           join(TEST_SOURCES_DIR, '..', 'test_assert.c'),\n           '-include', join(TEST_SOURCES_DIR, '..', 'test_assert.h'),\n           '-std=c11', '-fno-strict-aliasing', '-g', '-Werror',\n           '-o', 'sanity'] + test.compilerparams\n\n    if clang_has_sanitizers:\n        cmd += ['-fsanitize=address,undefined', '-fno-omit-frame-pointer',\n                '-fno-sanitize-recover=all']\n\n    if test.linkbefore:\n        cmd += [join(TEST_SOURCES_DIR, x) for x in test.linkbefore]\n    if test.linkafter:\n        cmd += [join(TEST_SOURCES_DIR, x) for x in test.linkafter]\n\n    if command(cmd) != 0:\n        error('Failed executing ' + clang)\n\n    env = {'ASAN_OPTIONS': 'detect_leaks=0',\n           'UBSAN_OPTIONS': 'print_stacktrace=1'}\n    ret = command_output(['./sanity'], env=env)\n    check_output(*ret, test.expectedoutput)\n\n\nif __name__ == \"__main__\":\n    from tests import tests\n\n    if len(argv) <= 1:\n        error('Usage: {0} test-name [args to slicer]'.format(argv[0]))\n\n    if have_svf:\n        configs['-pta'].append('svf')\n\n    try:\n        t = tests[argv[1]]\n    except KeyError:\n        error(\"Unknown test name: '{0}'\".format(argv[1]))\n\n    if 'debug' in argv[0]:\n        debug = True\n\n    set_environment()\n\n    # create tmpdir for given test\n    from os import mkdir\n    rmtree(argv[1], ignore_errors=True)  # just to be sure it does not exist\n    mkdir(argv[1])\n    chdir(argv[1])\n\n    # check that the unsliced original works as intended\n    sanity_check(t)\n\n    # compile the source\n    bccode = compile(join(TEST_SOURCES_DIR, t.source),\n                     params=t.compilerparams)\n\n    optbefore, linkbefore, optafter, linkafter = [], [], [], []\n\n    if t.linkbefore:\n        for l in t.linkbefore:\n            bctolink = compile(join(TEST_SOURCES_DIR, l),\n                               params=t.compilerparams)\n            linkbefore.append(bctolink)\n\n    if t.linkafter:\n        for l in t.linkafter:\n            bctolink = compile(join(TEST_SOURCES_DIR, l),\n                               params=t.compilerparams)\n            linkafter.append(bctolink)\n\n    if t.optbefore:\n        bccode = opt(bccode, t.optbefore)\n\n    if linkbefore:\n        bccode = link(bccode, linkbefore)\n\n    # always link test_assert() after slicing\n    assertbc = compile(join(TEST_SOURCES_DIR, '..', 'test_assert.c'),\n                       params=t.compilerparams)\n    linkafter.append(assertbc)\n\n    # RUN!\n    args = argv[2:]\n    endline = \"\\n\" if debug else \"\"\n    if args:\n        stdout.write(\"Executing setup: {0} ... {1}\".format(\" \".join(args),\n                                                           endline))\n        run_test(t, bccode, optafter, linkafter, args)\n    else:\n        for setup in get_variations():\n            if not _test_enabled(t, setup):\n                print(\"Skipping setup\", \" \".join(setup))\n                continue\n\n            stdout.write(\"Executing setup: {0} ... {1}\".format(\" \".join(setup),\n                                                               endline))\n            run_test(t, bccode, optafter, linkafter, setup)\n\n    # cleanup\n    cleanup()\n"
  },
  {
    "path": "tests/slicing/test_assert.c",
    "content": "#include <assert.h>\n#include <stdio.h>\n\nvoid test_assert(int cond) {\n    if (cond) {\n        printf(\"Assertion PASSED\\n\");\n    } else {\n        printf(\"Assertion FAILED\\n\");\n#ifndef ASSERT_NO_ABORT\n        assert(0 && \"assertion failed\");\n#endif\n    }\n}\n"
  },
  {
    "path": "tests/slicing/test_assert.h",
    "content": "void test_assert(int cond);\n"
  },
  {
    "path": "tests/slicing/tests.py",
    "content": "class Test:\n    def __init__(self, src, linkbefore=[], linkafter=[],\n                            optbefore=[], optafter=[],\n                            addparams=[], requiredparams=[],\n                            compilerparams=[], expectedoutput=None):\n        self.source = src\n        self.linkbefore = linkbefore\n        self.linkafter = linkafter\n        self.optbefore = optbefore\n        self.optafter = optafter\n        self.addparams = addparams\n        self.requiredparams = requiredparams\n        self.compilerparams = compilerparams\n        self.expectedoutput = expectedoutput\n\n\ntests = {\n    'test1'                : Test('test1.c'),\n    'test2'                : Test('test2.c'),\n    'test22'               : Test('test22.c', compilerparams=['-std=gnu11']),\n    'test222'              : Test('test222.c', compilerparams=['-std=gnu11']),\n    'test3'                : Test('test3.c'),\n    'test4'                : Test('test4.c'),\n    'test5'                : Test('test5.c'),\n    'test6'                : Test('test6.c'),\n    'test7'                : Test('test7.c'),\n    'test8'                : Test('test8.c'),\n    'recursive1'           : Test('recursive1.c'),\n    'recursive2'           : Test('recursive2.c'),\n    'recursive3'           : Test('recursive3.c'),\n    'recursive4'           : Test('recursive4.c'),\n    'recursive5'           : Test('recursive5.c'),\n    'interprocedural1'     : Test('interprocedural1.c'),\n    'interprocedural2'     : Test('interprocedural2.c'),\n    'interprocedural3'     : Test('interprocedural3.c'),\n    'interprocedural4'     : Test('interprocedural4.c'),\n    'interprocedural5'     : Test('interprocedural5.c'),\n    'interprocedural6'     : Test('interprocedural6.c'),\n    'interprocedural7'     : Test('interprocedural7.c'),\n    'interprocedural8'     : Test('interprocedural8.c',\n                                  compilerparams=['-DASSERT_NO_ABORT'],\n                                  expectedoutput='interprocedural8.output'),\n    'interprocedural8-a'   : Test('interprocedural8-a.c',\n                                  compilerparams=['-DASSERT_NO_ABORT'],\n                                  expectedoutput='interprocedural8.output'),\n    'interprocedural9'     : Test('interprocedural9.c'),\n    'funcptr1'             : Test('funcptr1.c'),\n    'funcptr2'             : Test('funcptr2.c'),\n    'funcptr3'             : Test('funcptr3.c'),\n    'funcptr4'             : Test('funcptr4.c'),\n    'funcptr5'             : Test('funcptr5.c'),\n    'funcptr6'             : Test('funcptr6.c'),\n    'funcptr7'             : Test('funcptr7.c'),\n    'funcptr8'             : Test('funcptr8.c'),\n    'funcptr9'             : Test('funcptr9.c'),\n    'funcptr10'            : Test('funcptr10.c'),\n    'funcptr11'            : Test('funcptr11.c'),\n    'funcptr12'            : Test('funcptr12.c'),\n    'funcptr13'            : Test('funcptr13.c',\n                                  linkafter=['get_ptr.c']),\n    'funcptr14'            : Test('funcptr14.c'),\n    'funcptr15'            : Test('funcptr15.c'),\n    'funcptr16'            : Test('funcptr16.c'),\n    'funcptr-regression1'  : Test('funcptr-regression1.c'),\n    'funcarray1'           : Test('funcarray1.c'),\n    'funcarray2'           : Test('funcarray2.c'),\n    'funcarray3'           : Test('funcarray3.c'),\n    'unknownptr1'          : Test('unknownptr1.c',\n                                  linkafter=['unknownptrfoo.c']),\n    'unknownptr2'          : Test('unknownptr2.c'),\n    'unknownptr3'          : Test('unknownptr3.c'),\n    'unknownptr4'          : Test('unknownptr4.c',\n                                  linkafter=['get_ptr.c']),\n    'unknownptr5'          : Test('unknownptr5.c' ,\n                                  linkafter=['get_ptr.c']),\n    'unknownptr6'          : Test('unknownptr6.c',\n                                  linkafter=['unknownptrfoo2.c']),\n    'unknownptr7'          : Test('unknownptr7.c',\n                                  linkafter=['unknownptrfoo2.c']),\n    'unknownptr8'          : Test('unknownptr8.c',\n                                  linkafter=['unknownptrfoo2.c']),\n    'unknownptr9'          : Test('unknownptr9.c',\n                                  linkafter=['ptr-9.c'],\n                                  addparams=['-undefined-funs=read-any']),\n    'unknownptr10'         : Test('unknownptr10.c',\n                                  linkafter=['glob_ptr.c'],\n                                  addparams=['-undefined-funs=read-any']),\n    'unknownptr10-a'       : Test('unknownptr10-a.c',\n                                  linkafter=['glob_ptr.c'],\n                                  addparams=['-undefined-funs=rw-any']),\n    'unknownptr11'         : Test('unknownptr11.c',\n                                  linkafter=['foo.c'],\n                                  addparams=['-undefined-funs=rw-any']),\n    'pointers1'            : Test('pointers1.c'),\n    'pointers2'            : Test('pointers2.c'),\n    'pointers3'            : Test('pointers3.c'),\n    'pointers4'            : Test('pointers4.c'),\n    'pointers5'            : Test('pointers5.c'),\n    'pointers6'            : Test('pointers6.c'),\n    'pointers7'            : Test('pointers7.c'),\n    'ptrarray1'            : Test('ptrarray1.c'),\n    'ptrarray2'            : Test('ptrarray2.c'),\n    'phi1-nophi'           : Test('phi1.c'),\n    'phi2-nophi'           : Test('phi2.c'),\n    'phi3-nophi'           : Test('phi3.c'),\n    'phi4-nophi'           : Test('phi4.c'),\n    'phi1'                 : Test('phi1.c',\n                                  optbefore=['-mem2reg']),\n    'phi2'                 : Test('phi2.c',\n                                  optbefore=['-mem2reg']),\n    'phi3'                 : Test('phi3.c',\n                                  optbefore=['-mem2reg']),\n    'phi4'                 : Test('phi4.c',\n                                  optbefore=['-mem2reg']),\n    'global1'              : Test('global1.c'),\n    'global2'              : Test('global2.c'),\n    'global3'              : Test('global3.c'),\n    'global4'              : Test('global4.c'),\n    'global5'              : Test('global5.c'),\n    'global6'              : Test('global6.c'),\n    'global7'              : Test('global7.c'),\n    'global8'              : Test('global8.c'),\n    'global9'              : Test('global9.c'),\n    'global10'             : Test('global10.c'),\n    'global-init'          : Test('global-init.c'),\n    'ptrtoint1'            : Test('ptrtoint1.c'),\n    'ptrtoint2'            : Test('ptrtoint2.c'),\n    'ptrtoint3'            : Test('ptrtoint3.c'),\n    'ptrtoint4'            : Test('ptrtoint4.c'),\n    'ptrtoint5'            : Test('ptrtoint5.c'),\n    'ptrtoint6'            : Test('ptrtoint6.c'),\n    'ptrtoint7'            : Test('ptrtoint7.c'),\n    'llvmmemcpy'           : Test('llvmmemcpy.c'),\n    'llvmmemcpy2'          : Test('llvmmemcpy2.c'),\n    'memset1'              : Test('memset1.c'),\n    'memcpy1'              : Test('memcpy1.c'),\n    'memcpy2'              : Test('memcpy2.c'),\n    'memcpy3'              : Test('memcpy3.c'),\n    'memcpy4'              : Test('memcpy4.c'),\n    'memcpy5'              : Test('memcpy5.c'),\n    'memcpy6'              : Test('memcpy6.c'),\n    'bitcast1'             : Test('bitcast1.c'),\n    'bitcast2'             : Test('bitcast2.c'),\n    'bitcast3'             : Test('bitcast3.c'),\n    'bitcast4'             : Test('bitcast4.c'),\n    'bitcast5'             : Test('bitcast5.c'),\n    'loop1'                : Test('loop1.c'),\n    'loop2'                : Test('loop2.c'),\n    'loop3'                : Test('loop3.c'),\n    'loop4'                : Test('loop4.c'),\n    'loop5'                : Test('loop5.c'),\n    'list1'                : Test('list1.c',\n                                  linkbefore=['wl_list.c']),\n    'list2'                : Test('list2.c',\n                                  linkbefore=['wl_list.c']),\n    'list3'                : Test('list3.c',\n                                  linkbefore=['wl_list.c']),\n    'list4'                : Test('list4.c',\n                                  linkbefore=['wl_list.c']),\n    'list5'                : Test('list5.c'),\n    'list6'                : Test('list6.c'),\n    'list7'                : Test('list7.c',\n                                  linkbefore=['wl_list.c']),\n    'list8'                : Test('list8.c'),\n    'list9'                : Test('list1.c',\n                                  linkafter=['wl_list.c'],\n                                  addparams=['-undefined-funs=rw-args']),\n    'dynalloc1'            : Test('dynalloc1.c'),\n    'dynalloc2'            : Test('dynalloc2.c'),\n    'dynalloc3'            : Test('dynalloc3.c'),\n    'dynalloc4'            : Test('dynalloc4.c'),\n    'dynalloc5'            : Test('dynalloc5.c'),\n    'dynalloc6'            : Test('dynalloc6.c'),\n    'dynalloc7'            : Test('dynalloc7.c'),\n    'realloc1'             : Test('realloc1.c'),\n    'realloc2'             : Test('realloc2.c'),\n    'realloc3'             : Test('realloc3.c'),\n    'switch1'              : Test('switch1.c'),\n    'switch2'              : Test('switch2.c'),\n    'vararg1'              : Test('vararg1.c'),\n    'vararg2'              : Test('vararg2.c'),\n    'vararg3'              : Test('vararg3.c'),\n    'vararg4'              : Test('vararg4.c'),\n    'negoffset1'           : Test('negoffset1.c'),\n    'negoffset2'           : Test('negoffset2.c'),\n    'negoffset3'           : Test('negoffset3.c'),\n    'sum1'                 : Test('sum1.c'),\n    'sum2'                 : Test('sum2.c'),\n    'sum3'                 : Test('sum3.c'),\n    'globalptr1'           : Test('globalptr1.c'),\n    'globalptr2'           : Test('globalptr2.c'),\n    'globalptr3'           : Test('globalptr3.c'),\n    'globalptr4'           : Test('globalptr4.c'),\n    'control-regression1'  : Test('control-regression1.c'),\n    'pta_fs_regression1'   : Test('pta_fs_regression1.c',\n                                   linkbefore=['get_output.c']),\n    'pta_fs_regression2'   : Test('pta_fs_regression1.c',\n                                   linkafter=['get_output.c']),\n    'pta_regression2'      : Test('pta_regression2.c' ,\n                                   linkbefore=['get_int.c']),\n    'pta_regression3'      : Test('pta_regression2.c' ,\n                                   linkafter=['get_int.c']),\n    'alias_of_return'      : Test('alias_of_return.c',\n                                  compilerparams=['-O1']),\n    'regression1'          : Test('regression1.c'),\n    'fptoui'               : Test('fptoui1.c'),\n    'malloc-redef'         : Test('malloc-redef.c'),\n    'pta-inv-infinite-loop': Test('pta-inv-infinite-loop.c',\n                                  requiredparams=['-pta=inv']),\n\n    'threads1'            : Test('threads1.c',\n                                  addparams=['-threads'],\n                                  requiredparams=['-pta=fi']),\n    'undefcall1'          : Test('undefcall1_true-unreach-call.c'),\n    'undefcall2'          : Test('undefcall2_true-unreach-call.c'),\n    'unknown-interproc'   : Test('unknown-interproc.c',\n                                  linkafter=['ptr.c']),\n    'unknown-interproc2'  : Test('unknown-interproc2.c',\n                                  linkafter=['glob_ptr.c']),\n    'unknown-interproc2-a': Test('unknown-interproc2-a.c',\n                                  linkafter=['glob_ptr-a.c']),\n    'unknown-interproc3'  : Test('unknown-interproc3.c',\n                                  linkafter=['a_ptr.c']),\n    'atomic1'             : Test('atomic1.c'),\n    'atomic2'             : Test('atomic2.c'),\n    'atomic3'             : Test('atomic3.c'),\n    'cyclic-realloc'      : Test('cyclic-realloc.c'),\n}\n"
  },
  {
    "path": "tests/slicing-stress.sh",
    "content": "set -e\n\nexport PATH=\"`dirname $0`/../tools\":$PATH\n\nfor i in $(seq 1 100); do\n\tSEED=$(echo $RANDOM)\n\techo \"Seed: $SEED\"\n\tllvm-stress -o slicing-stress-test.ll -seed $SEED\n\tllvm-slicer -c ret -entry \"autogen_SD$SEED\" slicing-stress-test.ll\ndone\n"
  },
  {
    "path": "tests/thread-regions-test-files/pthread_exit.c",
    "content": "#include <pthread.h>\n#include <stdio.h>\n#include <stdlib.h>\n\nvoid *func(void *ptr) {\n    int *x = (int *) ptr;\n    int *ret = (int *) malloc(sizeof(int));\n    int *ret1 = (int *) malloc(sizeof(int));\n    *ret1 = 100;\n    *x += 1;\n    if (*x == 1) {\n        *ret = 42;\n        pthread_exit(ret);\n    } else if (*x == 2) {\n        pthread_exit(ret1);\n    }\n\n    free(ret);\n    pthread_exit(NULL);\n}\n\nint (*ptr)(pthread_t *, const pthread_attr_t *, void *(*) (void *), void *);\n\nint main() {\n    int x = 0;\n    int y = 0;\n    void *ret_val;\n\n    ptr = &pthread_create;\n    pthread_t thread_func;\n\n    ptr(&thread_func, NULL, func, &x);\n    pthread_join(thread_func, &ret_val);\n    free(ret_val);\n    return 0;\n}\n"
  },
  {
    "path": "tests/thread-regions-test-files/simple.c",
    "content": "int sum(int a, int b) {\n    int j;\n    if (a) {\n        j = a + b;\n    } else {\n        j = a - b;\n    }\n    return j;\n}\n\nint main(void) {\n    int i = 2;\n    int j = 3;\n    int a = sum(i, j);\n    a++;\n    int b = a + 3;\n}\n"
  },
  {
    "path": "tests/thread-regions-test.cpp",
    "content": "#include <catch2/catch.hpp>\n\n#include \"dg/PointerAnalysis/PointerAnalysisFI.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n#include \"dg/llvm/ThreadRegions/ControlFlowGraph.h\"\n#include \"dg/llvm/ThreadRegions/ThreadRegion.h\"\n\n#include \"llvm/ThreadRegions/Graphs/GraphBuilder.h\"\n#include \"llvm/ThreadRegions/Nodes/Nodes.h\"\n\n#include <llvm/IR/Function.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/LLVMContext.h>\n#include <llvm/IR/Module.h>\n#include <llvm/IRReader/IRReader.h>\n#include <llvm/Support/SourceMgr.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#include <memory>\n#include <queue>\n#include <string>\n\nusing NodePtr = std::unique_ptr<Node>;\n\nTEST_CASE(\"Test of node class methods\", \"[node]\") {\n    NodePtr node0(createNode<NodeType::GENERAL>()),\n            node1(createNode<NodeType::CALL>());\n\n    REQUIRE(node0->isArtificial());\n    REQUIRE(node0->getType() == NodeType::GENERAL);\n\n    SECTION(\"Incrementing Ids\") { REQUIRE(node0->id() < node1->id()); }\n\n    SECTION(\"createNode creates the rightNode\") {\n        NodePtr General(createNode<NodeType::GENERAL>()),\n                Fork(createNode<NodeType::FORK>()),\n                Join(createNode<NodeType::JOIN>()),\n                Lock(createNode<NodeType::LOCK>()),\n                Unlock(createNode<NodeType::UNLOCK>()),\n                Entry(createNode<NodeType::ENTRY>()),\n                Exit(createNode<NodeType::EXIT>()),\n                Call(createNode<NodeType::CALL>()),\n                CallReturn(createNode<NodeType::CALL_RETURN>()),\n                CallFuncPtr(createNode<NodeType::CALL_FUNCPTR>(nullptr)),\n                Return(createNode<NodeType::RETURN>());\n\n        REQUIRE(General->getType() == NodeType::GENERAL);\n        REQUIRE(Fork->getType() == NodeType::FORK);\n        REQUIRE(Join->getType() == NodeType::JOIN);\n        REQUIRE(Lock->getType() == NodeType::LOCK);\n        REQUIRE(Unlock->getType() == NodeType::UNLOCK);\n        REQUIRE(Entry->getType() == NodeType::ENTRY);\n        REQUIRE(Exit->getType() == NodeType::EXIT);\n        REQUIRE(Call->getType() == NodeType::CALL);\n        REQUIRE(CallReturn->getType() == NodeType::CALL_RETURN);\n        REQUIRE(CallFuncPtr->getType() == NodeType::CALL_FUNCPTR);\n        REQUIRE(Return->getType() == NodeType::RETURN);\n    }\n\n    SECTION(\"nodeTypeToString works correctly\") {\n        std::string General = \"NodeType::GENERAL\";\n        std::string Fork = \"NodeType::FORK\";\n        std::string Join = \"NodeType::JOIN\";\n        std::string Lock = \"NodeType::LOCK\";\n        std::string Unlock = \"NodeType::UNLOCK\";\n        std::string Entry = \"NodeType::ENTRY\";\n        std::string Exit = \"NodeType::EXIT\";\n        std::string Call = \"NodeType::CALL\";\n        std::string CallReturn = \"NodeType::CALL_RETURN\";\n        std::string CallFuncPtr = \"NodeType::CALL_FUNCPTR\";\n        std::string Return = \"NodeType::RETURN\";\n\n        REQUIRE(nodeTypeToString(NodeType::GENERAL) == General);\n        REQUIRE(nodeTypeToString(NodeType::FORK) == Fork);\n        REQUIRE(nodeTypeToString(NodeType::JOIN) == Join);\n        REQUIRE(nodeTypeToString(NodeType::LOCK) == Lock);\n        REQUIRE(nodeTypeToString(NodeType::UNLOCK) == Unlock);\n        REQUIRE(nodeTypeToString(NodeType::ENTRY) == Entry);\n        REQUIRE(nodeTypeToString(NodeType::EXIT) == Exit);\n        REQUIRE(nodeTypeToString(NodeType::CALL) == Call);\n        REQUIRE(nodeTypeToString(NodeType::CALL_RETURN) == CallReturn);\n        REQUIRE(nodeTypeToString(NodeType::CALL_FUNCPTR) == CallFuncPtr);\n        REQUIRE(nodeTypeToString(NodeType::RETURN) == Return);\n    }\n\n    SECTION(\"Node can correctly output its type in dot format\") {\n        auto nodeString = node1->dump();\n        auto pos = nodeString.find(nodeTypeToString(NodeType::CALL));\n        REQUIRE(pos != std::string::npos);\n    }\n\n    SECTION(\"add new successor increases size of successors\"\n            \" of node0 and size of predecessors of node 1\") {\n        REQUIRE(node0->addSuccessor(node1.get()));\n        REQUIRE(node0->successors().size() == 1);\n        REQUIRE(node1->predecessors().size() == 1);\n\n        SECTION(\"adding the same successor for the second time does nothing\") {\n            REQUIRE_FALSE(node0->addSuccessor(node1.get()));\n            REQUIRE(node0->successors().size() == 1);\n            REQUIRE(node1->predecessors().size() == 1);\n        }\n    }\n\n    SECTION(\"Removing node1 from successors of node0\"\n            \" decreases size of successors of node0 and predecessors of \"\n            \"node1\") {\n        REQUIRE(node0->successors().empty());\n        REQUIRE(node0->addSuccessor(node1.get()));\n        auto foundNodeIterator = node0->successors().find(node1.get());\n        REQUIRE_FALSE(foundNodeIterator == node0->successors().end());\n        REQUIRE(node0->successors().size() == 1);\n        REQUIRE(node0->removeSuccessor(node1.get()));\n        REQUIRE(node0->successors().empty());\n    }\n\n    SECTION(\"Removing nonexistent successor does nothing\") {\n        REQUIRE(node0->successors().empty());\n        REQUIRE_FALSE(node0->removeSuccessor(node1.get()));\n        REQUIRE(node0->successors().empty());\n        NodePtr node2(createNode<NodeType::GENERAL>());\n        REQUIRE(node0->addSuccessor(node1.get()));\n        REQUIRE(node0->successors().size() == 1);\n        REQUIRE_FALSE(node0->removeSuccessor(node2.get()));\n        REQUIRE(node0->successors().size() == 1);\n    }\n\n    SECTION(\"add new predecessor increases size of predecessors\"\n            \" of node0 and size of successors of node 1\") {\n        REQUIRE(node0->predecessors().empty());\n        REQUIRE(node0->addPredecessor(node1.get()));\n        REQUIRE(node0->predecessors().size() == 1);\n        REQUIRE(node1->successors().size() == 1);\n\n        SECTION(\"adding the same predecessor for the second time does \"\n                \"nothing\") {\n            REQUIRE_FALSE(node0->addPredecessor(node1.get()));\n            REQUIRE(node0->predecessors().size() == 1);\n            REQUIRE(node1->successors().size() == 1);\n        }\n    }\n\n    SECTION(\"Removing node1 from predecessors of node0\"\n            \" decreases size of successors of node0 and predecessors of \"\n            \"node1\") {\n        REQUIRE(node0->successors().empty());\n        REQUIRE(node0->addPredecessor(node1.get()));\n        auto foundNodeIterator = node0->predecessors().find(node1.get());\n        REQUIRE_FALSE(foundNodeIterator == node0->predecessors().end());\n        REQUIRE(node0->predecessors().size() == 1);\n        REQUIRE(node0->removePredecessor(node1.get()));\n        REQUIRE(node0->successors().empty());\n    }\n\n    SECTION(\"Removing nonexistent predecessor does nothing\") {\n        REQUIRE(node0->predecessors().empty());\n        REQUIRE_FALSE(node0->removePredecessor(node1.get()));\n        REQUIRE(node0->successors().empty());\n        NodePtr node2(createNode<NodeType::GENERAL>());\n        REQUIRE(node0->addPredecessor(node1.get()));\n        REQUIRE(node0->predecessors().size() == 1);\n        REQUIRE_FALSE(node0->removePredecessor(node2.get()));\n        REQUIRE(node0->predecessors().size() == 1);\n    }\n\n    SECTION(\"Adding nullptr as successor should return false\") {\n        REQUIRE(node0->successors().empty());\n        REQUIRE_FALSE(node0->addSuccessor(nullptr));\n        REQUIRE(node0->successors().empty());\n    }\n\n    SECTION(\"Adding nullptr as predecessor should return false\") {\n        REQUIRE(node0->predecessors().empty());\n        REQUIRE_FALSE(node0->addPredecessor(nullptr));\n        REQUIRE(node0->predecessors().empty());\n    }\n\n    SECTION(\"Removing nullptr from successors should return false\") {\n        REQUIRE(node0->successors().empty());\n        REQUIRE_FALSE(node0->removeSuccessor(nullptr));\n        REQUIRE(node0->successors().empty());\n    }\n\n    SECTION(\"Removing nullptr from predecessors should return false\") {\n        REQUIRE(node0->predecessors().empty());\n        REQUIRE_FALSE(node0->removePredecessor(nullptr));\n        REQUIRE(node0->predecessors().empty());\n    }\n}\n\nTEST_CASE(\"Test of ThreadRegion class methods\", \"[ThreadRegion]\") {\n    NodePtr node0(createNode<NodeType::GENERAL>()),\n            node1(createNode<NodeType::GENERAL>());\n\n    std::unique_ptr<ThreadRegion> threadRegion0(new ThreadRegion(node0.get())),\n            threadRegion1(new ThreadRegion(node1.get()));\n\n    REQUIRE(threadRegion0->successors().empty());\n    REQUIRE(threadRegion1->successors().empty());\n\n    SECTION(\"Incrementing Ids\") {\n        REQUIRE(threadRegion0->id() < threadRegion1->id());\n    }\n\n    SECTION(\"Name of node is set properly\") {\n        std::string dotname = \"cluster\" + std::to_string(threadRegion0->id());\n        REQUIRE(dotname == threadRegion0->dotName());\n    }\n\n    SECTION(\"Add successor\") {\n        REQUIRE(threadRegion0->addSuccessor(threadRegion1.get()));\n        REQUIRE(threadRegion0->successors().size() == 1);\n        REQUIRE(threadRegion1->predecessors().size() == 1);\n    }\n\n    SECTION(\"Add predecessor\") {\n        REQUIRE(threadRegion0->addPredecessor(threadRegion1.get()));\n        REQUIRE(threadRegion0->predecessors().size() == 1);\n        REQUIRE(threadRegion1->successors().size() == 1);\n    }\n\n    SECTION(\"Remove existing successor\") {\n        threadRegion0->addSuccessor(threadRegion1.get());\n        REQUIRE(threadRegion0->successors().size() == 1);\n        REQUIRE(threadRegion0->removeSuccessor(threadRegion1.get()));\n        REQUIRE(threadRegion0->successors().empty());\n    }\n\n    SECTION(\"Removing existing predecessor\") {\n        threadRegion0->addPredecessor(threadRegion1.get());\n        REQUIRE(threadRegion0->predecessors().size() == 1);\n        REQUIRE(threadRegion0->removePredecessor(threadRegion1.get()));\n        REQUIRE(threadRegion0->predecessors().empty());\n    }\n\n    SECTION(\"Removing nonexistent successor\") {\n        REQUIRE_FALSE(threadRegion0->removeSuccessor(threadRegion1.get()));\n    }\n\n    SECTION(\"Removing nonexistent predecessor\") {\n        REQUIRE_FALSE(threadRegion0->removePredecessor(threadRegion1.get()));\n    }\n\n    SECTION(\"Remove nullptr from successor\") {\n        REQUIRE_FALSE(threadRegion0->removeSuccessor(nullptr));\n    }\n\n    SECTION(\"Remove nullptr from predecessor\") {\n        REQUIRE_FALSE(threadRegion0->removePredecessor(nullptr));\n    }\n}\n\nTEST_CASE(\"Test of EntryNode class methods\", \"[EntryNode]\") {\n    std::unique_ptr<ForkNode> forkNode(createNode<NodeType::FORK>());\n    std::unique_ptr<EntryNode> entryNode(createNode<NodeType::ENTRY>());\n\n    SECTION(\"Add fork predecessor\") {\n        REQUIRE(entryNode->addForkPredecessor(forkNode.get()));\n        REQUIRE(entryNode->forkPredecessors().size() == 1);\n        REQUIRE_FALSE(entryNode->addForkPredecessor(forkNode.get()));\n        REQUIRE(entryNode->forkPredecessors().size() == 1);\n        REQUIRE_FALSE(entryNode->addForkPredecessor(nullptr));\n        REQUIRE(entryNode->forkPredecessors().size() == 1);\n    }\n\n    SECTION(\"Remove fork predecessor\") {\n        entryNode->addForkPredecessor(forkNode.get());\n        REQUIRE(entryNode->forkPredecessors().size() == 1);\n        REQUIRE(entryNode->removeForkPredecessor(forkNode.get()));\n        REQUIRE(entryNode->forkPredecessors().empty());\n        REQUIRE_FALSE(entryNode->removeForkPredecessor(forkNode.get()));\n        REQUIRE(entryNode->forkPredecessors().empty());\n    }\n}\n\nTEST_CASE(\"Test of ExitNode class methods\", \"[ExitNode]\") {\n    std::unique_ptr<JoinNode> joinNode(createNode<NodeType::JOIN>());\n    std::unique_ptr<ExitNode> exitNode(createNode<NodeType::EXIT>());\n\n    SECTION(\"Add join successor\") {\n        REQUIRE(exitNode->addJoinSuccessor(joinNode.get()));\n        REQUIRE(exitNode->joinSuccessors().size() == 1);\n        REQUIRE_FALSE(exitNode->addJoinSuccessor(joinNode.get()));\n        REQUIRE(exitNode->joinSuccessors().size() == 1);\n        REQUIRE_FALSE(exitNode->addJoinSuccessor(nullptr));\n        REQUIRE(exitNode->joinSuccessors().size() == 1);\n    }\n\n    SECTION(\"Remove join successor\") {\n        exitNode->addJoinSuccessor(joinNode.get());\n        REQUIRE(exitNode->joinSuccessors().size() == 1);\n        REQUIRE(exitNode->removeJoinSuccessor(joinNode.get()));\n        REQUIRE(exitNode->joinSuccessors().empty());\n        REQUIRE_FALSE(exitNode->removeJoinSuccessor(joinNode.get()));\n        REQUIRE(exitNode->joinSuccessors().empty());\n        REQUIRE_FALSE(exitNode->removeJoinSuccessor(nullptr));\n        REQUIRE(exitNode->joinSuccessors().empty());\n    }\n}\n\nTEST_CASE(\"Test of ForkNode class methods\", \"[ForkNode]\") {\n    std::unique_ptr<ForkNode> forkNode(createNode<NodeType::FORK>());\n    std::unique_ptr<JoinNode> joinNode(createNode<NodeType::JOIN>());\n    std::unique_ptr<EntryNode> entryNode(createNode<NodeType::ENTRY>());\n\n    SECTION(\"Add corresponding join\") {\n        REQUIRE(forkNode->addCorrespondingJoin(joinNode.get()));\n        REQUIRE(forkNode->correspondingJoins().size() == 1);\n        REQUIRE_FALSE(forkNode->addCorrespondingJoin(joinNode.get()));\n        REQUIRE(forkNode->correspondingJoins().size() == 1);\n        REQUIRE_FALSE(forkNode->addCorrespondingJoin(nullptr));\n        REQUIRE(forkNode->correspondingJoins().size() == 1);\n    }\n\n    SECTION(\"Add fork successor\") {\n        REQUIRE(forkNode->addForkSuccessor(entryNode.get()));\n        REQUIRE(forkNode->forkSuccessors().size() == 1);\n        REQUIRE_FALSE(forkNode->addForkSuccessor(entryNode.get()));\n        REQUIRE(forkNode->forkSuccessors().size() == 1);\n        REQUIRE_FALSE(forkNode->addForkSuccessor(nullptr));\n        REQUIRE(forkNode->forkSuccessors().size() == 1);\n    }\n\n    SECTION(\"Remove fork successor\") {\n        forkNode->addForkSuccessor(entryNode.get());\n        REQUIRE(forkNode->forkSuccessors().size() == 1);\n        REQUIRE(forkNode->removeForkSuccessor(entryNode.get()));\n        REQUIRE(forkNode->forkSuccessors().empty());\n        REQUIRE_FALSE(forkNode->removeForkSuccessor(entryNode.get()));\n        REQUIRE(forkNode->forkSuccessors().empty());\n        REQUIRE_FALSE(forkNode->removeForkSuccessor(nullptr));\n        REQUIRE(forkNode->forkSuccessors().empty());\n    }\n}\n\nTEST_CASE(\"Test of JoinNode class methods\", \"[JoinNode]\") {\n    std::unique_ptr<JoinNode> joinNode(createNode<NodeType::JOIN>());\n    std::unique_ptr<ForkNode> forkNode(createNode<NodeType::FORK>());\n    std::unique_ptr<ExitNode> exitNode(createNode<NodeType::EXIT>());\n\n    SECTION(\"Add corresponding fork\") {\n        REQUIRE(joinNode->addCorrespondingFork(forkNode.get()));\n        REQUIRE(joinNode->correspondingForks().size() == 1);\n        REQUIRE_FALSE(joinNode->addCorrespondingFork(forkNode.get()));\n        REQUIRE(joinNode->correspondingForks().size() == 1);\n        REQUIRE_FALSE(joinNode->addCorrespondingFork(nullptr));\n        REQUIRE(joinNode->correspondingForks().size() == 1);\n    }\n\n    SECTION(\"Add join predecessor\") {\n        REQUIRE(joinNode->addJoinPredecessor(exitNode.get()));\n        REQUIRE(joinNode->joinPredecessors().size() == 1);\n        REQUIRE_FALSE(joinNode->addJoinPredecessor(exitNode.get()));\n        REQUIRE(joinNode->joinPredecessors().size() == 1);\n        REQUIRE_FALSE(joinNode->addJoinPredecessor(nullptr));\n        REQUIRE(joinNode->joinPredecessors().size() == 1);\n    }\n\n    SECTION(\"Remove join predecessor\") {\n        joinNode->addJoinPredecessor(exitNode.get());\n        REQUIRE(joinNode->joinPredecessors().size() == 1);\n        REQUIRE(joinNode->removeJoinPredecessor(exitNode.get()));\n        REQUIRE(joinNode->joinPredecessors().empty());\n        REQUIRE_FALSE(joinNode->removeJoinPredecessor(exitNode.get()));\n        REQUIRE(joinNode->joinPredecessors().empty());\n        REQUIRE_FALSE(joinNode->removeJoinPredecessor(nullptr));\n        REQUIRE(joinNode->joinPredecessors().empty());\n    }\n}\n\nTEST_CASE(\"Test of LockNode class methods\", \"[LockNode]\") {\n    std::unique_ptr<LockNode> lockNode(createNode<NodeType::LOCK>());\n    std::unique_ptr<UnlockNode> unlockNode(createNode<NodeType::UNLOCK>());\n\n    SECTION(\"Add corresponding unlock\") {\n        REQUIRE(lockNode->addCorrespondingUnlock(unlockNode.get()));\n        REQUIRE(lockNode->correspondingUnlocks().size() == 1);\n        REQUIRE_FALSE(lockNode->addCorrespondingUnlock(unlockNode.get()));\n        REQUIRE(lockNode->correspondingUnlocks().size() == 1);\n        REQUIRE_FALSE(lockNode->addCorrespondingUnlock(nullptr));\n        REQUIRE(lockNode->correspondingUnlocks().size() == 1);\n    }\n}\n\nTEST_CASE(\"Test of GraphBuilder class methods\", \"[GraphBuilder]\") {\n    using namespace llvm;\n    LLVMContext context;\n    SMDiagnostic SMD;\n    std::unique_ptr<Module> M = parseIRFile(SIMPLE_FILE, SMD, context);\n    const Function *function = M->getFunction(\"sum\");\n    dg::DGLLVMPointerAnalysis pointsToAnalysis(M.get(), \"main\",\n                                               dg::Offset::UNKNOWN, true);\n    pointsToAnalysis.run();\n    std::unique_ptr<GraphBuilder> graphBuilder(\n            new GraphBuilder(&pointsToAnalysis));\n\n    SECTION(\"Test of buildInstruction and findInstruction\") {\n        auto inst = graphBuilder->buildInstruction(nullptr);\n        REQUIRE(inst.first == nullptr);\n        REQUIRE(inst.second == nullptr);\n        REQUIRE_FALSE(graphBuilder->findInstruction(nullptr));\n        for (const auto &block : *function) {\n            for (const auto &instruction : block) {\n                inst = graphBuilder->buildInstruction(&instruction);\n                REQUIRE_FALSE(inst.first == nullptr);\n                REQUIRE_FALSE(inst.second == nullptr);\n                auto *instructionNode =\n                        graphBuilder->findInstruction(&instruction);\n                REQUIRE_FALSE(instructionNode == nullptr);\n                inst = graphBuilder->buildInstruction(&instruction);\n                REQUIRE(inst.first == nullptr);\n                REQUIRE(inst.second == nullptr);\n            }\n        }\n    }\n\n    SECTION(\"Test of buildBlock and findBlock\") {\n        auto nodeSeq = graphBuilder->buildBlock(nullptr);\n        REQUIRE_FALSE(graphBuilder->findBlock(nullptr));\n        REQUIRE(nodeSeq.first == nullptr);\n        REQUIRE(nodeSeq.second == nullptr);\n        for (const auto &block : *function) {\n            nodeSeq = graphBuilder->buildBlock(&block);\n            REQUIRE_FALSE(nodeSeq.first == nullptr);\n            REQUIRE_FALSE(nodeSeq.second == nullptr);\n            auto *blockGraph = graphBuilder->findBlock(&block);\n            REQUIRE_FALSE(blockGraph == nullptr);\n            nodeSeq = graphBuilder->buildBlock(&block);\n            REQUIRE(nodeSeq.first == nullptr);\n            REQUIRE(nodeSeq.second == nullptr);\n        }\n    }\n\n    SECTION(\"Test of buildFunction and findFunction\") {\n        auto nodeSeq = graphBuilder->buildFunction(nullptr);\n        REQUIRE(nodeSeq.first == nullptr);\n        REQUIRE(nodeSeq.second == nullptr);\n        REQUIRE_FALSE(graphBuilder->findFunction(nullptr));\n\n        for (auto &function : M->getFunctionList()) {\n            nodeSeq = graphBuilder->buildFunction(&function);\n            REQUIRE_FALSE(nodeSeq.first == nullptr);\n            REQUIRE_FALSE(nodeSeq.second == nullptr);\n            auto *functionGraph = graphBuilder->findFunction(&function);\n            REQUIRE_FALSE(functionGraph == nullptr);\n            nodeSeq = graphBuilder->buildFunction(&function);\n            REQUIRE(nodeSeq.first == nullptr);\n            REQUIRE(nodeSeq.second == nullptr);\n        }\n    }\n}\n\nTEST_CASE(\"GraphBuilder build tests\", \"[GraphBuilder]\") {\n    using namespace llvm;\n    LLVMContext context;\n    SMDiagnostic SMD;\n    std::unique_ptr<Module> M = parseIRFile(PTHREAD_EXIT_FILE, SMD, context);\n    dg::DGLLVMPointerAnalysis pointsToAnalysis(M.get(), \"main\",\n                                               dg::Offset::UNKNOWN, true);\n    pointsToAnalysis.run();\n    std::unique_ptr<GraphBuilder> graphBuilder(\n            new GraphBuilder(&pointsToAnalysis));\n\n    SECTION(\"Undefined function which is not really important for us\") {\n        auto *function = M->getFunction(\"free\");\n        auto nodeSeq = graphBuilder->buildFunction(function);\n        REQUIRE(nodeSeq.first == nodeSeq.second);\n    }\n\n    SECTION(\"Pthread exit\") {\n        auto *function = M->getFunction(\"func\");\n        std::set<const llvm::Instruction *> callInstruction;\n\n        const llvm::CallInst *pthreadExitCall = nullptr;\n        for (auto &block : *function) {\n            for (auto &instruction : block) {\n                if (isa<llvm::CallInst>(instruction)) {\n                    auto *callInst = dyn_cast<llvm::CallInst>(&instruction);\n#if LLVM_VERSION_MAJOR >= 8\n                    auto *calledValue = callInst->getCalledOperand();\n#else\n                    auto calledValue = callInst->getCalledValue();\n#endif\n                    if (isa<llvm::Function>(calledValue)) {\n                        auto *function = dyn_cast<llvm::Function>(calledValue);\n                        if (function->getName().equals(\"pthread_exit\")) {\n                            pthreadExitCall = callInst;\n                        }\n                    }\n                }\n            }\n        }\n\n        REQUIRE(pthreadExitCall != nullptr);\n        auto nodeSeq = graphBuilder->buildInstruction(pthreadExitCall);\n        REQUIRE(nodeSeq.first != nodeSeq.second);\n        REQUIRE(nodeSeq.second->getType() == NodeType::RETURN);\n        REQUIRE_FALSE(nodeSeq.first->isArtificial());\n        REQUIRE(nodeSeq.second->isArtificial());\n        REQUIRE(nodeSeq.first->successors().size() == 1);\n        REQUIRE(nodeSeq.second->predecessors().size() == 1);\n        REQUIRE(nodeSeq.first->successors().find(nodeSeq.second) !=\n                nodeSeq.first->successors().end());\n    }\n\n    SECTION(\"Func pointer call\") {\n        auto *function = M->getFunction(\"main\");\n        std::set<const llvm::Instruction *> callInstruction;\n\n        for (auto &block : *function) {\n            for (auto &instruction : block) {\n                if (isa<llvm::CallInst>(instruction)) {\n                    callInstruction.insert(&instruction);\n                }\n            }\n        }\n\n        const llvm::CallInst *funcPtrCall = nullptr;\n\n        for (const auto *instruction : callInstruction) {\n            const auto *callInst = dyn_cast<llvm::CallInst>(instruction);\n#if LLVM_VERSION_MAJOR >= 8\n            auto *calledValue = callInst->getCalledOperand();\n#else\n            auto calledValue = callInst->getCalledValue();\n#endif\n            if (!isa<llvm::Function>(calledValue)) {\n                funcPtrCall = callInst;\n            }\n        }\n\n        REQUIRE(funcPtrCall != nullptr);\n\n        auto nodeSeq = graphBuilder->buildInstruction(funcPtrCall);\n        REQUIRE(nodeSeq.first != nullptr);\n        REQUIRE(nodeSeq.second != nullptr);\n        REQUIRE_FALSE(nodeSeq.first->isArtificial());\n        REQUIRE(nodeSeq.first->successors().size() == 1);\n        auto successor = nodeSeq.first->successors();\n        for (auto *node : nodeSeq.first->successors()) {\n            REQUIRE(node->isArtificial());\n        }\n        std::queue<Node *> queue;\n        std::set<Node *> visited;\n\n        REQUIRE(nodeSeq.first->getType() == NodeType::CALL_FUNCPTR);\n        REQUIRE(nodeSeq.second->getType() == NodeType::FORK);\n        auto *fork = castNode<NodeType::FORK>(nodeSeq.second);\n        REQUIRE(fork->forkSuccessors().size() == 1);\n        visited.insert(*fork->forkSuccessors().begin());\n        queue.push(*fork->forkSuccessors().begin());\n        while (!queue.empty()) {\n            Node *currentNode = queue.front();\n            queue.pop();\n            for (auto *successor : currentNode->successors()) {\n                if (visited.find(successor) == visited.end()) {\n                    visited.insert(successor);\n                    queue.push(successor);\n                }\n            }\n        }\n        std::set<Node *> realNodes;\n        for (auto *node : visited) {\n            if (!node->isArtificial()) {\n                realNodes.insert(node);\n            }\n        }\n        REQUIRE(realNodes.size() > 30);\n        REQUIRE(realNodes.size() < 60);\n    }\n\n    SECTION(\"ForkNode iterator test\") {\n        std::unique_ptr<ForkNode> forkNode(createNode<NodeType::FORK>());\n        std::unique_ptr<EntryNode> entryNode0(createNode<NodeType::ENTRY>());\n        NodePtr node0(createNode<NodeType::GENERAL>());\n\n        forkNode->addForkSuccessor(entryNode0.get());\n        forkNode->addSuccessor(node0.get());\n\n        int i = 0;\n\n        for (auto it = forkNode->begin(), end = forkNode->end(); it != end;\n             ++it) {\n            ++i;\n        }\n\n        REQUIRE(i == 2);\n    }\n}\n"
  },
  {
    "path": "tests/value-relations-test.cpp",
    "content": "#include \"dg/ValueRelations/RelationsGraph.h\"\n#include <catch2/catch.hpp>\n#include <iostream>\n#include <sstream>\n\nusing namespace dg::vr;\n\nstruct Dummy {\n    void areMerged(const Bucket & /*unused*/, const Bucket & /*unused*/) {}\n};\n\nusing RelGraph = RelationsGraph<Dummy>;\n\nusing CollectedEdges = std::vector<Bucket::RelationEdge>;\nusing RelationsMap = RelGraph::RelationsMap;\n\nstd::string dump(__attribute__((unused)) const CollectedEdges &edges) {\n    std::ostringstream out;\n    out << \"{ \";\n#ifndef NDEBUG\n    for (const auto &item : edges)\n        out << item << \", \";\n#endif\n    out << \"}\";\n    return out.str();\n}\n\nstd::string dump(__attribute__((unused)) const RelationsMap &map) {\n    std::ostringstream out;\n    out << \"{ \";\n#ifndef NDEBUG\n    for (const auto &pair : map) {\n        out << \"{ \" << pair.first.get().id << \": \" << pair.second << \" }, \";\n    }\n#endif\n    out << \"}\" << std::endl;\n    return out.str();\n}\n\nCollectedEdges collect(RelGraph::iterator begin, RelGraph::iterator end) {\n    CollectedEdges result;\n\n    std::copy(begin, end, std::back_inserter(result));\n    return result;\n}\n\nvoid checkSize(const CollectedEdges &result,\n               __attribute__((unused)) const RelGraph &graph,\n               size_t expectedSize) {\n    INFO(\"result \" << dump(result));\n#ifndef NDEBUG\n    INFO(\"graph:\\n\" << graph);\n#endif\n    CHECK(result.size() == expectedSize);\n}\n\nvoid reportSet(RelGraph &graph, const Bucket &one, Relations::Type rel,\n               const Bucket &two) {\n    INFO(\"setting \" << one.id << \" \" << rel << \" \" << two.id);\n    graph.addRelation(one, rel, two);\n    INFO(\"done\");\n}\n\nvoid checkEdges(const RelGraph &graph, size_t relationsSet) {\n    SECTION(\"all\") {\n        CollectedEdges result =\n                collect(graph.begin(allRelations, false), graph.end());\n        checkSize(result, graph, relationsSet * 2 + graph.size());\n    }\n    SECTION(\"undirected\") {\n        CollectedEdges result = collect(graph.begin(), graph.end());\n        checkSize(result, graph, relationsSet + graph.size());\n    }\n}\n\nvoid checkRelations(const RelGraph &graph, const Bucket &start,\n                    size_t expectedSize) {\n    INFO(\"explored from \" << start.id);\n    CollectedEdges result = collect(graph.begin_related(start, allRelations),\n                                    graph.end_related(start));\n    checkSize(result, graph, expectedSize);\n}\n\nvoid checkRelations(const RelationsMap &real, const RelationsMap &expected) {\n    INFO(\"real \" << dump(real));\n    INFO(\"expected \" << dump(expected));\n    for (const auto &pair : expected) {\n        auto found = real.find(pair.first);\n        if (found == real.end()) {\n            INFO(\"no relations found for \" << pair.first.get().id);\n            CHECK(false);\n        } else {\n            INFO(\"relations to \" << pair.first.get().id);\n            CHECK(found->second == pair.second);\n        }\n    }\n    CHECK(real.size() == expected.size());\n}\n\nvoid checkRelations(const RelGraph &graph, const Bucket &start,\n                    const RelationsMap &expected) {\n    INFO(\"relations from \" << start.id);\n    RelationsMap real = graph.getRelated(start, allRelations);\n    checkRelations(real, expected);\n}\n\nbool forbids(Relations::Type one, Relations::Type two) {\n    return Relations::conflicting(one).has(two);\n}\n\nbool inferrs(Relations::Type one, Relations::Type two) {\n    switch (one) {\n    case Relations::SLE:\n        return two == Relations::NE || two == Relations::SLT;\n    case Relations::ULE:\n        return two == Relations::NE || two == Relations::ULT;\n    case Relations::SGE:\n        return two == Relations::NE || two == Relations::SGT;\n    case Relations::UGE:\n        return two == Relations::NE || two == Relations::UGT;\n    case Relations::NE:\n        return nonStrict.has(two) || strict.has(two);\n    case Relations::EQ:\n    case Relations::SLT:\n    case Relations::ULT:\n    case Relations::SGT:\n    case Relations::UGT:\n    case Relations::PT:\n    case Relations::PF:\n        return false;\n    }\n    assert(0 && \"unreachable\");\n    abort();\n}\n\n#define GEN_NONEQ_REL()                                                        \\\n    GENERATE(from_range(std::next(Relations::all.begin()),                     \\\n                        Relations::all.end()))\n#define GEN_REL() GENERATE(from_range(Relations::all))\n\nTEST_CASE(\"edge iterator\") {\n    Dummy d;\n    RelGraph graph(d);\n\n    SECTION(\"no nodes\") { CHECK(graph.begin() == graph.end()); }\n\n    const Bucket &one = graph.getNewBucket();\n\n    SECTION(\"one node\") { checkEdges(graph, 0); }\n\n    const Bucket &two = graph.getNewBucket();\n\n    SECTION(\"two nodes path\") {\n        Relations::Type relation = GEN_NONEQ_REL();\n\n        DYNAMIC_SECTION(\"setting \" << relation) {\n            reportSet(graph, one, relation, two);\n\n            checkEdges(graph, 1);\n        }\n    }\n\n    SECTION(\"two nodes cycle\") {\n        Relations::Type relOne = GEN_NONEQ_REL();\n        Relations::Type relTwo = GEN_NONEQ_REL();\n\n        if (!forbids(relOne, relTwo)) {\n            DYNAMIC_SECTION(\"setting \" << relOne << \" \" << relTwo) {\n                reportSet(graph, one, relOne, two);\n                Relations before = graph.getRelated(one, allRelations)[two];\n                reportSet(graph, one, relTwo, two);\n\n                if (nonStrict.has(relOne) &&\n                    relOne == Relations::inverted(relTwo))\n                    checkEdges(graph, 0);\n                else if (before.has(relTwo) || inferrs(relOne, relTwo))\n                    checkEdges(graph, 1);\n                else\n                    checkEdges(graph, 2);\n            }\n        }\n    }\n\n    const Bucket &three = graph.getNewBucket();\n\n    SECTION(\"three node one relation cycle\") {\n        Relations::Type relOne = GEN_NONEQ_REL();\n\n        if (!strict.has(relOne)) {\n            DYNAMIC_SECTION(\"setting \" << relOne) {\n                reportSet(graph, three, relOne, one);\n                reportSet(graph, one, relOne, two);\n                reportSet(graph, two, relOne, three);\n\n                if (nonStrict.has(relOne))\n                    checkEdges(graph, 0);\n                else\n                    checkEdges(graph, 3);\n            }\n        }\n    }\n\n    SECTION(\"three node dag\") {\n        Relations::Type relOne = GEN_NONEQ_REL();\n        Relations::Type relTwo = GEN_NONEQ_REL();\n        DYNAMIC_SECTION(\"setting \" << relOne << \" \" << relTwo) {\n            SECTION(\"chain\") {\n                reportSet(graph, one, relOne, two);\n                reportSet(graph, two, relTwo, three);\n                if (relOne == Relations::PF && relTwo == Relations::PT)\n                    checkEdges(graph, 1);\n                else\n                    checkEdges(graph, 2);\n            }\n\n            SECTION(\"fork 2 - 1 - 3\") {\n                reportSet(graph, one, relOne, two);\n                reportSet(graph, one, relTwo, three);\n                if ((relOne == Relations::PT && relTwo == Relations::PT))\n                    checkEdges(graph, 1);\n                else\n                    checkEdges(graph, 2);\n            }\n\n            SECTION(\"other fork 3 - 2 - 1\") {\n                reportSet(graph, three, relOne, two);\n                reportSet(graph, one, relTwo, two);\n                if ((relOne == Relations::PF && relTwo == Relations::PF))\n                    checkEdges(graph, 1);\n                else\n                    checkEdges(graph, 2);\n            }\n        }\n    }\n\n    SECTION(\"three node different relations cycle\") {\n        Relations::Type relOne = GEN_NONEQ_REL();\n        Relations::Type relTwo = GEN_NONEQ_REL();\n        Relations::Type relThree = GEN_NONEQ_REL();\n        auto ptpf = [](Relations::Type one, Relations::Type two) {\n            return one == Relations::PT && two == Relations::PF;\n        };\n        DYNAMIC_SECTION(\"setting \" << relOne << \" \" << relTwo) {\n            reportSet(graph, one, relOne, two);\n            reportSet(graph, two, relTwo, three);\n            RelationsMap between = graph.getRelated(one, allRelations);\n\n            if (ptpf(relTwo, relOne)) // equals one and three\n                checkEdges(graph, 1);\n            else if ((ptpf(relThree, relTwo) &&\n                      forbids(relOne, Relations::EQ)) ||\n                     (ptpf(relOne, relThree) &&\n                      forbids(relTwo, Relations::EQ)) ||\n                     between[three].conflictsWith(\n                             Relations::inverted(relThree)))\n                checkEdges(graph, 2);\n            else {\n                DYNAMIC_SECTION(\"and \" << relThree) {\n                    reportSet(graph, three, relThree, one);\n\n                    if ((relOne == relTwo && relTwo == relThree &&\n                         nonStrict.has(relOne)))\n                        checkEdges(graph, 0);\n                    else if (ptpf(relThree, relTwo) || ptpf(relOne, relThree))\n                        checkEdges(graph, 1);\n                    else if (between[three].has(Relations::inverted(relThree)))\n                        checkEdges(graph, 2);\n                    else\n                        checkEdges(graph, 3);\n                }\n            }\n        }\n    }\n}\n\nTEST_CASE(\"testing relations\") {\n    Dummy d;\n    RelGraph graph(d);\n\n    const Bucket &one = graph.getNewBucket();\n    const Bucket &two = graph.getNewBucket();\n\n    SECTION(\"unrelated\") {\n        Relations::Type rel = GEN_REL();\n        DYNAMIC_SECTION(rel) {\n            REQUIRE(!graph.areRelated(one, rel, two));\n            REQUIRE(!graph.areRelated(two, rel, one));\n        }\n    }\n\n    SECTION(\"reflexive\") {\n        REQUIRE(graph.areRelated(one, Relations::EQ, one));\n        REQUIRE(graph.areRelated(two, Relations::EQ, two));\n    }\n\n    SECTION(\"set and test\") {\n        Relations::Type rel = GEN_REL();\n        DYNAMIC_SECTION(rel) {\n            graph.addRelation(one, rel, two);\n#ifndef NDEBUG\n            INFO(graph);\n#endif\n            if (rel == Relations::EQ)\n                CHECK(graph.areRelated(one, rel, one));\n            else {\n                CHECK(graph.areRelated(one, rel, two));\n            }\n        }\n    }\n\n    SECTION(\"transitive\") {\n        const Bucket &three = graph.getNewBucket();\n\n        Relations::Type fst = GENERATE(Relations::SLT, Relations::SLE,\n                                       Relations::ULT, Relations::ULE);\n        Relations::Type snd = GENERATE(Relations::SLT, Relations::SLE,\n                                       Relations::ULT, Relations::ULE);\n\n        if (Relations::isSigned(fst) == Relations::isSigned(snd)) {\n            graph.addRelation(one, fst, two);\n            graph.addRelation(two, snd, three);\n\n            Relations::Type x = nonStrict.has(fst) && nonStrict.has(snd)\n                                        ? fst\n                                        : (Relations::isStrict(fst)\n                                                   ? fst\n                                                   : Relations::getStrict(fst));\n            CHECK(graph.areRelated(one, x, three));\n        }\n    }\n}\n\nTEST_CASE(\"big graph\") {\n    Dummy d;\n    RelGraph graph(d);\n\n    const Bucket &one = graph.getNewBucket();\n    const Bucket &two = graph.getNewBucket();\n    const Bucket &three = graph.getNewBucket();\n    const Bucket &four = graph.getNewBucket();\n    const Bucket &five = graph.getNewBucket();\n    const Bucket &six = graph.getNewBucket();\n    const Bucket &seven = graph.getNewBucket();\n\n    Relations eq = Relations().eq().addImplied();\n    Relations sle = Relations().sle();\n    Relations slt = Relations().slt().addImplied();\n    Relations ule = Relations().ule();\n    Relations ult = Relations().ult().addImplied();\n    Relations sge = Relations().sge();\n    Relations sgt = Relations().sgt().addImplied();\n    Relations uge = Relations().uge();\n    Relations ugt = Relations().ugt().addImplied();\n    Relations pt = Relations().pt();\n    Relations pf = Relations().pf();\n\n    SECTION(\"SLE cycle\") {\n        graph.addRelation(two, Relations::SGE, one);\n        checkEdges(graph, 1);\n        graph.addRelation(two, Relations::SLE, three);\n        checkEdges(graph, 2);\n        graph.addRelation(three, Relations::SLE, four);\n        checkEdges(graph, 3);\n        graph.addRelation(four, Relations::SLE, five);\n        checkEdges(graph, 4);\n        graph.addRelation(six, Relations::SGE, five);\n        checkEdges(graph, 5);\n        graph.addRelation(seven, Relations::SGE, six);\n        checkEdges(graph, 6);\n        graph.addRelation(seven, Relations::SLE, one);\n        checkEdges(graph, 0);\n    }\n\n    SECTION(\"ULE cycle\") {\n        graph.addRelation(two, Relations::UGE, one);\n        checkEdges(graph, 1);\n        graph.addRelation(two, Relations::ULE, three);\n        checkEdges(graph, 2);\n        graph.addRelation(three, Relations::ULE, four);\n        checkEdges(graph, 3);\n        graph.addRelation(four, Relations::ULE, five);\n        checkEdges(graph, 4);\n        graph.addRelation(six, Relations::UGE, five);\n        checkEdges(graph, 5);\n        graph.addRelation(seven, Relations::UGE, six);\n        checkEdges(graph, 6);\n        graph.addRelation(seven, Relations::ULE, one);\n        checkEdges(graph, 0);\n    }\n\n    SECTION(\"mess\") {\n        graph.addRelation(two, Relations::SGE, three);\n        checkEdges(graph, 1);\n        graph.addRelation(five, Relations::SLE, three);\n        checkEdges(graph, 2);\n        graph.addRelation(six, Relations::PF, four);\n        checkEdges(graph, 3);\n        graph.addRelation(three, Relations::SGE, six);\n        checkEdges(graph, 4);\n        graph.addRelation(five, Relations::SLT, six);\n        checkEdges(graph, 5);\n        graph.addRelation(four, Relations::PT, seven);\n        checkEdges(graph, 5);\n        graph.addRelation(five, Relations::UGT, two);\n        checkEdges(graph, 6);\n        graph.addRelation(five, Relations::UGT, three);\n        checkEdges(graph, 7);\n        graph.addRelation(two, Relations::SLE, three);\n        checkEdges(graph, 5);\n\n        SECTION(\"relations\") {\n            checkRelations(graph, one, 1);\n            checkRelations(graph, two, 5);\n            // three was deleted\n            checkRelations(graph, four, 2);\n            checkRelations(graph, five, 5);\n            checkRelations(graph, six, 4);\n            // seven was deleted\n\n            checkRelations(graph, one, {{one, eq}});\n            checkRelations(graph, two,\n                           {{two, eq},\n                            {five, Relations(sgt).ult().addImplied()},\n                            {six, sge}});\n            checkRelations(graph, four, {{four, eq}, {six, pt}});\n            checkRelations(graph, five,\n                           {{five, eq},\n                            {two, Relations(slt).ugt().addImplied()},\n                            {six, slt}});\n            checkRelations(graph, six,\n                           {{six, eq}, {two, sle}, {four, pf}, {five, sgt}});\n        }\n    }\n\n    SECTION(\"cascade load eq\") {\n        reportSet(graph, one, Relations::PT, three);\n        checkEdges(graph, 1);\n        reportSet(graph, two, Relations::PT, four);\n        checkEdges(graph, 2);\n        reportSet(graph, three, Relations::PT, five);\n        checkEdges(graph, 3);\n        reportSet(graph, four, Relations::PT, six);\n        checkEdges(graph, 4);\n\n        reportSet(graph, seven, Relations::PT, one);\n        checkEdges(graph, 5);\n\n        reportSet(graph, seven, Relations::PT, two);\n        checkEdges(graph, 3);\n\n        SECTION(\"relations\") {\n            checkRelations(graph, seven, 2);\n            checkRelations(graph, one, 3);\n            // two was deleted\n            checkRelations(graph, three, 3);\n            // four was deleted\n            checkRelations(graph, five, 2);\n            // six was deleted\n        }\n    }\n\n    SECTION(\"to first strict\") {\n        reportSet(graph, one, Relations::SGT, three);\n        checkEdges(graph, 1);\n        reportSet(graph, one, Relations::SGE, four);\n        checkEdges(graph, 2);\n        reportSet(graph, one, Relations::SGT, five);\n        checkEdges(graph, 3);\n        reportSet(graph, two, Relations::SGT, five);\n        checkEdges(graph, 4);\n        reportSet(graph, three, Relations::SGE, six);\n        checkEdges(graph, 5);\n        reportSet(graph, four, Relations::SGT, six);\n        checkEdges(graph, 6);\n        reportSet(graph, five, Relations::SGT, seven);\n        checkEdges(graph, 7);\n        reportSet(graph, seven, Relations::UGE, four);\n        checkEdges(graph, 8);\n        reportSet(graph, four, Relations::UGT, six);\n        checkEdges(graph, 9);\n\n        SECTION(\"relations\") {\n            checkRelations(graph, one, 7);\n            checkRelations(graph, two, 3);\n            checkRelations(graph, three, 3);\n            checkRelations(graph, four, 5);\n            checkRelations(graph, five, 4);\n            checkRelations(graph, six, 7);\n            checkRelations(graph, seven, 6);\n\n            checkRelations(graph, one,\n                           {{one, eq},\n                            {three, sgt},\n                            {four, sge},\n                            {five, sgt},\n                            {six, sgt},\n                            {seven, sgt}});\n            checkRelations(graph, two, {{two, eq}, {five, sgt}, {seven, sgt}});\n            checkRelations(graph, three, {{one, slt}, {three, eq}, {six, sge}});\n            checkRelations(graph, four,\n                           {{one, sle},\n                            {four, eq},\n                            {six, Relations(sgt).ugt().addImplied()},\n                            {seven, ule}});\n            checkRelations(graph, five,\n                           {{one, slt}, {two, slt}, {five, eq}, {seven, sgt}});\n            checkRelations(graph, six,\n                           {{one, slt},\n                            {three, sle},\n                            {four, Relations(slt).ult().addImplied()},\n                            {six, eq},\n                            {seven, ult}});\n            checkRelations(graph, seven,\n                           {{one, slt},\n                            {two, slt},\n                            {four, uge},\n                            {five, slt},\n                            {six, ugt},\n                            {seven, eq}});\n        }\n\n        SECTION(\"strict\") {\n            RelationsMap related = graph.getRelated(one, allRelations, true);\n            checkRelations(related, {{one, eq},\n                                     {three, sgt},\n                                     {four, sge},\n                                     {five, sgt},\n                                     {six, sgt}});\n        }\n    }\n\n    SECTION(\"to first strict tricky\") {\n        reportSet(graph, one, Relations::SGT, two);\n        reportSet(graph, one, Relations::SGE, three);\n        reportSet(graph, three, Relations::SGE, two);\n        reportSet(graph, two, Relations::SGT, four);\n\n        RelationsMap related = graph.getRelated(one, allRelations, true);\n        checkRelations(related, {{one, eq}, {two, sgt}, {three, sge}});\n    }\n}\n"
  },
  {
    "path": "tools/CMakeLists.txt",
    "content": "if (LLVM_DG)\n    include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)\n\n    # generate a git-version.h with a HEAD commit hash tag (if it changed)\n    find_package(Git)\n    if (NOT Git_FOUND OR NOT EXISTS ${CMAKE_SOURCE_DIR}/.git AND NOT GIT_VERSION)\n        set(GIT_VERSION \"unknown\")\n    else()\n        execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD\n                        OUTPUT_STRIP_TRAILING_WHITESPACE\n                        OUTPUT_VARIABLE NEW_GIT_VERSION)\n        if (NOT \"${GIT_VERSION}\" STREQUAL \"${NEW_GIT_VERSION}\")\n            set(GIT_VERSION ${NEW_GIT_VERSION})\n        endif()\n    endif()\n\n    set(GIT_VERSION ${GIT_VERSION} CACHE STRING \"Git version hash\" FORCE)\n    configure_file(git-version.h.in git-version.h @ONLY)\n    include_directories(${CMAKE_CURRENT_BINARY_DIR})\n\n    add_executable(llvm-dg-dump llvm-dg-dump.cpp)\n    target_link_libraries(llvm-dg-dump PRIVATE dgllvmslicer\n                                       PRIVATE ${llvm_bitwriter}\n                                       PRIVATE ${llvm_irreader})\n    if(HAVE_SVF)\n        target_link_libraries(llvm-dg-dump PRIVATE ${SVF_LIBS}\n                                           PRIVATE ${llvm_transformutils})\n    endif()\n\n\tadd_library(dgllvmslicer SHARED\n\t\t    llvm-slicer-metadata.cpp\n\t\t    llvm-slicer-opts.cpp\n\t\t    llvm-slicer-utils.cpp\n\t\t    llvm-slicer-preprocess.cpp\n\t\t    llvm-slicer-crit.cpp)\n\ttarget_link_libraries(dgllvmslicer PUBLIC dgllvmdg)\n\n\tadd_executable(llvm-slicer llvm-slicer.cpp)\n\ttarget_link_libraries(llvm-slicer PRIVATE dgllvmslicer\n\t\t\t\t\t  PRIVATE ${llvm_irreader}\n\t\t\t\t\t  PRIVATE ${llvm_bitwriter})\n    if(HAVE_SVF)\n        target_link_libraries(llvm-slicer PRIVATE ${SVF_LIBS}\n                                          PRIVATE ${llvm_transformutils})\n    endif()\n\n\tadd_executable(llvm-sdg-dump llvm-sdg-dump.cpp)\n\ttarget_link_libraries(llvm-sdg-dump PRIVATE dgllvmslicer\n\t\t\t\t\t    PRIVATE dgllvmsdg\n\t\t\t\t\t    PRIVATE ${SVF_LIBS}\n\t\t\t\t\t    PRIVATE ${llvm_irreader}\n\t\t\t\t\t    )\n\n\tadd_executable(llvm-cg-dump llvm-cg-dump.cpp)\n\ttarget_link_libraries(llvm-cg-dump PRIVATE dgllvmslicer\n\t\t\t\t\t   PRIVATE dgllvmpta\n\t\t\t\t\t   PRIVATE ${llvm_irreader}\n\t\t\t\t\t    )\nif (HAVE_SVF)\n   target_link_libraries(llvm-cg-dump PRIVATE ${SVF_LIBS}\n                                      PRIVATE ${llvm_bitwriter}\n                                      PRIVATE ${llvm_transformutils})\nendif (HAVE_SVF)\n\n\tadd_executable(llvm-cda-dump llvm-cda-dump.cpp)\n\ttarget_link_libraries(llvm-cda-dump PRIVATE dgllvmslicer\n                                            PRIVATE dgllvmcda\n\t\t\t\t\t    PRIVATE ${llvm_irreader}\n\t\t\t\t\t    )\nif (HAVE_SVF)\n   target_link_libraries(llvm-cda-dump PRIVATE ${SVF_LIBS}\n                                      PRIVATE ${llvm_bitwriter}\n                                      PRIVATE ${llvm_transformutils})\nendif (HAVE_SVF)\n\n\tadd_executable(llvm-cda-bench llvm-cda-bench.cpp)\n\ttarget_link_libraries(llvm-cda-bench PRIVATE dgllvmslicer\n                                            PRIVATE dgllvmcda\n\t\t\t\t\t    PRIVATE ${llvm_irreader}\n\t\t\t\t\t    )\n\n\tadd_executable(llvm-cda-stress llvm-cda-stress.cpp)\n\ttarget_link_libraries(llvm-cda-stress PRIVATE dgllvmslicer\n                                            PRIVATE dgcda\n\t\t\t\t\t    PRIVATE ${llvm_irreader}\n\t\t\t\t\t    )\n\n\tadd_executable(llvm-pta-dump llvm-pta-dump.cpp)\n\ttarget_link_libraries(llvm-pta-dump PRIVATE dgllvmpta\n                                            PRIVATE dgllvmslicer)\nif (HAVE_SVF)\n    target_link_libraries(llvm-pta-dump PRIVATE ${SVF_LIBS}\n                                        PRIVATE ${llvm_bitwriter}\n                                        PRIVATE ${llvm_transformutils})\nendif (HAVE_SVF)\n\n\n\ttarget_link_libraries(llvm-pta-dump\n\t\t\t\tPRIVATE ${llvm_irreader})\n\n    add_executable(llvm-pta-ben llvm-pta-ben.cpp)\n    target_link_libraries(llvm-pta-ben PRIVATE dgllvmslicer\n                                       PRIVATE ${llvm_irreader})\n\n\tadd_executable(llvm-pta-compare llvm-pta-compare.cpp)\n\ttarget_link_libraries(llvm-pta-compare PRIVATE dgllvmpta)\n\ttarget_link_libraries(llvm-pta-compare\n                                PRIVATE dgllvmslicer\n\t\t\t\tPRIVATE ${llvm_irreader})\nif (HAVE_SVF)\n\ttarget_link_libraries(llvm-pta-compare PRIVATE ${SVF_LIBS}\n                                               PRIVATE ${llvm_bitwriter}\n                                               PRIVATE ${llvm_transformutils})\nendif (HAVE_SVF)\n\n\n\n\tadd_executable(llvm-dda-dump llvm-dda-dump.cpp)\n\ttarget_link_libraries(llvm-dda-dump PRIVATE dgllvmdda)\n\ttarget_link_libraries(llvm-dda-dump\n                                PRIVATE dgllvmslicer\n\t\t\t\tPRIVATE ${llvm_irreader})\n\n\tadd_executable(llvm-vr-dump llvm-vr-dump.cpp)\n\ttarget_link_libraries(llvm-vr-dump\n\t\t\t\t# dynamic LLVM\n\t\t\t\tPRIVATE dgllvmvra\n\t\t\t\tPRIVATE ${llvm}\n\t\t\t\t# static LLVM\n\t\t\t\tPRIVATE ${llvm_irreader})\n\n\tadd_executable(llvm-to-source llvm-to-source.cpp)\n\ttarget_link_libraries(llvm-to-source\n\t\t\t\t# dynamic LLVM\n\t\t\t\tPRIVATE ${llvm}\n\t\t\t\t# static LLVM\n\t\t\t\tPRIVATE ${llvm_irreader})\n\n        add_executable(llvm-thread-regions-dump llvm-thread-regions-dump.cpp)\n        target_link_libraries(llvm-thread-regions-dump PRIVATE dgllvmthreadregions\n                                                       PRIVATE ${llvm_irreader})\n\n        add_executable(llvm-ntscd-dump llvm-ntscd-dump.cpp)\n        target_link_libraries(llvm-ntscd-dump PRIVATE dgllvmcda\n\t                                      PRIVATE ${llvm_analysis}\n                                              PRIVATE ${llvm_irreader})\n\n\tinstall(TARGETS llvm-slicer\n\t\tRUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})\n\n\tinstall(TARGETS dgllvmslicer\n\t\tLIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})\n\n        install(DIRECTORY include/\n\t        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})\nendif (LLVM_DG)\n"
  },
  {
    "path": "tools/dgtool",
    "content": "#!/usr/bin/env python3\n\nfrom subprocess import call\nfrom sys import argv, stderr, stdout, exit\nfrom os.path import isfile, join, dirname, basename, abspath\nfrom os import chdir, getcwd\nfrom tempfile import mkdtemp\nfrom shutil import rmtree\n\nwd = None\nolddir = getcwd()\ndebug = False\n\ndef err(msg):\n    stdout.flush()\n    stderr.flush()\n    stderr.write('[dgtool]: ' + msg + '\\n')\n\n    if wd:\n        chdir(olddir);\n        printcmd([\"rmtree\", wd])\n        rmtree(wd)\n    exit(1)\n\ndef printcmd(cmd):\n    if debug:\n        print('> {0}'.format(' '.join(cmd)))\n\nprog=None\nclang='clang'\nlink='llvm-link'\n\nclangcmd=[clang, '-emit-llvm', '-c', '-g']\ncmd=[]\nfiles=[]\nbcfiles=[]\nyamlfiles=[]\n\ndef get_tool(prog):\n    # try to use the binaries from the tools/ directory\n    path=f\"./{prog}\"\n    if isfile(path):\n        prog = abspath(path)\n    else:\n        path = join(dirname(argv[0]), prog)\n        if isfile(path):\n            prog = abspath(path)\n        # else keep prog untouched,\n        # maybe it is in PATH var\n    return prog\n\n###\n# Build the commands\noptions=[]\npasses=[]\nnext_is_dg=False\nnext_is_clang=False\nnext_is_opt=False\nall_is_clang=False\ncc_mode = False\nfor x in argv[1:]:\n    if next_is_clang:\n        clangcmd.append(x)\n        next_is_clang = False\n    elif next_is_dg:\n        options.append(x)\n        next_is_dg = False\n    elif next_is_opt:\n        passes.append(x)\n        next_is_opt = False\n    elif x == '-Xclang':\n        next_is_clang = True\n    elif x == '-Xdg':\n        next_is_dg = True\n    elif x == '-Xopt':\n        next_is_opt = True\n    elif x.endswith('.c') or x.endswith('.cpp') or x.endswith('.i'):\n        files.append(abspath(x))\n    elif x.endswith('.bc') or x.endswith('.ll'):\n        bcfiles.append(abspath(x))\n    elif x.endswith('.yml') or x.endswith('.yaml'):\n        yamlfiles.append(abspath(x))\n    else:\n        if all_is_clang: # (all except files)\n            clangcmd.append(x)\n        elif not cmd:\n            # cc mode we just compile, so everything goes to clang\n            if x == 'cc':\n                all_is_clang = True\n                cc_mode = True\n                continue\n            cmd.append(get_tool(x))\n        else:\n            cmd.append(x)\n\nif 'debug' in options or 'dbg' in options:\n    debug=True\n###\n# Try to find the right path to the program\nif not cmd and not cc_mode:\n    err('no command given')\n\nif yamlfiles:\n    try:\n        import yaml\n    except ImportError:\n        err(\"Got YAML file, but does not have yaml module\")\n\n    for fl in yamlfiles:\n        with open(fl) as yf:\n            data = yaml.load(yf, Loader=yaml.FullLoader)\n            inp = data['input_files'] #NOTE is always just one?\n            files.append(join(dirname(fl), inp))\n\ndef repl_suffix(fl):\n    f = basename(fl)\n    if f.endswith('.c') or f.endswith('.i'):\n        return '{0}.bc'.format(f[:-2])\n    elif f.endswith('.cpp'):\n        return '{0}.bc'.format(f[:-4])\n\nif len(files) < 1 and len(bcfiles) < 1:\n    err('No input files given')\n\nif 'tmpdir' in options:\n    ###\n    # Create temporary directory\n    wd = mkdtemp(suffix='dgtool')\n    printcmd([\"chdir\", wd])\n    chdir(wd)\n\n###\n# Issue clang to compile sources to bitcode(s)\nclangcmd += files\nbitcodes = bcfiles + list(map(repl_suffix, files))\nbitcode = None\n\nprintcmd(clangcmd)\nr = call(clangcmd)\nif r != 0:\n    err('clang command return non-zero status')\n\n###\n# Link multiple files if needed\nif len(bitcodes) > 1:\n    bitcode='bitcode.bc'\n    linkcmd=[link, '-o', bitcode] + bitcodes\n\n    printcmd(linkcmd)\n    r = call(linkcmd)\n    if r != 0:\n        err('llvm-link command return non-zero status')\n\nelse:\n    bitcode = bitcodes[0]\n\nif passes:\n    newname = bitcode + '.opt.bc'\n    optcmd = ['opt', bitcode, '-o', newname] + passes\n    printcmd(optcmd)\n    r = call(optcmd)\n    if r != 0:\n        err('opt command return non-zero status')\n\n    bitcode = newname\n\n###\n# Run the tool\nif not cc_mode:\n    cmd.append(bitcode)\n    printcmd(cmd)\n\n    try:\n        r = call(cmd)\n        if r != 0:\n            err('command return non-zero status')\n    except OSError as e:\n            err('command failed: {0}'.format(str(e)))\n\n##\n# remove working directory if we were in it\nif wd:\n    chdir(olddir);\n    # copy the created files here\n    printcmd([\"rmtree\", wd])\n    rmtree(wd)\nexit(0)\n"
  },
  {
    "path": "tools/git-version.h.in",
    "content": "#ifndef DG_GIT_VERSION\n#define DG_GIT_VERSION\n#define GIT_VERSION \"@GIT_VERSION@\"\n#endif // DG_GIT_VERSION\n"
  },
  {
    "path": "tools/include/dg/tools/llvm-slicer-opts.h",
    "content": "#ifndef DG_TOOLS_LLVM_SLICER_OPTS_H_\n#define DG_TOOLS_LLVM_SLICER_OPTS_H_\n\n#include <set>\n#include <vector>\n\n#include <llvm/Support/CommandLine.h>\n\n#include \"dg/llvm/LLVMDependenceGraphBuilder.h\"\n\n// CommandLine Category for slicer options\nextern llvm::cl::OptionCategory SlicingOpts;\n\n// Object representing options for slicer\nstruct SlicerOptions {\n    dg::llvmdg::LLVMDependenceGraphOptions dgOptions{};\n\n    // FIXME: get rid of this once we got the secondary SC\n    std::vector<std::string> additionalSlicingCriteria{};\n\n    // bodies of these functions will not be sliced\n    std::vector<std::string> preservedFunctions{};\n\n    // slice away also the slicing criteria nodes\n    // (if they are not dependent on themselves)\n    bool removeSlicingCriteria{false};\n\n    // do we perform forward slicing?\n    bool forwardSlicing{false};\n\n    // call abort() on those paths that may not\n    // reach the slicing criterion\n    bool cutoffDiverging{true};\n\n    // assume that slicing criteria are not the call-sites\n    // but the instructions that follow the call\n    bool criteriaAreNextInstr{false};\n\n    // string describing the slicing criteria\n    std::string slicingCriteria{};\n    // SC string in the old format\n    std::string legacySlicingCriteria{};\n    // legacy secondary SC\n    std::string legacySecondarySlicingCriteria{};\n\n    std::string inputFile{};\n    std::string outputFile{};\n};\n\n///\n// Return filled SlicerOptions structure.\nSlicerOptions parseSlicerOptions(int argc, char *argv[],\n                                 bool requireCrit = false,\n                                 bool inputFileRequired = true);\n\nstd::vector<const llvm::Value *>\ngetSlicingCriteriaValues(llvm::Module &M, const std::string &slicingCriteria,\n                         const std::string &legacyslicingCriteria,\n                         const std::string &legacySecondaryCriteria,\n                         bool criteria_are_next_instr = false);\n\nbool getSlicingCriteriaNodes(dg::LLVMDependenceGraph &dg,\n                             const std::string &slicingCriteria,\n                             const std::string &legacySlicingCriteria,\n                             const std::string &legacySecondarySlicingCriteria,\n                             std::set<dg::LLVMNode *> &criteria_nodes,\n                             bool criteria_are_next_instr = false);\n\n#endif // DG_TOOLS_LLVM_SLICER_OPTS_H_\n"
  },
  {
    "path": "tools/include/dg/tools/llvm-slicer-preprocess.h",
    "content": "#ifndef LLVM_SLICER_PREPROCESS_H_\n#define LLVM_SLICER_PREPROCESS_H_\n\n#include <vector>\n\nnamespace llvm {\nclass Module;\nclass Instruction;\n} // namespace llvm\n\nnamespace dg {\nnamespace llvmdg {\n\nbool cutoffDivergingBranches(llvm::Module &M, const std::string &entry,\n                             const std::vector<const llvm::Value *> &criteria);\n} // namespace llvmdg\n} // namespace dg\n\n#endif\n"
  },
  {
    "path": "tools/include/dg/tools/llvm-slicer-utils.h",
    "content": "#ifndef DG_LLVM_SLICER_UTILS_H_\n#define DG_LLVM_SLICER_UTILS_H_\n\n#include <functional>\n#include <memory>\n#include <utility>\n#include <vector>\n\n#include <llvm/ADT/StringRef.h>\n#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 7\n#include <llvm/IR/InstIterator.h>\n#endif\n\nnamespace llvm {\nclass LLVMContext;\nclass Module;\n} // namespace llvm\n\nstruct SlicerOptions;\n\nstd::vector<std::string> splitList(const std::string &opt, char sep = ',');\n\nstd::pair<std::vector<std::string>, std::vector<std::string>>\nsplitStringVector(std::vector<std::string> &vec,\n                  std::function<bool(std::string &)> cmpFunc);\n\nvoid replace_suffix(std::string &fl, const std::string &with);\n\ntemplate <typename T>\nbool array_match(llvm::StringRef name, const T &names) {\n    for (auto &n : names) {\n        if (name.equals(n))\n            return true;\n    }\n\n    return false;\n}\n\nvoid setupStackTraceOnError(int argc, char *argv[]);\n\nstd::unique_ptr<llvm::Module> parseModule(const char *tool,\n                                          llvm::LLVMContext &context,\n                                          const SlicerOptions &options);\n\n#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 7\nnamespace llvm {\nclass Function;\nstatic inline iterator_range<inst_iterator> instructions(Function &F) {\n    return make_range(inst_begin(F), inst_end(F));\n}\n\nstatic inline iterator_range<const_inst_iterator>\ninstructions(const Function &F) {\n    return make_range(inst_begin(F), inst_end(F));\n}\n} // namespace llvm\n#endif\n\n// The description of a C variable\nstruct CVariableDecl {\n    const std::string name;\n    unsigned line;\n    unsigned col;\n\n    CVariableDecl(std::string n, unsigned l = 0, unsigned c = 0)\n            : name(std::move(n)), line(l), col(c) {}\n    CVariableDecl(CVariableDecl &&) = default;\n    CVariableDecl(const CVariableDecl &) = default;\n};\n\n#endif // DG_LLVM_SLICER_UTILS_H_\n"
  },
  {
    "path": "tools/include/dg/tools/llvm-slicer.h",
    "content": "#ifndef DG_TOOL_LLVM_SLICER_H_\n#define DG_TOOL_LLVM_SLICER_H_\n\n#include <ctime>\n#include <fstream>\n\n#include <llvm/IR/Module.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#if LLVM_VERSION_MAJOR >= 4\n#include <llvm/Bitcode/BitcodeReader.h>\n#include <llvm/Bitcode/BitcodeWriter.h>\n#else\n#include <llvm/Bitcode/ReaderWriter.h>\n#endif\n\n#include \"dg/llvm/LLVMDependenceGraph.h\"\n#include \"dg/llvm/LLVMDependenceGraphBuilder.h\"\n#include \"dg/llvm/LLVMSlicer.h\"\n\n#include \"dg/llvm/LLVMDG2Dot.h\"\n#include \"dg/llvm/LLVMDGAssemblyAnnotationWriter.h\"\n\n#include \"dg/util/TimeMeasure.h\"\n\n#include \"llvm-slicer-opts.h\"\n#include \"llvm-slicer-utils.h\"\n\n/// --------------------------------------------------------------------\n//   - Slicer class -\n//\n//  The main class that takes the bitcode, constructs the dependence graph\n//  and then slices it w.r.t given slicing criteria.\n//  The usual workflow is as follows:\n//\n//  Slicer slicer(M, options);\n//  slicer.buildDG();\n//  slicer.mark(criteria);\n//  slicer.slice();\n//\n//  In the case that the slicer is not used for slicing,\n//  but just for building the graph, the user may do the following:\n//\n//  Slicer slicer(M, options);\n//  slicer.buildDG();\n//  slicer.computeDependencies();\n//\n//  or:\n//\n//  Slicer slicer(M, options);\n//  slicer.buildDG(true /* compute dependencies */);\n//\n/// --------------------------------------------------------------------\nclass Slicer {\n    llvm::Module *M{};\n    const SlicerOptions &_options;\n\n    dg::llvmdg::LLVMDependenceGraphBuilder _builder;\n    std::unique_ptr<dg::LLVMDependenceGraph> _dg{};\n\n    dg::llvmdg::LLVMSlicer slicer;\n    uint32_t slice_id = 0;\n    const uint32_t _default_slice_id = 0xdead;\n    bool _computed_deps{false};\n\n  public:\n    Slicer(llvm::Module *mod, const SlicerOptions &opts)\n            : M(mod), _options(opts), _builder(mod, _options.dgOptions) {\n        assert(mod && \"Need module\");\n    }\n\n    const dg::LLVMDependenceGraph &getDG() const { return *_dg; }\n    dg::LLVMDependenceGraph &getDG() { return *_dg; }\n\n    const SlicerOptions &getOptions() const { return _options; }\n\n    // Mirror LLVM to nodes of dependence graph,\n    // No dependence edges are added here unless the\n    // 'compute_deps' parameter is set to true.\n    // Otherwise, dependencies must be computed later\n    // using computeDependencies().\n    bool buildDG(bool compute_deps = false) {\n        _dg = std::move(_builder.constructCFGOnly());\n\n        if (!_dg) {\n            llvm::errs() << \"Building the dependence graph failed!\\n\";\n            return false;\n        }\n\n        if (compute_deps)\n            computeDependencies();\n\n        return true;\n    }\n\n    // Explicitely compute dependencies after building the graph.\n    // This method can be used to compute dependencies without\n    // calling mark() afterwards (mark() calls this function).\n    // It must not be called before calling mark() in the future.\n    void computeDependencies() {\n        assert(!_computed_deps && \"Already called computeDependencies()\");\n        // must call buildDG() before this function\n        assert(_dg && \"Must build dg before computing dependencies\");\n\n        _dg = _builder.computeDependencies(std::move(_dg));\n        _computed_deps = true;\n\n        const auto &stats = _builder.getStatistics();\n        llvm::errs() << \"[llvm-slicer] CPU time of pointer analysis: \"\n                     << double(stats.ptaTime) / CLOCKS_PER_SEC << \" s\\n\";\n        llvm::errs() << \"[llvm-slicer] CPU time of data dependence analysis: \"\n                     << double(stats.rdaTime) / CLOCKS_PER_SEC << \" s\\n\";\n        llvm::errs()\n                << \"[llvm-slicer] CPU time of control dependence analysis: \"\n                << double(stats.cdaTime) / CLOCKS_PER_SEC << \" s\\n\";\n    }\n\n    // Mark the nodes from the slice.\n    // This method calls computeDependencies(),\n    // but buildDG() must be called before.\n    bool mark(std::set<dg::LLVMNode *> &criteria_nodes) {\n        assert(_dg && \"mark() called without the dependence graph built\");\n        assert(!criteria_nodes.empty() && \"Do not have slicing criteria\");\n\n        dg::debug::TimeMeasure tm;\n\n        // compute dependece edges\n        computeDependencies();\n\n        // unmark this set of nodes after marking the relevant ones.\n        // Used to mimic the Weissers algorithm\n        std::set<dg::LLVMNode *> unmark;\n\n        if (_options.removeSlicingCriteria)\n            unmark = criteria_nodes;\n\n        _dg->getCallSites(_options.additionalSlicingCriteria, &criteria_nodes);\n\n        for (const auto &funcName : _options.preservedFunctions)\n            slicer.keepFunctionUntouched(funcName.c_str());\n\n        slice_id = _default_slice_id;\n\n        tm.start();\n        for (dg::LLVMNode *start : criteria_nodes)\n            slice_id = slicer.mark(start, slice_id, _options.forwardSlicing);\n\n        assert(slice_id != 0 && \"Somethig went wrong when marking nodes\");\n\n        // if we have some nodes in the unmark set, unmark them\n        for (dg::LLVMNode *nd : unmark)\n            nd->setSlice(0);\n\n        tm.stop();\n        tm.report(\"[llvm-slicer] Finding dependent nodes took\");\n\n        return true;\n    }\n\n    bool slice() {\n        assert(_dg && \"Must run buildDG() and computeDependencies()\");\n        assert(slice_id != 0 && \"Must run mark() method before slice()\");\n\n        dg::debug::TimeMeasure tm;\n\n        tm.start();\n        slicer.slice(_dg.get(), nullptr, slice_id);\n\n        tm.stop();\n        tm.report(\"[llvm-slicer] Slicing dependence graph took\");\n\n        dg::SlicerStatistics &st = slicer.getStatistics();\n        llvm::errs() << \"[llvm-slicer] Sliced away \" << st.nodesRemoved\n                     << \" from \" << st.nodesTotal << \" nodes in DG\\n\";\n\n        return true;\n    }\n\n    ///\n    // Create new empty main in the module. If 'call_entry' is set to true,\n    // then call the entry function from the new main (if entry is not main),\n    // otherwise the main is going to be empty\n    bool createEmptyMain(bool call_entry = false) {\n        llvm::LLVMContext &ctx = M->getContext();\n        llvm::Function *main_func = M->getFunction(\"main\");\n        if (!main_func) {\n            auto C = M->getOrInsertFunction(\"main\", llvm::Type::getInt32Ty(ctx)\n#if LLVM_VERSION_MAJOR < 5\n                                                            ,\n                                            nullptr\n#endif // LLVM < 5\n            );\n#if LLVM_VERSION_MAJOR < 9\n            if (!C) {\n                llvm::errs() << \"Could not create new main function\\n\";\n                return false;\n            }\n\n            main_func = llvm::cast<llvm::Function>(C);\n#else\n            main_func = llvm::cast<llvm::Function>(C.getCallee());\n#endif\n        } else {\n            // delete old function body\n            main_func->deleteBody();\n        }\n\n        assert(main_func && \"Do not have the main func\");\n        assert(main_func->empty() && \"The main func is not empty\");\n\n        // create new function body\n        llvm::BasicBlock *blk =\n                llvm::BasicBlock::Create(ctx, \"entry\", main_func);\n\n        if (call_entry && _options.dgOptions.entryFunction != \"main\") {\n            llvm::Function *entry =\n                    M->getFunction(_options.dgOptions.entryFunction);\n            assert(entry && \"The entry function is not present in the module\");\n\n            // TODO: we should set the arguments to undef\n            llvm::CallInst::Create(entry, \"entry\", blk);\n        }\n\n        llvm::Type *Ty = main_func->getReturnType();\n        llvm::Value *retval = nullptr;\n        if (Ty->isIntegerTy())\n            retval = llvm::ConstantInt::get(Ty, 0);\n        llvm::ReturnInst::Create(ctx, retval, blk);\n\n        return true;\n    }\n};\n\nclass ModuleWriter {\n    const SlicerOptions &options;\n    llvm::Module *M;\n\n  public:\n    ModuleWriter(const SlicerOptions &o, llvm::Module *m) : options(o), M(m) {}\n\n    int cleanAndSaveModule(bool should_verify_module = true) {\n        // remove unneeded parts of the module\n        removeUnusedFromModule();\n\n        // fix linkage of declared functions (if needs to be fixed)\n        makeDeclarationsExternal();\n\n        return saveModule(should_verify_module);\n    }\n\n    int saveModule(bool should_verify_module = true) {\n        if (should_verify_module)\n            return verifyAndWriteModule();\n        return writeModule();\n    }\n\n    void removeUnusedFromModule() {\n        bool fixpoint;\n\n        do {\n            fixpoint = _removeUnusedFromModule();\n        } while (fixpoint);\n    }\n\n    // after we slice the LLVM, we somethimes have troubles\n    // with function declarations:\n    //\n    //   Global is external, but doesn't have external or dllimport or weak\n    //   linkage! i32 (%struct.usbnet*)* @always_connected invalid linkage type\n    //   for function declaration\n    //\n    // This function makes the declarations external\n    void makeDeclarationsExternal() {\n        using namespace llvm;\n\n        // iterate over all functions in module\n        for (auto &F : *M) {\n            if (F.empty()) {\n                // this will make sure that the linkage has right type\n                F.deleteBody();\n            }\n        }\n    }\n\n  private:\n    bool writeModule() {\n        // compose name if not given\n        std::string fl;\n        if (!options.outputFile.empty()) {\n            fl = options.outputFile;\n        } else {\n            fl = options.inputFile;\n            replace_suffix(fl, \".sliced\");\n        }\n\n        // open stream to write to\n        std::ofstream ofs(fl);\n        llvm::raw_os_ostream ostream(ofs);\n\n        // write the module\n        llvm::errs() << \"[llvm-slicer] saving sliced module to: \" << fl.c_str()\n                     << \"\\n\";\n\n#if (LLVM_VERSION_MAJOR > 6)\n        llvm::WriteBitcodeToFile(*M, ostream);\n#else\n        llvm::WriteBitcodeToFile(M, ostream);\n#endif\n\n        return true;\n    }\n\n    bool verifyModule() {\n        // the verifyModule function returns false if there\n        // are no errors\n\n#if ((LLVM_VERSION_MAJOR >= 4) || (LLVM_VERSION_MINOR >= 5))\n        return !llvm::verifyModule(*M, &llvm::errs());\n#else\n        return !llvm::verifyModule(*M, llvm::PrintMessageAction);\n#endif\n    }\n\n    int verifyAndWriteModule() {\n        if (!verifyModule()) {\n            llvm::errs() << \"[llvm-slicer] ERROR: Verifying module failed, the \"\n                            \"IR is not valid\\n\";\n            llvm::errs()\n                    << \"[llvm-slicer] Saving anyway so that you can check it\\n\";\n            return 1;\n        }\n\n        if (!writeModule()) {\n            llvm::errs() << \"Saving sliced module failed\\n\";\n            return 1;\n        }\n\n        // exit code\n        return 0;\n    }\n\n    bool _removeUnusedFromModule() {\n        using namespace llvm;\n        // do not slice away these functions no matter what\n        // FIXME do it a vector and fill it dynamically according\n        // to what is the setup (like for sv-comp or general..)\n        const char *keep[] = {options.dgOptions.entryFunction.c_str()};\n\n        // when erasing while iterating the slicer crashes\n        // so set the to be erased values into container\n        // and then erase them\n        std::set<Function *> funs;\n        std::set<GlobalVariable *> globals;\n        std::set<GlobalAlias *> aliases;\n\n        for (auto &I : *M) {\n            Function *func = &I;\n            if (array_match(func->getName(), keep))\n                continue;\n\n            // if the function is unused or we haven't constructed it\n            // at all in dependence graph, we can remove it\n            // (it may have some uses though - like when one\n            // unused func calls the other unused func\n            if (func->hasNUses(0))\n                funs.insert(func);\n        }\n\n        for (auto I = M->global_begin(), E = M->global_end(); I != E; ++I) {\n            GlobalVariable *gv = &*I;\n            if (gv->hasNUses(0))\n                globals.insert(gv);\n        }\n\n        for (GlobalAlias &ga : M->getAliasList()) {\n            if (ga.hasNUses(0))\n                aliases.insert(&ga);\n        }\n\n        for (Function *f : funs)\n            f->eraseFromParent();\n        for (GlobalVariable *gv : globals)\n            gv->eraseFromParent();\n        for (GlobalAlias *ga : aliases)\n            ga->eraseFromParent();\n\n        return (!funs.empty() || !globals.empty() || !aliases.empty());\n    }\n};\n\nclass DGDumper {\n    const SlicerOptions &options;\n    LLVMDependenceGraph *dg;\n    bool bb_only{false};\n    uint32_t dump_opts{debug::PRINT_DD | debug::PRINT_CD | debug::PRINT_USE |\n                       debug::PRINT_ID};\n\n  public:\n    DGDumper(const SlicerOptions &opts, LLVMDependenceGraph *dg,\n             bool bb_only = false,\n             uint32_t dump_opts = debug::PRINT_DD | debug::PRINT_CD |\n                                  debug::PRINT_USE | debug::PRINT_ID)\n            : options(opts), dg(dg), bb_only(bb_only), dump_opts(dump_opts) {}\n\n    void dumpToDot(const char *suffix = nullptr) {\n        // compose new name\n        std::string fl(options.inputFile);\n        if (suffix)\n            replace_suffix(fl, suffix);\n        else\n            replace_suffix(fl, \".dot\");\n\n        llvm::errs() << \"[llvm-slicer] Dumping DG to \" << fl << \"\\n\";\n\n        if (bb_only) {\n            debug::LLVMDGDumpBlocks dumper(dg, dump_opts, fl.c_str());\n            dumper.dump();\n        } else {\n            debug::LLVMDG2Dot dumper(dg, dump_opts, fl.c_str());\n            dumper.dump();\n        }\n    }\n};\n\nnamespace {\ninline std::string undefFunsBehaviorToStr(dg::dda::UndefinedFunsBehavior b) {\n    using namespace dg::dda;\n    if (b == PURE)\n        return \"pure\";\n\n    std::string ret;\n    if (b & (WRITE_ANY | WRITE_ARGS)) {\n        ret = \"write \";\n        if (b & WRITE_ANY) {\n            if (b & WRITE_ARGS) {\n                ret += \"any+args\";\n            } else {\n                ret += \"any\";\n            }\n        } else if (b & WRITE_ARGS) {\n            ret += \"args\";\n        }\n    }\n    if (b & (READ_ANY | READ_ARGS)) {\n        if (b & (WRITE_ANY | WRITE_ARGS)) {\n            ret += \" read \";\n        } else {\n            ret = \"read \";\n        }\n\n        if (b & READ_ANY) {\n            if (b & READ_ARGS) {\n                ret += \"any+args\";\n            } else {\n                ret += \"any\";\n            }\n        } else if (b & READ_ARGS) {\n            ret += \"args\";\n        }\n    }\n\n    return ret;\n}\n} // anonymous namespace\n\nclass ModuleAnnotator {\n    using AnnotationOptsT =\n            dg::debug::LLVMDGAssemblyAnnotationWriter::AnnotationOptsT;\n\n    const SlicerOptions &options;\n    LLVMDependenceGraph *dg;\n    AnnotationOptsT annotationOptions;\n\n  public:\n    ModuleAnnotator(const SlicerOptions &o, LLVMDependenceGraph *dg,\n                    AnnotationOptsT annotO)\n            : options(o), dg(dg), annotationOptions(annotO) {}\n\n    bool shouldAnnotate() const { return annotationOptions != 0; }\n\n    void annotate(const std::set<LLVMNode *> *criteria = nullptr) {\n        // compose name\n        std::string fl(options.inputFile);\n        replace_suffix(fl, \"-debug.ll\");\n\n        // open stream to write to\n        std::ofstream ofs(fl);\n        llvm::raw_os_ostream outputstream(ofs);\n\n        std::string module_comment =\n                \"; -- Generated by llvm-slicer --\\n\"\n                \";   * slicing criteria: '\" +\n                options.slicingCriteria + \"'\\n\" +\n                \";   * legacy slicing criteria: '\" +\n                options.legacySlicingCriteria + \"'\\n\" +\n                \";   * legacy secondary slicing criteria: '\" +\n                options.legacySecondarySlicingCriteria + \"'\\n\" +\n                \";   * forward slice: '\" +\n                std::to_string(options.forwardSlicing) + \"'\\n\" +\n                \";   * remove slicing criteria: '\" +\n                std::to_string(options.removeSlicingCriteria) + \"'\\n\" +\n                \";   * undefined functions behavior: '\" +\n                undefFunsBehaviorToStr(\n                        options.dgOptions.DDAOptions.undefinedFunsBehavior) +\n                \"'\\n\" + \";   * pointer analysis: \";\n\n        using AnalysisType = LLVMPointerAnalysisOptions::AnalysisType;\n        switch (options.dgOptions.PTAOptions.analysisType) {\n        case AnalysisType::fi:\n            module_comment += \"flow-insensitive\\n\";\n            break;\n        case AnalysisType::fs:\n            module_comment += \"flow-sensitive\\n\";\n            break;\n        case AnalysisType::inv:\n            module_comment += \"flow-sensitive with invalidate\\n\";\n            break;\n        case AnalysisType::svf:\n            module_comment += \"SVF\\n\";\n            break;\n        }\n\n        module_comment += \";   * PTA field sensitivity: \";\n        if (options.dgOptions.PTAOptions.fieldSensitivity == Offset::UNKNOWN)\n            module_comment += \"full\\n\\n\";\n        else\n            module_comment +=\n                    std::to_string(\n                            *options.dgOptions.PTAOptions.fieldSensitivity) +\n                    \"\\n\\n\";\n\n        llvm::errs() << \"[llvm-slicer] Saving IR with annotations to \" << fl\n                     << \"\\n\";\n        auto *annot = new dg::debug::LLVMDGAssemblyAnnotationWriter(\n                annotationOptions, dg->getPTA(), dg->getDDA(), criteria);\n        annot->emitModuleComment(std::move(module_comment));\n        llvm::Module *M = dg->getModule();\n        M->print(outputstream, annot);\n\n        delete annot;\n    }\n};\n\n#endif // DG_TOOL_LLVM_SLICER_H_\n"
  },
  {
    "path": "tools/llvm-cda-bench.cpp",
    "content": "#include <cassert>\n#include <ctime>\n#include <iostream>\n\n#include \"dg/tools/llvm-slicer-opts.h\"\n#include \"dg/tools/llvm-slicer-utils.h\"\n#include \"dg/tools/llvm-slicer.h\"\n\n#if LLVM_VERSION_MAJOR >= 4\n#include <llvm/Bitcode/BitcodeReader.h>\n#include <llvm/Bitcode/BitcodeWriter.h>\n#else\n#include <llvm/Bitcode/ReaderWriter.h>\n#endif\n\n#include <llvm/IR/InstIterator.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/LLVMContext.h>\n#include <llvm/Support/raw_ostream.h>\n\n#ifdef HAVE_SVF\n#include \"dg/llvm/PointerAnalysis/SVFPointerAnalysis.h\"\n#endif\n#include \"dg/ADT/Queue.h\"\n#include \"dg/llvm/ControlDependence/ControlDependence.h\"\n#include \"dg/llvm/PointerAnalysis/DGPointerAnalysis.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n#include \"dg/util/debug.h\"\n\n#include \"ControlDependence/CDGraph.h\"\n#include \"llvm/ControlDependence/DOD.h\"\n#include \"llvm/ControlDependence/NTSCD.h\"\n\nusing namespace dg;\n\nusing llvm::errs;\n\nllvm::cl::opt<bool> enable_debug(\n        \"dbg\", llvm::cl::desc(\"Enable debugging messages (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> quiet(\n        \"q\",\n        llvm::cl::desc(\"Do not generate output, just run the analysis \"\n                       \"(e.g., for performance analysis) (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        total_only(\"total-only\",\n                   llvm::cl::desc(\"Do not generate output other than the total \"\n                                  \"time (default=false).\"),\n                   llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        fun_info_only(\"fun-info-only\",\n                      llvm::cl::desc(\"Only dump statistics about the functions \"\n                                     \"in module (default=false).\"),\n                      llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        scd(\"scd\", llvm::cl::desc(\"Benchmark standard CD (default=false).\"),\n            llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> ntscd(\"ntscd\",\n                          llvm::cl::desc(\"Benchmark NTSCD (default=false).\"),\n                          llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> ntscd2(\"ntscd2\",\n                           llvm::cl::desc(\"Benchmark NTSCD 2 (default=false).\"),\n                           llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> ntscd_ranganath(\n        \"ntscd-ranganath\",\n        llvm::cl::desc(\n                \"Benchmark NTSCD (Ranganath algorithm) (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> ntscd_ranganath_wrong(\n        \"ntscd-ranganath-wrong\",\n        llvm::cl::desc(\"Benchmark NTSCD (Ranganath original - wrong - \"\n                       \"algorithm) (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> ntscd_legacy(\n        \"ntscd-legacy\",\n        llvm::cl::desc(\n                \"Benchmark NTSCD (legacy implementation) (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> dod(\"dod\", llvm::cl::desc(\"Benchmark DOD (default=false).\"),\n                        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        dod_ranganath(\"dod-ranganath\",\n                      llvm::cl::desc(\"Benchmark DOD (default=false).\"),\n                      llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        dod_ntscd(\"dod+ntscd\",\n                  llvm::cl::desc(\"Benchmark DOD + NTSCD (default=false).\"),\n                  llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        scc(\"scc\", llvm::cl::desc(\"Strong control closure (default=false).\"),\n            llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> compare(\n        \"compare\",\n        llvm::cl::desc(\n                \"Compare the resulting control dependencies (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nvoid compareResults(\n        const std::set<std::pair<const llvm::Value *, const llvm::Value *>> &R1,\n        const std::set<std::pair<const llvm::Value *, const llvm::Value *>> &R2,\n        const std::string &A1, const std::string &A2, const llvm::Function &F) {\n    std::cout << \"In function '\" << F.getName().str() << \"'\\n\";\n    std::cout << \" \" << A1 << \" computed \" << R1.size() << \" dependencies\\n\";\n    std::cout << \" \" << A2 << \" computed \" << R2.size() << \" dependencies\\n\";\n    std::cout << \"-----\\n\";\n\n    size_t a1has = 0, a2has = 0;\n    for (const auto &d : R1) {\n        if (R2.count(d) == 0) {\n            ++a1has;\n        }\n    }\n    for (const auto &d : R2) {\n        if (R1.count(d) == 0) {\n            ++a2has;\n        }\n    }\n\n    if (a1has > 0 || a2has > 0) {\n        std::cout << \" \" << A1 << \" has \" << a1has << \" that are not in \" << A2\n                  << \"\\n\";\n        std::cout << \" \" << A2 << \" has \" << a2has << \" that are not in \" << A1\n                  << std::endl;\n    }\n}\n\nstatic inline bool hasSuccessors(const llvm::BasicBlock *B) {\n    return succ_begin(B) != succ_end(B);\n}\n\nstatic void dumpFunStats(const llvm::Function &F) {\n    unsigned instrs = 0, branches = 0, blinds = 0;\n    std::cout << \"Function '\" << F.getName().str() << \"'\\n\";\n    for (const auto &B : F) {\n        instrs += B.size();\n        auto n = 0;\n        for (const auto *s : successors(&B)) {\n            (void) s;\n            ++n;\n        }\n        if (n == 0)\n            ++blinds;\n        if (n > 1)\n            ++branches;\n    }\n    std::cout << \"  bblocks: \" << F.size() << \"\\n\";\n    std::cout << \"  instructions: \" << instrs << \"\\n\";\n    std::cout << \"  branches: \" << branches << \"\\n\";\n    std::cout << \"  blind ends: \" << blinds << \"\\n\";\n\n    // visited, on_stack\n    std::map<const llvm::BasicBlock *, bool> on_stack;\n    unsigned backedges = 0;\n    unsigned tree = 0;\n    unsigned nontree = 0;\n    unsigned forward = 0;\n    size_t maxdepth = 0;\n    struct StackNode {\n        const llvm::BasicBlock *block;\n        // next successor to follow\n        const llvm::BasicBlock *next_succ{nullptr};\n\n        StackNode(const llvm::BasicBlock *b,\n                  const llvm::BasicBlock *s = nullptr)\n                : block(b), next_succ(s) {}\n    };\n\n    std::vector<StackNode> stack;\n    on_stack[&F.getEntryBlock()] = true;\n\n    stack.emplace_back(&F.getEntryBlock(),\n                       hasSuccessors(&F.getEntryBlock())\n                               ? *succ_begin(&F.getEntryBlock())\n                               : nullptr);\n    maxdepth = 1;\n\n    while (!stack.empty()) {\n        auto &si = stack.back();\n        assert(si.block);\n        const auto *nextblk = si.next_succ;\n        // set next successor\n        if (!nextblk) {\n            on_stack[si.block] = false;\n            stack.pop_back();\n            continue;\n        }\n\n        auto it = succ_begin(si.block);\n        auto et = succ_end(si.block);\n        while (it != et && *it != si.next_succ) {\n            ++it;\n        }\n\n        assert(*it == si.next_succ);\n        // can have multiple same successors\n        auto sit = on_stack.find(*it);\n\n        while (it != et && *it == si.next_succ) {\n            // XXX: we may loose some back/forward edges here\n            // (we do not count the multiplicity)\n            ++it;\n        }\n        if (it == et) {\n            si.next_succ = nullptr;\n        } else {\n            si.next_succ = *it;\n        }\n\n        sit = on_stack.find(nextblk);\n        if (sit != on_stack.end()) {\n            // we have already visited this node\n            ++nontree;\n            if (sit->second) { // still on stack\n                ++backedges;\n            } else {\n                ++forward;\n            }\n            // backtrack\n            sit->second = false;\n            stack.pop_back();\n        } else {\n            ++tree;\n            on_stack[nextblk] = true;\n            stack.emplace_back(nextblk, hasSuccessors(nextblk)\n                                                ? *succ_begin(nextblk)\n                                                : nullptr);\n            maxdepth = std::max(maxdepth, stack.size());\n        }\n    }\n\n    std::cout << \"  DFS tree edges: \" << tree << \"\\n\";\n    std::cout << \"  DFS nontree edges: \" << nontree << \"\\n\";\n    std::cout << \"  DFS forward: \" << forward << \"\\n\";\n    std::cout << \"  DFS backedges: \" << backedges << \"\\n\";\n    std::cout << \"  DFS max depth: \" << maxdepth << \"\\n\";\n}\n\nstatic inline std::unique_ptr<LLVMControlDependenceAnalysis>\ncreateAnalysis(llvm::Module *M,\n               const LLVMControlDependenceAnalysisOptions &opts) {\n    return std::unique_ptr<LLVMControlDependenceAnalysis>(\n            new LLVMControlDependenceAnalysis(M, opts));\n}\n\nint main(int argc, char *argv[]) {\n    setupStackTraceOnError(argc, argv);\n    SlicerOptions options = parseSlicerOptions(argc, argv);\n\n    if (enable_debug) {\n        DBG_ENABLE();\n    }\n\n    if (total_only) {\n        quiet = true;\n    }\n\n    llvm::LLVMContext context;\n    std::unique_ptr<llvm::Module> M =\n            parseModule(\"llvm-cda-bench\", context, options);\n    if (!M)\n        return 1;\n\n    if (fun_info_only) {\n        for (auto &F : *M) {\n            if (F.isDeclaration()) {\n                continue;\n            }\n\n            dumpFunStats(F);\n        }\n        return 0;\n    }\n\n    std::vector<\n            std::tuple<std::string,\n                       std::unique_ptr<LLVMControlDependenceAnalysis>, size_t>>\n            analyses;\n\n    clock_t start, end, elapsed;\n    auto &opts = options.dgOptions.CDAOptions;\n    if (scd) {\n        opts.algorithm =\n                dg::ControlDependenceAnalysisOptions::CDAlgorithm::STANDARD;\n        analyses.emplace_back(\"scd\", createAnalysis(M.get(), opts), 0);\n    }\n    if (ntscd) {\n        opts.algorithm =\n                dg::ControlDependenceAnalysisOptions::CDAlgorithm::NTSCD;\n        analyses.emplace_back(\"ntscd\", createAnalysis(M.get(), opts), 0);\n    }\n    if (ntscd2) {\n        opts.algorithm =\n                dg::ControlDependenceAnalysisOptions::CDAlgorithm::NTSCD2;\n        analyses.emplace_back(\"ntscd2\", createAnalysis(M.get(), opts), 0);\n    }\n    if (ntscd_ranganath) {\n        opts.algorithm = dg::ControlDependenceAnalysisOptions::CDAlgorithm::\n                NTSCD_RANGANATH;\n        analyses.emplace_back(\"ntscd-ranganath\", createAnalysis(M.get(), opts),\n                              0);\n    }\n    if (ntscd_ranganath_wrong) {\n        opts.algorithm = dg::ControlDependenceAnalysisOptions::CDAlgorithm::\n                NTSCD_RANGANATH_ORIG;\n        analyses.emplace_back(\"ntscd-ranganath-wrong\",\n                              createAnalysis(M.get(), opts), 0);\n    }\n    if (ntscd_legacy) {\n        opts.algorithm =\n                dg::ControlDependenceAnalysisOptions::CDAlgorithm::NTSCD_LEGACY;\n        analyses.emplace_back(\"ntscd-legacy\", createAnalysis(M.get(), opts), 0);\n    }\n    if (dod) {\n        opts.algorithm = dg::ControlDependenceAnalysisOptions::CDAlgorithm::DOD;\n        analyses.emplace_back(\"dod\", createAnalysis(M.get(), opts), 0);\n    }\n    if (dod_ranganath) {\n        opts.algorithm = dg::ControlDependenceAnalysisOptions::CDAlgorithm::\n                DOD_RANGANATH;\n        analyses.emplace_back(\"dod-ranganath\", createAnalysis(M.get(), opts),\n                              0);\n    }\n    if (dod_ntscd) {\n        opts.algorithm =\n                dg::ControlDependenceAnalysisOptions::CDAlgorithm::DODNTSCD;\n        analyses.emplace_back(\"dod+ntscd\", createAnalysis(M.get(), opts), 0);\n    }\n    if (scc) {\n        opts.algorithm =\n                dg::ControlDependenceAnalysisOptions::CDAlgorithm::STRONG_CC;\n        analyses.emplace_back(\"scc\", createAnalysis(M.get(), opts), 0);\n    }\n\n    if (analyses.empty()) {\n        std::cerr << \"Warning: No analysis to run specified, \"\n                     \"dumping just info about funs\\n\";\n    }\n\n    for (auto &F : *M) {\n        if (F.isDeclaration()) {\n            continue;\n        }\n\n        if (!quiet) {\n            dumpFunStats(F);\n            std::cout << \"Elapsed time: \\n\";\n        }\n\n        for (auto &it : analyses) {\n            start = clock();\n            std::get<1>(it)->compute(&F); // compute all the information\n            end = clock();\n            elapsed = end - start;\n            std::get<2>(it) += elapsed;\n            if (!quiet) {\n                std::cout << \"  \" << std::get<0>(it) << \": \"\n                          << static_cast<float>(elapsed) / CLOCKS_PER_SEC\n                          << \" s (\" << elapsed << \" ticks)\\n\";\n            }\n        }\n        if (!quiet) {\n            std::cout << \"-----\" << std::endl;\n        }\n    }\n\n    if (!quiet || total_only) {\n        std::cout << \"Total elapsed time:\\n\";\n        for (auto &it : analyses) {\n            std::cout << \"  \" << std::get<0>(it) << \": \"\n                      << static_cast<float>(std::get<2>(it)) / CLOCKS_PER_SEC\n                      << \" s (\" << std::get<2>(it) << \" ticks)\" << std::endl;\n        }\n    }\n\n    // compare the results if requested\n    if (!compare)\n        return 0;\n\n    std::cout << \"\\n ==== Comparison ====\\n\";\n    for (auto &F : *M) {\n        if (F.isDeclaration()) {\n            continue;\n        }\n\n        // not very efficient...\n        std::vector<\n                std::set<std::pair<const llvm::Value *, const llvm::Value *>>>\n                results;\n        results.resize(analyses.size());\n        unsigned n = 0;\n        for (auto &it : analyses) {\n            auto *cda = std::get<1>(it).get();\n            for (auto &B : F) {\n                for (auto *d : cda->getDependencies(&B)) {\n                    results[n].emplace(d, &B);\n                }\n\n                for (auto &I : B) {\n                    for (auto *d : cda->getDependencies(&I)) {\n                        results[n].emplace(d, &I);\n                    }\n                }\n            }\n\n            ++n;\n        }\n\n        for (n = 0; n < results.size(); ++n) {\n            for (unsigned m = 0; m < n; ++m) {\n                compareResults(results[n], results[m], std::get<0>(analyses[n]),\n                               std::get<0>(analyses[m]), F);\n            }\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tools/llvm-cda-dump.cpp",
    "content": "#include <cassert>\n#include <fstream>\n#include <iostream>\n#include <set>\n#include <sstream>\n#include <string>\n#include <vector>\n\n#include \"dg/tools/llvm-slicer-opts.h\"\n#include \"dg/tools/llvm-slicer-utils.h\"\n#include \"dg/tools/llvm-slicer.h\"\n\n#if LLVM_VERSION_MAJOR >= 4\n#include <llvm/Bitcode/BitcodeReader.h>\n#include <llvm/Bitcode/BitcodeWriter.h>\n#else\n#include <llvm/Bitcode/ReaderWriter.h>\n#endif\n\n#include <llvm/IR/InstIterator.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/LLVMContext.h>\n#include <llvm/Support/raw_ostream.h>\n\n#ifdef HAVE_SVF\n#include \"dg/llvm/PointerAnalysis/SVFPointerAnalysis.h\"\n#endif\n#include \"dg/llvm/ControlDependence/ControlDependence.h\"\n#include \"dg/llvm/PointerAnalysis/DGPointerAnalysis.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n#include \"dg/util/debug.h\"\n\n#include \"ControlDependence/CDGraph.h\"\n#include \"llvm/ControlDependence/DOD.h\"\n#include \"llvm/ControlDependence/NTSCD.h\"\n\nusing namespace dg;\n\nusing llvm::errs;\n\nllvm::cl::opt<bool> enable_debug(\n        \"dbg\", llvm::cl::desc(\"Enable debugging messages (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> show_cfg(\"cfg\",\n                             llvm::cl::desc(\"Show CFG edges (default=false).\"),\n                             llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> dump_ir(\"ir\",\n                            llvm::cl::desc(\"Show internal representation \"\n                                           \"instead of LLVM (default=false).\"),\n                            llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> stats(\"statistics\",\n                          llvm::cl::desc(\"Dump statistics(default=false).\"),\n                          llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> quiet(\n        \"q\",\n        llvm::cl::desc(\"Do not generate output, just run the analysis \"\n                       \"(e.g., for performance analysis) (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        todot(\"dot\", llvm::cl::desc(\"Output in graphviz format (forced atm.).\"),\n              llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> dump_c_lines(\n        \"c-lines\",\n        llvm::cl::desc(\"Dump output as C lines (line:column where possible).\"\n                       \"Requires metadata in the bitcode (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> use_pta(\n        \"use-pta\",\n        llvm::cl::desc(\n                \"Use pointer analysis to build call graph. \"\n                \"Makes sense only with -cda-icfg switch (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nusing VariablesMapTy = std::map<const llvm::Value *, CVariableDecl>;\nVariablesMapTy allocasToVars(const llvm::Module &M);\nVariablesMapTy valuesToVars;\n\nstatic std::string getInstName(const llvm::Value *val) {\n    assert(val);\n    std::ostringstream ostr;\n    llvm::raw_os_ostream ro(ostr);\n\n    if (dump_c_lines) {\n        if (const auto *I = llvm::dyn_cast<llvm::Instruction>(val)) {\n            const auto &DL = I->getDebugLoc();\n            if (DL) {\n                ro << DL.getLine() << \":\" << DL.getCol();\n            } else {\n                auto Vit = valuesToVars.find(I);\n                if (Vit != valuesToVars.end()) {\n                    auto &decl = Vit->second;\n                    ro << decl.line << \":\" << decl.col;\n                } else {\n                    ro << \"(no dbg) \";\n                    ro << *val;\n                }\n            }\n        } else {\n            ro << \"(no inst) \";\n            ro << *val;\n        }\n        ro.flush();\n        return ostr.str();\n    }\n\n    if (llvm::isa<llvm::Function>(val))\n        ro << val->getName().data();\n    else\n        ro << *val;\n\n    ro.flush();\n\n    // break the string if it is too long\n    return ostr.str();\n}\n\nstatic inline void dumpEdge(const llvm::Value *from, const llvm::Value *to,\n                            const char *attrs = nullptr) {\n    using namespace llvm;\n\n    const auto *fromB = dyn_cast<BasicBlock>(from);\n    const auto *toB = dyn_cast<BasicBlock>(to);\n\n    std::cout << \"instr\";\n    if (fromB) {\n        std::cout << &fromB->back();\n    } else {\n        std::cout << from;\n    }\n\n    std::cout << \" -> instr\";\n    if (toB) {\n        std::cout << &toB->front();\n    } else {\n        std::cout << to;\n    }\n\n    std::cout << \"[\";\n    if (attrs) {\n        std::cout << attrs;\n    } else {\n        std::cout << \"color=blue minlen=2 penwidth=2\";\n    }\n    if (fromB || toB) {\n        if (fromB) {\n            std::cout << \" ltail=cluster_bb_\" << fromB;\n        }\n        if (toB) {\n            std::cout << \" lhead=cluster_bb_\" << toB;\n        }\n    }\n    std::cout << \"]\";\n\n    std::cout << \"\\n\";\n}\n\nstatic void dumpCdaToDot(LLVMControlDependenceAnalysis &cda,\n                         const llvm::Module *m) {\n    std::cout << \"digraph ControlDependencies {\\n\";\n    std::cout << \"  compound=true;\\n\";\n\n    // dump nodes\n    for (const auto &f : *m) {\n        if (f.isDeclaration())\n            continue;\n\n        std::cout << \"subgraph cluster_f_\" << f.getName().str() << \" {\\n\";\n        std::cout << \"label=\\\"\" << f.getName().str() << \"\\\"\\n\";\n        for (const auto &b : f) {\n            std::cout << \"subgraph cluster_bb_\" << &b << \" {\\n\";\n            std::cout << \"  style=dotted;\\n\";\n            for (const auto &I : b) {\n                std::cout << \" instr\" << &I << \" [shape=rectangle label=\\\"\"\n                          << getInstName(&I) << \"\\\"]\\n\";\n            }\n\n            const llvm::Instruction *last = nullptr;\n            // give the block top-down structure\n            for (const auto &I : b) {\n                if (last) {\n                    std::cout << \" instr\" << last << \" -> \"\n                              << \"instr\" << &I;\n                    if (show_cfg) {\n                        std::cout << \" [style=dotted]\\n\";\n                    } else {\n                        std::cout << \" [style=invis]\\n\";\n                    }\n                }\n                last = &I;\n            }\n            std::cout << \"}\\n\";\n        }\n        std::cout << \"}\\n\";\n    }\n\n    // dump CFG edges between blocks\n    if (show_cfg) {\n        for (const auto &f : *m) {\n            for (const auto &b : f) {\n                for (const auto *succ : successors(&b)) {\n                    dumpEdge(&b, succ, \"style=dashed minlen=2 color=black\");\n                }\n            }\n        }\n    }\n\n    // dump edges\n    for (const auto &f : *m) {\n        for (const auto &b : f) {\n            for (auto *D : cda.getDependencies(&b)) {\n                dumpEdge(D, &b);\n            }\n\n            for (const auto &I : b) {\n                for (auto *D : cda.getDependencies(&I)) {\n                    dumpEdge(D, &I);\n                }\n            }\n        }\n    }\n\n    std::cout << \"}\\n\";\n}\n\nstatic void dumpCda(LLVMControlDependenceAnalysis &cda) {\n    const auto *m = cda.getModule();\n\n    if (dump_c_lines) {\n#if (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7)\n        llvm::errs() << \"WARNING: Variables names matching is not supported \"\n                        \"for LLVM older than 3.7\\n\";\n#else\n        valuesToVars = allocasToVars(*m);\n#endif // LLVM > 3.6\n        if (valuesToVars.empty()) {\n            llvm::errs() << \"WARNING: No debugging information found, \"\n                         << \"the C lines output will be corrupted\\n\";\n        }\n    }\n\n    if (todot) {\n        dumpCdaToDot(cda, m);\n        return;\n    }\n\n    for (const auto &F : *m) {\n        for (const auto &B : F) {\n            for (const auto &I : B) {\n                for (auto *dep : cda.getDependencies(&B)) {\n                    auto *depB = llvm::cast<llvm::BasicBlock>(dep);\n                    std::cout << getInstName(&I) << \" -> \"\n                              << getInstName(depB->getTerminator()) << \"\\n\";\n                }\n\n                for (auto *dep : cda.getDependencies(&I)) {\n                    std::cout << getInstName(&I) << \" -> \" << getInstName(dep)\n                              << \"\\n\";\n                }\n            }\n        }\n    }\n}\n\nstatic void dump_graph(CDGraph *graph) {\n    assert(graph);\n    // dump nodes\n    for (const auto *nd : *graph) {\n        std::cout << \" \" << graph->getName() << \"_\" << nd->getID()\n                  << \" [label=\\\"\" << graph->getName() << \":\" << nd->getID()\n                  << \"\\\"\";\n        if (graph->isPredicate(*nd)) {\n            std::cout << \" color=blue\";\n        }\n        std::cout << \"]\\n\";\n    }\n\n    // dump edges\n    for (const auto *nd : *graph) {\n        for (const auto *succ : nd->successors()) {\n            std::cout << \" \" << graph->getName() << \"_\" << nd->getID() << \" -> \"\n                      << graph->getName() << \"_\" << succ->getID() << \"\\n\";\n        }\n    }\n}\n\nstatic void dumpIr(LLVMControlDependenceAnalysis &cda) {\n    const auto *m = cda.getModule();\n    auto *impl = cda.getImpl();\n\n    std::cout << \"digraph ControlDependencies {\\n\";\n    std::cout << \"  compound=true;\\n\";\n\n    if (cda.getOptions().ICFG()) {\n        cda.compute();\n        dump_graph(impl->getGraph(nullptr));\n        std::cout << \"}\\n\";\n        return;\n    }\n\n    // dump nodes\n    for (const auto &f : *m) {\n        cda.compute(&f);\n        auto *graph = impl->getGraph(&f);\n        if (!graph)\n            continue;\n        std::cout << \"subgraph cluster_f_\" << f.getName().str() << \" {\\n\";\n        std::cout << \"label=\\\"\" << f.getName().str() << \"\\\"\\n\";\n\n        dump_graph(graph);\n\n        if (cda.getOptions().ntscdCD() || cda.getOptions().ntscd2CD() ||\n            cda.getOptions().ntscdRanganathCD()) {\n            auto *ntscd = static_cast<dg::llvmdg::NTSCD *>(impl);\n            const auto *info = ntscd->_getFunInfo(&f);\n            if (info) {\n                for (auto *nd : *graph) {\n                    auto it = info->controlDependence.find(nd);\n                    if (it == info->controlDependence.end())\n                        continue;\n\n                    for (const auto *dep : it->second) {\n                        // FIXME: for interproc CD this will not work as the\n                        // nodes would be in a different graph\n                        std::cout << \" \" << graph->getName() << \"_\"\n                                  << dep->getID() << \" -> \" << graph->getName()\n                                  << \"_\" << nd->getID() << \" [ color=red ]\\n\";\n                    }\n                }\n            }\n        } else if (cda.getOptions().dodCD() ||\n                   cda.getOptions().dodRanganathCD() ||\n                   cda.getOptions().dodntscdCD()) {\n            auto *dod = static_cast<dg::llvmdg::DOD *>(impl);\n            const auto *info = dod->_getFunInfo(&f);\n            if (info) {\n                for (auto *nd : *graph) {\n                    auto it = info->controlDependence.find(nd);\n                    if (it == info->controlDependence.end())\n                        continue;\n\n                    for (const auto *dep : it->second) {\n                        std::cout << \" \" << graph->getName() << \"_\"\n                                  << dep->getID() << \" -> \" << graph->getName()\n                                  << \"_\" << nd->getID() << \" [ color=red ]\\n\";\n                    }\n                }\n            }\n        }\n\n        std::cout << \"}\\n\";\n    }\n\n    std::cout << \"}\\n\";\n}\n\nint main(int argc, char *argv[]) {\n    setupStackTraceOnError(argc, argv);\n    SlicerOptions options = parseSlicerOptions(argc, argv);\n\n    if (enable_debug) {\n        DBG_ENABLE();\n    }\n\n    llvm::LLVMContext context;\n    std::unique_ptr<llvm::Module> M =\n            parseModule(\"llvm-cda-dump\", context, options);\n    if (!M)\n        return 1;\n\n    if (!M->getFunction(options.dgOptions.entryFunction)) {\n        llvm::errs() << \"The entry function not found: \"\n                     << options.dgOptions.entryFunction << \"\\n\";\n        return 1;\n    }\n    std::unique_ptr<LLVMPointerAnalysis> pta{nullptr};\n    if (use_pta) {\n        auto &ptaopts = options.dgOptions.PTAOptions;\n#ifdef HAVE_SVF\n        if (ptaopts.isSVF()) {\n            pta.reset(new SVFPointerAnalysis(M.get(), ptaopts));\n            pta->run();\n        } else\n#endif // HAVE_SVF\n        {\n            pta.reset(new DGLLVMPointerAnalysis(M.get(), ptaopts));\n            pta->run();\n        }\n    }\n\n    LLVMControlDependenceAnalysis cda(M.get(), options.dgOptions.CDAOptions,\n                                      pta.get());\n\n    if (quiet) {\n        cda.compute(); // compute all the information\n        if (stats) {\n            // FIXME\n            // dumpStats(cda);\n        }\n    } else {\n        if (dump_ir) {\n            dumpIr(cda);\n        } else {\n            dumpCda(cda);\n        }\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tools/llvm-cda-stress.cpp",
    "content": "#include <cassert>\n#include <ctime>\n#include <iostream>\n#include <random>\n\n#include \"dg/tools/llvm-slicer-opts.h\"\n#include \"dg/tools/llvm-slicer-utils.h\"\n\n#include \"dg/ADT/Queue.h\"\n#include \"dg/util/debug.h\"\n\n#include \"ControlDependence/CDGraph.h\"\n#include \"ControlDependence/DOD.h\"\n#include \"ControlDependence/DODNTSCD.h\"\n#include \"ControlDependence/NTSCD.h\"\n\nusing namespace dg;\n\nusing llvm::errs;\n\nllvm::cl::opt<bool> enable_debug(\n        \"dbg\", llvm::cl::desc(\"Enable debugging messages (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> quiet(\n        \"q\",\n        llvm::cl::desc(\"Do not generate output, just run the analysis \"\n                       \"(e.g., for performance analysis) (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        total_only(\"total-only\",\n                   llvm::cl::desc(\"Do not generate output other than the total \"\n                                  \"time (default=false).\"),\n                   llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        fun_info_only(\"fun-info-only\",\n                      llvm::cl::desc(\"Only dump statistics about the functions \"\n                                     \"in module (default=false).\"),\n                      llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        scd(\"scd\", llvm::cl::desc(\"Benchmark standard CD (default=false).\"),\n            llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> ntscd(\"ntscd\",\n                          llvm::cl::desc(\"Benchmark NTSCD (default=false).\"),\n                          llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> ntscd2(\"ntscd2\",\n                           llvm::cl::desc(\"Benchmark NTSCD 2 (default=false).\"),\n                           llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> ntscd_ranganath(\n        \"ntscd-ranganath\",\n        llvm::cl::desc(\n                \"Benchmark NTSCD (Ranganath algorithm) (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> ntscd_legacy(\n        \"ntscd-legacy\",\n        llvm::cl::desc(\n                \"Benchmark NTSCD (legacy implementation) (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> dod(\"dod\", llvm::cl::desc(\"Benchmark DOD (default=false).\"),\n                        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        dod_ranganath(\"dod-ranganath\",\n                      llvm::cl::desc(\"Benchmark DOD (default=false).\"),\n                      llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        dod_ntscd(\"dod+ntscd\",\n                  llvm::cl::desc(\"Benchmark DOD + NTSCD (default=false).\"),\n                  llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        scc(\"scc\", llvm::cl::desc(\"Strong control closure (default=false).\"),\n            llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> compare(\n        \"compare\",\n        llvm::cl::desc(\n                \"Compare the resulting control dependencies (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<unsigned> Vn(\"nodes\",\n                           llvm::cl::desc(\"The number of nodes (default=100).\"),\n                           llvm::cl::init(100), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<unsigned>\n        En(\"edges\", llvm::cl::desc(\"The number of edges (default=1.5*nodes).\"),\n           llvm::cl::init(0), llvm::cl::cat(SlicingOpts));\n\nvoid generateRandomGraph(CDGraph &G, unsigned Vnum = 100, unsigned Enum = 0) {\n    if (Enum == 0 || Enum > 2 * Vnum)\n        Enum = Vnum;\n\n    std::vector<CDNode *> nodes;\n    nodes.push_back(nullptr);\n    nodes.reserve(Vnum + 1);\n    for (unsigned i = 0; i < Vnum; ++i) {\n        auto &nd = G.createNode();\n        nodes.push_back(&nd);\n        assert(nodes.size() - 1 == nd.getID());\n    }\n    // create random edges\n    std::random_device dev;\n    std::mt19937 rng(dev());\n    std::uniform_int_distribution<std::mt19937::result_type> ids(1, Vnum);\n\n    unsigned n = 0;\n    while (Enum > 0 && ++n < 10 * Enum) {\n        auto id1 = ids(rng);\n        if (nodes[id1]->successors().size() > 1)\n            continue;\n        auto id2 = ids(rng);\n        G.addNodeSuccessor(*nodes[id1], *nodes[id2]);\n        // std::cout << id1 << \" -> \" << id2 << \"\\n\";\n        --Enum;\n    }\n}\n\nint main(int argc, char *argv[]) {\n    setupStackTraceOnError(argc, argv);\n    SlicerOptions options = parseSlicerOptions(argc, argv,\n                                               /* requireCrit = */ false,\n                                               /* inputFileRequired = */ false);\n    if (enable_debug) {\n        DBG_ENABLE();\n    }\n\n    CDGraph G;\n    if (En == 0)\n        En = (unsigned) 1.5 * Vn;\n    generateRandomGraph(G, Vn, En);\n\n    clock_t start, end, elapsed;\n\n    if (ntscd) {\n        dg::NTSCD ntscd;\n        start = clock();\n        ntscd.compute(G);\n        end = clock();\n        elapsed = end - start;\n\n        std::cout << \"ntscd: \" << static_cast<float>(elapsed) / CLOCKS_PER_SEC\n                  << \" s (\" << elapsed << \" ticks)\\n\";\n    }\n    if (ntscd2) {\n        dg::NTSCD2 ntscd;\n        start = clock();\n        ntscd.compute(G);\n        end = clock();\n        elapsed = end - start;\n\n        std::cout << \"ntscd: \" << static_cast<float>(elapsed) / CLOCKS_PER_SEC\n                  << \" s (\" << elapsed << \" ticks)\\n\";\n    }\n    if (ntscd_ranganath) {\n        dg::NTSCDRanganath ntscd;\n        start = clock();\n        ntscd.compute(G);\n        end = clock();\n        elapsed = end - start;\n\n        std::cout << \"ntscd: \" << static_cast<float>(elapsed) / CLOCKS_PER_SEC\n                  << \" s (\" << elapsed << \" ticks)\\n\";\n    }\n    if (dod) {\n        dg::DOD dod;\n        start = clock();\n        dod.compute(G);\n        end = clock();\n        elapsed = end - start;\n\n        std::cout << \"dod: \" << static_cast<float>(elapsed) / CLOCKS_PER_SEC\n                  << \" s (\" << elapsed << \" ticks)\\n\";\n    }\n    if (dod_ranganath) {\n        dg::DODRanganath ntscd;\n        start = clock();\n        ntscd.compute(G);\n        end = clock();\n        elapsed = end - start;\n\n        std::cout << \"dod-ranganath: \"\n                  << static_cast<float>(elapsed) / CLOCKS_PER_SEC << \" s (\"\n                  << elapsed << \" ticks)\\n\";\n    }\n    if (dod_ntscd) {\n        dg::DODNTSCD ntscd;\n        start = clock();\n        ntscd.compute(G);\n        end = clock();\n        elapsed = end - start;\n\n        std::cout << \"dod+ntscd: \"\n                  << static_cast<float>(elapsed) / CLOCKS_PER_SEC << \" s (\"\n                  << elapsed << \" ticks)\\n\";\n    }\n    /*\n\n    }\n    if (ntscd_legacy) {\n        opts.algorithm =\n   dg::ControlDependenceAnalysisOptions::CDAlgorithm::NTSCD_LEGACY;\n        analyses.emplace_back(\"ntscd-legacy\", new\n   LLVMControlDependenceAnalysis(M.get(), opts), 0);\n    }\n   if (scc) {\n        opts.algorithm =\n   dg::ControlDependenceAnalysisOptions::CDAlgorithm::STRONG_CC;\n        analyses.emplace_back(\"scc\", new LLVMControlDependenceAnalysis(M.get(),\n   opts), 0);\n    }\n    */\n    return 0;\n}\n"
  },
  {
    "path": "tools/llvm-cg-dump.cpp",
    "content": "#include <cassert>\n#include <fstream>\n#include <iostream>\n#include <set>\n#include <string>\n#include <vector>\n\n#include \"dg/tools/llvm-slicer-opts.h\"\n#include \"dg/tools/llvm-slicer-utils.h\"\n#include \"dg/tools/llvm-slicer.h\"\n\n#if LLVM_VERSION_MAJOR >= 4\n#include <llvm/Bitcode/BitcodeReader.h>\n#include <llvm/Bitcode/BitcodeWriter.h>\n#else\n#include <llvm/Bitcode/ReaderWriter.h>\n#endif\n\n#include <llvm/IR/InstIterator.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/LLVMContext.h>\n#include <llvm/Support/raw_ostream.h>\n\n#ifdef HAVE_SVF\n#include \"dg/llvm/PointerAnalysis/SVFPointerAnalysis.h\"\n#endif\n#include \"dg/llvm/CallGraph/CallGraph.h\"\n#include \"dg/llvm/PointerAnalysis/DGPointerAnalysis.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n#include \"dg/util/debug.h\"\n\nusing namespace dg;\n\nusing llvm::errs;\n\nllvm::cl::opt<bool> enable_debug(\n        \"dbg\", llvm::cl::desc(\"Enable debugging messages (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> usepta(\"use-pta\",\n                           llvm::cl::desc(\"Use points analysis to build CG.\"),\n                           llvm::cl::init(true), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> lazy(\"lazy-cg\",\n                         llvm::cl::desc(\"Use the LazyLLVMCallGraph.\"),\n                         llvm::cl::init(true), llvm::cl::cat(SlicingOpts));\n\nstatic void dumpCallGraph(llvmdg::CallGraph &CG) {\n    std::cout << \"digraph CallGraph {\\n\";\n\n    for (const auto *f : CG.functions()) {\n        for (const auto *c : CG.callees(f)) {\n            std::cout << \"  \\\"\" << f->getName().str() << \"\\\" -> \\\"\"\n                      << c->getName().str() << \"\\\"\\n\";\n        }\n    }\n\n    std::cout << \"}\\n\";\n}\n\nint main(int argc, char *argv[]) {\n    setupStackTraceOnError(argc, argv);\n    SlicerOptions options = parseSlicerOptions(argc, argv);\n\n    if (enable_debug) {\n        DBG_ENABLE();\n    }\n\n    llvm::LLVMContext context;\n    std::unique_ptr<llvm::Module> M =\n            parseModule(\"llvm-cg-dump\", context, options);\n    if (!M)\n        return 1;\n\n    if (!M->getFunction(options.dgOptions.entryFunction)) {\n        llvm::errs() << \"The entry function not found: \"\n                     << options.dgOptions.entryFunction << \"\\n\";\n        return 1;\n    }\n\n    if (usepta) {\n        auto &ptaopts = options.dgOptions.PTAOptions;\n#ifdef HAVE_SVF\n        if (ptaopts.isSVF()) {\n            SVFPointerAnalysis PTA(M.get(), ptaopts);\n            PTA.run();\n\n            llvmdg::CallGraph CG(M.get(), &PTA, lazy);\n            dumpCallGraph(CG);\n        } else\n#endif // HAVE_SVF\n        {\n            DGLLVMPointerAnalysis PTA(M.get(), ptaopts);\n            PTA.run();\n\n            if (lazy) {\n                llvmdg::CallGraph CG(M.get(), &PTA, lazy);\n                CG.build();\n                dumpCallGraph(CG);\n            } else {\n                // re-use the call-graph from PTA\n                llvmdg::CallGraph CG(PTA.getPTA()->getPG()->getCallGraph());\n                dumpCallGraph(CG);\n            }\n        }\n    } else {\n        if (!lazy) {\n            llvm::errs() << \"Can build CG without PTA only with -lazy option\\n\";\n            return 1;\n        }\n\n        llvmdg::CallGraph CG(M.get());\n        CG.build();\n        dumpCallGraph(CG);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tools/llvm-dda-dump.cpp",
    "content": "#include <cassert>\n#include <cinttypes>\n#include <cstdio>\n#include <fstream>\n#include <iostream>\n#include <set>\n#include <sstream>\n#include <string>\n\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/LLVMContext.h>\n#include <llvm/IR/Module.h>\n#include <llvm/Support/raw_ostream.h>\n\n#if LLVM_VERSION_MAJOR >= 4\n#include <llvm/Bitcode/BitcodeReader.h>\n#include <llvm/Bitcode/BitcodeWriter.h>\n#else\n#include <llvm/Bitcode/ReaderWriter.h>\n#endif\n\n#include \"dg/PointerAnalysis/Pointer.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFI.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFS.h\"\n\n#include \"dg/llvm/DataDependence/DataDependence.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n\n#include \"dg/tools/llvm-slicer-opts.h\"\n#include \"dg/tools/llvm-slicer-utils.h\"\n\n#include \"dg/util/TimeMeasure.h\"\n#include \"dg/util/debug.h\"\n\nusing namespace dg;\nusing namespace dg::dda;\nusing llvm::errs;\n\nllvm::cl::opt<bool> enable_debug(\n        \"dbg\", llvm::cl::desc(\"Enable debugging messages (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> verbose(\"v\",\n                            llvm::cl::desc(\"Verbose output (default=false).\"),\n                            llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> graph_only(\n        \"graph-only\",\n        llvm::cl::desc(\n                \"Dump only graph, do not run any analysis (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        todot(\"dot\", llvm::cl::desc(\"Output in graphviz format (forced atm.).\"),\n              llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> quiet(\"q\", llvm::cl::desc(\"No output (for benchmarking).\"),\n                          llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> dump_c_lines(\n        \"c-lines\",\n        llvm::cl::desc(\"Dump output as C lines (line:column where possible).\"\n                       \"Requires metadata in the bitcode (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nusing VariablesMapTy = std::map<const llvm::Value *, CVariableDecl>;\nVariablesMapTy allocasToVars(const llvm::Module &M);\nVariablesMapTy valuesToVars;\n\nstatic inline size_t count_ws(const std::string &str) {\n    size_t n = 0;\n    while (isspace(str[n])) {\n        ++n;\n    }\n    return n;\n}\n\nstatic inline size_t trim_name_idx(const std::string &str) {\n    // skip, e.g., align attributes, etc.\n    auto m = str.rfind(\", align\");\n    if (m == std::string::npos)\n        return str.length();\n    return m - 1;\n}\n\nstatic std::string getInstName(const llvm::Value *val) {\n    assert(val);\n    std::ostringstream ostr;\n    llvm::raw_os_ostream ro(ostr);\n\n    if (dump_c_lines) {\n        if (const auto *I = llvm::dyn_cast<llvm::Instruction>(val)) {\n            const auto &DL = I->getDebugLoc();\n            if (DL) {\n                ro << DL.getLine() << \":\" << DL.getCol();\n            } else {\n                auto Vit = valuesToVars.find(I);\n                if (Vit != valuesToVars.end()) {\n                    auto &decl = Vit->second;\n                    ro << decl.line << \":\" << decl.col;\n                } else {\n                    ro << \"(no dbg) \";\n                    ro << *val;\n                }\n            }\n        }\n    } else {\n        ro << *val;\n    }\n\n    ro.flush();\n\n    auto str = ostr.str();\n    auto n = count_ws(str);\n    auto m = trim_name_idx(str);\n    if (n > 0)\n        str = str.substr(n, m);\n\n    if (dump_c_lines)\n        return str;\n\n    if (const auto *I = llvm::dyn_cast<llvm::Instruction>(val)) {\n        const auto &fun = I->getParent()->getParent()->getName();\n        auto funstr = fun.str();\n        if (funstr.length() > 15)\n            funstr = funstr.substr(0, 15);\n        funstr += \"::\";\n        funstr += str;\n        return funstr;\n    }\n\n    return str;\n}\n\nstatic void printRWNodeType(enum RWNodeType type) {\n#define ELEM(t)                                                                \\\n    case (t):                                                                  \\\n        do {                                                                   \\\n            printf(\"%s\", #t);                                                  \\\n        } while (0);                                                           \\\n        break;\n    switch (type) {\n        ELEM(RWNodeType::ALLOC)\n        ELEM(RWNodeType::DYN_ALLOC)\n        ELEM(RWNodeType::GLOBAL)\n        ELEM(RWNodeType::STORE)\n        ELEM(RWNodeType::LOAD)\n        ELEM(RWNodeType::PHI)\n        ELEM(RWNodeType::INARG)\n        ELEM(RWNodeType::OUTARG)\n        ELEM(RWNodeType::CALLIN)\n        ELEM(RWNodeType::CALLOUT)\n        ELEM(RWNodeType::MU)\n        ELEM(RWNodeType::CALL)\n        ELEM(RWNodeType::FORK)\n        ELEM(RWNodeType::JOIN)\n        ELEM(RWNodeType::RETURN)\n        ELEM(RWNodeType::NOOP)\n        ELEM(RWNodeType::GENERIC)\n        ELEM(RWNodeType::NONE)\n    default:\n        printf(\"!unknown RWNodeType!\");\n    };\n#undef ELEM\n}\n\ntemplate <typename T>\nstatic void printInterval(T &I, const char *pref = nullptr,\n                          const char *suff = nullptr) {\n    if (pref)\n        printf(\"%s\", pref);\n\n    if (I.start.isUnknown())\n        printf(\"[? - \");\n    else\n        printf(\"[%\" PRIu64 \" - \", *I.start);\n\n    if (I.end.isUnknown())\n        printf(\"?]\");\n    else\n        printf(\"%\" PRIu64 \"]\", *I.end);\n\n    if (suff)\n        printf(\"%s\", suff);\n}\n\nclass Dumper {\n  protected:\n    LLVMDataDependenceAnalysis *DDA;\n    bool dot{false};\n\n    virtual void dumpBBlockDefinitions(RWBBlock * /*unused*/) {}\n\n    virtual void dumpSubgraphLabel(RWSubgraph *subgraph) {\n        printf(\"  label=\\\"subgraph: %s(%p)\\\\n\\\";\\n\",\n               subgraph->getName().c_str(), subgraph);\n    }\n\n    void printName(const RWNode *node) {\n        if (node == nullptr) {\n            printf(\"nullptr\");\n            return;\n        }\n\n        if (node == UNKNOWN_MEMORY) {\n            printf(\"unknown mem\");\n            return;\n        }\n\n        const char *name = nullptr;\n\n        std::string nm;\n        if (!name) {\n            const auto *val = DDA->getValue(node);\n            if (!val) {\n                printRWNodeType(node->getType());\n                printId(node);\n                return;\n            }\n\n            nm = getInstName(val);\n            name = nm.c_str();\n        }\n\n        // escape the \" character\n        for (int i = 0; name[i] != '\\0'; ++i) {\n            // crop long names\n            if (i >= 70) {\n                printf(\" ...\");\n                break;\n            }\n\n            if (name[i] == '\"')\n                putchar('\\\\');\n\n            putchar(name[i]);\n        }\n    }\n\n    void nodeToDot(RWNode *node) {\n        static std::set<RWNode *> _dumped;\n        if (!_dumped.insert(node).second) // already dumped\n            return;\n\n        printf(\"\\tNODE%p \", static_cast<const void *>(node));\n        printf(\"[label=<<table border=\\\"0\\\"><tr><td>(%u)</td> \", node->getID());\n        printf(\"<td><font color=\\\"#af0000\\\">\");\n        printName(node);\n        printf(\"</font></td>\");\n        printf(\"</tr>\\n\");\n\n        if (node->getSize() > 0) {\n            printf(\"<tr><td></td><td>size: %zu</td></tr>\\n\", node->getSize());\n        }\n\n        if (verbose) {\n            printf(\"<tr><td>type:</td><td>\");\n            printRWNodeType(node->getType());\n            printf(\"</td></tr>\\n\");\n            printf(\"<tr><td colspan=\\\"2\\\">bblock: %p</td></tr>\\n\",\n                   node->getBBlock());\n            dumpDefines(node);\n            dumpOverwrites(node);\n            dumpUses(node);\n        }\n\n        // dumped data for undefined functions\n        // (call edges will be dumped with other edges)\n        if (auto *C = RWNodeCall::get(node)) {\n            for (auto &cv : C->getCallees()) {\n                if (const RWNode *undef = cv.getCalledValue()) {\n                    printf(\"<tr><td></td><td>------ undef call \"\n                           \"------</td></tr>\\n\");\n                    dumpDefines(undef);\n                    dumpOverwrites(undef);\n                    dumpUses(undef);\n                }\n            }\n        }\n\n        puts(\"</table>>\"); // end of label\n        printf(\" style=filled fillcolor=white shape=box]\\n\");\n    }\n\n    void dumpNodeEdges(RWNode *node) {\n        static std::set<RWNode *> dumped;\n        if (!dumped.insert(node).second)\n            return;\n\n        if (verbose || node->isPhi()) {\n            for (RWNode *def : node->defuse) {\n                printf(\"\\tNODE%p->NODE%p [style=dotted constraint=false]\\n\",\n                       static_cast<void *>(def), static_cast<void *>(node));\n            }\n        }\n        if (!graph_only && node->isUse()) {\n            for (RWNode *def : DDA->getDefinitions(node)) {\n                nodeToDot(def);\n                printf(\"\\tNODE%p->NODE%p [style=dotted constraint=false \"\n                       \"color=blue]\\n\",\n                       static_cast<void *>(def), static_cast<void *>(node));\n            }\n        }\n        if (auto *C = RWNodeCall::get(node)) {\n            for (auto &cv : C->getCallees()) {\n                if (auto *s = cv.getSubgraph()) {\n                    assert(s->getRoot() && \"Subgraph has no root\");\n                    printf(\"\\tNODE%p->NODE%p \"\n                           \"[penwidth=4 color=blue \"\n                           \"ltail=cluster_subg_%p]\\n\",\n                           static_cast<void *>(C),\n                           static_cast<const void *>(s->getRoot()), s);\n                } else {\n                    printf(\"\\tNODE%p->NODE%p [style=dashed constraint=false \"\n                           \"color=blue]\\n\",\n                           static_cast<void *>(C),\n                           static_cast<void *>(cv.getCalledValue()));\n                }\n            }\n        }\n    }\n\n  public:\n    Dumper(LLVMDataDependenceAnalysis *DDA, bool todot = false)\n            : DDA(DDA), dot(todot) {}\n\n    static void dumpBBlockEdges(RWBBlock *block) {\n        // dump CFG edges between nodes in one block\n        RWNode *last = nullptr;\n        for (RWNode *node : block->getNodes()) {\n            if (last) { // successor edge\n                printf(\"\\tNODE%p->NODE%p [constraint=true]\\n\",\n                       static_cast<void *>(last), static_cast<void *>(node));\n            }\n            last = node;\n        }\n        putchar('\\n');\n    }\n\n    void dumpBBlock(RWBBlock *block) {\n        printf(\"subgraph cluster_bb_%p {\\n\", block);\n        printf(\"    style=filled;\\n\");\n        printf(\"    fillcolor=\\\"#eeeeee\\\";\\n\");\n        printf(\"    color=\\\"black\\\";\\n\");\n\n        puts(\"label=<<table border=\\\"0\\\">\");\n        printf(\"<tr><td colspan=\\\"4\\\">bblock %u (%p)</td></tr>\", block->getID(),\n               block);\n        dumpBBlockDefinitions(block);\n        printf(\"</table>>\\nlabelloc=b\\n\");\n\n        /* dump nodes */\n        if (block->empty()) {\n            // if the block is empty, create at least a\n            // dummy node so that we can draw CFG edges to it\n            printf(\"\\tNODE%p [label=\\\"empty blk\\\"]\\n\",\n                   static_cast<void *>(block));\n        } else {\n            for (RWNode *node : block->getNodes()) {\n                nodeToDot(node);\n\n                if (auto *C = RWNodeCall::get(node)) {\n                    for (auto &cv : C->getCallees()) {\n                        if (auto *val = cv.getCalledValue())\n                            nodeToDot(val);\n                    }\n\n                    for (auto *i : C->getInputs()) {\n                        nodeToDot(i);\n                    }\n                    for (auto *o : C->getOutputs()) {\n                        nodeToDot(o);\n                    }\n                }\n            }\n        }\n\n        printf(\"}\\n\");\n    }\n\n    void dump() {\n        if (dot)\n            dumpToDot();\n        else\n            dumpToTty();\n    }\n\n    void dumpRWNode(RWNode *n) {\n        printf(\"NODE [%u]: \", n->getID());\n        if (n == nullptr) {\n            printf(\"nullptr\\n\");\n            return;\n        }\n        printName(n);\n        if (n->getSize() > 0)\n            printf(\" [size: %zu]\", n->getSize());\n        putchar('\\n');\n    }\n\n    void dumpToTty() {\n        for (auto *subg : DDA->getGraph()->subgraphs()) {\n            printf(\"=========== fun: %s ===========\\n\",\n                   subg->getName().c_str());\n            for (auto *bb : subg->bblocks()) {\n                printf(\"<<< bblock: %u >>>\\n\", bb->getID());\n                for (auto *node : bb->getNodes()) {\n                    dumpRWNode(node);\n                    if (!graph_only && node->isUse() && !node->isPhi()) {\n                        for (RWNode *def : DDA->getDefinitions(node)) {\n                            printf(\"  <- \");\n                            printName(def);\n                            putchar('\\n');\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    void dumpToDot() {\n        assert(dot && \"Non-dot dump unsupported right now\");\n\n        printf(\"digraph \\\"Data Dependencies Graph\\\" {\\n\");\n        printf(\"  compound=true;\\n\\n\");\n\n        /*\n        for (auto *global : DDA->getGraph()->getGlobals()) {\n            nodeToDot(global);\n        }\n        */\n\n        for (auto *subg : DDA->getGraph()->subgraphs()) {\n            printf(\"subgraph cluster_subg_%p {\\n\", subg);\n            printf(\"  compound=true;\\n\\n\");\n            printf(\"  style=filled;\\n\");\n            printf(\"  fillcolor=white; color=blue;\\n\");\n\n            dumpSubgraphLabel(subg);\n\n            // dump summary nodes\n            auto *SSA = static_cast<MemorySSATransformation *>(\n                    DDA->getDDA()->getImpl());\n            const auto *summary = SSA->getSummary(subg);\n            if (summary) {\n                for (const auto &i : summary->inputs) {\n                    for (const auto &it : i.second)\n                        for (auto *nd : it.second)\n                            nodeToDot(nd);\n                }\n                for (const auto &o : summary->outputs) {\n                    for (const auto &it : o.second)\n                        for (auto *nd : it.second)\n                            nodeToDot(nd);\n                }\n            }\n\n            for (auto *block : subg->bblocks()) {\n                dumpBBlock(block);\n            }\n            printf(\"}\\n\");\n        }\n\n        for (auto *subg : DDA->getGraph()->subgraphs()) {\n            // dump summary nodes edges\n            auto *SSA = static_cast<MemorySSATransformation *>(\n                    DDA->getDDA()->getImpl());\n            const auto *summary = SSA->getSummary(subg);\n            if (summary) {\n                for (const auto &i : summary->inputs) {\n                    for (const auto &it : i.second)\n                        for (auto *nd : it.second)\n                            dumpNodeEdges(nd);\n                }\n                for (const auto &o : summary->outputs) {\n                    for (const auto &it : o.second)\n                        for (auto *nd : it.second)\n                            dumpNodeEdges(nd);\n                }\n            }\n\n            // CFG\n            for (auto *bblock : subg->bblocks()) {\n                dumpBBlockEdges(bblock);\n\n                for (auto *succ : bblock->successors()) {\n                    printf(\"\\tNODE%p -> NODE%p \"\n                           \"[penwidth=2 constraint=true\"\n                           \" lhead=\\\"cluster_bb_%p\\\"\"\n                           \" ltail=\\\"cluster_bb_%p\\\"]\\n\",\n                           bblock->empty()\n                                   ? static_cast<void *>(bblock)\n                                   : static_cast<void *>(bblock->getLast()),\n                           succ->empty()\n                                   ? static_cast<void *>(succ)\n                                   : static_cast<void *>(succ->getFirst()),\n                           static_cast<void *>(bblock),\n                           static_cast<void *>(succ));\n                }\n            }\n\n            // def-use\n            for (auto *bblock : subg->bblocks()) {\n                for (auto *node : bblock->getNodes()) {\n                    dumpNodeEdges(node);\n\n                    if (auto *C = RWNodeCall::get(node)) {\n                        for (auto *n : C->getInputs())\n                            dumpNodeEdges(n);\n                        for (auto *n : C->getOutputs())\n                            dumpNodeEdges(n);\n                    }\n                }\n            }\n        }\n\n        printf(\"}\\n\");\n    }\n\n  private:\n    static void printId(const RWNode *node) { printf(\" [%u]\", node->getID()); }\n\n    void _dumpDefSites(const std::set<DefSite> &defs, const char *kind) {\n        if (defs.empty())\n            return;\n\n        printf(\"<tr><td></td><td>------ %s ------</td></tr>\\n\", kind);\n        for (const DefSite &def : defs) {\n            puts(\"<tr><td></td><td>\");\n            printName(def.target);\n            if (def.offset.isUnknown())\n                printf(\" [? - \");\n            else\n                printf(\" [%\" PRIu64 \" - \", *def.offset);\n\n            if (def.len.isUnknown())\n                printf(\"?]\");\n            else\n                printf(\"%\" PRIu64 \"]\", *def.offset + (*def.len - 1));\n            puts(\"</td></tr>\\n\");\n        }\n    }\n\n    void dumpDefines(const RWNode *node) {\n        if (!node->getDefines().empty()) {\n            _dumpDefSites(node->getDefines(), \"defines\");\n        }\n    }\n\n    void dumpOverwrites(const RWNode *node) {\n        if (!node->getOverwrites().empty()) {\n            _dumpDefSites(node->getOverwrites(), \"overwrites\");\n        }\n    }\n\n    void dumpUses(const RWNode *node) {\n        if (!node->getUses().empty()) {\n            _dumpDefSites(node->getUses(), \"uses\");\n        }\n    }\n};\n\nclass MemorySSADumper : public Dumper {\n    void _dumpDefSites(RWNode *n, const std::set<DefSite> &defs) {\n        if (defs.empty())\n            return;\n\n        for (const DefSite &def : defs) {\n            printf(\"<tr><td>at (%u): </td><td>(%u)</td><td>\", n->getID(),\n                   def.target->getID());\n            printName(def.target);\n            printf(\"</td><td>\");\n            if (def.offset.isUnknown())\n                printf(\" [? - \");\n            else\n                printf(\" [%\" PRIu64 \" - \", *def.offset);\n\n            if (def.len.isUnknown())\n                printf(\"?]\");\n            else\n                printf(\"%\" PRIu64 \"]\", *def.offset + (*def.len - 1));\n            puts(\"</td></tr>\\n\");\n        }\n    }\n\n    void dumpDDIMap(const DefinitionsMap<RWNode> &map) {\n        for (const auto &it : map) {\n            for (const auto &it2 : it.second) {\n                printf(R\"(<tr><td align=\"left\" colspan=\"4\">)\");\n                printName(it.first);\n                printf(\"</td></tr>\");\n                for (auto *where : it2.second) {\n                    printf(\"<tr><td>&nbsp;&nbsp;</td><td>\");\n                    printInterval(it2.first);\n                    printf(\"</td><td>@</td><td>\");\n                    printName(where);\n                    puts(\"</td></tr>\");\n                }\n            }\n        }\n    }\n\n    void dumpBBlockDefinitions(RWBBlock *block) override {\n        auto *SSA = static_cast<MemorySSATransformation *>(\n                DDA->getDDA()->getImpl());\n        const auto *D = SSA->getDefinitions(block);\n        if (!D)\n            return;\n        printf(\"<tr><td colspan=\\\"4\\\">==  defines ==</td></tr>\");\n        dumpDDIMap(D->definitions);\n        printf(\"<tr><td colspan=\\\"4\\\">==  kills ==</td></tr>\");\n        dumpDDIMap(D->kills);\n    }\n\n    void dumpSubgraphLabel(RWSubgraph *subgraph) override {\n        auto *SSA = static_cast<MemorySSATransformation *>(\n                DDA->getDDA()->getImpl());\n        const auto *summary = SSA->getSummary(subgraph);\n\n        if (!summary) {\n            printf(\"  label=<<table cellborder=\\\"0\\\">\\n\"\n                   \"<tr><td>subgraph %s(%p)</td></tr>\\n\"\n                   \"<tr><td>no summary</td></tr></table>>;\\n\",\n                   subgraph->getName().c_str(), subgraph);\n            return;\n        }\n\n        printf(\"  label=<<table cellborder=\\\"0\\\"><tr><td \"\n               \"colspan=\\\"4\\\">subgraph %s (%p)</td></tr>\\n\"\n               \"<tr><td colspan=\\\"4\\\">-- summary -- </td></tr>\\n\",\n               subgraph->getName().c_str(), subgraph);\n        printf(\"<tr><td colspan=\\\"4\\\">==  inputs ==</td></tr>\");\n        dumpDDIMap(summary->inputs);\n        printf(\"<tr><td colspan=\\\"4\\\">==  outputs ==</td></tr>\");\n        dumpDDIMap(summary->outputs);\n        printf(\"</table>>;\\n\");\n    }\n\n  public:\n    MemorySSADumper(LLVMDataDependenceAnalysis *DDA, bool todot)\n            : Dumper(DDA, todot) {}\n};\n\nstatic void dumpDefs(LLVMDataDependenceAnalysis *DDA, bool todot) {\n    assert(DDA);\n\n    if (DDA->getOptions().isSSA()) {\n        auto *SSA = static_cast<MemorySSATransformation *>(\n                DDA->getDDA()->getImpl());\n        if (!graph_only)\n            SSA->computeAllDefinitions();\n\n        if (quiet)\n            return;\n\n        MemorySSADumper dumper(DDA, todot);\n        dumper.dump();\n    } else {\n        Dumper dumper(DDA, todot);\n        dumper.dump();\n    }\n}\n\nint main(int argc, char *argv[]) {\n    setupStackTraceOnError(argc, argv);\n    SlicerOptions options = parseSlicerOptions(argc, argv);\n\n    if (enable_debug) {\n        DBG_ENABLE();\n    }\n\n    llvm::LLVMContext context;\n    std::unique_ptr<llvm::Module> M =\n            parseModule(\"llvm-dda-dump\", context, options);\n    if (!M)\n        return 1;\n\n    if (!M->getFunction(options.dgOptions.entryFunction)) {\n        llvm::errs() << \"The entry function not found: \"\n                     << options.dgOptions.entryFunction << \"\\n\";\n        return 1;\n    }\n\n    debug::TimeMeasure tm;\n\n    DGLLVMPointerAnalysis PTA(M.get(), options.dgOptions.PTAOptions);\n\n    tm.start();\n    PTA.run();\n\n    tm.stop();\n    tm.report(\"INFO: Pointer analysis took\");\n\n    tm.start();\n    LLVMDataDependenceAnalysis DDA(M.get(), &PTA, options.dgOptions.DDAOptions);\n    if (graph_only) {\n        DDA.buildGraph();\n    } else {\n        DDA.run();\n    }\n    tm.stop();\n    tm.report(\"INFO: Data dependence analysis took\");\n\n    if (dump_c_lines) {\n#if (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7)\n        llvm::errs() << \"WARNING: Variables names matching is not supported \"\n                        \"for LLVM older than 3.7\\n\";\n#else\n        valuesToVars = allocasToVars(*M);\n#endif // LLVM > 3.6\n        if (valuesToVars.empty()) {\n            llvm::errs() << \"WARNING: No debugging information found, \"\n                         << \"the C lines output will be corrupted\\n\";\n        }\n    }\n\n    dumpDefs(&DDA, todot);\n\n    return 0;\n}\n"
  },
  {
    "path": "tools/llvm-dg-dump.cpp",
    "content": "#include <fstream>\n#include <iostream>\n#include <set>\n#include <sstream>\n#include <string>\n\n#include <cassert>\n#include <cstdio>\n\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/LLVMContext.h>\n#include <llvm/IR/Module.h>\n#include <llvm/Support/raw_ostream.h>\n\n#if LLVM_VERSION_MAJOR >= 4\n#include <llvm/Bitcode/BitcodeReader.h>\n#include <llvm/Bitcode/BitcodeWriter.h>\n#else\n#include <llvm/Bitcode/ReaderWriter.h>\n#endif\n\n#include \"dg/PointerAnalysis/PointerAnalysisFI.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFS.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFSInv.h\"\n#include \"dg/llvm/DataDependence/DataDependence.h\"\n#include \"dg/llvm/LLVMDG2Dot.h\"\n#include \"dg/llvm/LLVMDependenceGraph.h\"\n#include \"dg/llvm/LLVMDependenceGraphBuilder.h\"\n#include \"dg/llvm/LLVMSlicer.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n\n#include \"dg/tools/llvm-slicer-opts.h\"\n#include \"dg/tools/llvm-slicer-utils.h\"\n\n#include \"dg/util/TimeMeasure.h\"\n\nusing namespace dg;\nusing namespace dg::debug;\nusing llvm::errs;\n\nllvm::cl::opt<bool> enable_debug(\n        \"dbg\", llvm::cl::desc(\"Enable debugging messages (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> bb_only(\n        \"bb-only\",\n        llvm::cl::desc(\"Only dump basic blocks of dependence graph to dot\"\n                       \" (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> mark_only(\n        \"mark\",\n        llvm::cl::desc(\"Only mark nodes that are going to be in the slice\"\n                       \" (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<std::string>\n        dump_func_only(\"func\", llvm::cl::desc(\"Only dump a given function.\"),\n                       llvm::cl::value_desc(\"string\"), llvm::cl::init(\"\"),\n                       llvm::cl::cat(SlicingOpts));\n\n// TODO: This machinery can be replaced with llvm::cl::callback setting\n// the desired flags directly when we drop support for LLVM 9 and older.\nenum PrintingOpts {\n    call,\n    cfgall,\n    postdom,\n    no_cfg,\n    no_control,\n    no_data,\n    no_use\n};\n\nllvm::cl::list<PrintingOpts> print_opts(\n        llvm::cl::desc(\"Dot printer options:\"),\n        llvm::cl::values(\n                clEnumVal(call, \"Print calls (default=false).\"),\n                clEnumVal(cfgall,\n                          \"Print full control flow graph (default=false).\"),\n                clEnumVal(postdom,\n                          \"Print post dominator tree (default=false).\"),\n                clEnumValN(no_cfg, \"no-cfg\",\n                           \"Do not print control flow graph (default=false).\"),\n                clEnumValN(\n                        no_control, \"no-control\",\n                        \"Do not print control dependencies (default=false).\"),\n                clEnumValN(no_data, \"no-data\",\n                           \"Do not print data dependencies (default=false).\"),\n                clEnumValN(no_use, \"no-use\",\n                           \"Do not print uses (default=false).\")\n#if LLVM_VERSION_MAJOR < 4\n                        ,\n                nullptr\n#endif\n                ),\n        llvm::cl::cat(SlicingOpts));\n\nint main(int argc, char *argv[]) {\n    setupStackTraceOnError(argc, argv);\n    SlicerOptions options = parseSlicerOptions(argc, argv);\n\n    uint32_t opts = PRINT_CFG | PRINT_DD | PRINT_CD | PRINT_USE | PRINT_ID;\n    for (auto opt : print_opts) {\n        switch (opt) {\n        case no_control:\n            opts &= ~PRINT_CD;\n            break;\n        case no_use:\n            opts &= ~PRINT_USE;\n            break;\n        case no_data:\n            opts &= ~PRINT_DD;\n            break;\n        case no_cfg:\n            opts &= ~PRINT_CFG;\n            break;\n        case call:\n            opts |= PRINT_CALL;\n            break;\n        case postdom:\n            opts |= PRINT_POSTDOM;\n            break;\n        case cfgall:\n            opts |= PRINT_CFG | PRINT_REV_CFG;\n            break;\n        }\n    }\n\n    if (enable_debug) {\n        DBG_ENABLE();\n    }\n\n    llvm::LLVMContext context;\n    std::unique_ptr<llvm::Module> M =\n            parseModule(\"llvm-dg-dump\", context, options);\n    if (!M)\n        return 1;\n\n    llvmdg::LLVMDependenceGraphBuilder builder(M.get(), options.dgOptions);\n    auto dg = builder.build();\n\n    std::set<LLVMNode *> callsites;\n    const std::string &slicingCriteria = options.slicingCriteria;\n    if (!slicingCriteria.empty()) {\n        const char *sc[] = {slicingCriteria.c_str(), \"klee_assume\", nullptr};\n\n        dg->getCallSites(sc, &callsites);\n\n        llvmdg::LLVMSlicer slicer;\n\n        if (slicingCriteria == \"ret\") {\n            if (mark_only)\n                slicer.mark(dg->getExit());\n            else\n                slicer.slice(dg.get(), dg->getExit());\n        } else {\n            if (callsites.empty()) {\n                errs() << \"ERR: slicing criterion not found: \"\n                       << slicingCriteria << \"\\n\";\n                exit(1);\n            }\n\n            uint32_t slid = 0;\n            for (LLVMNode *start : callsites)\n                slid = slicer.mark(start, slid);\n\n            if (!mark_only)\n                slicer.slice(dg.get(), nullptr, slid);\n        }\n\n        if (!mark_only) {\n            std::string fl(options.inputFile);\n            fl.append(\".sliced\");\n            std::ofstream ofs(fl);\n            llvm::raw_os_ostream output(ofs);\n\n            SlicerStatistics &st = slicer.getStatistics();\n            errs() << \"INFO: Sliced away \" << st.nodesRemoved << \" from \"\n                   << st.nodesTotal << \" nodes\\n\";\n\n#if LLVM_VERSION_MAJOR > 6\n            llvm::WriteBitcodeToFile(*M, output);\n#else\n            llvm::WriteBitcodeToFile(M.get(), output);\n#endif\n        }\n    }\n    const char *only_func = nullptr;\n    if (!dump_func_only.empty())\n        only_func = dump_func_only.c_str();\n\n    if (bb_only) {\n        LLVMDGDumpBlocks dumper(dg.get(), opts);\n        dumper.dump(nullptr, only_func);\n    } else {\n        LLVMDG2Dot dumper(dg.get(), opts);\n        dumper.dump(nullptr, only_func);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tools/llvm-ntscd-dump.cpp",
    "content": "#include \"dg/PointerAnalysis/PointerAnalysisFI.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n\n#include \"llvm/ControlDependence/legacy/GraphBuilder.h\"\n#include \"llvm/ControlDependence/legacy/NTSCD.h\"\n\n#include <llvm/IR/LLVMContext.h>\n#include <llvm/IR/Module.h>\n#include <llvm/IRReader/IRReader.h>\n#include <llvm/Support/CommandLine.h>\n#include <llvm/Support/SourceMgr.h>\n\n#include <fstream>\n#include <memory>\n\nint main(int argc, const char *argv[]) {\n    using namespace std;\n    using namespace llvm;\n\n    llvm::cl::opt<string> OutputFilename(\n            \"o\", cl::desc(\"Specify output filename\"),\n            cl::value_desc(\"filename\"), cl::init(\"\"));\n\n    llvm::cl::opt<std::string> inputFile(cl::Positional, cl::Required,\n                                         cl::desc(\"<input file>\"),\n                                         cl::init(\"\"));\n    llvm::cl::opt<bool> threads(\n            \"consider-threads\",\n            llvm::cl::desc(\n                    \"Consider threads are in input file (default=false).\"),\n            llvm::cl::init(false));\n\n    llvm::cl::opt<bool> withpta(\n            \"pta\",\n            llvm::cl::desc(\"Run pointer analysis to ger reachable functions \"\n                           \"(default=false).\"),\n            llvm::cl::init(false));\n    llvm::LLVMContext context;\n    llvm::SMDiagnostic SMD;\n\n    cl::ParseCommandLineOptions(argc, argv);\n\n    string module = inputFile;\n    string graphVizFileName = OutputFilename;\n\n    std::unique_ptr<Module> M = llvm::parseIRFile(module, SMD, context);\n\n    if (!M) {\n        llvm::errs() << \"Failed parsing '\" << module << \"' file:\\n\";\n        SMD.print(argv[0], errs());\n        return 1;\n    }\n\n    std::unique_ptr<dg::LLVMPointerAnalysis> PTA;\n    if (withpta) {\n        dg::LLVMPointerAnalysisOptions opts;\n        opts.setEntryFunction(\"main\");\n        opts.analysisType = dg::LLVMPointerAnalysisOptions::AnalysisType::fi;\n        opts.threads = threads;\n        opts.setFieldSensitivity(dg::Offset::UNKNOWN);\n\n        PTA = std::unique_ptr<dg::DGLLVMPointerAnalysis>(\n                new dg::DGLLVMPointerAnalysis(M.get(), opts));\n        PTA->run();\n    }\n\n    dg::llvmdg::legacy::NTSCD controlDependencyAnalysis(M.get(), {}, PTA.get());\n    controlDependencyAnalysis.compute();\n\n    if (graphVizFileName.empty()) {\n        controlDependencyAnalysis.dump(std::cout);\n    } else {\n        std::ofstream graphvizFile(graphVizFileName);\n        controlDependencyAnalysis.dump(graphvizFile);\n    }\n    return 0;\n}\n"
  },
  {
    "path": "tools/llvm-pta-ben.cpp",
    "content": "#include <cassert>\n#include <cstdio>\n#include <cstdlib>\n#include <fstream>\n#include <iostream>\n#include <set>\n#include <sstream>\n#include <string>\n#include <vector>\n\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/LLVMContext.h>\n#include <llvm/IR/Module.h>\n#include <llvm/Support/raw_ostream.h>\n\n#if LLVM_VERSION_MAJOR >= 4\n#include <llvm/Bitcode/BitcodeReader.h>\n#else\n#include <llvm/Bitcode/ReaderWriter.h>\n#endif\n\n#include \"dg/PointerAnalysis/Pointer.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFI.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFS.h\"\n#include \"dg/PointerAnalysis/PointerAnalysisFSInv.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n\n#include \"dg/tools/llvm-slicer-opts.h\"\n#include \"dg/tools/llvm-slicer-utils.h\"\n\n#include \"dg/util/TimeMeasure.h\"\n\n#include \"llvm/llvm-utils.h\"\n\nusing namespace dg;\nusing namespace dg::pta;\nusing dg::debug::TimeMeasure;\nusing llvm::errs;\n\nllvm::cl::opt<bool> enable_debug(\n        \"dbg\", llvm::cl::desc(\"Enable debugging messages (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nstatic std::string getInstName(const llvm::Value *val) {\n    std::ostringstream ostr;\n    llvm::raw_os_ostream ro(ostr);\n\n    assert(val);\n    if (llvm::isa<llvm::Function>(val))\n        ro << val->getName().data();\n    else\n        ro << *val;\n\n    ro.flush();\n\n    // break the string if it is too long\n    return ostr.str();\n}\n\nvoid printPSNodeType(enum PSNodeType type) {\n    printf(\"%s\", PSNodeTypeToCString(type));\n}\n\nstatic void printName(PSNode *node, bool dot) {\n    std::string nm;\n    const char *name = nullptr;\n    if (node->isNull()) {\n        name = \"null\";\n    } else if (node->isUnknownMemory()) {\n        name = \"unknown\";\n    }\n\n    if (!name) {\n        if (!node->getUserData<llvm::Value>()) {\n            printPSNodeType(node->getType());\n            if (dot)\n                printf(\" %p\\\\n\", node);\n            else\n                printf(\" %p\\n\", node);\n\n            return;\n        }\n\n        nm = getInstName(node->getUserData<llvm::Value>());\n        name = nm.c_str();\n    }\n\n    // escape the \" character\n    for (int i = 0; name[i] != '\\0'; ++i) {\n        // crop long names\n        if (i >= 70) {\n            printf(\" ...\");\n            break;\n        }\n\n        if (name[i] == '\"')\n            putchar('\\\\');\n\n        putchar(name[i]);\n    }\n}\n\nstatic int dump_pointer(const Pointer &ptr, const char *name) {\n    printf(\"target %s=\", name);\n    printName(ptr.target, false);\n    printf(\"\\n\");\n    return 0;\n}\n\nusing AliasResult = int;\nconst AliasResult NoAlias = 1;\nconst AliasResult MayAlias = 2;\nconst AliasResult MustAlias = 3;\nconst AliasResult PartialAlias = 4;\n\nstatic int compare_pointer(const Pointer &ptr1, const Pointer &ptr2) {\n    dump_pointer(ptr1, \"1\");\n    dump_pointer(ptr2, \"2\");\n\n    if (ptr1.isUnknown() || ptr2.isUnknown())\n        return MayAlias;\n\n    if (ptr1.target == ptr2.target) {\n        if (ptr1.offset.isUnknown() || ptr2.offset.isUnknown()) {\n            return MayAlias;\n        }\n        if (ptr1.offset == ptr2.offset) {\n            return MustAlias;\n        }\n        // fall-through to NoAlias\n    }\n\n    return NoAlias;\n}\n\nstatic int check_pointer(const Pointer &ptr, const char *name) {\n    printf(\"target %s=\", name);\n    printName(ptr.target, false);\n    if (ptr.isUnknown()) {\n        printf(\"Unknown Ptr\\n\");\n        return MayAlias;\n    }\n    if (ptr.isNull()) {\n        printf(\"Null Ptr\\n\");\n        return MayAlias;\n    }\n    printf(\"\\n\");\n    return NoAlias;\n}\n\nstatic AliasResult doAlias(DGLLVMPointerAnalysis *pta, llvm::Value *V1,\n                           llvm::Value *V2) {\n    PSNode *p1 = pta->getPointsToNode(V1);\n    PSNode *p2 = pta->getPointsToNode(V2);\n    int count1 = 0;\n    int count2 = 0;\n    for (const Pointer &ptr1 : p1->pointsTo) {\n        count1++;\n        if (!ptr1.isValid())\n            continue;\n    }\n    for (const Pointer &ptr2 : p2->pointsTo) {\n        count2++;\n        if (!ptr2.isValid())\n            continue;\n    }\n\n    printf(\"counts = %d %d\\n\", count1, count2);\n    if (count1 > 1 || count2 > 1) {\n        for (const Pointer &ptr1 : p1->pointsTo) {\n            if (!ptr1.isValid())\n                continue;\n            dump_pointer(ptr1, \"1\");\n        }\n        for (const Pointer &ptr2 : p2->pointsTo) {\n            if (!ptr2.isValid())\n                continue;\n            dump_pointer(ptr2, \"2\");\n        }\n        return MayAlias;\n    }\n    Pointer ptr1(UNKNOWN_MEMORY, Offset::UNKNOWN);\n    Pointer ptr2(UNKNOWN_MEMORY, Offset::UNKNOWN);\n    if (count1 == 0 && count2 == 0) {\n        return NoAlias;\n    }\n    if (count1 == 1) {\n        auto itr1 = p1->pointsTo.begin();\n        ptr1 = *itr1;\n        for (; itr1 != p1->pointsTo.end(); ++itr1) {\n            ptr1 = *itr1;\n            if (!ptr1.isValid())\n                continue;\n            break;\n        }\n    }\n    if (count2 == 1) {\n        auto itr2 = p2->pointsTo.begin();\n        ptr2 = *itr2;\n        for (; itr2 != p2->pointsTo.end(); ++itr2) {\n            ptr2 = *itr2;\n            if (!ptr2.isValid())\n                continue;\n            break;\n        }\n    }\n    if (count1 == 0) {\n        return check_pointer(ptr2, \"2\");\n    }\n    if (count2 == 0) {\n        return check_pointer(ptr1, \"1\");\n    }\n    return compare_pointer(ptr1, ptr2);\n}\n\nstatic llvm::StringRef NOALIAS(\"NOALIAS\"), MAYALIAS(\"MAYALIAS\"),\n        MUSTALIAS(\"MUSTALIAS\"), PARTIALALIAS(\"PARTIALALIAS\"),\n        EXPECTEDFAIL_MAYALIAS = (\"EXPECTEDFAIL_MAYALIAS\"),\n        EXPECTEDFAIL_NOALIAS(\"EXPECTEDFAIL_NOALIAS\");\n\nstatic int test_checkfunc(const llvm::StringRef &fun) {\n    if (fun.equals(NOALIAS) || fun.equals(MAYALIAS) || fun.equals(MUSTALIAS) ||\n        fun.equals(PARTIALALIAS) || fun.equals(EXPECTEDFAIL_MAYALIAS) ||\n        fun.equals(EXPECTEDFAIL_NOALIAS)) {\n        return true;\n    }\n    return false;\n}\n\nstatic void evalPSNode(DGLLVMPointerAnalysis *pta, PSNode *node) {\n    enum PSNodeType nodetype = node->getType();\n    if (nodetype != PSNodeType::CALL) {\n        return;\n    }\n    if (node->isNull() || node->isUnknownMemory()) {\n        return;\n    }\n\n    const llvm::Value *val = node->getUserData<llvm::Value>();\n    if (!val)\n        return;\n    const llvm::CallInst *call = llvm::dyn_cast<llvm::CallInst>(val);\n    if (!call)\n        return;\n\n    const llvm::Value *v = call->getCalledFunction();\n    if (v == nullptr)\n        return;\n\n    const llvm::Function *called = llvm::cast<llvm::Function>(v);\n    const llvm::StringRef &fun = called->getName();\n\n    if (llvmutils::getNumArgOperands(call) != 2)\n        return;\n\n    if (!test_checkfunc(fun))\n        return;\n\n    llvm::Value *V1 = call->getArgOperand(0);\n    llvm::Value *V2 = call->getArgOperand(1);\n    const char *ex, *s, *score;\n    AliasResult aares = doAlias(pta, V1, V2);\n    // bool r = false;\n\n    if (fun.equals(NOALIAS)) {\n        // r = (aares == NoAlias);\n        ex = \"NO\";\n\n        if (aares == NoAlias)\n            score = \"true\";\n        else if (aares == MayAlias || aares == PartialAlias)\n            score = \"inadequate\";\n        else if (aares == MustAlias)\n            score = \"buggy\";\n        else\n            score = \"unknown\";\n    } else if (fun.equals(MAYALIAS) || fun.equals(PARTIALALIAS)) {\n        // r = (aares == MayAlias || aares == MustAlias);\n        ex = \"MAY\";\n\n        if (aares == NoAlias)\n            score = \"false\";\n        else if (aares == MayAlias || aares == PartialAlias)\n            score = \"true\";\n        else if (aares == MustAlias)\n            score = \"toomuch\";\n        else\n            score = \"unknown\";\n    } else if (fun.equals(MUSTALIAS)) {\n        // r = (aares == MustAlias);\n        ex = \"MUST\";\n\n        if (aares == NoAlias)\n            score = \"false\";\n        else if (aares == MayAlias)\n            score = \"inadequate\";\n        else if (aares == MustAlias)\n            score = \"true\";\n        else\n            score = \"unknown\";\n    } else if (fun.equals(EXPECTEDFAIL_MAYALIAS)) {\n        // r = (aares != MayAlias && aares != MustAlias);\n        ex = \"EXPECTEDFAIL_MAY\";\n\n        if (aares == NoAlias || aares == MustAlias)\n            score = \"true\";\n        else if (aares == MayAlias || aares == PartialAlias)\n            score = \"inadequate\";\n        else\n            score = \"unknown\";\n    } else if (fun.equals(EXPECTEDFAIL_NOALIAS)) {\n        // r = (aares != NoAlias);\n        ex = \"EXPECTEDFAIL_NO\";\n\n        if (aares == NoAlias)\n            score = \"false\";\n        else if (aares == MayAlias || aares == MustAlias ||\n                 aares == PartialAlias)\n            score = \"true\";\n        else\n            score = \"unknown\";\n    } else {\n        return;\n    }\n\n    if (aares == NoAlias)\n        s = \"NO\";\n    else if (aares == MayAlias)\n        s = \"MAY\";\n    else if (aares == MustAlias)\n        s = \"MUST\";\n    else\n        s = \"UNKNOWN\";\n    printf(\"  pta %s %s ex %s\\n\", score, s, ex);\n}\n\nstatic void evalPTA(DGLLVMPointerAnalysis *pta) {\n    for (const auto &node : pta->getNodes()) {\n        if (!node)\n            continue;\n        evalPSNode(pta, node.get());\n    }\n}\n\nint main(int argc, char *argv[]) {\n    setupStackTraceOnError(argc, argv);\n    SlicerOptions options = parseSlicerOptions(argc, argv);\n\n    if (enable_debug) {\n        DBG_ENABLE();\n    }\n\n    llvm::LLVMContext context;\n    std::unique_ptr<llvm::Module> M =\n            parseModule(\"llvm-pta-ben\", context, options);\n    if (!M)\n        return 1;\n\n    TimeMeasure tm;\n    auto &opts = options.dgOptions.PTAOptions;\n\n    DGLLVMPointerAnalysis PTA(M.get(), opts);\n\n    tm.start();\n\n    PTA.run();\n\n    tm.stop();\n    tm.report(\"INFO: Pointer analysis took\");\n\n    evalPTA(&PTA);\n\n    return 0;\n}\n"
  },
  {
    "path": "tools/llvm-pta-compare.cpp",
    "content": "#include <fstream>\n#include <iostream>\n#include <set>\n#include <sstream>\n#include <string>\n\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/LLVMContext.h>\n#include <llvm/IR/Module.h>\n#include <llvm/Support/raw_ostream.h>\n\n#if LLVM_VERSION_MAJOR >= 4\n#include <llvm/Bitcode/BitcodeReader.h>\n#else\n#include <llvm/Bitcode/ReaderWriter.h>\n#endif\n\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n\n#include \"dg/tools/llvm-slicer-opts.h\"\n#include \"dg/tools/llvm-slicer-utils.h\"\n\nusing namespace dg;\nusing namespace dg::pta;\nusing llvm::errs;\n\nllvm::cl::opt<bool> enable_debug(\n        \"dbg\", llvm::cl::desc(\"Enable debugging messages (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> uoff_covers(\n        \"uoff-covers\",\n        llvm::cl::desc(\n                \"Pointers with unknown offset cover pointers with concrete\"\n                \"offsets.(default=true).\"),\n        llvm::cl::init(true), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> unknown_covers(\n        \"unknown-covers\",\n        llvm::cl::desc(\n                \"Unknown pointers cover all concrete pointers (default=true).\"),\n        llvm::cl::init(true), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        strict(\"strict\",\n               llvm::cl::desc(\"Compare points-to sets by element by element.\"\n                              \"I.e., uoff-covers=false and \"\n                              \"unknown-covers=false (default=false).\"),\n               llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> fi(\"fi\", llvm::cl::desc(\"Run flow-insensitive PTA.\"),\n                       llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> fs(\"fs\", llvm::cl::desc(\"Run flow-sensitive PTA.\"),\n                       llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> fsinv(\n        \"fsinv\",\n        llvm::cl::desc(\n                \"Run flow-sensitive PTA with invalidated memory analysis.\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\n#if HAVE_SVF\nllvm::cl::opt<bool> svf(\"svf\", llvm::cl::desc(\"Run SVF PTA (Andersen).\"),\n                        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n#endif\n\nstatic std::string valToStr(const llvm::Value *val) {\n    using namespace llvm;\n\n    std::ostringstream ostr;\n    raw_os_ostream ro(ostr);\n\n    if (const auto *F = dyn_cast<Function>(val)) {\n        ro << \"fun '\" << F->getName().str() << \"'\";\n    } else {\n        if (const auto *I = dyn_cast<Instruction>(val)) {\n            ro << I->getParent()->getParent()->getName().str();\n            ro << \"::\";\n        }\n\n        assert(val);\n        ro << *val;\n    }\n\n    ro.flush();\n\n    return ostr.str();\n}\n\nstatic std::string offToStr(const Offset &off) {\n    if (off.isUnknown())\n        return \"?\";\n    return std::to_string(*off);\n}\n\nstatic bool verify_ptsets(const llvm::Value *val, const std::string &N1,\n                          const std::string &N2, LLVMPointerAnalysis *A1,\n                          LLVMPointerAnalysis *A2) {\n    bool ret = true;\n\n    auto ptset1 = A1->getLLVMPointsTo(val);\n    auto ptset2 = A2->getLLVMPointsTo(val);\n\n    // llvm::errs() << \"Points-to for: \" << *val << \"\\n\";\n    // for (const auto& ptr : ptset1) {\n    //    llvm::errs() << \"  \" << N1 << *ptr.value << \"\\n\";\n    //}\n    // if (ptset1.hasUnknown()) {\n    //    llvm::errs() << N1 << \"  unknown\\n\";\n    //}\n\n    // for (const auto& ptr : ptset2) {\n    //    llvm::errs() << \"  \" << N2 << *ptr.value << \"\\n\";\n    //}\n    // if (ptset2.hasUnknown()) {\n    //    llvm::errs() << N2 << \"  unknown\\n\";\n    //}\n\n    for (const auto &ptr : ptset1) {\n        bool found = false;\n        if (unknown_covers && ptset2.hasUnknown()) {\n            found = true;\n        } else {\n            for (const auto &ptr2 : ptset2) {\n                if (ptr == ptr2) {\n                    found = true;\n                    break;\n                }\n                if (uoff_covers && ptr.value == ptr2.value &&\n                    ptr2.offset.isUnknown()) {\n                    found = true;\n                    break;\n                }\n            }\n        }\n\n        if (!found) {\n            llvm::errs() << N1 << \" has a pointer that \" << N2\n                         << \" does not:\\n\";\n            llvm::errs() << \"  \" << valToStr(val) << \" -> \"\n                         << valToStr(ptr.value) << \" + \" << offToStr(ptr.offset)\n                         << \"\\n\";\n            ret = false;\n        }\n    }\n\n    return ret;\n}\n\nstatic bool verify_ptsets(llvm::Module *M, const std::string &N1,\n                          const std::string &N2, LLVMPointerAnalysis *A1,\n                          LLVMPointerAnalysis *A2) {\n    using namespace llvm;\n\n    if (A1 == A2)\n        return true;\n\n    bool ret = true;\n\n    for (Function &F : *M) {\n        for (BasicBlock &B : F) {\n            for (Instruction &I : B) {\n                if (!verify_ptsets(&I, N1, N2, A1, A2))\n                    ret = false;\n            }\n        }\n    }\n\n    return ret;\n}\n\ntemplate <typename PTAObj>\nstd::unique_ptr<LLVMPointerAnalysis>\ncreateAnalysis(llvm::Module *M, const LLVMPointerAnalysisOptions &opts) {\n    return std::unique_ptr<LLVMPointerAnalysis>(new PTAObj(M, opts));\n}\n\nint main(int argc, char *argv[]) {\n    setupStackTraceOnError(argc, argv);\n    SlicerOptions options = parseSlicerOptions(argc, argv);\n\n    if (enable_debug) {\n        DBG_ENABLE();\n    }\n\n    if (strict) {\n        uoff_covers = false;\n        unknown_covers = false;\n    }\n\n    llvm::LLVMContext context;\n    std::unique_ptr<llvm::Module> M =\n            parseModule(\"llvm-pta-compare\", context, options);\n    if (!M)\n        return 1;\n\n    std::vector<std::tuple<std::string, std::unique_ptr<LLVMPointerAnalysis>,\n                           size_t>>\n            analyses;\n\n    clock_t start, end, elapsed;\n    auto &opts = options.dgOptions.PTAOptions;\n\n    if (fi) {\n        opts.analysisType = dg::LLVMPointerAnalysisOptions::AnalysisType::fi;\n        analyses.emplace_back(\n                \"DG FI\", createAnalysis<DGLLVMPointerAnalysis>(M.get(), opts),\n                0);\n    }\n    if (fs) {\n        opts.analysisType = dg::LLVMPointerAnalysisOptions::AnalysisType::fs;\n        analyses.emplace_back(\n                \"DG FS\", createAnalysis<DGLLVMPointerAnalysis>(M.get(), opts),\n                0);\n    }\n    if (fsinv) {\n        opts.analysisType = dg::LLVMPointerAnalysisOptions::AnalysisType::inv;\n        analyses.emplace_back(\n                \"DG FSinv\",\n                createAnalysis<DGLLVMPointerAnalysis>(M.get(), opts), 0);\n    }\n#ifdef HAVE_SVF\n    if (svf) {\n        opts.analysisType = dg::LLVMPointerAnalysisOptions::AnalysisType::svf;\n        analyses.emplace_back(\"SVF (Andersen)\",\n                              createAnalysis<SVFPointerAnalysis>(M.get(), opts),\n                              0);\n    }\n#endif\n\n    for (auto &it : analyses) {\n        start = clock();\n        std::get<1>(it)->run(); // compute all the information\n        end = clock();\n        elapsed = end - start;\n        std::get<2>(it) += elapsed;\n        std::cout << \"  \" << std::get<0>(it) << \": \"\n                  << static_cast<float>(elapsed) / CLOCKS_PER_SEC << \" s (\"\n                  << elapsed << \" ticks)\\n\";\n        std::cout << \"-----\" << std::endl;\n    }\n\n    if (analyses.size() < 2)\n        return 0;\n\n    int ret = 0;\n    for (auto &analysis1 : analyses) {\n        for (auto &analysis2 : analyses) {\n            ret = !verify_ptsets(\n                    M.get(), std::get<0>(analysis1), std::get<0>(analysis2),\n                    std::get<1>(analysis1).get(), std::get<1>(analysis2).get());\n        }\n    }\n\n    return ret;\n}\n"
  },
  {
    "path": "tools/llvm-pta-dump.cpp",
    "content": "#include <algorithm>\n#include <cassert>\n#include <cinttypes>\n#include <cstdio>\n#include <cstdlib>\n#include <fstream>\n#include <iostream>\n#include <set>\n#include <sstream>\n#include <string>\n#include <vector>\n\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/LLVMContext.h>\n#include <llvm/IR/Module.h>\n#include <llvm/Support/raw_ostream.h>\n\n#if LLVM_VERSION_MAJOR >= 4\n#include <llvm/Bitcode/BitcodeReader.h>\n#else\n#include <llvm/Bitcode/ReaderWriter.h>\n#endif\n\n#include \"dg/PointerAnalysis/Pointer.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n\n#include \"dg/tools/llvm-slicer-opts.h\"\n#include \"dg/tools/llvm-slicer-utils.h\"\n\n#include \"dg/util/TimeMeasure.h\"\n\nusing namespace dg;\nusing namespace dg::pta;\nusing dg::debug::TimeMeasure;\nusing llvm::errs;\n\nusing PTType = dg::LLVMPointerAnalysisOptions::AnalysisType;\n\nllvm::cl::opt<bool> enable_debug(\n        \"dbg\", llvm::cl::desc(\"Enable debugging messages (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        verbose(\"v\", llvm::cl::desc(\"Enable verbose output (default=false).\"),\n                llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        verbose_more(\"vv\",\n                     llvm::cl::desc(\"Enable verbose output (default=false).\"),\n                     llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> ids_only(\n        \"ids-only\",\n        llvm::cl::desc(\n                \"Dump only IDs of nodes, not instructions (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> dump_graph_only(\n        \"graph-only\",\n        llvm::cl::desc(\n                \"Dump only graph (do not run the analysis) (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> names_with_funs(\n        \"names-with-funs\",\n        llvm::cl::desc(\n                \"Dump names of functions with instructions (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        callgraph(\"callgraph\",\n                  llvm::cl::desc(\"Dump also call graph (default=false).\"),\n                  llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        callgraph_only(\"callgraph-only\",\n                       llvm::cl::desc(\"Dump only call graph (default=false).\"),\n                       llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<uint64_t> dump_iteration(\n        \"iteration\",\n        llvm::cl::desc(\"Stop and dump analysis after the given iteration.\"),\n        llvm::cl::init(0), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<std::string>\n        display_only(\"display-only\",\n                     llvm::cl::desc(\"Show results only for the given \"\n                                    \"function(s) (separated by comma).\"),\n                     llvm::cl::init(\"\"), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> _stats(\"statistics\",\n                           llvm::cl::desc(\"Dump statistics (default=false).\"),\n                           llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> _quiet(\n        \"q\",\n        llvm::cl::desc(\n                \"Quite mode - no output (for benchmarking) (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        todot(\"dot\",\n              llvm::cl::desc(\"Dump IR to graphviz format (default=false). \"\n                             \"Has an effect only with -ir switch.\"),\n              llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> dump_ir(\n        \"ir\",\n        llvm::cl::desc(\n                \"Dump IR of the analysis (DG analyses only) (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> dump_c_lines(\n        \"c-lines\",\n        llvm::cl::desc(\"Dump output as C lines (line:column where possible).\"\n                       \"Requires metadata in the bitcode (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nusing VariablesMapTy = std::map<const llvm::Value *, CVariableDecl>;\nVariablesMapTy allocasToVars(const llvm::Module &M);\nVariablesMapTy valuesToVars;\n\nstatic std::vector<const llvm::Function *> display_only_func;\n\nstd::unique_ptr<LLVMPointerAnalysis> PA;\n\nstatic std::string valToStr(const llvm::Value *val) {\n    using namespace llvm;\n\n    std::ostringstream ostr;\n    raw_os_ostream ro(ostr);\n\n    if (const auto *F = dyn_cast<Function>(val)) {\n        ro << \"fun '\" << F->getName().str() << \"'\";\n    } else {\n        const auto *I = dyn_cast<Instruction>(val);\n        if (dump_c_lines) {\n            if (I) {\n                const auto &DL = I->getDebugLoc();\n                if (DL) {\n                    ro << DL.getLine() << \":\" << DL.getCol();\n                } else {\n                    auto Vit = valuesToVars.find(I);\n                    if (Vit != valuesToVars.end()) {\n                        auto &decl = Vit->second;\n                        ro << decl.line << \":\" << decl.col;\n                    }\n                }\n            }\n        } else {\n            if (I) {\n                ro << I->getParent()->getParent()->getName().str();\n                ro << \"::\";\n            }\n\n            assert(val);\n            ro << *val;\n        }\n    }\n\n    ro.flush();\n\n    return ostr.str();\n}\n\n// FIXME: get rid of this...\nstatic std::string getInstName(const llvm::Value *val) {\n    std::ostringstream ostr;\n    llvm::raw_os_ostream ro(ostr);\n\n    if (names_with_funs) {\n        if (const auto *I = llvm::dyn_cast<llvm::Instruction>(val)) {\n            ro << I->getParent()->getParent()->getName().data() << \":\";\n        }\n    }\n\n    assert(val);\n    if (llvm::isa<llvm::Function>(val))\n        ro << val->getName().data();\n    else\n        ro << *val;\n\n    ro.flush();\n\n    // break the string if it is too long\n    return ostr.str();\n}\n\nvoid printPSNodeType(enum PSNodeType type) {\n    printf(\"%s\", PSNodeTypeToCString(type));\n}\n\nstatic void dumpPointer(const Pointer &ptr, bool dot);\n\nstatic void printName(PSNode *node, bool dot = false) {\n    std::string nm;\n    const char *name = nullptr;\n    if (node->isNull()) {\n        name = \"null\";\n    } else if (node->isUnknownMemory()) {\n        name = \"unknown\";\n    } else if (node->isInvalidated() && !node->getUserData<llvm::Value>()) {\n        name = \"invalidated\";\n    }\n\n    if (!name) {\n        if (ids_only) {\n            printf(\" <%u>\", node->getID());\n            return;\n        }\n\n        if (!node->getUserData<llvm::Value>()) {\n            if (dot) {\n                printf(\"<%u> (no name)\\\\n\", node->getID());\n\n                if (node->getType() == PSNodeType::CONSTANT) {\n                    dumpPointer(*(node->pointsTo.begin()), dot);\n                } else if (node->getType() == PSNodeType::CALL_RETURN) {\n                    if (PSNode *paired = node->getPairedNode())\n                        printName(paired, dot);\n                } else if (PSNodeEntry *entry = PSNodeEntry::get(node)) {\n                    printf(\"%s\\\\n\", entry->getFunctionName().c_str());\n                }\n            } else {\n                printf(\"<%u> \", node->getID());\n                printPSNodeType(node->getType());\n            }\n\n            return;\n        }\n\n        nm = getInstName(node->getUserData<llvm::Value>());\n        name = nm.c_str();\n    }\n\n    if (ids_only) {\n        printf(\" <%u>\", node->getID());\n        return;\n    }\n\n    // escape the \" character\n    for (int i = 0; name[i] != '\\0'; ++i) {\n        // crop long names\n        if (i >= 70) {\n            printf(\" ...\");\n            break;\n        }\n\n        if (name[i] == '\"')\n            putchar('\\\\');\n\n        putchar(name[i]);\n    }\n}\n\nstatic void dumpPointer(const Pointer &ptr, bool dot) {\n    printName(ptr.target, dot);\n\n    if (ptr.offset.isUnknown())\n        printf(\" + UNKNOWN\");\n    else\n        printf(\" + %\" PRIu64, *ptr.offset);\n}\n\nstatic void dumpMemoryObject(MemoryObject *mo, int ind, bool dot) {\n    bool printed_multi = false;\n    for (auto &it : mo->pointsTo) {\n        int width = 0;\n        for (const Pointer &ptr : it.second) {\n            // print indentation\n            printf(\"%*s\", ind, \"\");\n\n            if (width > 0) {\n                printf(\"%*s -> \", width, \"\");\n            } else {\n                if (it.first.isUnknown())\n                    width = printf(\"[??]\");\n                else\n                    width = printf(\"[%\" PRIu64 \"]\", *it.first);\n\n                // print a new line if there are multiple items\n                if (dot && (it.second.size() > 1 ||\n                            (printed_multi && mo->pointsTo.size() > 1))) {\n                    printed_multi = true;\n                    printf(\"\\\\l%*s\", ind + width, \"\");\n                }\n\n                printf(\" -> \");\n\n                assert(width > 0);\n            }\n\n            dumpPointer(ptr, dot);\n\n            if (dot)\n                printf(\"\\\\l\");\n            else\n                putchar('\\n');\n        }\n    }\n}\n\nstatic void dumpMemoryMap(PointerAnalysisFS::MemoryMapT *mm, int ind,\n                          bool dot) {\n    for (const auto &it : *mm) {\n        // print the key\n        if (!dot)\n            printf(\"%*s\", ind, \"\");\n\n        putchar('<');\n        printName(it.first, dot);\n        putchar('>');\n\n        if (dot)\n            printf(\"\\\\l\");\n        else\n            putchar('\\n');\n\n        dumpMemoryObject(it.second.get(), ind + 4, dot);\n    }\n}\n\nstatic bool mmChanged(PSNode *n) {\n    if (n->predecessorsNum() == 0)\n        return true;\n\n    PointerAnalysisFS::MemoryMapT *mm =\n            n->getData<PointerAnalysisFS::MemoryMapT>();\n\n    for (PSNode *pred : n->predecessors()) {\n        if (pred->getData<PointerAnalysisFS::MemoryMapT>() != mm)\n            return true;\n    }\n\n    return false;\n}\n\nstatic void dumpPointerGraphData(PSNode *n, PTType type, bool dot = false) {\n    assert(n && \"No node given\");\n    if (type == dg::LLVMPointerAnalysisOptions::AnalysisType::fi) {\n        MemoryObject *mo = n->getData<MemoryObject>();\n        if (!mo)\n            return;\n\n        if (dot)\n            printf(\"\\\\n    Memory: ---\\\\n\");\n        else\n            printf(\"    Memory: ---\\n\");\n\n        dumpMemoryObject(mo, 6, dot);\n\n        if (!dot)\n            printf(\"    -----------\\n\");\n    } else {\n        PointerAnalysisFS::MemoryMapT *mm =\n                n->getData<PointerAnalysisFS::MemoryMapT>();\n        if (!mm)\n            return;\n\n        if (dot)\n            printf(R\"(\\n------\\n    --- Memory map [%p] ---\\n)\",\n                   static_cast<void *>(mm));\n        else\n            printf(\"    Memory map: [%p]\\n\", static_cast<void *>(mm));\n\n        if (verbose_more || mmChanged(n))\n            dumpMemoryMap(mm, 6, dot);\n\n        if (!dot)\n            printf(\"    ----------------\\n\");\n    }\n}\n\nstatic void dumpPSNode(PSNode *n, PTType type) {\n    printf(\"NODE %3u: \", n->getID());\n    printName(n);\n\n    PSNodeAlloc *alloc = PSNodeAlloc::get(n);\n    if (alloc &&\n        (alloc->getSize() || alloc->isHeap() || alloc->isZeroInitialized()))\n        printf(\" [size: %zu, heap: %u, zeroed: %u]\", alloc->getSize(),\n               alloc->isHeap(), alloc->isZeroInitialized());\n\n    printf(\" (points-to size: %zu)\\n\", n->pointsTo.size());\n\n    for (const Pointer &ptr : n->pointsTo) {\n        printf(\"    -> \");\n        printName(ptr.target, false);\n        if (ptr.offset.isUnknown())\n            puts(\" + Offset::UNKNOWN\");\n        else\n            printf(\" + %\" PRIu64 \"\\n\", *ptr.offset);\n    }\n    if (verbose) {\n        dumpPointerGraphData(n, type);\n    }\n}\n\nstatic void dumpNodeToDot(PSNode *node, PTType type) {\n    printf(\"\\tNODE%u [label=\\\"<%u> \", node->getID(), node->getID());\n    printPSNodeType(node->getType());\n    printf(\"\\\\n\");\n    printName(node, true);\n    printf(\"\\\\nparent: %u\\\\n\",\n           node->getParent() ? node->getParent()->getID() : 0);\n\n    PSNodeAlloc *alloc = PSNodeAlloc::get(node);\n    if (alloc &&\n        (alloc->getSize() || alloc->isHeap() || alloc->isZeroInitialized()))\n        printf(\"\\\\n[size: %zu, heap: %u, zeroed: %u]\", alloc->getSize(),\n               alloc->isHeap(), alloc->isZeroInitialized());\n    if (verbose) {\n        if (PSNodeEntry *entry = PSNodeEntry::get(node)) {\n            printf(\"called from: [\");\n            for (auto *r : entry->getCallers())\n                printf(\"%u \", r->getID());\n            printf(\"]\\\\n\");\n        }\n        if (PSNodeCallRet *CR = PSNodeCallRet::get(node)) {\n            printf(\"returns from: [\");\n            for (auto *r : CR->getReturns())\n                printf(\"%u \", r->getID());\n            printf(\"]\\\\n\");\n        }\n        if (PSNodeRet *R = PSNodeRet::get(node)) {\n            printf(\"returns to: [\");\n            for (auto *r : R->getReturnSites())\n                printf(\"%u \", r->getID());\n            printf(\"]\\\\n\");\n        }\n    }\n\n    if (verbose && node->getOperandsNum() > 0) {\n        printf(\"\\\\n--- operands ---\\\\n\");\n        for (PSNode *op : node->getOperands()) {\n            printName(op, true);\n        }\n        printf(\"\\\\n------\\\\n\");\n    }\n\n    if (verbose && !node->pointsTo.empty()) {\n        printf(\"\\\\n--- points-to set ---\\\\n\");\n    }\n\n    for (const Pointer &ptr : node->pointsTo) {\n        printf(\"\\\\n    -> \");\n        printName(ptr.target, true);\n        printf(\" + \");\n        if (ptr.offset.isUnknown())\n            printf(\"Offset::UNKNOWN\");\n        else\n            printf(\"%\" PRIu64, *ptr.offset);\n    }\n\n    if (verbose) {\n        dumpPointerGraphData(node, type, true /* dot */);\n    }\n\n    printf(\"\\\", shape=box\");\n    if (node->getType() != PSNodeType::STORE) {\n        if (node->pointsTo.empty() && (node->getType() == PSNodeType::LOAD ||\n                                       node->getType() == PSNodeType::GEP ||\n                                       node->getType() == PSNodeType::CAST ||\n                                       node->getType() == PSNodeType::PHI))\n            printf(\", style=filled, fillcolor=red\");\n    } else {\n        printf(\", style=filled, fillcolor=orange\");\n    }\n\n    printf(\"]\\n\");\n}\n\nstatic void dumpNodeEdgesToDot(PSNode *node) {\n    for (PSNode *succ : node->successors()) {\n        printf(\"\\tNODE%u -> NODE%u [penwidth=2]\\n\", node->getID(),\n               succ->getID());\n    }\n\n    for (PSNode *op : node->getOperands()) {\n        printf(\"\\tNODE%u -> NODE%u \"\n               \"[color=blue,style=dotted,constraint=false]\\n\",\n               op->getID(), node->getID());\n    }\n\n    if (auto *C = PSNodeCall::get(node)) {\n        for (auto *const subg : C->getCallees()) {\n            printf(\"\\tNODE%u -> NODE%u \"\n                   \"[penwidth=4,style=dashed,constraint=false]\\n\",\n                   node->getID(), subg->root->getID());\n        }\n    }\n\n    if (auto *R = PSNodeRet::get(node)) {\n        for (auto *const succ : R->getReturnSites()) {\n            printf(\"\\tNODE%u -> NODE%u \"\n                   \"[penwidth=4,style=dashed,constraint=false]\\n\",\n                   node->getID(), succ->getID());\n        }\n    }\n}\n\nPSNode *getNodePtr(PSNode *ptr) { return ptr; }\nPSNode *getNodePtr(const std::unique_ptr<PSNode> &ptr) { return ptr.get(); }\n\ntemplate <typename ContT>\nstatic void dumpToDot(const ContT &nodes, PTType type) {\n    /* dump nodes */\n    for (const auto &node : nodes) {\n        if (!node)\n            continue;\n        dumpNodeToDot(getNodePtr(node), type);\n    }\n\n    /* dump edges */\n    for (const auto &node : nodes) {\n        if (!node) // node id 0 is nullptr\n            continue;\n        dumpNodeEdgesToDot(getNodePtr(node));\n    }\n}\n\nstatic void dumpPointerGraphdot(DGLLVMPointerAnalysis *pta, PTType type) {\n    printf(\"digraph \\\"Pointer State Subgraph\\\" {\\n\");\n\n    if (callgraph) {\n        // dump call-graph\n        const auto &CG = pta->getPS()->getCallGraph();\n        for (const auto &it : CG) {\n            printf(\"NODEcg%u [label=\\\"%s\\\"]\\n\", it.second.getID(),\n                   it.first->getUserData<llvm::Function>()\n                           ->getName()\n                           .str()\n                           .c_str());\n        }\n        for (const auto &it : CG) {\n            for (auto *succ : it.second.getCalls()) {\n                printf(\"NODEcg%u -> NODEcg%u\\n\", it.second.getID(),\n                       succ->getID());\n            }\n        }\n        if (callgraph_only) {\n            printf(\"}\\n\");\n            return;\n        }\n    }\n\n    if (!display_only_func.empty()) {\n        std::set<PSNode *> nodes;\n        for (const auto *llvmFunc : display_only_func) {\n            auto func_nodes = pta->getFunctionNodes(llvmFunc);\n            if (func_nodes.empty()) {\n                llvm::errs() << \"ERROR: Did not find any nodes for function \"\n                             << display_only << \"\\n\";\n            } else {\n                llvm::errs() << \"Found \" << func_nodes.size()\n                             << \" nodes for function \" << display_only << \"\\n\";\n            }\n\n            // use std::set to get rid of duplicates\n            for (auto *nd : func_nodes) {\n                nodes.insert(nd);\n                // get also operands of the nodes,\n                // be it in any function\n                for (PSNode *ops : nd->getOperands()) {\n                    nodes.insert(ops);\n                }\n            }\n        }\n\n        dumpToDot(nodes, type);\n\n        // dump edges representing procedure calls, so that\n        // the graph is conntected\n        for (auto *nd : nodes) {\n            if (nd->getType() == PSNodeType::CALL ||\n                nd->getType() == PSNodeType::CALL_FUNCPTR) {\n                auto *ret = nd->getPairedNode();\n                if (ret == nullptr)\n                    continue;\n\n                printf(\"\\tNODE%u -> NODE%u [penwidth=2 style=dashed]\\n\",\n                       nd->getID(), ret->getID());\n            }\n        }\n    } else {\n        dumpToDot(pta->getPS()->getGlobals(), type);\n        dumpToDot(pta->getNodes(), type);\n    }\n\n    printf(\"}\\n\");\n}\n\nstatic void dumpPointerGraph(DGLLVMPointerAnalysis *pta, PTType type) {\n    assert(pta);\n\n    if (todot)\n        dumpPointerGraphdot(pta, type);\n    else {\n        const auto &nodes = pta->getNodes();\n        for (const auto &node : nodes) {\n            if (node) // node id 0 is nullptr\n                dumpPSNode(node.get(), type);\n        }\n    }\n}\n\nstatic void dumpStats(DGLLVMPointerAnalysis *pta) {\n    const auto &nodes = pta->getNodes();\n    printf(\"Pointer subgraph size: %zu\\n\", nodes.size() - 1);\n\n    size_t nonempty_size = 0; // number of nodes with non-empty pt-set\n    size_t maximum = 0;       // maximum pt-set size\n    size_t pointing_to_unknown = 0;\n    size_t pointing_only_to_unknown = 0;\n    size_t pointing_to_invalidated = 0;\n    size_t pointing_only_to_invalidated = 0;\n    size_t singleton_count = 0;\n    size_t singleton_nonconst_count = 0;\n    size_t pointing_to_heap = 0;\n    size_t pointing_to_global = 0;\n    size_t pointing_to_stack = 0;\n    size_t pointing_to_function = 0;\n    size_t has_known_size = 0;\n    size_t allocation_num = 0;\n    size_t points_to_only_known_size = 0;\n    size_t known_size_known_offset = 0;\n    size_t only_valid_target = 0;\n    size_t only_valid_and_some_known = 0;\n\n    for (const auto &node : nodes) {\n        if (!node)\n            continue;\n\n        if (!node->pointsTo.empty())\n            ++nonempty_size;\n\n        if (node->pointsTo.size() == 1) {\n            ++singleton_count;\n            if (node->getType() == PSNodeType::CONSTANT ||\n                node->getType() == PSNodeType::FUNCTION)\n                ++singleton_nonconst_count;\n        }\n\n        if (node->pointsTo.size() > maximum)\n            maximum = node->pointsTo.size();\n\n        bool _points_to_only_known_size = true;\n        bool _known_offset_only = true;\n        bool _has_known_size_offset = false;\n        bool _has_only_valid_targets = true;\n        for (const auto &ptr : node->pointsTo) {\n            if (ptr.offset.isUnknown()) {\n                _known_offset_only = false;\n            }\n\n            if (ptr.isUnknown()) {\n                _has_only_valid_targets = false;\n                ++pointing_to_unknown;\n                if (node->pointsTo.size() == 1)\n                    ++pointing_only_to_unknown;\n            }\n\n            if (ptr.isInvalidated()) {\n                _has_only_valid_targets = false;\n                ++pointing_to_invalidated;\n                if (node->pointsTo.size() == 1)\n                    ++pointing_only_to_invalidated;\n            }\n\n            if (ptr.isNull()) {\n                _has_only_valid_targets = false;\n            }\n\n            auto *alloc = PSNodeAlloc::get(ptr.target);\n            if (alloc) {\n                ++allocation_num;\n                if (node->getSize() != 0 &&\n                    node->getSize() != Offset::UNKNOWN) {\n                    ++has_known_size;\n                    if (!ptr.offset.isUnknown())\n                        _has_known_size_offset = true;\n                } else\n                    _points_to_only_known_size = false;\n\n                if (alloc->isHeap()) {\n                    ++pointing_to_heap;\n                } else if (alloc->isGlobal()) {\n                    ++pointing_to_global;\n                } else if (alloc->getType() == PSNodeType::ALLOC) {\n                    assert(!alloc->isGlobal());\n                    ++pointing_to_stack;\n                }\n            } else {\n                _points_to_only_known_size = false;\n                ;\n\n                if (ptr.target->getType() == PSNodeType::FUNCTION) {\n                    ++pointing_to_function;\n                }\n            }\n        }\n\n        if (_points_to_only_known_size) {\n            ++points_to_only_known_size;\n            if (_known_offset_only)\n                ++known_size_known_offset;\n        }\n\n        if (_has_only_valid_targets) {\n            ++only_valid_target;\n            if (_has_known_size_offset)\n                ++only_valid_and_some_known;\n        }\n    }\n\n    printf(\"Allocations: %zu\\n\", allocation_num);\n    printf(\"Allocations with known size: %zu\\n\", has_known_size);\n    printf(\"Nodes with non-empty pt-set: %zu\\n\", nonempty_size);\n    printf(\"Pointers pointing only to known-size allocations: %zu\\n\",\n           points_to_only_known_size);\n    printf(\"Pointers pointing only to known-size allocations with known \"\n           \"offset: %zu\\n\",\n           known_size_known_offset);\n    printf(\"Pointers pointing only to valid targets: %zu\\n\", only_valid_target);\n    printf(\"Pointers pointing only to valid targets and some known \"\n           \"size+offset: %zu\\n\",\n           only_valid_and_some_known);\n\n    double avg_ptset_size = 0;\n    double avg_nonempty_ptset_size = 0; // avg over non-empty sets only\n    size_t accumulated_ptset_size = 0;\n\n    for (const auto &node : nodes) {\n        if (!node)\n            continue;\n\n        if (accumulated_ptset_size > (~((size_t) 0)) - node->pointsTo.size()) {\n            printf(\"Accumulated points to sets size > 2^64 - 1\");\n            avg_ptset_size += (accumulated_ptset_size /\n                               static_cast<double>(nodes.size() - 1));\n            avg_nonempty_ptset_size += (accumulated_ptset_size /\n                                        static_cast<double>(nonempty_size));\n            accumulated_ptset_size = 0;\n        }\n        accumulated_ptset_size += node->pointsTo.size();\n    }\n\n    avg_ptset_size +=\n            (accumulated_ptset_size / static_cast<double>(nodes.size() - 1));\n    avg_nonempty_ptset_size +=\n            (accumulated_ptset_size / static_cast<double>(nonempty_size));\n    printf(\"Average pt-set size: %6.3f\\n\", avg_ptset_size);\n    printf(\"Average non-empty pt-set size: %6.3f\\n\", avg_nonempty_ptset_size);\n    printf(\"Pointing to singleton: %zu\\n\", singleton_count);\n    printf(\"Non-constant pointing to singleton: %zu\\n\",\n           singleton_nonconst_count);\n    printf(\"Pointing to unknown: %zu\\n\", pointing_to_unknown);\n    printf(\"Pointing to unknown singleton: %zu\\n\", pointing_only_to_unknown);\n    printf(\"Pointing to invalidated: %zu\\n\", pointing_to_invalidated);\n    printf(\"Pointing to invalidated singleton: %zu\\n\",\n           pointing_only_to_invalidated);\n    printf(\"Pointing to heap: %zu\\n\", pointing_to_heap);\n    printf(\"Pointing to global: %zu\\n\", pointing_to_global);\n    printf(\"Pointing to stack: %zu\\n\", pointing_to_stack);\n    printf(\"Pointing to function: %zu\\n\", pointing_to_function);\n    printf(\"Maximum pt-set size: %zu\\n\", maximum);\n}\n\nint main(int argc, char *argv[]) {\n    setupStackTraceOnError(argc, argv);\n    SlicerOptions options = parseSlicerOptions(argc, argv);\n\n    if (enable_debug) {\n        DBG_ENABLE();\n    }\n\n    if (verbose_more) {\n        verbose = true;\n    }\n    if (callgraph_only) {\n        callgraph = true;\n    }\n\n    llvm::LLVMContext context;\n    std::unique_ptr<llvm::Module> M =\n            parseModule(\"llvm-pta-dump\", context, options);\n    if (!M)\n        return 1;\n\n    if (!display_only.empty()) {\n        for (const auto &func : splitList(display_only)) {\n            auto *llvmFunc = M->getFunction(func);\n            if (!llvmFunc) {\n                llvm::errs() << \"Invalid function to display: \" << func\n                             << \". Function not found in the module\\n\";\n                return 1;\n            }\n            display_only_func.push_back(llvmFunc);\n        }\n    }\n\n    TimeMeasure tm;\n    auto &opts = options.dgOptions.PTAOptions;\n\n#ifdef HAVE_SVF\n    if (opts.isSVF()) {\n        assert(dump_iteration == 0 && \"SVF does not support -iteration\");\n        assert(!dump_graph_only && \"SVF does not support -dump_graph_only\");\n        assert(!dump_graph_only && \"SVF does not support -statistics yet\");\n    }\n#endif\n\n    if (!dump_ir) {\n        std::unique_ptr<LLVMPointerAnalysis> llvmpta;\n\n#ifdef HAVE_SVF\n        if (opts.isSVF())\n            llvmpta.reset(new SVFPointerAnalysis(M.get(), opts));\n        else\n#endif\n            llvmpta.reset(new DGLLVMPointerAnalysis(M.get(), opts));\n\n        tm.start();\n        llvmpta->run();\n        tm.stop();\n        tm.report(\"INFO: Pointer analysis took\");\n\n        if (_stats) {\n            if (opts.isSVF()) {\n                llvm::errs() << \"SVF analysis does not support stats dumping\\n\";\n            } else {\n                dumpStats(static_cast<DGLLVMPointerAnalysis *>(llvmpta.get()));\n            }\n            return 0;\n        }\n\n        if (_quiet) {\n            return 0;\n        }\n\n        if (dump_c_lines) {\n#if (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7)\n            llvm::errs() << \"WARNING: Variables names matching is not \"\n                            \"supported for LLVM older than 3.7\\n\";\n#else\n            valuesToVars = allocasToVars(*M);\n#endif // LLVM > 3.6\n            if (valuesToVars.empty()) {\n                llvm::errs() << \"WARNING: No debugging information found, \"\n                             << \"the C lines output will be corrupted\\n\";\n            }\n        }\n\n        for (auto &F : *M) {\n            if (!display_only_func.empty() &&\n                std::find(display_only_func.begin(), display_only_func.end(),\n                          &F) == display_only_func.end()) {\n                continue;\n            }\n            for (auto &B : F) {\n                for (auto &I : B) {\n                    if (!I.getType()->isPointerTy() &&\n                        !I.getType()->isIntegerTy()) {\n                        continue;\n                    }\n\n                    if (dump_c_lines && llvm::isa<llvm::AllocaInst>(&I)) {\n                        // do not dump I->I for alloca, it makes no sense for C\n                        continue;\n                    }\n\n                    auto pts = llvmpta->getLLVMPointsTo(&I);\n                    if (pts.isUnknownSingleton()) {\n                        // do not dump the \"no-information\"\n                        continue;\n                    }\n\n                    std::cout << valToStr(&I) << \"\\n\";\n                    for (const auto &ptr : pts) {\n                        std::cout << \"  -> \" << valToStr(ptr.value) << \"\\n\";\n                    }\n                    if (pts.hasUnknown()) {\n                        std::cout << \"  -> unknown\\n\";\n                    }\n                    if (pts.hasNull()) {\n                        std::cout << \"  -> null\\n\";\n                    }\n                    if (pts.hasNullWithOffset()) {\n                        std::cout << \"  -> null + ?\\n\";\n                    }\n                    if (pts.hasInvalidated()) {\n                        std::cout << \"  -> invalidated\\n\";\n                    }\n                }\n            }\n        }\n        return 0;\n    }\n\n    ///\n    // Dumping the IR of pointer analysis\n    //\n    DGLLVMPointerAnalysis PTA(M.get(), opts);\n\n    tm.start();\n\n    PTA.initialize();\n\n    if (dump_graph_only) {\n        tm.stop();\n        tm.report(\"INFO: Pointer analysis (building graph) took\");\n        dumpPointerGraph(&PTA, opts.analysisType);\n        return 0;\n    }\n\n    auto *PA = PTA.getPTA();\n    assert(PA && \"Did not initialize the analysis\");\n\n    // run the analysis\n    if (dump_iteration > 0) {\n        // do preprocessing and queue the nodes\n        PA->preprocess();\n        PA->initialize_queue();\n\n        // do fixpoint\n        for (unsigned i = 0; i < dump_iteration; ++i) {\n            if (!PA->iteration())\n                break;\n            PA->queue_changed();\n        }\n    } else {\n        PA->run();\n    }\n\n    tm.stop();\n    tm.report(\"INFO: Pointer analysis took\");\n\n    if (_stats) {\n        dumpStats(&PTA);\n    }\n\n    if (_quiet)\n        return 0;\n\n    dumpPointerGraph(&PTA, opts.analysisType);\n\n    return 0;\n}\n"
  },
  {
    "path": "tools/llvm-sdg-dump.cpp",
    "content": "#include <cassert>\n#include <fstream>\n#include <iostream>\n#include <set>\n#include <string>\n#include <vector>\n\n#include \"dg/tools/llvm-slicer-opts.h\"\n#include \"dg/tools/llvm-slicer-utils.h\"\n#include \"dg/tools/llvm-slicer.h\"\n\n#if LLVM_VERSION_MAJOR >= 4\n#include <llvm/Bitcode/BitcodeReader.h>\n#include <llvm/Bitcode/BitcodeWriter.h>\n#else\n#include <llvm/Bitcode/ReaderWriter.h>\n#endif\n\n#include <llvm/IR/InstIterator.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/LLVMContext.h>\n#include <llvm/Support/raw_ostream.h>\n\n#include \"dg/llvm/SystemDependenceGraph/SDG2Dot.h\"\n#include \"dg/util/debug.h\"\n\nusing namespace dg;\n\nusing llvm::errs;\n\nllvm::cl::opt<bool> enable_debug(\n        \"dbg\", llvm::cl::desc(\"Enable debugging messages (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> dump_bb_only(\n        \"dump-bb-only\",\n        llvm::cl::desc(\"Only dump basic blocks of dependence graph to dot\"\n                       \" (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nclass SDGDumper {\n    const SlicerOptions &options;\n    llvmdg::SystemDependenceGraph *dg;\n    bool bb_only{false};\n    // uint32_t dump_opts{0};//{debug::PRINT_DD | debug::PRINT_CD |\n    // debug::PRINT_USE | debug::PRINT_ID};\n\n  public:\n    SDGDumper(const SlicerOptions &opts, llvmdg::SystemDependenceGraph *dg,\n              bool bb_only = false, uint32_t /* dump_opts */ = 0)\n            : options(opts), dg(dg),\n              bb_only(bb_only) /*, dump_opts(dump_opts) */ {}\n\n    void dumpToDot(const char *suffix = nullptr) {\n        // compose new name\n        std::string fl(options.inputFile);\n        if (suffix)\n            replace_suffix(fl, suffix);\n        else\n            replace_suffix(fl, \".dot\");\n\n        errs() << \"Dumping SDG to \" << fl << \"\\n\";\n\n        if (bb_only) {\n            assert(false && \"Not implemented\");\n            // SDGDumpBlocks dumper(dg, dump_opts, fl.c_str());\n            // dumper.dump();\n        } else {\n            llvmdg::SDG2Dot dumper(dg);\n            dumper.dump(fl);\n        }\n    }\n};\n\nint main(int argc, char *argv[]) {\n    setupStackTraceOnError(argc, argv);\n    SlicerOptions options = parseSlicerOptions(argc, argv);\n\n    if (enable_debug) {\n        DBG_ENABLE();\n    }\n\n    llvm::LLVMContext context;\n    std::unique_ptr<llvm::Module> M =\n            parseModule(\"llvm-sdg-dump\", context, options);\n    if (!M)\n        return 1;\n\n    if (!M->getFunction(options.dgOptions.entryFunction)) {\n        llvm::errs() << \"The entry function not found: \"\n                     << options.dgOptions.entryFunction << \"\\n\";\n        return 1;\n    }\n\n    DGLLVMPointerAnalysis PTA(M.get(), options.dgOptions.PTAOptions);\n    PTA.run();\n    LLVMDataDependenceAnalysis DDA(M.get(), &PTA, options.dgOptions.DDAOptions);\n    DDA.run();\n    LLVMControlDependenceAnalysis CDA(M.get(), options.dgOptions.CDAOptions);\n    // CDA runs on-demand\n\n    llvmdg::SystemDependenceGraph sdg(M.get(), &PTA, &DDA, &CDA);\n\n    SDGDumper dumper(options, &sdg, dump_bb_only);\n    dumper.dumpToDot();\n\n    return 0;\n}\n"
  },
  {
    "path": "tools/llvm-slicer-crit.cpp",
    "content": "#include <cassert>\n#include <set>\n#include <string>\n#include <vector>\n\n#include <llvm/IR/CFG.h>\n#include <llvm/IR/DebugInfoMetadata.h>\n#include <llvm/IR/InstIterator.h>\n#include <llvm/IR/Instructions.h>\n#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 7\n#include <llvm/IR/LLVMContext.h>\n#endif\n#include <llvm/IR/Module.h>\n#include <llvm/IR/Value.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#include \"dg/ADT/Queue.h\"\n#include \"dg/llvm/LLVMDependenceGraph.h\"\n#include \"dg/llvm/LLVMNode.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n#include \"dg/tools/llvm-slicer-utils.h\"\n\nusing namespace dg;\n\nusing llvm::errs;\n\n// mapping of AllocaInst to the names of C variables\nstatic std::map<const llvm::Value *, std::string> valuesToVariables;\n\nstatic inline bool isNumber(const std::string &s) {\n    assert(!s.empty());\n\n    for (const auto c : s)\n        if (!isdigit(c))\n            return false;\n\n    return true;\n}\n\nstatic inline bool mayBeTheVar(const llvm::Value *val, const std::string &var) {\n    // global variables have names, just compare it\n    if (auto *G = llvm::dyn_cast<llvm::GlobalVariable>(val)) {\n        return G->getName() == var;\n    }\n\n    // for other cases, we must relay on the information about allocas\n    auto name = valuesToVariables.find(val);\n    if (name != valuesToVariables.end() && name->second != var) {\n        return false;\n    }\n\n    // either the var matches or we do not know the var,\n    // which we must take as a match\n    return true;\n}\n\nstatic llvm::Value *constExprVar(const llvm::ConstantExpr *CE) {\n    using namespace llvm;\n    Value *var = nullptr;\n#if LLVM_VERSION_MAJOR <= 10\n    Instruction *Inst = const_cast<ConstantExpr *>(CE)->getAsInstruction();\n#else\n    Instruction *Inst = CE->getAsInstruction();\n#endif\n\n    switch (Inst->getOpcode()) {\n    case Instruction::GetElementPtr:\n        var = cast<GetElementPtrInst>(Inst)->getPointerOperand();\n        break;\n    case Instruction::BitCast:\n        var = Inst->getOperand(0);\n        break;\n    default:\n        break;\n    }\n\n#if LLVM_VERSION_MAJOR < 5\n    delete Inst;\n#else\n    Inst->deleteValue();\n#endif\n\n    if (var && isa<ConstantExpr>(var))\n        var = constExprVar(cast<ConstantExpr>(var));\n    return var;\n}\n\nstatic bool usesTheVariable(const llvm::Instruction &I, const std::string &var,\n                            bool isglobal = false,\n                            LLVMPointerAnalysis *pta = nullptr) {\n    if (!I.mayReadOrWriteMemory())\n        return false;\n\n    if (!pta) {\n        // try basic cases that we can decide without PTA\n        using namespace llvm;\n        const Value *operand = nullptr;\n        if (auto *S = dyn_cast<StoreInst>(&I)) {\n            auto *A = S->getPointerOperand()->stripPointerCasts();\n            if (auto *C = dyn_cast<ConstantExpr>(A)) {\n                operand = constExprVar(C);\n            } else if ((isa<AllocaInst>(A) || isa<GlobalVariable>(A))) {\n                operand = A;\n            }\n        } else if (auto *L = dyn_cast<LoadInst>(&I)) {\n            auto *A = L->getPointerOperand()->stripPointerCasts();\n            if (auto *C = dyn_cast<ConstantExpr>(A)) {\n                operand = constExprVar(C);\n            } else if ((isa<AllocaInst>(A) || isa<GlobalVariable>(A))) {\n                operand = A;\n            }\n        }\n\n        if (operand && !mayBeTheVar(operand, var)) {\n            return false;\n        }\n        return true;\n    }\n\n    auto memacc = pta->getAccessedMemory(&I);\n    if (memacc.first) {\n        // PTA has no information, it may be a definition of the variable,\n        // we do not know\n        llvm::errs() << \"WARNING: matched due to a lack of information: \" << I\n                     << \"\\n\";\n        return true;\n    }\n\n    for (const auto &region : memacc.second) {\n        if (isglobal &&\n            !llvm::isa<llvm::GlobalVariable>(region.pointer.value)) {\n            continue;\n        }\n        if (mayBeTheVar(region.pointer.value, var)) {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nstatic bool funHasAddrTaken(const llvm::Function *fun) {\n    using namespace llvm;\n\n    for (auto use_it = fun->use_begin(), use_end = fun->use_end();\n         use_it != use_end; ++use_it) {\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n        Value *user = *use_it;\n#else\n        Value *user = use_it->getUser();\n#endif\n        if (auto *C = dyn_cast<CallInst>(user)) {\n            // FIXME: use getCalledOperand() and strip the casts\n            if (fun != C->getCalledFunction()) {\n                return true;\n            }\n        } else if (auto *S = dyn_cast<StoreInst>(user)) {\n            if (S->getValueOperand()->stripPointerCasts() == fun) {\n                return true;\n            } else {\n                llvm::errs() << \"Unhandled function use: \" << *user << \"\\n\";\n                return true;\n            }\n            // FIXME: the function can be in a cast instruction that is just\n            // used in call,\n            //   we can detect that\n        } else {\n            llvm::errs() << \"Unhandled function use: \" << *user << \"\\n\";\n            return true;\n        }\n    }\n    return false;\n}\n\nstatic bool funHasAddrTaken(const llvm::Module *M, const std::string &name) {\n    const auto *fun = M->getFunction(name);\n    if (!fun) {\n        // the module does not have this function\n        return false;\n    }\n    return funHasAddrTaken(fun);\n}\n\nstatic bool instIsCallOf(const llvm::Instruction &I, const std::string &name,\n                         LLVMPointerAnalysis *pta = nullptr) {\n    const auto *C = llvm::dyn_cast<llvm::CallInst>(&I);\n    if (!C)\n        return false;\n\n    auto *fun = C->getCalledFunction();\n    if (fun) {\n        return name == fun->getName().str();\n    }\n\n#if LLVM_VERSION_MAJOR >= 8\n    auto *V = C->getCalledOperand()->stripPointerCasts();\n#else\n    auto *V = C->getCalledValue()->stripPointerCasts();\n#endif\n\n    if (!pta) {\n        auto *M = I.getParent()->getParent()->getParent();\n        return funHasAddrTaken(M, name);\n    }\n\n    auto pts = pta->getLLVMPointsTo(V);\n    if (pts.empty()) {\n        auto *M = I.getParent()->getParent()->getParent();\n        return funHasAddrTaken(M, name);\n    }\n\n    for (const auto &ptr : pts) {\n        fun = llvm::dyn_cast<llvm::Function>(ptr.value);\n        if (!fun)\n            continue;\n        if (name == fun->getName().str())\n            return true;\n    }\n\n    return false;\n}\n\nstatic bool fileMatch(const std::string &file, const llvm::Instruction &I) {\n#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 7\n    const auto *F = I.getParent()->getParent();\n    const auto *subprog = llvm::cast<llvm::DISubprogram>(\n            F->getMetadata(llvm::LLVMContext::MD_dbg));\n#else\n    const auto *subprog = I.getFunction()->getSubprogram();\n#endif\n    return subprog->getFile()->getFilename() == file;\n}\n\nstatic bool fileMatch(const std::string &file, const llvm::GlobalVariable &G) {\n#if LLVM_VERSION_MAJOR < 4\n    return true;\n#else\n    llvm::SmallVector<llvm::DIGlobalVariableExpression *, 2> GVs;\n    G.getDebugInfo(GVs);\n    bool has_match = false;\n    for (auto *GV : GVs) {\n        auto *var = GV->getVariable();\n        if (var->getFile()->getFilename() == file) {\n            has_match = true;\n            break;\n        }\n    }\n    return has_match;\n#endif\n}\n\nstatic bool instMatchesCrit(const llvm::Instruction &I, const std::string &fun,\n                            unsigned line, const std::string &obj,\n                            LLVMPointerAnalysis *pta = nullptr) {\n    // function match?\n    if (!fun.empty() && I.getParent()->getParent()->getName().str() != fun)\n        return false;\n\n    // line match?\n    if (line > 0) {\n        const auto &Loc = I.getDebugLoc();\n#if (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7)\n        if (Loc.getLine() != line)\n#else\n        if (!Loc || line != Loc.getLine())\n#endif\n        {\n            return false;\n        }\n    }\n\n    if (obj.empty()) {\n        // we passed the line check and we have no obj to check\n        return true;\n    }\n\n    // TODO: allow speficy namespaces, not only global/non-global\n    bool isvar = obj[0] == '&';\n    std::string objname;\n    if (isvar) {\n        objname = obj.substr(1);\n    } else {\n        objname = obj;\n    }\n\n    bool isglobal = objname[0] == '@';\n    if (isglobal) {\n        objname = obj.substr(1);\n    }\n\n    auto len = objname.length();\n    bool isfunc = len > 2 && objname.compare(len - 2, 2, \"()\") == 0;\n    if (isfunc) {\n        objname = objname.substr(0, len - 2);\n    }\n\n    if (isvar && isfunc) {\n        static std::set<std::string> reported;\n        if (reported.insert(obj).second) {\n            llvm::errs() << \"ERROR: ignoring invalid criterion (var and func \"\n                            \"at the same time: \"\n                         << obj << \"\\n\";\n        }\n        return false;\n    }\n\n    // obj match?\n    if (!isvar && instIsCallOf(I, objname, pta)) {\n        return true;\n    } // else fall through to check the vars\n\n    if (!isfunc && usesTheVariable(I, objname, isglobal, pta)) {\n        return true;\n    }\n\n    return false;\n}\n\nstatic bool globalMatchesCrit(const llvm::GlobalVariable &G, unsigned line,\n                              const std::string &obj) {\n    if (obj != G.getName().str()) {\n        return false;\n    }\n\n#if LLVM_VERSION_MAJOR < 4\n    return true;\n#else\n    if (line > 0) {\n        llvm::SmallVector<llvm::DIGlobalVariableExpression *, 2> GVs;\n        G.getDebugInfo(GVs);\n        bool has_match = false;\n        for (auto *GV : GVs) {\n            auto *var = GV->getVariable();\n            if (var->getLine() == line) {\n                has_match = true;\n                break;\n            }\n        }\n        if (!has_match)\n            return false;\n    }\n#endif // LLVM >= 4\n\n    return true;\n}\n\nstatic unsigned parseLine(const std::vector<std::string> &parts) {\n    unsigned idx = -1;\n    switch (parts.size()) {\n    case 2:\n        idx = 0;\n        break;\n    case 3:\n        idx = 1;\n        break;\n    case 4:\n        idx = 2;\n        break;\n    default:\n        return 0;\n    }\n\n    assert(idx == 0 || idx <= 2);\n    assert(idx < parts.size());\n\n    if (parts[idx].empty() || parts[idx] == \"*\")\n        return 0; // any line\n\n    // will we support multiple lines separated by comma?\n    if (!isNumber(parts[idx])) {\n        llvm::errs() << \"ERROR: invalid line number: \" << parts[idx] << \"\\n\";\n        return 0;\n    }\n\n    return atoi(parts[idx].c_str());\n}\n\nstatic std::string parseFile(const std::vector<std::string> &parts) {\n    if (parts.size() == 4)\n        return parts[0];\n    return \"\";\n}\n\nstatic std::string parseFun(const std::vector<std::string> &parts) {\n    switch (parts.size()) {\n    case 4:\n        return parts[1];\n    case 3:\n        return parts[0];\n    default:\n        return \"\";\n    }\n}\n\nstatic std::string parseObj(const std::vector<std::string> &parts) {\n    assert(parts.size() > 0);\n    return parts[parts.size() - 1];\n}\n\nstatic void getCriteriaInstructions(llvm::Module &M, LLVMPointerAnalysis *pta,\n                                    const std::string &criterion,\n                                    std::set<const llvm::Value *> &result,\n                                    bool constructed_only = false) {\n    assert(!criterion.empty() && \"No criteria given\");\n\n    auto parts = splitList(criterion, '#');\n    if (parts.size() > 4 || parts.empty()) {\n        llvm::errs() << \"WARNING: ignoring invalid slicing criterion: \"\n                     << criterion << \"\\n\";\n        return;\n    }\n\n    unsigned line = parseLine(parts);\n    auto fun = parseFun(parts);\n    auto obj = parseObj(parts);\n    auto file = parseFile(parts);\n\n    DBG(llvm - slicer, \"Criterion file # fun # line # obj ==> \"\n                               << file << \" # \" << fun << \" # \" << line << \" # \"\n                               << obj);\n\n    if (!fun.empty() && obj.empty() && line == 0) {\n        llvm::errs() << \"WARNING: ignoring invalid slicing criterion: \"\n                     << criterion << \"\\n\";\n        return;\n    }\n\n    // try match globals\n    DBG(llvm - slicer, \"Checking global variables for slicing criteria\");\n    if (fun.empty()) {\n        for (auto &G : M.globals()) {\n            if (!file.empty() && !fileMatch(file, G))\n                continue;\n            if (globalMatchesCrit(G, line, obj)) {\n                result.insert(&G);\n            }\n        }\n    }\n\n    if (constructed_only) {\n        DBG(llvm - slicer,\n            \"Checking constructed functions for slicing criteria\");\n\n        for (auto &it : getConstructedFunctions()) {\n            for (auto &I :\n                 llvm::instructions(*llvm::cast<llvm::Function>(it.first))) {\n                if (!file.empty() && !fileMatch(file, I))\n                    continue;\n\n                if (instMatchesCrit(I, fun, line, obj, pta)) {\n                    result.insert(&I);\n                }\n            }\n        }\n    } else {\n        DBG(llvm - slicer, \"Checking all instructions for slicing criteria\");\n\n        for (auto &F : M) {\n            for (auto &I : llvm::instructions(F)) {\n                if (file != \"\" && !fileMatch(file, I))\n                    continue;\n\n                if (instMatchesCrit(I, fun, line, obj, pta)) {\n                    result.insert(&I);\n                }\n            }\n        }\n    }\n}\n\nstruct SlicingCriteriaSet {\n    std::set<const llvm::Value *> primary;\n    std::set<const llvm::Value *> secondary;\n\n    SlicingCriteriaSet() = default;\n    SlicingCriteriaSet(SlicingCriteriaSet &&) = default;\n};\n\nstatic std::set<const llvm::Value *>\nmapToNextInstr(const std::set<const ::llvm::Value *> &vals) {\n    std::set<const llvm::Value *> newset;\n    for (const auto *val : vals) {\n        const auto *I = llvm::dyn_cast<llvm::Instruction>(val);\n        I = I ? I->getNextNode() : nullptr;\n        if (!I) {\n            llvm::errs() << \"WARNING: unable to get next instr for \" << *val\n                         << \"\\n\";\n            continue;\n        }\n        newset.insert(I);\n    }\n    return newset;\n}\n\nstatic void initDebugInfo(LLVMDependenceGraph &dg) {\n    if (!valuesToVariables.empty())\n        return;\n\n#if (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7)\n    llvm::errs() << \"WARNING: Variables names matching is not supported for \"\n                    \"LLVM older than 3.7\\n\";\n    llvm::errs() << \"WARNING: The slicing criteria with variables names will \"\n                    \"not work\\n\";\n#else // LLVM >= 3.8\n#if (LLVM_VERSION_MAJOR < 4)\n    llvm::errs() << \"WARNING: Function/global names matching is not supported \"\n                    \"for LLVM older than 4\\n\";\n    llvm::errs() << \"WARNING: The slicing criteria with variables names will \"\n                    \"not work well\\n\";\n#endif\n    // create the mapping from LLVM values to C variable names\n    for (const auto &it : getConstructedFunctions()) {\n        for (auto &I :\n             llvm::instructions(*llvm::cast<llvm::Function>(it.first))) {\n            if (const llvm::DbgDeclareInst *DD =\n                        llvm::dyn_cast<llvm::DbgDeclareInst>(&I)) {\n                auto *val = DD->getAddress();\n                valuesToVariables[val] = DD->getVariable()->getName().str();\n            } else if (const llvm::DbgValueInst *DV =\n                               llvm::dyn_cast<llvm::DbgValueInst>(&I)) {\n                auto *val = DV->getValue();\n                valuesToVariables[val] = DV->getVariable()->getName().str();\n            }\n        }\n    }\n\n    bool no_dbg = valuesToVariables.empty();\n    if (no_dbg) {\n        llvm::errs()\n                << \"No debugging information found in program, \"\n                << \"slicing criteria with lines and variables will work\\n\"\n                << \"only for global variables. \"\n                << \"You can still use the criteria based on call sites ;)\\n\";\n    }\n\n    for (const auto &GV : dg.getModule()->globals()) {\n        valuesToVariables[&GV] = GV.getName().str();\n    }\n#endif // LLVM > 3.6\n}\n\n///\n/// constructed_only  Search the criteria in DG's constructed functions\n///\nstatic std::vector<SlicingCriteriaSet> getSlicingCriteriaInstructions(\n        llvm::Module &M, const std::string &slicingCriteria,\n        bool criteria_are_next_instr, LLVMPointerAnalysis *pta = nullptr,\n        bool constructed_only = false) {\n    std::vector<std::string> criteria = splitList(slicingCriteria, ';');\n    assert(!criteria.empty() && \"Did not get slicing criteria\");\n\n    std::vector<SlicingCriteriaSet> result;\n    std::set<const llvm::Value *> secondaryToAll;\n\n    // map the criteria to instructions\n    for (const auto &crit : criteria) {\n        if (crit.empty())\n            continue;\n\n        result.emplace_back();\n\n        auto primsec = splitList(crit, '|');\n        if (primsec.size() > 2) {\n            llvm::errs() << \"WARNING: Only one | in SC supported, ignoring the \"\n                            \"rest\\n\";\n        }\n        assert(primsec.size() >= 1 && \"Invalid criterium\");\n        auto &SC = result.back();\n        // do we have some criterion of the form |X?\n        // I.e., only secondary SC? It means that that should\n        // be added to every primary SC\n        bool ssctoall = primsec[0].empty() && primsec.size() > 1;\n        if (!primsec[0].empty()) {\n            getCriteriaInstructions(M, pta, primsec[0], SC.primary,\n                                    constructed_only);\n        }\n\n        if (!SC.primary.empty()) {\n            llvm::errs() << \"SC: Matched '\" << primsec[0] << \"' to: \\n\";\n            size_t n = 0;\n            for (const auto *val : SC.primary) {\n                if (++n > 10)\n                    break;\n                llvm::errs() << \"  \" << *val << \"\\n\";\n            }\n            if (SC.primary.size() >= n) {\n                llvm::errs() << \" ... and  \" << SC.primary.size() - n + 1\n                             << \" more\\n\";\n            }\n\n            if (criteria_are_next_instr) {\n                // the given (primary) criteria are just markers for the\n                // next instruction, so map the criteria to\n                // the next instructions\n                auto newset = mapToNextInstr(SC.primary);\n                SC.primary.swap(newset);\n\n                n = 0;\n                for (const auto *val : SC.primary) {\n                    if (++n > 10)\n                        break;\n                    llvm::errs() << \"  SC (next): \" << *val << \"\\n\";\n                }\n                if (SC.primary.size() >= n) {\n                    llvm::errs() << \" ... and  \" << SC.primary.size() - n + 1\n                                 << \" more\\n\";\n                }\n            }\n        }\n\n        if ((!SC.primary.empty() || ssctoall) && primsec.size() > 1) {\n            getCriteriaInstructions(M, pta, primsec[1], SC.secondary,\n                                    constructed_only);\n\n            if (!SC.secondary.empty()) {\n                size_t n = 0;\n                llvm::errs() << \"SC: Matched '\" << primsec[1]\n                             << \"' (secondary) to: \\n\";\n                for (const auto *val : SC.secondary) {\n                    if (++n > 10)\n                        break;\n                    llvm::errs() << \"  \" << *val << \"\\n\";\n                }\n                if (SC.secondary.size() >= n) {\n                    llvm::errs() << \" ... and  \" << SC.primary.size() - n + 1\n                                 << \" more\\n\";\n                }\n            }\n\n            if (ssctoall) {\n                secondaryToAll.insert(SC.secondary.begin(), SC.secondary.end());\n            }\n        }\n    }\n\n    if (!secondaryToAll.empty()) {\n        for (auto &SC : result) {\n            if (SC.primary.empty())\n                continue;\n            SC.secondary.insert(secondaryToAll.begin(), secondaryToAll.end());\n        }\n    }\n\n    return result;\n}\n\nvoid mapInstrsToNodes(LLVMDependenceGraph &dg,\n                      const std::set<const llvm::Value *> &vals,\n                      std::set<LLVMNode *> &result) {\n    const auto &funs = getConstructedFunctions();\n    for (const auto *val : vals) {\n        if (llvm::isa<llvm::GlobalVariable>(val)) {\n            auto *G = dg.getGlobalNode(const_cast<llvm::Value *>(val));\n            assert(G);\n            result.insert(G);\n        } else if (const auto *I = llvm::dyn_cast<llvm::Instruction>(val)) {\n            auto *fun =\n                    const_cast<llvm::Function *>(I->getParent()->getParent());\n            auto it = funs.find(fun);\n            assert(it != funs.end() && \"Do not have DG for a fun\");\n            LLVMNode *nd = it->second->getNode(const_cast<llvm::Value *>(val));\n            assert(nd);\n            result.insert(nd);\n        } else {\n            assert(false && \"Unhandled slicing criterion\");\n        }\n    }\n}\n\nstd::vector<const llvm::Function *>\ngetCalledFunctions(LLVMDependenceGraph &dg, const llvm::CallInst *C) {\n    auto *fun = C->getCalledFunction();\n    if (fun)\n        return {fun};\n\n#if LLVM_VERSION_MAJOR >= 8\n    auto *V = C->getCalledOperand()->stripPointerCasts();\n#else\n    auto *V = C->getCalledValue()->stripPointerCasts();\n#endif\n\n    return dg::getCalledFunctions(V, dg.getPTA());\n}\n\n// WHOO, this is horrible. Refactor it into a class...\nvoid processBlock(LLVMDependenceGraph &dg, const llvm::BasicBlock *block,\n                  std::set<const llvm::BasicBlock *> &visited,\n                  ADT::QueueLIFO<const llvm::BasicBlock *> &queue,\n                  const std::set<const llvm::Value *> &secondary,\n                  std::set<const llvm::Value *> &result,\n                  const llvm::Instruction *till = nullptr) {\n    for (const auto &I : *block) {\n        if (till == &I)\n            break;\n\n        if (secondary.count(&I) > 0) {\n            result.insert(&I);\n        }\n\n        if (const auto *C = llvm::dyn_cast<llvm::CallInst>(&I)) {\n            // queue ret blocks from the called functions\n            for (const auto *fun : getCalledFunctions(dg, C)) {\n                for (const auto &blk : *fun) {\n                    if (llvm::isa<llvm::ReturnInst>(blk.getTerminator())) {\n                        if (visited.insert(&blk).second)\n                            queue.push(&blk);\n                    }\n                }\n            }\n        }\n    }\n}\n\n// mark nodes that are going to be in the slice\nstd::set<const llvm::Value *>\nfindSecondarySlicingCriteria(LLVMDependenceGraph &dg,\n                             const std::set<const llvm::Value *> &primary,\n                             const std::set<const llvm::Value *> &secondary) {\n    std::set<const llvm::Value *> result;\n    std::set<const llvm::BasicBlock *> visited;\n    ADT::QueueLIFO<const llvm::BasicBlock *> queue;\n\n    for (const auto *c : primary) {\n        const auto *I = llvm::dyn_cast<llvm::Instruction>(c);\n        // the criterion instr may be a global variable and in that\n        // case it has no basic block (but also no predecessors,\n        // so we can skip it)\n        if (!I)\n            continue;\n\n        processBlock(dg, I->getParent(), visited, queue, secondary, result, I);\n\n        // queue local predecessors\n        for (const auto *pred : llvm::predecessors(I->getParent())) {\n            if (visited.insert(pred).second)\n                queue.push(pred);\n        }\n    }\n\n    // get basic blocks\n    while (!queue.empty()) {\n        const auto *cur = queue.pop();\n\n        processBlock(dg, cur, visited, queue, secondary, result);\n\n        // queue local predecessors\n        for (const auto *pred : llvm::predecessors(cur)) {\n            if (visited.insert(pred).second)\n                queue.push(pred);\n        }\n    }\n\n    return result;\n}\n\nbool getSlicingCriteriaNodes(LLVMDependenceGraph &dg,\n                             const std::string &slicingCriteria,\n                             std::set<LLVMNode *> &criteria_nodes,\n                             bool criteria_are_next_instr) {\n    initDebugInfo(dg);\n\n    auto crits =\n            getSlicingCriteriaInstructions(*dg.getModule(), slicingCriteria,\n                                           criteria_are_next_instr, dg.getPTA(),\n                                           /* constructed only */ true);\n    if (crits.empty()) {\n        return true; // no criteria found\n    }\n\n    for (auto &SC : crits) {\n        if (SC.primary.empty()) {\n            continue;\n        }\n\n        mapInstrsToNodes(dg, SC.primary, criteria_nodes);\n\n        if (SC.secondary.empty()) {\n            continue;\n        }\n        auto ssc = findSecondarySlicingCriteria(dg, SC.primary, SC.secondary);\n        mapInstrsToNodes(dg, ssc, criteria_nodes);\n    }\n\n    return true;\n}\n\nnamespace legacy {\n\nstatic bool\ninstMatchesCrit(LLVMDependenceGraph &dg, const llvm::Instruction &I,\n                const std::vector<std::pair<int, std::string>> &parsedCrit) {\n    for (const auto &c : parsedCrit) {\n        const auto &Loc = I.getDebugLoc();\n#if (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7)\n        if (Loc.getLine() <= 0) {\n#else\n        if (!Loc) {\n#endif\n            continue;\n        }\n\n        if (static_cast<int>(Loc.getLine()) != c.first)\n            continue;\n\n        if (instIsCallOf(I, c.second, dg.getPTA())) {\n            llvm::errs() << \"Matched line \" << c.first << \" with call of \"\n                         << c.second << \" to:\\n\"\n                         << I << \"\\n\";\n            return true;\n        } // else fall through to check the vars\n\n        if (usesTheVariable(I, c.second, dg.getPTA())) {\n            llvm::errs() << \"Matched line \" << c.first << \" with variable \"\n                         << c.second << \" to:\\n\"\n                         << I << \"\\n\";\n            return true;\n        }\n    }\n\n    return false;\n}\n\nstatic bool\nglobalMatchesCrit(const llvm::GlobalVariable &G,\n                  const std::vector<std::pair<int, std::string>> &parsedCrit) {\n    for (const auto &c : parsedCrit) {\n        if (c.first != -1)\n            continue;\n        if (c.second == G.getName().str()) {\n            llvm::errs() << \"Matched global variable \" << c.second << \" to:\\n\"\n                         << G << \"\\n\";\n            return true;\n        }\n    }\n\n    return false;\n}\n\nstatic void getLineCriteriaNodes(LLVMDependenceGraph &dg,\n                                 std::vector<std::string> &criteria,\n                                 std::set<LLVMNode *> &nodes) {\n    assert(!criteria.empty() && \"No criteria given\");\n\n    std::vector<std::pair<int, std::string>> parsedCrit;\n    for (auto &crit : criteria) {\n        auto parts = splitList(crit, ':');\n        assert(parts.size() == 2);\n\n        // parse the line number\n        if (parts[0].empty()) {\n            // global variable\n            parsedCrit.emplace_back(-1, parts[1]);\n        } else if (isNumber(parts[0])) {\n            int line = atoi(parts[0].c_str());\n            if (line > 0)\n                parsedCrit.emplace_back(line, parts[1]);\n        } else {\n            llvm::errs()\n                    << \"Invalid line: '\" << parts[0] << \"'. \"\n                    << \"Needs to be a number or empty for global variables.\\n\";\n        }\n    }\n\n    assert(!parsedCrit.empty() && \"Failed parsing criteria\");\n\n    initDebugInfo(dg);\n\n    // try match globals\n    for (auto &G : dg.getModule()->globals()) {\n        if (globalMatchesCrit(G, parsedCrit)) {\n            LLVMNode *nd = dg.getGlobalNode(&G);\n            assert(nd);\n            nodes.insert(nd);\n        }\n    }\n\n    // we do not have any mapping, we will not match anything\n    if (valuesToVariables.empty()) {\n        return;\n    }\n\n    // map line criteria to nodes\n    for (const auto &it : getConstructedFunctions()) {\n        for (auto &I :\n             llvm::instructions(*llvm::cast<llvm::Function>(it.first))) {\n            if (instMatchesCrit(dg, I, parsedCrit)) {\n                LLVMNode *nd = it.second->getNode(&I);\n                assert(nd);\n                nodes.insert(nd);\n            }\n        }\n    }\n}\n\nstatic std::set<LLVMNode *>\n_mapToNextInstr(LLVMDependenceGraph & /*unused*/,\n                const std::set<LLVMNode *> &callsites) {\n    std::set<LLVMNode *> nodes;\n\n    for (LLVMNode *cs : callsites) {\n        llvm::Instruction *I =\n                llvm::dyn_cast<llvm::Instruction>(cs->getValue());\n        assert(I && \"Callsite is not an instruction\");\n        llvm::Instruction *succ = I->getNextNode();\n        if (!succ) {\n            llvm::errs() << *I << \"has no successor that could be criterion\\n\";\n            // abort for now\n            abort();\n        }\n\n        LLVMDependenceGraph *local_dg = cs->getDG();\n        LLVMNode *node = local_dg->getNode(succ);\n        assert(node && \"DG does not have such node\");\n        nodes.insert(node);\n    }\n\n    return nodes;\n}\n\nstatic std::set<LLVMNode *>\ngetPrimarySlicingCriteriaNodes(LLVMDependenceGraph &dg,\n                               const std::string &slicingCriteria,\n                               bool criteria_are_next_instr) {\n    std::set<LLVMNode *> nodes;\n    std::vector<std::string> criteria = splitList(slicingCriteria);\n    assert(!criteria.empty() && \"Did not get slicing criteria\");\n\n    std::vector<std::string> line_criteria;\n    std::vector<std::string> node_criteria;\n    std::tie(line_criteria, node_criteria) =\n            splitStringVector(criteria, [](std::string &s) -> bool {\n                return s.find(':') != std::string::npos;\n            });\n\n    // if user wants to slice with respect to the return of main,\n    // insert the ret instructions to the nodes.\n    for (const auto &c : node_criteria) {\n        if (c == \"ret\") {\n            LLVMNode *exit = dg.getExit();\n            // We could insert just the exit node, but this way we will\n            // get annotations to the functions.\n            for (auto it = exit->rev_control_begin(),\n                      et = exit->rev_control_end();\n                 it != et; ++it) {\n                nodes.insert(*it);\n            }\n        }\n    }\n\n    // map the criteria to nodes\n    if (!node_criteria.empty())\n        dg.getCallSites(node_criteria, &nodes);\n    if (!line_criteria.empty())\n        getLineCriteriaNodes(dg, line_criteria, nodes);\n\n    if (criteria_are_next_instr && !nodes.empty()) {\n        // the given criteria are just markers for the\n        // next instruction, so map the criteria to\n        // the next instructions\n        auto mappedNodes = _mapToNextInstr(dg, nodes);\n        nodes.swap(mappedNodes);\n    }\n\n    return nodes;\n}\n\nstatic std::pair<std::set<std::string>, std::set<std::string>>\nparseSecondarySlicingCriteria(const std::string &slicingCriteria) {\n    std::vector<std::string> criteria = splitList(slicingCriteria);\n\n    std::set<std::string> control_criteria;\n    std::set<std::string> data_criteria;\n\n    // if user wants to slice with respect to the return of main,\n    // insert the ret instructions to the nodes.\n    for (const auto &c : criteria) {\n        auto s = c.size();\n        if (s > 2 && c[s - 2] == '(' && c[s - 1] == ')')\n            data_criteria.insert(c.substr(0, s - 2));\n        else\n            control_criteria.insert(c);\n    }\n\n    return {control_criteria, data_criteria};\n}\n\n// FIXME: copied from LLVMDependenceGraph.cpp, do not duplicate the code\nstatic bool isCallTo(LLVMNode *callNode, const std::set<std::string> &names) {\n    using namespace llvm;\n\n    if (!isa<llvm::CallInst>(callNode->getValue())) {\n        return false;\n    }\n\n    // if the function is undefined, it has no subgraphs,\n    // but is not called via function pointer\n    if (!callNode->hasSubgraphs()) {\n        const CallInst *callInst = cast<CallInst>(callNode->getValue());\n#if LLVM_VERSION_MAJOR >= 8\n        const Value *calledValue = callInst->getCalledOperand();\n#else\n        const Value *calledValue = callInst->getCalledValue();\n#endif\n        const Function *func =\n                dyn_cast<Function>(calledValue->stripPointerCasts());\n        // in the case we haven't run points-to analysis\n        if (!func)\n            return false;\n\n        return array_match(func->getName(), names);\n    } // simply iterate over the subgraphs, get the entry node\n    // and check it\n    for (LLVMDependenceGraph *dg : callNode->getSubgraphs()) {\n        LLVMNode *entry = dg->getEntry();\n        assert(entry && \"No entry node in graph\");\n\n        const Function *func =\n                cast<Function>(entry->getValue()->stripPointerCasts());\n        return array_match(func->getName(), names);\n    }\n\n    return false;\n}\n\nstatic inline void\ncheckSecondarySlicingCrit(std::set<LLVMNode *> &criteria_nodes,\n                          const std::set<std::string> &secondaryControlCriteria,\n                          const std::set<std::string> &secondaryDataCriteria,\n                          LLVMNode *nd) {\n    if (isCallTo(nd, secondaryControlCriteria))\n        criteria_nodes.insert(nd);\n    if (isCallTo(nd, secondaryDataCriteria)) {\n        // XXX: Not fully supported, so add it...\n\n        // static std::set<LLVMNode *> reported;\n        // if (reported.insert(nd).second) {\n        //     llvm::errs()\n        //             << \"WARNING: Found possible data secondary slicing\n        //             criterion: \"\n        //             << *nd->getValue() << \"\\n\";\n        //     llvm::errs() << \"This is not fully supported, so adding to be\n        //     sound\\n\";\n        // }\n        criteria_nodes.insert(nd);\n    }\n}\n\n// mark nodes that are going to be in the slice\nstatic bool findSecondarySlicingCriteria(\n        std::set<LLVMNode *> &criteria_nodes,\n        const std::set<std::string> &secondaryControlCriteria,\n        const std::set<std::string> &secondaryDataCriteria) {\n    // FIXME: do this more efficiently (and use the new DFS class)\n    std::set<LLVMBBlock *> visited;\n    ADT::QueueLIFO<LLVMBBlock *> queue;\n    auto tmp = criteria_nodes;\n    for (const auto &c : tmp) {\n        // the criteria may be a global variable and in that\n        // case it has no basic block (but also no predecessors,\n        // so we can skip it)\n        if (!c->getBBlock())\n            continue;\n\n        queue.push(c->getBBlock());\n        visited.insert(c->getBBlock());\n\n        for (auto *nd : c->getBBlock()->getNodes()) {\n            if (nd == c)\n                break;\n\n            if (nd->hasSubgraphs()) {\n                // we search interprocedurally\n                for (auto *dg : nd->getSubgraphs()) {\n                    auto *exit = dg->getExitBB();\n                    assert(exit && \"No exit BB in a graph\");\n                    if (visited.insert(exit).second)\n                        queue.push(exit);\n                }\n            }\n\n            checkSecondarySlicingCrit(criteria_nodes, secondaryControlCriteria,\n                                      secondaryDataCriteria, nd);\n        }\n    }\n\n    // get basic blocks\n    while (!queue.empty()) {\n        auto *cur = queue.pop();\n        for (auto *pred : cur->predecessors()) {\n            for (auto *nd : pred->getNodes()) {\n                if (nd->hasSubgraphs()) {\n                    // we search interprocedurally\n                    for (auto *dg : nd->getSubgraphs()) {\n                        auto *exit = dg->getExitBB();\n                        assert(exit && \"No exit BB in a graph\");\n                        if (visited.insert(exit).second)\n                            queue.push(exit);\n                    }\n                }\n\n                checkSecondarySlicingCrit(criteria_nodes,\n                                          secondaryControlCriteria,\n                                          secondaryDataCriteria, nd);\n            }\n            if (visited.insert(pred).second)\n                queue.push(pred);\n        }\n    }\n\n    return true;\n}\n\nbool getSlicingCriteriaNodes(LLVMDependenceGraph &dg,\n                             const std::string &slicingCriteria,\n                             const std::string &secondarySlicingCriteria,\n                             std::set<LLVMNode *> &criteria_nodes,\n                             bool criteria_are_next_instr) {\n    auto nodes = getPrimarySlicingCriteriaNodes(dg, slicingCriteria,\n                                                criteria_are_next_instr);\n    if (nodes.empty()) {\n        return true; // no criteria found\n    }\n\n    criteria_nodes.swap(nodes);\n\n    auto secondaryCriteria =\n            parseSecondarySlicingCriteria(secondarySlicingCriteria);\n    const auto &secondaryControlCriteria = secondaryCriteria.first;\n    const auto &secondaryDataCriteria = secondaryCriteria.second;\n\n    // mark nodes that are going to be in the slice\n    if (!findSecondarySlicingCriteria(criteria_nodes, secondaryControlCriteria,\n                                      secondaryDataCriteria)) {\n        llvm::errs() << \"Finding secondary slicing criteria nodes failed\\n\";\n        return false;\n    }\n\n    return true;\n}\n} // namespace legacy\n\nbool getSlicingCriteriaNodes(LLVMDependenceGraph &dg,\n                             const std::string &slicingCriteria,\n                             const std::string &legacySlicingCriteria,\n                             const std::string &secondarySlicingCriteria,\n                             std::set<LLVMNode *> &criteria_nodes,\n                             bool criteria_are_next_instr) {\n    if (!legacySlicingCriteria.empty()) {\n        if (!::legacy::getSlicingCriteriaNodes(\n                    dg, legacySlicingCriteria, secondarySlicingCriteria,\n                    criteria_nodes, criteria_are_next_instr))\n            return false;\n    }\n\n    if (!slicingCriteria.empty()) {\n        if (!getSlicingCriteriaNodes(dg, slicingCriteria, criteria_nodes,\n                                     criteria_are_next_instr))\n            return false;\n    }\n\n    return true;\n}\n\nstd::vector<const llvm::Value *>\ngetSlicingCriteriaValues(llvm::Module &M, const std::string &slicingCriteria,\n                         const std::string &legacySlicingCriteria,\n                         const std::string &legacySecondaryCriteria,\n                         bool criteria_are_next_instr) {\n    std::string criteria = slicingCriteria;\n    if (legacySlicingCriteria != \"\") {\n        auto legacyCriteriaParts = splitList(legacySlicingCriteria, ',');\n        for (auto &legacyCriterion : legacyCriteriaParts) {\n            if (criteria != \"\")\n                criteria += \";\";\n\n            auto parts = splitList(legacyCriterion, ':');\n            if (parts.size() == 2) {\n                criteria += parts[0] + \"#\" + parts[1];\n            } else if (parts.size() == 1) {\n                criteria += legacyCriterion + \"()\";\n            } else {\n                llvm::errs()\n                        << \"Unsupported criteria: \" << legacyCriterion << \"\\n\";\n                return {};\n            }\n            if (legacySecondaryCriteria != \"\") {\n                criteria += \"|\" + legacySecondaryCriteria + \"()\";\n            }\n        }\n    }\n\n    std::vector<const llvm::Value *> ret;\n    auto C = getSlicingCriteriaInstructions(\n            M, criteria, criteria_are_next_instr,\n            /*pta = */ nullptr, /* constructed only */ false);\n    for (auto &critset : C) {\n        ret.insert(ret.end(), critset.primary.begin(), critset.primary.end());\n        ret.insert(ret.end(), critset.secondary.begin(),\n                   critset.secondary.end());\n    }\n    return ret;\n}\n"
  },
  {
    "path": "tools/llvm-slicer-metadata.cpp",
    "content": "#include <llvm/IR/DebugInfoMetadata.h>\n#include <llvm/IR/InstIterator.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/IntrinsicInst.h>\n#include <llvm/IR/Module.h>\n\n#include \"dg/tools/llvm-slicer-utils.h\"\n\n#include <map>\n\nusing MapTy = std::map<const llvm::Value *, CVariableDecl>;\n\n// create the mapping from LLVM values to C variable names\nMapTy allocasToVars(const llvm::Function &F) {\n    MapTy valuesToVariables;\n\n    for (const auto &I : llvm::instructions(F)) {\n        llvm::DIVariable *var = nullptr;\n        auto loc = I.getDebugLoc();\n        if (const llvm::DbgDeclareInst *DD =\n                    llvm::dyn_cast<llvm::DbgDeclareInst>(&I)) {\n            auto *val = DD->getAddress();\n            var = DD->getVariable();\n            valuesToVariables.emplace(\n                    val, CVariableDecl(var->getName().str(),\n                                       loc ? loc.getLine() : var->getLine(),\n                                       loc ? loc.getCol() : 0));\n        } else if (const llvm::DbgValueInst *DV =\n                           llvm::dyn_cast<llvm::DbgValueInst>(&I)) {\n            auto *val = DV->getValue();\n            auto *var = DV->getVariable();\n            valuesToVariables.emplace(\n                    val, CVariableDecl(var->getName().str(),\n                                       loc ? loc.getLine() : var->getLine(),\n                                       loc ? loc.getCol() : 0));\n        }\n    }\n\n    return valuesToVariables;\n}\n\nMapTy allocasToVars(const llvm::Module &M) {\n    MapTy valuesToVariables;\n    for (const auto &F : M) {\n        auto tmp = allocasToVars(F);\n        valuesToVariables.insert(tmp.begin(), tmp.end());\n    }\n    return valuesToVariables;\n}\n"
  },
  {
    "path": "tools/llvm-slicer-opts.cpp",
    "content": "#include \"dg/tools/llvm-slicer-opts.h\"\n\n#include \"dg/Offset.h\"\n#include \"dg/llvm/ControlDependence/LLVMControlDependenceAnalysisOptions.h\"\n#include \"dg/llvm/DataDependence/LLVMDataDependenceAnalysisOptions.h\"\n#include \"dg/llvm/LLVMDependenceGraph.h\"\n#include \"dg/llvm/LLVMDependenceGraphBuilder.h\"\n#include \"dg/llvm/PointerAnalysis/LLVMPointerAnalysisOptions.h\"\n\n#include \"dg/tools/llvm-slicer-utils.h\"\n#include \"dg/tools/llvm-slicer.h\"\n\n#include \"git-version.h\"\n\nusing dg::LLVMDataDependenceAnalysisOptions;\nusing dg::LLVMPointerAnalysisOptions;\n\nstatic void addAllocationFuns(dg::llvmdg::LLVMDependenceGraphOptions &dgOptions,\n                              const std::string &allocationFuns) {\n    using dg::AllocationFunction;\n\n    auto items = splitList(allocationFuns);\n    for (auto &item : items) {\n        auto subitms = splitList(item, ':');\n        if (subitms.size() != 2) {\n            llvm::errs() << \"ERROR: Invalid allocation function: \" << item\n                         << \"\\n\";\n            continue;\n        }\n\n        AllocationFunction type;\n        if (subitms[1] == \"malloc\")\n            type = AllocationFunction::MALLOC;\n        else if (subitms[1] == \"calloc\")\n            type = AllocationFunction::CALLOC;\n        else if (subitms[1] == \"realloc\")\n            type = AllocationFunction::REALLOC;\n        else {\n            llvm::errs() << \"ERROR: Invalid type of allocation function: \"\n                         << item << \"\\n\";\n            continue;\n        }\n\n        dgOptions.PTAOptions.addAllocationFunction(subitms[0], type);\n        dgOptions.DDAOptions.addAllocationFunction(subitms[0], type);\n    }\n}\n\nllvm::cl::OptionCategory SlicingOpts(\"Slicer options\", \"\");\n\n// Use LLVM's CommandLine library to parse\n// command line arguments\nSlicerOptions parseSlicerOptions(int argc, char *argv[], bool requireCrit,\n                                 bool inputFileRequired) {\n    llvm::cl::opt<std::string> outputFile(\n            \"o\",\n            llvm::cl::desc(\n                    \"Save the output to given file. If not specified,\\n\"\n                    \"a .sliced suffix is used with the original module name.\"),\n            llvm::cl::value_desc(\"filename\"), llvm::cl::init(\"\"),\n            llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<std::string> inputFile(\n            llvm::cl::Positional, llvm::cl::desc(\"<input file>\"),\n            llvm::cl::init(\"\"), llvm::cl::cat(SlicingOpts));\n\n    if (inputFileRequired) {\n        inputFile.setNumOccurrencesFlag(llvm::cl::Required);\n    }\n\n    llvm::cl::opt<std::string> slicingCriteria(\n            \"sc\",\n            llvm::cl::desc(\n                    \"Slicing criterion\\n\"\n                    \"S ::= file1,file2#line1,line2#[var1,fun1],[var2,fun2]\\n\"\n                    \"S[&S];S[&S]\\n\"),\n            llvm::cl::value_desc(\"crit\"), llvm::cl::init(\"\"),\n            llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<std::string> legacySlicingCriteria(\n            \"c\",\n            llvm::cl::desc(\n                    \"Slice with respect to the call-sites of a given function\\n\"\n                    \"i. e.: '-c foo' or '-c __assert_fail'. Special value is a \"\n                    \"'ret'\\n\"\n                    \"in which case the slice is taken with respect to the \"\n                    \"return value\\n\"\n                    \"of the main function. Further, you can specify the \"\n                    \"criterion as\\n\"\n                    \"l:v where l is the line in the original code and v is the \"\n                    \"variable.\\n\"\n                    \"l must be empty when v is a global variable. For local \"\n                    \"variables,\\n\"\n                    \"the variable v must be used on the line l.\\n\"\n                    \"You can use comma-separated list of more slicing \"\n                    \"criteria,\\n\"\n                    \"e.g. -c foo,5:x,:glob\\n\"),\n            llvm::cl::value_desc(\"crit\"), llvm::cl::init(\"\"),\n            llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<std::string> legacySecondarySlicingCriteria(\n            \"2c\",\n            llvm::cl::desc(\n                    \"Set secondary slicing criterion. The criterion is a call\\n\"\n                    \"to a given function. If just a name of the function is\\n\"\n                    \"given, it is a 'control' slicing criterion. If there is \"\n                    \"()\\n\"\n                    \"appended, it is 'data' slicing criterion. E.g. foo means\\n\"\n                    \"control secondary slicing criterion, foo() means data\\n\"\n                    \"data secondary slicing criterion.\\n\"),\n            llvm::cl::value_desc(\"crit\"), llvm::cl::init(\"\"),\n            llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<bool> removeSlicingCriteria(\n            \"remove-slicing-criteria\",\n            llvm::cl::desc(\n                    \"By default, slicer keeps also slicing criteria\\n\"\n                    \"in the sliced program. This switch makes slicer to \"\n                    \"remove\\n\"\n                    \"also the criteria (i.e. behave like Weisser's algorithm)\"),\n            llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<std::string> preservedFuns(\n            \"preserved-functions\",\n            llvm::cl::desc(\n                    \"Do not slice bodies of the given functions.\\n\"\n                    \"The argument is a comma-separated list of functions.\\n\"),\n            llvm::cl::value_desc(\"funs\"), llvm::cl::init(\"\"),\n            llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<bool> interprocCd(\n            \"interproc-cd\",\n            llvm::cl::desc(\n                    \"Compute interprocedural dependencies that cover, e.g.,\\n\"\n                    \"calls calls to exit() from inside of procedures. Default: \"\n                    \"true.\\n\"),\n            llvm::cl::init(true), llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<bool> cdaPerInstr(\n            \"cda-per-inst\",\n            llvm::cl::desc(\"Compute control dependencies per instruction (the \"\n                           \"default\\n\"\n                           \"is per basic block)\\n\"),\n            llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<bool> icfgCD(\n            \"cda-icfg\",\n            llvm::cl::desc(\n                    \"Compute control dependencies on interprocedural CFG.\\n\"\n                    \"Default: false (interprocedral CD are computed by\\n\"\n                    \"a separate analysis.\\n\"),\n            llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<uint64_t> ptaFieldSensitivity(\n            \"pta-field-sensitive\",\n            llvm::cl::desc(\"Make PTA field sensitive/insensitive. The offset \"\n                           \"in a pointer\\n\"\n                           \"is cropped to Offset::UNKNOWN when it is greater \"\n                           \"than N bytes.\\n\"\n                           \"Default is full field-sensitivity (N = \"\n                           \"Offset::UNKNOWN).\\n\"),\n            llvm::cl::value_desc(\"N\"), llvm::cl::init(dg::Offset::UNKNOWN),\n            llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<dg::dda::UndefinedFunsBehavior> undefinedFunsBehavior(\n            \"undefined-funs\",\n            llvm::cl::desc(\"Set the behavior of undefined functions\\n\"),\n            llvm::cl::values(\n                    clEnumValN(dg::dda::PURE, \"pure\",\n                               \"Assume that undefined functions do not read \"\n                               \"nor write memory\"),\n                    clEnumValN(dg::dda::WRITE_ANY, \"write-any\",\n                               \"Assume that undefined functions may write any \"\n                               \"memory\"),\n                    clEnumValN(dg::dda::READ_ANY, \"read-any\",\n                               \"Assume that undefined functions may read any \"\n                               \"memory\"),\n                    clEnumValN(dg::dda::READ_ANY | dg::dda::WRITE_ANY, \"rw-any\",\n                               \"Assume that undefined functions may read and \"\n                               \"write any memory\"),\n                    clEnumValN(dg::dda::WRITE_ARGS, \"write-args\",\n                               \"Assume that undefined functions may write to \"\n                               \"arguments\"),\n                    clEnumValN(dg::dda::READ_ARGS, \"read-args\",\n                               \"Assume that undefined functions may read from \"\n                               \"arguments (default)\"),\n                    clEnumValN(dg::dda::WRITE_ARGS | dg::dda::READ_ARGS,\n                               \"rw-args\",\n                               \"Assume that undefined functions may read or \"\n                               \"write from/to arguments\")\n#if LLVM_VERSION_MAJOR < 4\n                            ,\n                    nullptr\n#endif\n                    ),\n            llvm::cl::init(dg::dda::READ_ARGS), llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<std::string> entryFunction(\n            \"entry\", llvm::cl::desc(\"Entry function of the program\\n\"),\n            llvm::cl::init(\"main\"), llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<bool> forwardSlicing(\n            \"forward\", llvm::cl::desc(\"Perform forward slicing\\n\"),\n            llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<bool> threads(\n            \"consider-threads\",\n            llvm::cl::desc(\n                    \"Consider threads are in input file (default=false).\"),\n            llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<bool> preserveDbg(\n            \"preserve-dbg\",\n            llvm::cl::desc(\"Preserve debugging information (default=true).\"),\n            llvm::cl::init(true), llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<std::string> allocationFuns(\n            \"allocation-funs\",\n            llvm::cl::desc(\n                    \"Treat these functions as allocation functions\\n\"\n                    \"The argument is a comma-separated list of func:type,\\n\"\n                    \"where func is the function and type is one of\\n\"\n                    \"malloc, calloc, or realloc.\\n\"\n                    \"E.g., myAlloc:malloc will treat myAlloc as malloc.\\n\"),\n            llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<LLVMPointerAnalysisOptions::AnalysisType> ptaType(\n            \"pta\", llvm::cl::desc(\"Choose pointer analysis to use:\"),\n            llvm::cl::values(\n                    clEnumValN(LLVMPointerAnalysisOptions::AnalysisType::fi,\n                               \"fi\", \"Flow-insensitive PTA (default)\"),\n                    clEnumValN(LLVMPointerAnalysisOptions::AnalysisType::fs,\n                               \"fs\", \"Flow-sensitive PTA\"),\n                    clEnumValN(LLVMPointerAnalysisOptions::AnalysisType::inv,\n                               \"inv\", \"PTA with invalidate nodes\")\n#ifdef HAVE_SVF\n                            ,\n                    clEnumValN(LLVMPointerAnalysisOptions::AnalysisType::svf,\n                               \"svf\", \"Use pointer analysis from SVF project\")\n#endif\n#if LLVM_VERSION_MAJOR < 4\n                            ,\n                    nullptr\n#endif\n                    ),\n            llvm::cl::init(LLVMPointerAnalysisOptions::AnalysisType::fi),\n            llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<LLVMDataDependenceAnalysisOptions::AnalysisType> ddaType(\n            \"dda\", llvm::cl::desc(\"Choose data dependence analysis to use:\"),\n            llvm::cl::values(\n                    clEnumValN(LLVMDataDependenceAnalysisOptions::AnalysisType::\n                                       ssa,\n                               \"ssa\",\n                               \"MemorySSA DDA (the only option right now)\")\n#if LLVM_VERSION_MAJOR < 4\n                            ,\n                    nullptr\n#endif\n                    ),\n            llvm::cl::init(\n                    LLVMDataDependenceAnalysisOptions::AnalysisType::ssa),\n            llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<dg::ControlDependenceAnalysisOptions::CDAlgorithm>\n            cdAlgorithm(\n                    \"cda\",\n                    llvm::cl::desc(\"Choose control dependencies algorithm:\"),\n                    llvm::cl::values(\n                            clEnumValN(dg::ControlDependenceAnalysisOptions::\n                                               CDAlgorithm::STANDARD,\n                                       \"standard\",\n                                       \"Ferrante's algorithm (default)\"),\n                            clEnumValN(dg::ControlDependenceAnalysisOptions::\n                                               CDAlgorithm::STANDARD,\n                                       \"classic\", \"Alias to \\\"standard\\\"\"),\n                            clEnumValN(dg::ControlDependenceAnalysisOptions::\n                                               CDAlgorithm::STANDARD,\n                                       \"scd\", \"Alias to \\\"standard\\\"\"),\n                            clEnumValN(dg::ControlDependenceAnalysisOptions::\n                                               CDAlgorithm::NTSCD,\n                                       \"ntscd\",\n                                       \"Non-termination sensitive control \"\n                                       \"dependencies algorithm\"),\n                            clEnumValN(dg::ControlDependenceAnalysisOptions::\n                                               CDAlgorithm::NTSCD2,\n                                       \"ntscd2\",\n                                       \"Non-termination sensitive control \"\n                                       \"dependencies algorithm (a different \"\n                                       \"implementation)\"),\n                            clEnumValN(dg::ControlDependenceAnalysisOptions::\n                                               CDAlgorithm::NTSCD_RANGANATH,\n                                       \"ntscd-ranganath\",\n                                       \"Non-termination sensitive control \"\n                                       \"dependencies algorithm (the fixed \"\n                                       \"version of the original Ranganath et \"\n                                       \"al.'s algorithm)\"),\n                            clEnumValN(\n                                    dg::ControlDependenceAnalysisOptions::\n                                            CDAlgorithm::NTSCD_RANGANATH_ORIG,\n                                    \"ntscd-ranganath-orig\",\n                                    \"Non-termination sensitive control \"\n                                    \"dependencies algorithm (the original \"\n                                    \"(wrong) Ranganath et al.'s algorithm)\"),\n                            clEnumValN(dg::ControlDependenceAnalysisOptions::\n                                               CDAlgorithm::NTSCD_LEGACY,\n                                       \"ntscd-legacy\",\n                                       \"Non-termination sensitive control \"\n                                       \"dependencies algorithm (legacy \"\n                                       \"implementation)\"),\n                            clEnumValN(dg::ControlDependenceAnalysisOptions::\n                                               CDAlgorithm::DOD_RANGANATH,\n                                       \"dod-ranganath\",\n                                       \"Decisive order dependencies algorithm \"\n                                       \"by Ranganath et al. - fixed version \"\n                                       \"(standalone - for debugging)\"),\n                            clEnumValN(dg::ControlDependenceAnalysisOptions::\n                                               CDAlgorithm::DOD,\n                                       \"dod\",\n                                       \"Decisive order dependencies algorithm \"\n                                       \"(standalone - for debugging)\"),\n                            clEnumValN(dg::ControlDependenceAnalysisOptions::\n                                               CDAlgorithm::DODNTSCD,\n                                       \"dod+ntscd\", \"NTSCD and DOD together\"),\n                            clEnumValN(dg::ControlDependenceAnalysisOptions::\n                                               CDAlgorithm::STRONG_CC,\n                                       \"scc\",\n                                       \"Use strong control closure algorithm\")\n#if LLVM_VERSION_MAJOR < 4\n                                    ,\n                            nullptr\n#endif\n                            ),\n                    llvm::cl::init(dg::ControlDependenceAnalysisOptions::\n                                           CDAlgorithm::STANDARD),\n                    llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::alias cdAlgAlias(\n            \"cd-alg\",\n            llvm::cl::desc(\"Choose control dependencies algorithm to use\"\n                           \"(this options is obsolete, it is alias to -cda):\"),\n            llvm::cl::aliasopt(cdAlgorithm), llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::alias cdaInterprocAlias(\n            \"cda-interproc\", llvm::cl::desc(\"Alias to interproc-cd\"),\n            llvm::cl::aliasopt(interprocCd), llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<bool> cutoffDiverging(\n            \"cutoff-diverging\",\n            llvm::cl::desc(\"Cutoff diverging paths. That is, call abort() on \"\n                           \"those paths that may not reach the slicing \"\n                           \"criterion (default=true).\"),\n            llvm::cl::init(true), llvm::cl::cat(SlicingOpts));\n\n    llvm::cl::opt<bool> criteriaAreNextInstr(\n            \"criteria-are-next-instr\",\n            llvm::cl::desc(\n                    \"Assume that slicing criteria are not the call-sites\\n\"\n                    \"of the given function, but the instructions that\\n\"\n                    \"follow the call. I.e. the call is used just to mark\\n\"\n                    \"the instruction.\\n\"\n                    \"E.g. for 'crit' being set as the criterion, slicing \"\n                    \"critera are all instructions that follow any call of \"\n                    \"'crit'.\\n\"),\n            llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\n    ////////////////////////////////////\n    // ===-- End of the options --=== //\n    ////////////////////////////////////\n\n    // hide all options except ours options\n    // this method is available since LLVM 3.7\n#if ((LLVM_VERSION_MAJOR > 3) ||                                               \\\n     ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR >= 7)))\n    llvm::cl::HideUnrelatedOptions(SlicingOpts);\n#endif\n    llvm::cl::ParseCommandLineOptions(argc, argv);\n\n    if (requireCrit) {\n        if (slicingCriteria.getNumOccurrences() +\n                    legacySlicingCriteria.getNumOccurrences() ==\n            0) {\n            llvm::errs()\n                    << \"No slicing criteria specified (-sc or -c option)\\n\";\n            std::exit(1);\n        }\n    }\n\n    /// Fill the structure\n    SlicerOptions options;\n\n    options.inputFile = inputFile;\n    options.outputFile = outputFile;\n    options.slicingCriteria = slicingCriteria;\n    options.legacySlicingCriteria = legacySlicingCriteria;\n    options.legacySecondarySlicingCriteria = legacySecondarySlicingCriteria;\n    options.preservedFunctions = splitList(preservedFuns);\n    options.removeSlicingCriteria = removeSlicingCriteria;\n    options.forwardSlicing = forwardSlicing;\n    options.cutoffDiverging = cutoffDiverging;\n    options.criteriaAreNextInstr = criteriaAreNextInstr;\n\n    auto &dgOptions = options.dgOptions;\n    auto &PTAOptions = dgOptions.PTAOptions;\n    auto &DDAOptions = dgOptions.DDAOptions;\n    auto &CDAOptions = dgOptions.CDAOptions;\n\n    dgOptions.entryFunction = entryFunction;\n    dgOptions.preserveDbg = preserveDbg;\n    dgOptions.threads = threads;\n\n    CDAOptions.algorithm = cdAlgorithm;\n    CDAOptions.interprocedural = interprocCd;\n    CDAOptions._icfg = icfgCD;\n    CDAOptions.setNodePerInstruction(cdaPerInstr);\n\n    addAllocationFuns(dgOptions, allocationFuns);\n\n    PTAOptions.entryFunction = entryFunction;\n    PTAOptions.fieldSensitivity = dg::Offset(ptaFieldSensitivity);\n    PTAOptions.analysisType = ptaType;\n    PTAOptions.threads = threads;\n\n    DDAOptions.threads = threads;\n    DDAOptions.entryFunction = entryFunction;\n    DDAOptions.undefinedFunsBehavior = undefinedFunsBehavior;\n    DDAOptions.analysisType = ddaType;\n\n    return options;\n}\n"
  },
  {
    "path": "tools/llvm-slicer-preprocess.cpp",
    "content": "#include <llvm/IR/CFG.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/LLVMContext.h>\n#include <llvm/IR/Module.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#include <set>\n#include <stack>\n#include <vector>\n\n#include \"dg/llvm/CallGraph/CallGraph.h\"\n#include \"dg/tools/llvm-slicer-preprocess.h\"\n\nusing namespace llvm;\n\nnamespace dg {\nnamespace llvmdg {\n\ntemplate <typename C>\ninline bool hasRelevantPredecessor(llvm::BasicBlock *B, const C &relevant) {\n    for (auto *p : llvm::predecessors(B)) {\n        if (relevant.count(p) > 0)\n            return true;\n    }\n    return false;\n}\n\n// FIXME: refactor\n// FIXME: configurable entry\nbool cutoffDivergingBranches(Module &M, const std::string &entry,\n                             const std::vector<const llvm::Value *> &criteria) {\n    if (criteria.empty()) {\n        assert(false && \"Have no slicing criteria instructions\");\n        return false;\n    }\n\n    llvmdg::LazyLLVMCallGraph CG(&M);\n    std::set<BasicBlock *> relevant;\n    std::set<BasicBlock *> visited;\n    std::stack<BasicBlock *> queue; // not efficient...\n    auto &Ctx = M.getContext();\n    auto *entryFun = M.getFunction(entry);\n\n    if (!entryFun) {\n        llvm::errs() << \"Did not find the entry function\\n\";\n        return false;\n    }\n\n    // initialize the queue with blocks of slicing criteria\n    for (auto *c : criteria) {\n        auto *I = llvm::dyn_cast<Instruction>(const_cast<llvm::Value *>(c));\n        if (!I) {\n            continue;\n        }\n        auto *blk = I->getParent();\n        // add the block of slicing criteria\n        if (visited.insert(blk).second) {\n            queue.push(blk);\n        }\n\n        // add the callers of calls that reach this SC in this block\n        for (auto &blkI : *blk) {\n            if (&blkI == I)\n                break;\n            auto *blkCall = llvm::dyn_cast<llvm::CallInst>(&blkI);\n            if (!blkCall)\n                continue;\n            for (auto *fun : CG.getCalledFunctions(blkCall)) {\n                for (auto &funBlk : *fun) {\n                    if (llvm::isa<llvm::ReturnInst>(funBlk.getTerminator())) {\n                        if (visited.insert(const_cast<llvm::BasicBlock *>(\n                                                   &funBlk))\n                                    .second) {\n                            queue.push(const_cast<llvm::BasicBlock *>(&funBlk));\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // get all backward reachable blocks in the ICFG, only those blocks\n    // can be relevant in the slice\n    while (!queue.empty()) {\n        auto *cur = queue.top();\n        queue.pop();\n\n        // paths from this block go to the slicing criteria\n        relevant.insert(cur);\n\n        // queue the blocks from calls in current block\n        for (auto &blkI : *cur) {\n            auto *blkCall = llvm::dyn_cast<llvm::CallInst>(&blkI);\n            if (!blkCall)\n                continue;\n            for (auto *fun : CG.getCalledFunctions(blkCall)) {\n                for (auto &funBlk : *fun) {\n                    if (llvm::isa<llvm::ReturnInst>(funBlk.getTerminator())) {\n                        if (visited.insert(const_cast<llvm::BasicBlock *>(\n                                                   &funBlk))\n                                    .second) {\n                            queue.push(const_cast<llvm::BasicBlock *>(&funBlk));\n                        }\n                    }\n                }\n            }\n        }\n\n        if ((pred_begin(cur) == pred_end(cur))) {\n            // pop-up from call\n            for (auto *C : CG.getCallsOf(cast<Function>(cur->getParent()))) {\n                if (visited.insert(const_cast<llvm::BasicBlock *>(\n                                           C->getParent()))\n                            .second)\n                    queue.push(const_cast<llvm::BasicBlock *>(C->getParent()));\n            }\n        } else {\n            for (auto *pred : predecessors(cur)) {\n                if (visited.insert(pred).second)\n                    queue.push(pred);\n            }\n        }\n    }\n\n    // Now kill the irrelevant blocks (those from which the execution will\n    // never reach the slicing criterion\n\n    // FIXME Do also a pass from entry to remove dead code\n    // FIXME: make configurable... and insert __dg_abort()\n    // which will be internally implemented as abort() or exit().\n    Type *argTy = Type::getInt32Ty(Ctx);\n    auto exitC = M.getOrInsertFunction(\"exit\", Type::getVoidTy(Ctx), argTy\n#if LLVM_VERSION_MAJOR < 5\n                                       ,\n                                       nullptr\n#endif\n    );\n#if LLVM_VERSION_MAJOR >= 9\n    auto exitF = cast<Function>(exitC.getCallee());\n#else\n    auto exitF = cast<Function>(exitC);\n#endif\n    exitF->addFnAttr(Attribute::NoReturn);\n\n    size_t removed = 0;\n    size_t cutoff = 0;\n    for (auto &F : M) {\n        std::vector<llvm::BasicBlock *> irrelevant;\n        for (auto &B : F) {\n            if (relevant.count(&B) == 0) {\n                irrelevant.push_back(&B);\n            }\n        }\n        for (auto *B : irrelevant) {\n            // if this irrelevant block has predecessors in relevant,\n            // replace it with abort/exit\n            if (hasRelevantPredecessor(B, relevant)) {\n                auto *newB = BasicBlock::Create(Ctx, \"diverge\", &F);\n                CallInst::Create(exitF, {ConstantInt::get(argTy, 0)}, \"\", newB);\n                // CloneMetadata(point, new_CI);\n                new UnreachableInst(Ctx, newB);\n                // we cannot do the replacement here, we would break the\n                // iterator\n                B->replaceAllUsesWith(newB);\n                ++cutoff;\n            } else {\n                // else just erase it\n                ++removed;\n            }\n            B->dropAllReferences();\n            B->eraseFromParent();\n        }\n    }\n\n    llvm::errs() << \"[llvm-slicer] cutoff \" << cutoff\n                 << \" diverging blocks and \" << removed\n                 << \" completely removed\\n\";\n\n    return true;\n}\n\n} // namespace llvmdg\n} // namespace dg\n"
  },
  {
    "path": "tools/llvm-slicer-utils.cpp",
    "content": "#include \"dg/tools/llvm-slicer-utils.h\"\n\n#include \"dg/tools/llvm-slicer-opts.h\"\n\n#include <llvm/IR/LLVMContext.h>\n#include <llvm/IR/Module.h>\n#include <llvm/IRReader/IRReader.h>\n#include <llvm/Support/PrettyStackTrace.h>\n#include <llvm/Support/Signals.h>\n#include <llvm/Support/SourceMgr.h>\n#include <llvm/Support/raw_ostream.h>\n\n#include <string>\n\nstd::vector<std::string> splitList(const std::string &opt, char sep) {\n    std::vector<std::string> ret;\n    if (opt.empty())\n        return ret;\n\n    size_t old_pos = 0;\n    size_t pos = 0;\n    while (true) {\n        old_pos = pos;\n\n        pos = opt.find(sep, pos);\n        ret.push_back(opt.substr(old_pos, pos - old_pos));\n\n        if (pos == std::string::npos)\n            break;\n        ++pos;\n    }\n\n    return ret;\n}\n\nstd::pair<std::vector<std::string>, std::vector<std::string>>\nsplitStringVector(std::vector<std::string> &vec,\n                  std::function<bool(std::string &)> cmpFunc) {\n    std::vector<std::string> part1;\n    std::vector<std::string> part2;\n\n    for (auto &str : vec) {\n        if (cmpFunc(str)) {\n            part1.push_back(std::move(str));\n        } else {\n            part2.push_back(std::move(str));\n        }\n    }\n\n    return {part1, part2};\n}\n\nvoid replace_suffix(std::string &fl, const std::string &with) {\n    if (fl.size() > 2) {\n        if (fl.compare(fl.size() - 2, 2, \".o\") == 0)\n            fl.replace(fl.end() - 2, fl.end(), with);\n        else if (fl.compare(fl.size() - 3, 3, \".bc\") == 0)\n            fl.replace(fl.end() - 3, fl.end(), with);\n        else\n            fl += with;\n    } else {\n        fl += with;\n    }\n}\n\nstd::unique_ptr<llvm::Module> parseModule(const char *tool,\n                                          llvm::LLVMContext &context,\n                                          const SlicerOptions &options) {\n    llvm::SMDiagnostic smd;\n\n#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 5\n    auto _m = llvm::parseIRFile(options.inputFile, smd, context);\n    auto m = std::unique_ptr<llvm::Module>(_m);\n#else\n    auto m = llvm::parseIRFile(options.inputFile, smd, context);\n#endif\n\n    if (!m) {\n        llvm::errs() << \"Failed parsing '\" << options.inputFile << \"' file:\\n\";\n        smd.print(tool, llvm::errs());\n    }\n\n    return m;\n}\n\n#ifndef USING_SANITIZERS\nvoid setupStackTraceOnError(int argc, char *argv[]) {\n#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 9\n    llvm::sys::PrintStackTraceOnErrorSignal();\n#else\n    llvm::sys::PrintStackTraceOnErrorSignal(llvm::StringRef());\n#endif\n    llvm::PrettyStackTraceProgram X(argc, argv);\n}\n#else\nvoid setupStackTraceOnError(int, char **) {}\n#endif // not USING_SANITIZERS\n"
  },
  {
    "path": "tools/llvm-slicer.cpp",
    "content": "#include <cassert>\n#include <fstream>\n#include <iostream>\n#include <set>\n#include <string>\n#include <vector>\n\n#include \"dg/tools/llvm-slicer-opts.h\"\n#include \"dg/tools/llvm-slicer-preprocess.h\"\n#include \"dg/tools/llvm-slicer-utils.h\"\n#include \"dg/tools/llvm-slicer.h\"\n#include \"git-version.h\"\n\n#include <llvm/IR/InstIterator.h>\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/LLVMContext.h>\n#include <llvm/Support/raw_ostream.h>\n\n#include \"dg/ADT/Queue.h\"\n#include \"dg/util/debug.h\"\n\nusing namespace dg;\n\nusing dg::LLVMDataDependenceAnalysisOptions;\nusing dg::LLVMPointerAnalysisOptions;\nusing llvm::errs;\n\nusing AnnotationOptsT =\n        dg::debug::LLVMDGAssemblyAnnotationWriter::AnnotationOptsT;\n\nllvm::cl::opt<bool> enable_debug(\n        \"dbg\", llvm::cl::desc(\"Enable debugging messages (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> should_verify_module(\n        \"dont-verify\", llvm::cl::desc(\"Verify sliced module (default=true).\"),\n        llvm::cl::init(true), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> remove_unused_only(\n        \"remove-unused-only\",\n        llvm::cl::desc(\"Only remove unused parts of module (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> statistics(\n        \"statistics\",\n        llvm::cl::desc(\"Print statistics about slicing (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool>\n        dump_dg(\"dump-dg\",\n                llvm::cl::desc(\"Dump dependence graph to dot (default=false).\"),\n                llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> dump_dg_only(\n        \"dump-dg-only\",\n        llvm::cl::desc(\"Only dump dependence graph to dot,\"\n                       \" do not slice the module (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<bool> dump_bb_only(\n        \"dump-bb-only\",\n        llvm::cl::desc(\"Only dump basic blocks of dependence graph to dot\"\n                       \" (default=false).\"),\n        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));\n\nllvm::cl::opt<std::string> annotationOpts(\n        \"annotate\",\n        llvm::cl::desc(\n                \"Save annotated version of module as a text (.ll).\\n\"\n                \"Options:\\n\"\n                \"  dd: data dependencies,\\n\"\n                \"  cd:control dependencies,\\n\"\n                \"  pta: points-to information,\\n\"\n                \"  memacc: memory accesses of instructions,\\n\"\n                \"  slice: comment out what is going to be sliced away).\\n\"\n                \"for more options, use comma separated list\"),\n        llvm::cl::value_desc(\"val1,val2,...\"), llvm::cl::init(\"\"),\n        llvm::cl::cat(SlicingOpts));\n\nstatic void maybe_print_statistics(llvm::Module *M,\n                                   const char *prefix = nullptr) {\n    if (!statistics)\n        return;\n\n    using namespace llvm;\n    uint64_t inum, bnum, fnum, gnum;\n    inum = bnum = fnum = gnum = 0;\n\n    for (const auto &F : *M) {\n        // don't count in declarations\n        if (F.empty())\n            continue;\n\n        ++fnum;\n\n        for (const BasicBlock &B : F) {\n            ++bnum;\n            inum += B.size();\n        }\n    }\n\n    for (auto I = M->global_begin(), E = M->global_end(); I != E; ++I)\n        ++gnum;\n\n    if (prefix)\n        errs() << prefix;\n\n    errs() << \"Globals/Functions/Blocks/Instr.: \" << gnum << \" \" << fnum << \" \"\n           << bnum << \" \" << inum << \"\\n\";\n}\n\nstatic AnnotationOptsT parseAnnotationOptions(const std::string &annot) {\n    if (annot.empty())\n        return {};\n\n    AnnotationOptsT opts{};\n    std::vector<std::string> lst = splitList(annot);\n    for (const std::string &opt : lst) {\n        if (opt == \"dd\")\n            opts |= AnnotationOptsT::ANNOTATE_DD;\n        else if (opt == \"cd\" || opt == \"cda\")\n            opts |= AnnotationOptsT::ANNOTATE_CD;\n        else if (opt == \"dda\" || opt == \"du\")\n            opts |= AnnotationOptsT::ANNOTATE_DEF;\n        else if (opt == \"pta\")\n            opts |= AnnotationOptsT::ANNOTATE_PTR;\n        else if (opt == \"memacc\")\n            opts |= AnnotationOptsT::ANNOTATE_MEMORYACC;\n        else if (opt == \"slice\" || opt == \"sl\" || opt == \"slicer\")\n            opts |= AnnotationOptsT::ANNOTATE_SLICE;\n    }\n\n    return opts;\n}\n\nint main(int argc, char *argv[]) {\n    setupStackTraceOnError(argc, argv);\n\n#if ((LLVM_VERSION_MAJOR >= 6))\n    llvm::cl::SetVersionPrinter([](llvm::raw_ostream & /*unused*/) {\n        printf(\"%s\\n\", GIT_VERSION);\n    });\n#else\n    llvm::cl::SetVersionPrinter([]() { printf(\"%s\\n\", GIT_VERSION); });\n#endif\n\n    SlicerOptions options = parseSlicerOptions(argc, argv,\n                                               /* requireCrit = */ true);\n\n    if (enable_debug) {\n        DBG_ENABLE();\n    }\n\n    // dump_dg_only implies dumg_dg\n    if (dump_dg_only) {\n        dump_dg = true;\n    }\n\n    llvm::LLVMContext context;\n    std::unique_ptr<llvm::Module> M =\n            parseModule(\"llvm-slicer\", context, options);\n    if (!M)\n        return 1;\n\n    if (!M->getFunction(options.dgOptions.entryFunction)) {\n        llvm::errs() << \"The entry function not found: \"\n                     << options.dgOptions.entryFunction << \"\\n\";\n        return 1;\n    }\n\n    maybe_print_statistics(M.get(), \"Statistics before \");\n\n    // remove unused from module, we don't need that\n    ModuleWriter writer(options, M.get());\n    writer.removeUnusedFromModule();\n\n    if (remove_unused_only) {\n        errs() << \"[llvm-slicer] removed unused parts of module, exiting...\\n\";\n        maybe_print_statistics(M.get(), \"Statistics after \");\n        return writer.saveModule(should_verify_module);\n    }\n\n    /// ---------------\n    // slice the code\n    /// ---------------\n    if (options.cutoffDiverging && options.dgOptions.threads) {\n        llvm::errs() << \"[llvm-slicer] threads are enabled, not cutting off \"\n                        \"diverging\\n\";\n        options.cutoffDiverging = false;\n    }\n\n    if (options.cutoffDiverging) {\n        DBG(llvm - slicer, \"Searching for slicing criteria values\");\n        auto csvalues = getSlicingCriteriaValues(\n                *M, options.slicingCriteria, options.legacySlicingCriteria,\n                options.legacySecondarySlicingCriteria,\n                options.criteriaAreNextInstr);\n        if (csvalues.empty()) {\n            llvm::errs() << \"No reachable slicing criteria: '\"\n                         << options.slicingCriteria << \"' '\"\n                         << options.legacySlicingCriteria << \"'\\n\";\n            ::Slicer slicer(M.get(), options);\n            if (!slicer.createEmptyMain()) {\n                llvm::errs() << \"ERROR: failed creating an empty main\\n\";\n                return 1;\n            }\n\n            maybe_print_statistics(M.get(), \"Statistics after \");\n            return writer.cleanAndSaveModule(should_verify_module);\n        }\n\n        DBG(llvm - slicer, \"Cutting off diverging branches\");\n        if (!llvmdg::cutoffDivergingBranches(\n                    *M, options.dgOptions.entryFunction, csvalues)) {\n            errs() << \"[llvm-slicer]: Failed cutting off diverging branches\\n\";\n            return 1;\n        }\n\n        maybe_print_statistics(M.get(), \"Statistics after cutoff-diverging \");\n    }\n\n    ::Slicer slicer(M.get(), options);\n    if (!slicer.buildDG()) {\n        errs() << \"ERROR: Failed building DG\\n\";\n        return 1;\n    }\n\n    ModuleAnnotator annotator(options, &slicer.getDG(),\n                              parseAnnotationOptions(annotationOpts));\n\n    std::set<LLVMNode *> criteria_nodes;\n    if (!getSlicingCriteriaNodes(slicer.getDG(), options.slicingCriteria,\n                                 options.legacySlicingCriteria,\n                                 options.legacySecondarySlicingCriteria,\n                                 criteria_nodes,\n                                 options.criteriaAreNextInstr)) {\n        llvm::errs() << \"ERROR: Failed finding slicing criteria: '\"\n                     << options.slicingCriteria << \"'\\n\";\n\n        if (annotator.shouldAnnotate()) {\n            slicer.computeDependencies();\n            annotator.annotate();\n        }\n\n        return 1;\n    }\n\n    if (criteria_nodes.empty()) {\n        llvm::errs() << \"No reachable slicing criteria: '\"\n                     << options.slicingCriteria << \"' '\"\n                     << options.legacySlicingCriteria << \"'\\n\";\n        if (annotator.shouldAnnotate()) {\n            slicer.computeDependencies();\n            annotator.annotate();\n        }\n\n        if (!slicer.createEmptyMain()) {\n            llvm::errs() << \"ERROR: failed creating an empty main\\n\";\n            return 1;\n        }\n\n        maybe_print_statistics(M.get(), \"Statistics after \");\n        return writer.cleanAndSaveModule(should_verify_module);\n    }\n\n    // mark nodes that are going to be in the slice\n    if (!slicer.mark(criteria_nodes)) {\n        llvm::errs() << \"Finding dependent nodes failed\\n\";\n        return 1;\n    }\n\n    // print debugging llvm IR if user asked for it\n    if (annotator.shouldAnnotate())\n        annotator.annotate(&criteria_nodes);\n\n    DGDumper dumper(options, &slicer.getDG(), dump_bb_only);\n    if (dump_dg) {\n        dumper.dumpToDot();\n\n        if (dump_dg_only)\n            return 0;\n    }\n\n    // slice the graph\n    if (!slicer.slice()) {\n        errs() << \"ERROR: Slicing failed\\n\";\n        return 1;\n    }\n\n    if (dump_dg) {\n        dumper.dumpToDot(\".sliced.dot\");\n    }\n\n    // remove unused from module again, since slicing\n    // could and probably did make some other parts unused\n    maybe_print_statistics(M.get(), \"Statistics after \");\n    return writer.cleanAndSaveModule(should_verify_module);\n}\n"
  },
  {
    "path": "tools/llvm-thread-regions-dump.cpp",
    "content": "#include <llvm/IR/Instructions.h>\n#include <llvm/IR/LLVMContext.h>\n#include <llvm/IR/Module.h>\n#include <llvm/IRReader/IRReader.h>\n#include <llvm/Support/CommandLine.h>\n#include <llvm/Support/SourceMgr.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#if LLVM_VERSION_MAJOR >= 4\n#include <llvm/Bitcode/BitcodeReader.h>\n#else\n#include <llvm/Bitcode/ReaderWriter.h>\n#endif\n\n#include <fstream>\n#include <iostream>\n\n#include \"dg/PointerAnalysis/PointerAnalysisFI.h\"\n#include \"dg/llvm/PointerAnalysis/PointerAnalysis.h\"\n#include \"dg/llvm/ThreadRegions/ControlFlowGraph.h\"\n#include \"llvm/ThreadRegions/Graphs/GraphBuilder.h\"\n#include \"llvm/ThreadRegions/Graphs/ThreadRegionsBuilder.h\"\n\n#include <iostream>\n\nusing namespace std;\n\nint main(int argc, const char *argv[]) {\n    using namespace llvm;\n\n    cl::opt<string> OutputFilename(\"o\", cl::desc(\"Specify output filename\"),\n                                   cl::value_desc(\"filename\"), cl::init(\"\"));\n    cl::opt<std::string> inputFile(cl::Positional, cl::Required,\n                                   cl::desc(\"<input file>\"), cl::init(\"\"));\n\n    cl::ParseCommandLineOptions(argc, argv);\n\n    std::string module = inputFile;\n    std::string graphvizFileName = OutputFilename;\n\n    llvm::LLVMContext context;\n    llvm::SMDiagnostic SMD;\n\n    std::unique_ptr<Module> M = llvm::parseIRFile(module, SMD, context);\n\n    if (!M) {\n        llvm::errs() << \"Failed parsing '\" << module << \"' file:\\n\";\n        SMD.print(argv[0], errs());\n        return 1;\n    }\n\n    dg::DGLLVMPointerAnalysis pointsToAnalysis(M.get(), \"main\",\n                                               dg::Offset::UNKNOWN, true);\n    pointsToAnalysis.run();\n\n    ControlFlowGraph controlFlowGraph(&pointsToAnalysis);\n    controlFlowGraph.buildFunction(M->getFunction(\"main\"));\n\n    if (graphvizFileName.empty()) {\n        controlFlowGraph.printWithRegions(std::cout);\n    } else {\n        std::ofstream graphvizFile(graphvizFileName);\n        controlFlowGraph.printWithRegions(graphvizFile);\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tools/llvm-to-source.cpp",
    "content": "#include <fstream>\n#include <iostream>\n#include <limits>\n#include <map>\n#include <set>\n#include <sstream>\n#include <stack>\n\n#include <llvm/Config/llvm-config.h>\n\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))\n#include <llvm/DebugInfo.h>\n#else\n#include <llvm/DebugInfo/DIContext.h>\n#endif\n\n#include <llvm/IR/LLVMContext.h>\n#include <llvm/IR/Module.h>\n#include <llvm/IRReader/IRReader.h>\n#include <llvm/Support/CommandLine.h>\n#include <llvm/Support/SourceMgr.h>\n#include <llvm/Support/raw_os_ostream.h>\n\nllvm::cl::opt<std::string> inputFile(llvm::cl::Positional, llvm::cl::Required,\n                                     llvm::cl::desc(\"<input file>\"),\n                                     llvm::cl::init(\"\"));\n\nllvm::cl::opt<std::string> sourceFile(llvm::cl::Positional, llvm::cl::Optional,\n                                      llvm::cl::desc(\"[source code]\"),\n                                      llvm::cl::init(\"\"));\n\n// lines with matching braces\nstd::vector<std::pair<unsigned, unsigned>> matching_braces;\n// mapping line->index in matching_braces\nstd::map<unsigned, unsigned> nesting_structure;\n\nstatic void get_lines_from_module(const llvm::Module &M,\n                                  std::set<unsigned> &lines) {\n    // iterate over all instructions\n    for (const auto &F : M) {\n        for (const auto &B : F) {\n            for (const auto &I : B) {\n                const auto &Loc = I.getDebugLoc();\n                // Make sure that the llvm istruction has corresponding dbg LOC\n#if ((LLVM_VERSION_MAJOR > 3) ||                                               \\\n     ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR > 6)))\n                if (Loc)\n#else\n                if (Loc.getLine() > 0)\n#endif\n                    lines.insert(Loc.getLine());\n            }\n        }\n    }\n\n    // iterate over all globals\n    /*\n    for (const GlobalVariable& G : M->globals()) {\n        const DebugLoc& Loc = G.getDebugLoc();\n        lines.insert(Loc.getLine());\n    }\n    */\n}\n\nstatic void get_nesting_structure(const std::string &source) {\n    std::ifstream ifs(source);\n    if (!ifs.is_open() || ifs.bad()) {\n        llvm::errs() << \"Failed opening given source file: \" << source << \"\\n\";\n        abort();\n    }\n\n    char ch;\n    unsigned cur_line = 1;\n    unsigned idx;\n    std::stack<unsigned> nesting;\n    while (ifs.get(ch)) {\n        switch (ch) {\n        case '\\n':\n            ++cur_line;\n            if (!nesting.empty())\n                nesting_structure.emplace(cur_line, nesting.top());\n            break;\n        case '{':\n            nesting.push(matching_braces.size());\n            matching_braces.emplace_back(cur_line, 0);\n            break;\n        case '}':\n            idx = nesting.top();\n            assert(idx < matching_braces.size());\n            assert(matching_braces[idx].second == 0);\n            matching_braces[idx].second = cur_line;\n            nesting.pop();\n            break;\n        default:\n            break;\n        }\n    }\n\n    ifs.close();\n}\n\nstatic void print_lines(std::ifstream &ifs, std::set<unsigned> &lines) {\n    char buf[1024];\n    unsigned cur_line = 1;\n    while (!ifs.eof()) {\n        ifs.getline(buf, sizeof buf);\n\n        if (lines.count(cur_line) > 0) {\n            std::cout << cur_line << \": \";\n            std::cout << buf << \"\\n\";\n        }\n\n        if (ifs.bad()) {\n            llvm::errs() << \"An error occured\\n\";\n            break;\n        }\n\n        ++cur_line;\n    }\n}\n\nstatic void print_lines_numbers(std::set<unsigned> &lines) {\n    for (unsigned ln : lines)\n        std::cout << ln << \"\\n\";\n}\n\nint main(int argc, char *argv[]) {\n    llvm::cl::ParseCommandLineOptions(argc, argv);\n\n    llvm::LLVMContext context;\n    llvm::SMDiagnostic SMD;\n\n    std::unique_ptr<llvm::Module> M =\n            llvm::parseIRFile(inputFile, SMD, context);\n    if (!M) {\n        llvm::errs() << \"Failed parsing '\" << inputFile << \"' file:\\n\";\n        SMD.print(argv[0], llvm::errs());\n        return 1;\n    }\n\n    // FIXME find out if we have debugging info at all\n    // no difficult machineris - just find out\n    // which lines are in our module and print them\n    std::set<unsigned> lines;\n    get_lines_from_module(*M, lines);\n\n    if (sourceFile.empty())\n        print_lines_numbers(lines);\n    else {\n        get_nesting_structure(sourceFile);\n        /* fill in the lines with braces */\n        /* really not efficient, but easy */\n        size_t old_size;\n        do {\n            old_size = lines.size();\n            std::set<unsigned> new_lines;\n\n            for (unsigned i : lines) {\n                new_lines.insert(i);\n                auto it = nesting_structure.find(i);\n                if (it != nesting_structure.end()) {\n                    auto &pr = matching_braces[it->second];\n                    new_lines.insert(pr.first);\n                    new_lines.insert(pr.second);\n                }\n            }\n\n            lines.swap(new_lines);\n        } while (lines.size() > old_size);\n\n        std::ifstream ifs(sourceFile);\n        if (!ifs.is_open() || ifs.bad()) {\n            llvm::errs() << \"Failed opening given source file: \" << sourceFile\n                         << \"\\n\";\n            return 1;\n        }\n\n        // print_lines_numbers(lines);\n        print_lines(ifs, lines);\n        ifs.close();\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "tools/llvm-vr-dump.cpp",
    "content": "#include <cassert>\n#include <cstdio>\n#include <fstream>\n#include <iostream>\n#include <set>\n#include <sstream>\n#include <string>\n\n#include <llvm/IR/Instructions.h>\n#include <llvm/IR/LLVMContext.h>\n#include <llvm/IR/Module.h>\n#include <llvm/IRReader/IRReader.h>\n#include <llvm/Support/CommandLine.h>\n#include <llvm/Support/SourceMgr.h>\n#include <llvm/Support/raw_os_ostream.h>\n\n#if LLVM_VERSION_MAJOR >= 4\n#include <llvm/Bitcode/BitcodeReader.h>\n#include <llvm/Bitcode/BitcodeWriter.h>\n#else\n#include <llvm/Bitcode/ReaderWriter.h>\n#endif\n\n#include \"dg/llvm/ValueRelations/GraphBuilder.h\"\n#include \"dg/llvm/ValueRelations/GraphElements.h\"\n#include \"dg/llvm/ValueRelations/RelationsAnalyzer.h\"\n#include \"dg/llvm/ValueRelations/StructureAnalyzer.h\"\n#include \"dg/llvm/ValueRelations/getValName.h\"\n\n#include \"dg/util/TimeMeasure.h\"\n\nusing namespace dg::vr;\nusing llvm::errs;\n\nllvm::cl::opt<bool> todot(\"dot\", llvm::cl::desc(\"Dump graph in grahviz format\"),\n                          llvm::cl::init(false));\n\nllvm::cl::opt<bool> joins(\"joins\", llvm::cl::desc(\"Dump join informations\"),\n                          llvm::cl::init(false));\n\nllvm::cl::opt<unsigned> max_iter(\"max-iter\",\n                                 llvm::cl::desc(\"Maximal number of iterations\"),\n                                 llvm::cl::init(20));\n\nllvm::cl::opt<std::string> inputFile(llvm::cl::Positional, llvm::cl::Required,\n                                     llvm::cl::desc(\"<input file>\"),\n                                     llvm::cl::init(\"\"));\n\nstd::string node(const VRLocation &loc) {\n    return \"  NODE\" + std::to_string(loc.id);\n}\n\nstd::string node(unsigned i) { return \"  DUMMY_NODE\" + std::to_string(i); }\n\ntemplate <typename N1, typename N2>\nstd::string edge(const N1 &n1, const N2 &n2) {\n    return node(n1) + \"  ->\" + node(n2);\n}\n\nstd::string edgeTypeToColor(EdgeType type) {\n    switch (type) {\n    case EdgeType::TREE:\n        return \"darkgreen\";\n    case EdgeType::FORWARD:\n        return \"blue\";\n    case EdgeType::BACK:\n        return \"red\";\n    case EdgeType::DEFAULT:\n        return \"pink\";\n    }\n    assert(0 && \"unreach\");\n    abort();\n}\n\nvoid dumpNodes(const VRCodeGraph &codeGraph) {\n    for (auto &loc : codeGraph) {\n        std::cout << node(loc);\n        std::cout << \"[shape=box, margin=0.15, label=\\\"\";\n        std::cout << \"LOCATION \" << loc.id << \"\\n\";\n#ifndef NDEBUG\n        std::cout << loc.relations;\n#endif\n        std::cout << \"  \\\"];\\n\";\n    }\n}\n\nvoid dumpEdges(const VRCodeGraph &codeGraph) {\n    unsigned dummyIndex = 0;\n    for (const auto &loc : codeGraph) {\n        for (const auto &succ : loc.successors) {\n            if (succ->target)\n                std::cout << edge(loc, *succ->target);\n            else {\n                std::cout << node(++dummyIndex) << \"\\n\";\n                std::cout << edge(loc, dummyIndex);\n            }\n            std::cout << \" [label=\\\"\";\n#ifndef NDEBUG\n            succ->op->dump();\n#endif\n            std::cout << \"\\\", color=\" << edgeTypeToColor(succ->type) << \"];\\n\";\n        }\n\n        if (loc.isJustLoopJoin()) {\n            for (auto e : loc.loopEnds) {\n                std::cout << edge(loc, *e->target) << \" [color=magenta];\\n\";\n            }\n        }\n\n        if (joins && loc.join)\n            std::cout << edge(loc, *loc.join) << \" [color=pink];\\n\";\n    }\n}\n\nvoid dotDump(const VRCodeGraph &codeGraph) {\n    std::cout << \"digraph VR {\\n\";\n\n    dumpNodes(codeGraph);\n    dumpEdges(codeGraph);\n\n    std::cout << \"}\\n\";\n}\n\nint main(int argc, char *argv[]) {\n    llvm::Module *M;\n    llvm::LLVMContext context;\n    llvm::SMDiagnostic SMD;\n\n    llvm::cl::ParseCommandLineOptions(argc, argv);\n\n    if (inputFile.empty()) {\n        errs() << \"Usage: % IR_module\\n\";\n        return 1;\n    }\n\n#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR <= 5))\n    M = llvm::ParseIRFile(inputFile, SMD, context);\n#else\n    auto _M = llvm::parseIRFile(inputFile, SMD, context);\n    // _M is unique pointer, we need to get Module *\n    M = _M.get();\n#endif\n\n    if (!M) {\n        llvm::errs() << \"Failed parsing '\" << inputFile << \"' file:\\n\";\n        SMD.print(argv[0], errs());\n        return 1;\n    }\n\n    dg::debug::TimeMeasure tm;\n\n    tm.start();\n\n    // perform preparations and analysis\n    VRCodeGraph codeGraph;\n\n    GraphBuilder gb(*M, codeGraph);\n    gb.build();\n\n    StructureAnalyzer structure(*M, codeGraph);\n    structure.analyzeBeforeRelationsAnalysis();\n\n    RelationsAnalyzer ra(*M, codeGraph, structure);\n    unsigned num_iter = ra.analyze(max_iter);\n    structure.analyzeAfterRelationsAnalysis();\n    // call to analyzeAfterRelationsAnalysis is unnecessary, but better for\n    // testing end analysis\n\n    tm.stop();\n    tm.report(\"INFO: Value Relations analysis took\");\n    std::cerr << \"INFO: The analysis made \" << num_iter << \" passes.\"\n              << \"\\n\";\n    std::cerr << \"\\n\";\n\n    if (todot)\n        dotDump(codeGraph);\n\n    return 0;\n}\n"
  },
  {
    "path": "tools/llvmdda-dump",
    "content": "#!/bin/bash\n\n#defult program\nGUI=xdg-open\nDIRECTDOT=0\n\nset -e\n\nif which xdot &>/dev/null; then\n\tGUI=xdot\n\tDIRECTDOT=1\nelif which okular &>/dev/null; then\n\tGUI=okular\nelif which evince &>/dev/null; then\n\tGUI=evince\nfi\n\nPATH=`dirname $0`:$PATH\nllvm-dda-dump -dot $@ > _dda.dot\n\nif [ $DIRECTDOT -eq 1 ]; then\n\t$GUI _dda.dot\n\trm _dda.dot\nelse\n\tdot -Tpdf -o _dda.pdf _dda.dot\n\t$GUI _dda.pdf\n\trm _dda.pdf _dda.dot\nfi\n"
  },
  {
    "path": "tools/llvmdg-show",
    "content": "#!/bin/sh\n\nDIR=`dirname $0`\n\n#defult program\nGUI=xdg-open\nDIRECTDOT=0\n\nset -e\n\nif which xdot &>/dev/null; then\n\tGUI=xdot\n\tDIRECTDOT=1\nelif which okular &>/dev/null; then\n\tGUI=okular\nelif which evince &>/dev/null; then\n\tGUI=evince\nfi\n\n$DIR/llvm-dg-dump $* > _ldg-show-output.dot\n\nif [ $DIRECTDOT -eq 1 ]; then\n\t$GUI _ldg-show-output.dot\nelse\n\tdot -Tpdf _ldg-show-output.dot -o ldg-show-output.pdf\n\t$GUI _ldg-show-output.pdf\nfi\n\nrm _ldg-show-output*\n"
  },
  {
    "path": "tools/pta-show",
    "content": "#!/bin/bash\n\n#defult program\nGUI=xdg-open\nDIRECTDOT=0\n\n# exit on any error\nset -e\n\nif which xdot &>/dev/null; then\n\tGUI=xdot\n\tDIRECTDOT=1\nelif which okular &>/dev/null; then\n\tGUI=okular\nelif which evince &>/dev/null; then\n\tGUI=evince\nfi\n\nexport PATH=`dirname $0`:$PATH\nllvm-pta-dump -dot $@ > _ps.dot\n\n\nif [ $DIRECTDOT -eq 1 ]; then\n\t$GUI _ps.dot\n\trm _ps.dot\nelse\n\tdot -Tpdf -o _ps.pdf _ps.dot\n\t$GUI _ps.pdf\n\trm _ps.pdf _ps.dot\nfi\n"
  },
  {
    "path": "tools/sliced-diff.sh",
    "content": "#!/bin/bash\n\nM=\"$1\"\n\nllvm-dis \"$M\" -o __m.ll\nllvm-dis \"${M%%.bc}.sliced\" -o __m.sliced.ll\n\nCMD=diff\nif which meld &>/dev/null; then\n\tCMD=meld\nelif which kompare &>/dev/null; then\n\tCMD=kompare\nfi\n\n$CMD __m.ll __m.sliced.ll\nrm __m.ll __m.sliced.ll\n\n"
  }
]