Skip to content

Commit ac41dd7

Browse files
committed
Address comments
- remove reliance on default arguments - restructure IR extraction - fall back to using clang w/ llvm-reduce - don't assume all -O options are going to work with other tools
1 parent 7cd989e commit ac41dd7

File tree

1 file changed

+73
-42
lines changed

1 file changed

+73
-42
lines changed

clang/utils/reduce-clang-crash.py

Lines changed: 73 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -80,23 +80,23 @@ def write_to_script(text, filename):
8080
os.chmod(filename, os.stat(filename).st_mode | stat.S_IEXEC)
8181

8282

83-
def extract_opt_level(args_list: List[str]) -> Optional[str]:
83+
def extract_opt_level(args_list: List[str]) -> str:
8484
"""
8585
Finds the last optimization flag (-O...) from a list of arguments.
8686
8787
Args:
8888
args_list: A list of string arguments passed to the compiler.
8989
9090
Returns:
91-
The last matching optimization flag string if found, otherwise None.
91+
The last matching optimization flag string if found, otherwise -O2.
9292
"""
93-
valid_opt_flags = {"-O0", "-O1", "-O2", "-O3", "-Os", "-Oz", "-Og", "-Ofast"}
93+
valid_opt_flags = {"-O0", "-O1", "-O2", "-O3", "-Os", "-Oz"}
9494

9595
# Iterate in reverse to find the last occurrence
9696
for arg in reversed(args_list):
9797
if arg in valid_opt_flags:
9898
return arg
99-
return None
99+
return "-O2"
100100

101101

102102
def remove_first_line(file_path):
@@ -237,16 +237,10 @@ def skip_function(func_name):
237237

238238
self.expected_output = result
239239

240-
def check_expected_output(self, cmd=None, args=None, filename=None):
241-
if not cmd:
242-
cmd = self.clang
243-
if not args:
244-
args = self.clang_args
245-
if not filename:
246-
filename = self.file_to_reduce
247-
240+
def check_expected_output(self, cmd, args, filename):
241+
cmd = self.get_crash_cmd(cmd=cmd, args=args, filename=filename)
248242
p = subprocess.Popen(
249-
self.get_crash_cmd(cmd=cmd, args=args, filename=filename),
243+
cmd,
250244
stdout=subprocess.PIPE,
251245
stderr=subprocess.STDOUT,
252246
)
@@ -300,7 +294,7 @@ def check_interestingness(self, cmd, use_llvm_reduce=False):
300294
with tempfile.NamedTemporaryFile() as empty_file:
301295
new_args = cmd[1:] if use_llvm_reduce else cmd[1:-1]
302296
is_interesting = self.check_expected_output(
303-
cmd=cmd[0], args=new_args, filename=empty_file.name
297+
cmd[0], new_args, empty_file.name
304298
)
305299
if is_interesting:
306300
sys.exit("The interestingness test passes for an empty file.")
@@ -312,12 +306,16 @@ def clang_preprocess(self):
312306
cmd_preprocess_no_lines = cmd_preprocess + ["-P"]
313307
try:
314308
subprocess.check_call(cmd_preprocess_no_lines)
315-
if self.check_expected_output(filename=tmpfile.name):
309+
if self.check_expected_output(
310+
self.clang, self.clang_args, tmpfile.name
311+
):
316312
print("Successfully preprocessed with line markers removed")
317313
shutil.copy(tmpfile.name, self.file_to_reduce)
318314
else:
319315
subprocess.check_call(cmd_preprocess)
320-
if self.check_expected_output(filename=tmpfile.name):
316+
if self.check_expected_output(
317+
self.clang, self.clang_args, tmpfile.name
318+
):
321319
print("Successfully preprocessed without removing line markers")
322320
shutil.copy(tmpfile.name, self.file_to_reduce)
323321
else:
@@ -356,7 +354,9 @@ def try_remove_args(self, args, msg=None, extra_arg=None, **kwargs):
356354
new_args.remove(extra_arg)
357355
new_args.append(extra_arg)
358356

359-
if new_args != args and self.check_expected_output(args=new_args):
357+
if new_args != args and self.check_expected_output(
358+
self.clang, new_args, self.file_to_reduce
359+
):
360360
if msg:
361361
verbose_print(msg)
362362
return new_args
@@ -372,7 +372,7 @@ def try_remove_arg_by_index(self, args, index):
372372
del new_args[index]
373373
removed_arg += " " + args[index + 1]
374374

375-
if self.check_expected_output(args=new_args):
375+
if self.check_expected_output(self.clang, new_args, self.file_to_reduce):
376376
verbose_print("Removed", removed_arg)
377377
return new_args, index
378378
return args, index + 1
@@ -507,13 +507,15 @@ def run_llvm_reduce(self):
507507

508508
def classify_crash(self) -> FailureType:
509509
print("Classifying crash ...")
510-
if self.check_expected_output(args=self.clang_args + ["-fsyntax-only"]):
510+
if self.check_expected_output(
511+
self.clang, self.clang_args + ["-fsyntax-only"], self.file_to_reduce
512+
):
511513
print("Found Frontend Crash")
512514
return FailureType.FrontEnd
513515

