diff --git a/llvm/utils/lit/lit/TestRunner.py b/llvm/utils/lit/lit/TestRunner.py
--- a/llvm/utils/lit/lit/TestRunner.py
+++ b/llvm/utils/lit/lit/TestRunner.py
@@ -612,7 +612,7 @@
     stderrTempFiles = []
     opened_files = []
     named_temp_files = []
-    builtin_commands = set(['cat', 'diff'])
+    builtin_commands = set(['cat', 'diff', 'not'])
     builtin_commands_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "builtin_commands")
     inproc_builtins = {'cd': executeBuiltinCd,
                        'export': executeBuiltinExport,
@@ -645,7 +645,9 @@
                     raise InternalShellError(j, "Error: 'env' requires a"
                                                 " subcommand")
             elif args[0] == 'not':
-                not_args.append(args.pop(0))
+                cmd_shenv.env['PYTHONPATH'] = os.path.dirname(os.path.abspath(__file__))
+                not_args.append(sys.executable)
+                not_args.append(os.path.join(builtin_commands_dir, args.pop(0) + ".py"))
                 not_count += 1
                 if args and args[0] == '--crash':
                     not_args.append(args.pop(0))
@@ -1199,7 +1201,7 @@
         return processed
 
     process = processLine if recursion_limit is None else processLineToFixedPoint
-    
+
     return [unescape(process(ln)) for ln in script]
 
 
diff --git a/llvm/utils/lit/lit/builtin_commands/not.py b/llvm/utils/lit/lit/builtin_commands/not.py
new file mode 100644
--- /dev/null
+++ b/llvm/utils/lit/lit/builtin_commands/not.py
@@ -0,0 +1,64 @@
+#===----------------------------------------------------------------------===##
+#
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#
+#===----------------------------------------------------------------------===##
+
+import subprocess
+import sys
+
+"""
+Inverts the return code of a command.
+
+For example:
+    $ not.py echo hello
+    $ echo $?
+    1
+"""
+
+def find_program(prog):
+    """Find a program in a way similar to `which`.
+       Returns the path to the program if found, and None otherwise.
+    """
+    # Allow for import errors on distutils.spawn
+    found = None
+    try:
+        import distutils.spawn
+        found = distutils.spawn.find_executable(prog)
+    except:
+        pass
+    if found is None:
+        sys.stderr.write('Failed to find program {}'.format(prog))
+    return found
+
+
+def main(argv):
+    if len(argv) > 0 and argv[0] == '--crash':
+        crash = True
+        argv.pop(0)
+    else:
+        crash = False
+
+    if not argv: # No command provided
+        return 1
+
+    if find_program(argv[0]) is None:
+        return 1
+
+    result = subprocess.call(argv)
+
+    # The program crashed
+    if result < 0:
+        return 0 if crash else 1
+
+    # The program didn't crash, but we were expecting a crash
+    if crash:
+        return 1
+
+    # The program didn't crash, and we were not expecting a crash
+    return result == 0
+
+if __name__ == '__main__':
+    exit(main(sys.argv[1:]))