514516
print("Found Middle/Backend failure")
515517

516-
self.opt_level = extract_opt_level(self.clang_args) or "-O2"
518+
self.opt_level = extract_opt_level(self.clang_args)
517519
backend_result = self.check_backend()
518520
if backend_result == FailureType.BackEnd:
519521
return backend_result
@@ -524,12 +526,14 @@ def classify_crash(self) -> FailureType:
524526

525527
def check_llc_failure(self) -> bool:
526528
return self.check_expected_output(
527-
cmd=self.llc, args=[self.opt_level, "-filetype=obj"], filename=self.ir_file
529+
self.llc, [self.opt_level, "-filetype=obj"], self.ir_file
528530
)
529531

530532
def extract_backend_ir(self) -> bool:
531533
return not self.check_expected_output(
532-
args=self.clang_args + ["-emit-llvm", "-o", self.ir_file]
534+
self.clang,
535+
self.clang_args + ["-emit-llvm", "-o", self.ir_file],
536+
self.file_to_reduce,
533537
)
534538

535539
def check_backend(self) -> Optional[FailureType]:
@@ -539,38 +543,67 @@ def check_backend(self) -> Optional[FailureType]:
539543
print("Checking llc for failure")
540544
if self.check_llc_failure():
541545
print("Found BackEnd Crash")
546+
self.new_cmd = [self.llc, self.opt_level, "-filetype=obj"]
542547
return FailureType.BackEnd
543548

544-
def extract_crashing_ir(self):
549+
def extract_crashing_ir(self, use_print_on_crash=False):
545550
"""
546551
Extract IR just before the crash using --print-on-crash
547552
"""
548-
args = self.clang_args + [
549-
"-mllvm",
550-
"--print-on-crash",
551-
"-mllvm",
552-
f"--print-on-crash-path={self.ir_file}",
553-
"-mllvm",
554-
"--print-module-scope",
555-
]
553+
if use_print_on_crash:
554+
args = self.clang_args + [
555+
"-mllvm",
556+
"--print-on-crash",
557+
"-mllvm",
558+
f"--print-on-crash-path={self.ir_file}",
559+
"-mllvm",
560+
"--print-module-scope",
561+
]
556562

557-
if not self.check_expected_output(args=args):
558-
sys.exit("The interestingness test does not pass with '--print-on-crash'.")
563+
if not self.check_expected_output(self.clang, args, self.file_to_reduce):
564+
sys.exit(
565+
"The interestingness test does not pass with '--print-on-crash'."
566+
)
559567

560-
# The output from --print-on-crash has an invalid first line (pass name).
561-
remove_first_line(self.ir_file)
568+
# The output from --print-on-crash has an invalid first line (pass name).
569+
remove_first_line(self.ir_file)
570+
return
571+
args = self.clang_args + [
572+
"-disable-llvm-passes",
573+
"-S",
574+
"-emit-llvm",
575+
"-o",
576+
self.ir_file,
577+
]
578+
if self.check_expected_output(self.clang, args, self.file_to_reduce):
579+
sys.exit("The interestingness test does not pass when generating llvm ir.")
580+
# print(quote_cmd(self.get_crash_cmd(self.clang, args, self.file_to_reduce)))
562581

563582
def check_middle_end(self) -> FailureType:
564583
# TODO: parse the exact pass from the backtrace and set the pass
565584
# pipeline directly via -passes="...".
566585
print("Checking opt for failure")
586+
args = [self.opt_level, "-disable-output"]
587+
if self.check_expected_output(
588+
self.opt,
589+
args,
590+
self.ir_file,
591+
):
592+
print("Found MiddleEnd Crash")
593+
self.new_cmd = [self.opt] + args
594+
return FailureType.MiddleEnd
595+
596+
print("Check clang on IR file")
597+
args = self.clang_args[:-1] + ["ir"]
567598
if self.check_expected_output(
568-
cmd=self.opt,
569-
args=[self.opt_level, "-disable-output"],
570-
filename=self.ir_file,
599+
self.clang,
600+
args,
601+
self.ir_file,
571602
):
572603
print("Found MiddleEnd Crash")
604+
self.new_cmd = [self.clang] + args
573605
return FailureType.MiddleEnd
606+
574607
print(
575608
"Could not automatically detect crash type, falling back to creduce/cvise."
576609
)
@@ -671,12 +704,10 @@ def main():
671704
print("Starting reduction with creduce/cvise")
672705
pass
673706
case FailureType.MiddleEnd:
674-
new_cmd = [opt_cmd, "-disable-output", r.opt_level]
675-
r.reduce_ir_crash(new_cmd)
707+
r.reduce_ir_crash(r.new_cmd)
676708
return
677709
case FailureType.BackEnd:
678-
new_cmd = [llc_cmd, "-filetype=obj", r.opt_level]
679-
r.reduce_ir_crash(new_cmd)
710+
r.reduce_ir_crash(r.new_cmd)
680711
return
681712

682713
r.simplify_clang_args()

0 commit comments

Comments
 (0)