diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 7ddb86d80bf..d72cf592298 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -628,12 +628,15 @@ void AsmPrinter::EmitDebugThreadLocal(const MCExpr *Value, /// EmitFunctionHeader - This method emits the header for the current /// function. void AsmPrinter::EmitFunctionHeader() { + const Function *F = MF->getFunction(); + + if (isVerbose()) + OutStreamer->GetCommentOS() << "-- Begin function " << F->getName() << '\n'; + // Print out constants referenced by the function EmitConstantPool(); // Print the 'header' of function. - const Function *F = MF->getFunction(); - OutStreamer->SwitchSection(getObjFileLowering().SectionForGlobal(F, TM)); EmitVisibility(CurrentFnSym, F->getVisibility()); @@ -1107,6 +1110,9 @@ void AsmPrinter::EmitFunctionBody() { HI.Handler->endFunction(MF); } + if (isVerbose()) + OutStreamer->GetCommentOS() << "-- End function\n"; + OutStreamer->AddBlankLine(); } diff --git a/test/CodeGen/AArch64/asm-print-comments.ll b/test/CodeGen/AArch64/asm-print-comments.ll new file mode 100644 index 00000000000..e997dce2358 --- /dev/null +++ b/test/CodeGen/AArch64/asm-print-comments.ll @@ -0,0 +1,17 @@ +; RUN: llc %s -mtriple=arm64-apple-darwin -o - | FileCheck %s + +; CHECK-LABEL: ; -- Begin function foo +; CHECK: foo: +define hidden i32 @foo() { + entry: + ret i32 30 +} +; CHECK: ; -- End function + +; CHECK-LABEL: ; -- Begin function bar +; CHECK: bar: +define i32 @bar() { + entry: + ret i32 30 +} +; CHECK: ; -- End function diff --git a/test/CodeGen/ARM/fastisel-thumb-litpool.ll b/test/CodeGen/ARM/fastisel-thumb-litpool.ll index aa9e7260fb2..53653a5a4f5 100644 --- a/test/CodeGen/ARM/fastisel-thumb-litpool.ll +++ b/test/CodeGen/ARM/fastisel-thumb-litpool.ll @@ -5,6 +5,7 @@ ; hence the CHECK-NOT. define i32 @test_thumb_ldrlit() minsize { +; CHECK-LABEL: test_thumb_ldrlit: ; CHECK: ldr r0, LCPI0_0 ; CHECK-NOT: ldr ret i32 12345678 diff --git a/test/CodeGen/X86/fast-isel-select-cmp.ll b/test/CodeGen/X86/fast-isel-select-cmp.ll index 1af30e9f32f..4a8e8792f98 100644 --- a/test/CodeGen/X86/fast-isel-select-cmp.ll +++ b/test/CodeGen/X86/fast-isel-select-cmp.ll @@ -4,9 +4,9 @@ ; different basic blocks. define i32 @select_cmp_cmov_i32(i32 %a, i32 %b) { -; CHECK-LABEL: select_cmp_cmov_i32 +; CHECK-LABEL: select_cmp_cmov_i32: ; CHECK-LABEL: continue -; CHECK-NOT: cmp +; CHECK-NOT: cmp{{[^_]}} %1 = icmp ult i32 %a, %b br i1 %1, label %continue, label %exit @@ -19,9 +19,9 @@ exit: } define float @select_fcmp_oeq_f32(float %a, float %b, float %c, float %d) { -; CHECK-LABEL: select_fcmp_oeq_f32 +; CHECK-LABEL: select_fcmp_oeq_f32: ; CHECK-LABEL: continue -; CHECK-NOT: cmp +; CHECK-NOT: cmp{{[^_]}} %1 = fcmp oeq float %a, %b br i1 %1, label %continue, label %exit @@ -34,7 +34,7 @@ exit: } define float @select_fcmp_one_f32(float %a, float %b, float %c, float %d) { -; CHECK-LABEL: select_fcmp_one_f32 +; CHECK-LABEL: select_fcmp_one_f32: ; CHECK-LABEL: continue ; CHECK-NOT: ucomi %1 = fcmp one float %a, %b diff --git a/test/CodeGen/X86/x87.ll b/test/CodeGen/X86/x87.ll index 683d7b05cf8..9bc654861b6 100644 --- a/test/CodeGen/X86/x87.ll +++ b/test/CodeGen/X86/x87.ll @@ -1,13 +1,16 @@ ; RUN: llc < %s -march=x86 | FileCheck %s -check-prefix=X87 ; RUN: llc < %s -march=x86-64 -mattr=-sse | FileCheck %s -check-prefix=X87 -; RUN: llc < %s -march=x86 -mattr=-x87 | FileCheck %s -check-prefix=NOX87 --implicit-check-not "{{ }}f{{.*}}" -; RUN: llc < %s -march=x86-64 -mattr=-x87,-sse | FileCheck %s -check-prefix=NOX87 --implicit-check-not "{{ }}f{{.*}}" -; RUN: llc < %s -march=x86 -mattr=-x87,+sse | FileCheck %s -check-prefix=NOX87 --implicit-check-not "{{ }}f{{.*}}" -; RUN: llc < %s -march=x86-64 -mattr=-x87,-sse2 | FileCheck %s -check-prefix=NOX87 --implicit-check-not "{{ }}f{{.*}}" +; RUN: llc < %s -march=x86 -mattr=-x87 | FileCheck %s -check-prefix=NOX87 +; RUN: llc < %s -march=x86-64 -mattr=-x87,-sse | FileCheck %s -check-prefix=NOX87 +; RUN: llc < %s -march=x86 -mattr=-x87,+sse | FileCheck %s -check-prefix=NOX87 +; RUN: llc < %s -march=x86-64 -mattr=-x87,-sse2 | FileCheck %s -check-prefix=NOX87 define void @test(i32 %i, i64 %l, float* %pf, double* %pd, fp128* %pld) nounwind readnone { ; X87-LABEL: test: ; NOX87-LABEL: test: + +; NOX87-NOT: {{ }}f{{.*}} + ; X87: fild ; NOX87: __floatunsisf %tmp = uitofp i32 %i to float diff --git a/test/CodeGen/XCore/epilogue_prologue.ll b/test/CodeGen/XCore/epilogue_prologue.ll index aed49f4b67b..d214c40dd9b 100644 --- a/test/CodeGen/XCore/epilogue_prologue.ll +++ b/test/CodeGen/XCore/epilogue_prologue.ll @@ -6,7 +6,7 @@ ; When using FP, for large or small frames, we may need one scratch register. ; FP + small frame: spill FP+SR = entsp 2 -; CHECKFP-LABEL: f1 +; CHECKFP-LABEL: f1: ; CHECKFP: entsp 2 ; CHECKFP-NEXT: stw r10, sp[1] ; CHECKFP-NEXT: ldaw r10, sp[0] @@ -15,7 +15,7 @@ ; CHECKFP-NEXT: retsp 2 ; ; !FP + small frame: no spills = no stack adjustment needed -; CHECK-LABEL: f1 +; CHECK-LABEL: f1: ; CHECK: stw lr, sp[0] ; CHECK: ldw lr, sp[0] ; CHECK-NEXT: retsp 0 @@ -27,7 +27,7 @@ entry: ; FP + small frame: spill FP+SR+R0+LR = entsp 3 + extsp 1 -; CHECKFP-LABEL:f3 +; CHECKFP-LABEL: f3: ; CHECKFP: entsp 3 ; CHECKFP-NEXT: stw r10, sp[1] ; CHECKFP-NEXT: ldaw r10, sp[0] @@ -43,7 +43,7 @@ entry: ; CHECKFP-NEXT: retsp 3 ; ; !FP + small frame: spill R0+LR = entsp 2 -; CHECK-LABEL: f3 +; CHECK-LABEL: f3: ; CHECK: entsp 2 ; CHECK-NEXT: stw [[REG:r[4-9]+]], sp[1] ; CHECK-NEXT: mov [[REG]], r0 @@ -60,7 +60,7 @@ entry: ; FP + large frame: spill FP+SR = entsp 2 + 100000 -; CHECKFP-LABEL: f4 +; CHECKFP-LABEL: f4: ; CHECKFP: entsp 65535 ; CHECKFP-NEXT: .Lcfi{{[0-9]+}} ; CHECKFP-NEXT: .cfi_def_cfa_offset 262140 @@ -81,7 +81,7 @@ entry: ; CHECKFP-NEXT: retsp 34467 ; ; !FP + large frame: spill SR+SR = entsp 2 + 100000 -; CHECK-LABEL: f4 +; CHECK-LABEL: f4: ; CHECK: entsp 65535 ; CHECK-NEXT: .Lcfi{{[0-9]+}} ; CHECK-NEXT: .cfi_def_cfa_offset 262140 @@ -107,7 +107,7 @@ entry: ; CHECKFP-NEXT: .LCPI[[CNST1:[0-9_]+]]: ; CHECKFP-NEXT: .long 200001 ; CHECKFP-NEXT: .text -; CHECKFP-LABEL: f6 +; CHECKFP-LABEL: f6: ; CHECKFP: entsp 65535 ; CHECKFP-NEXT: .Lcfi{{[0-9]+}} ; CHECKFP-NEXT: .cfi_def_cfa_offset 262140 @@ -160,7 +160,7 @@ entry: ; CHECK-NEXT: .LCPI[[CNST1:[0-9_]+]]: ; CHECK-NEXT: .long 200002 ; CHECK-NEXT: .text -; CHECK-LABEL: f6 +; CHECK-LABEL: f6: ; CHECK: entsp 65535 ; CHECK-NEXT: .Lcfi{{[0-9]+}} ; CHECK-NEXT: .cfi_def_cfa_offset 262140 @@ -207,7 +207,7 @@ entry: } ; FP + large frame: spill FP+SR+LR = entsp 2 + 256 + extsp 1 -; CHECKFP-LABEL:f8 +; CHECKFP-LABEL: f8: ; CHECKFP: entsp 258 ; CHECKFP-NEXT: stw r10, sp[1] ; CHECKFP-NEXT: ldaw r10, sp[0] @@ -221,7 +221,7 @@ entry: ; CHECKFP-NEXT: retsp 258 ; ; !FP + large frame: spill SR+SR+LR = entsp 3 + 256 -; CHECK-LABEL:f8 +; CHECK-LABEL: f8: ; CHECK: entsp 257 ; CHECK-NEXT: ldaw r0, sp[254] ; CHECK-NEXT: bl f5 @@ -235,7 +235,7 @@ entry: } ; FP + large frame: spill FP+SR+LR = entsp 2 + 32768 + extsp 1 -; CHECKFP-LABEL:f9 +; CHECKFP-LABEL: f9: ; CHECKFP: entsp 32770 ; CHECKFP-NEXT: stw r10, sp[1] ; CHECKFP-NEXT: ldaw r10, sp[0] @@ -249,7 +249,7 @@ entry: ; CHECKFP-NEXT: retsp 32770 ; ; !FP + large frame: spill SR+SR+LR = entsp 3 + 32768 -; CHECK-LABEL:f9 +; CHECK-LABEL: f9: ; CHECK: entsp 32771 ; CHECK-NEXT: ldaw r0, sp[32768] ; CHECK-NEXT: bl f5 diff --git a/utils/abtest.py b/utils/abtest.py new file mode 100755 index 00000000000..1219dbae1b2 --- /dev/null +++ b/utils/abtest.py @@ -0,0 +1,232 @@ +#!/usr/bin/env python +# +# Given a previous good compile narrow down miscompiles. +# Expects two directories named "before" and "after" each containing a set of +# assembly or object files where the "after" version is assumed to be broken. +# You also have to provide a script called "link_test". It is called with a list +# of files which should be linked together and result tested. "link_test" should +# returns with exitcode 0 if the linking and testing succeeded. +# +# abtest.py operates by taking all files from the "before" directory and +# in each step replacing one of them with a file from the "bad" directory. +# +# Additionally you can perform the same steps with a single .s file. In this +# mode functions are identified by " -- Begin function FunctionName" and +# " -- End function" markers. The abtest.py then takes all +# function from the file in the "before" directory and replaces one function +# with the corresponding function from the "bad" file in each step. +# +# Example usage to identify miscompiled files: +# 1. Create a link_test script, make it executable. Simple Example: +# clang "$@" -o /tmp/test && /tmp/test || echo "PROBLEM" +# 2. Run the script to figure out which files are miscompiled: +# > ./abtest.py +# somefile.s: ok +# someotherfile.s: skipped: same content +# anotherfile.s: failed: './link_test' exitcode != 0 +# ... +# Example usage to identify miscompiled functions inside a file: +# 3. Run the tests on a single file (assuming before/file.s and +# after/file.s exist) +# > ./abtest.py file.s +# funcname1 [0/XX]: ok +# funcname2 [1/XX]: ok +# funcname3 [2/XX]: skipped: same content +# funcname4 [3/XX]: failed: './link_test' exitcode != 0 +# ... +from fnmatch import filter +from sys import stderr +import argparse +import filecmp +import os +import subprocess +import sys + +LINKTEST="./link_test" +ESCAPE="\033[%sm" +BOLD=ESCAPE % "1" +RED=ESCAPE % "31" +NORMAL=ESCAPE % "0" +FAILED=RED+"failed"+NORMAL + +def find(dir, file_filter=None): + files = [walkdir[0]+"/"+file for walkdir in os.walk(dir) for file in walkdir[2]] + if file_filter != None: + files = filter(files, file_filter) + return files + +def error(message): + stderr.write("Error: %s\n" % (message,)) + +def warn(message): + stderr.write("Warning: %s\n" % (message,)) + +def extract_functions(file): + functions = [] + in_function = None + for line in open(file): + marker = line.find(" -- Begin function ") + if marker != -1: + if in_function != None: + warn("Missing end of function %s" % (in_function,)) + funcname = line[marker + 19:-1] + in_function = funcname + text = line + continue + + marker = line.find(" -- End function") + if marker != -1: + text += line + functions.append( (in_function, text) ) + in_function = None + continue + + if in_function != None: + text += line + return functions + +def replace_function(file, function, replacement, dest): + out = open(dest, "w") + skip = False + found = False + in_function = None + for line in open(file): + marker = line.find(" -- Begin function ") + if marker != -1: + if in_function != None: + warn("Missing end of function %s" % (in_function,)) + funcname = line[marker + 19:-1] + in_function = funcname + if in_function == function: + out.write(replacement) + skip = True + else: + marker = line.find(" -- End function") + if marker != -1: + in_function = None + if skip: + skip = False + continue + + if not skip: + out.write(line) + +def announce_test(name): + stderr.write("%s%s%s: " % (BOLD, name, NORMAL)) + stderr.flush() + +def announce_result(result, info): + stderr.write(result) + if info != "": + stderr.write(": %s" % info) + stderr.write("\n") + stderr.flush() + +def testrun(files): + linkline="%s %s" % (LINKTEST, " ".join(files),) + res = subprocess.call(linkline, shell=True) + if res != 0: + announce_result(FAILED, "'%s' exitcode != 0" % LINKTEST) + return False + else: + announce_result("ok", "") + return True + +def check_files(): + """Check files mode""" + for i in range(0, len(NO_PREFIX)): + f = NO_PREFIX[i] + b=baddir+"/"+f + if b not in BAD_FILES: + warn("There is no corresponding file to '%s' in %s" \ + % (gooddir+"/"+f, baddir)) + continue + + announce_test(f + " [%s/%s]" % (i+1, len(NO_PREFIX))) + + # combine files (everything from good except f) + testfiles=[] + skip=False + for c in NO_PREFIX: + badfile = baddir+"/"+c + goodfile = gooddir+"/"+c + if c == f: + testfiles.append(badfile) + if filecmp.cmp(goodfile, badfile): + announce_result("skipped", "same content") + skip = True + break + else: + testfiles.append(goodfile) + if skip: + continue + testrun(testfiles) + +def check_functions_in_file(base, goodfile, badfile): + functions = extract_functions(goodfile) + if len(functions) == 0: + warn("Couldn't find any function in %s, missing annotations?" % (goodfile,)) + return + badfunctions = dict(extract_functions(badfile)) + if len(functions) == 0: + warn("Couldn't find any function in %s, missing annotations?" % (badfile,)) + return + + COMBINED="/tmp/combined.s" + i = 0 + for (func,func_text) in functions: + announce_test(func + " [%s/%s]" % (i+1, len(functions))) + i+=1 + if func not in badfunctions: + warn("Function '%s' missing from bad file" % func) + continue + if badfunctions[func] == func_text: + announce_result("skipped", "same content") + continue + replace_function(goodfile, func, badfunctions[func], COMBINED) + testfiles=[] + for c in NO_PREFIX: + if c == base: + testfiles.append(COMBINED) + continue + testfiles.append(gooddir + "/" + c) + + testrun(testfiles) + +parser = argparse.ArgumentParser() +parser.add_argument('--a', dest='dir_a', default='before') +parser.add_argument('--b', dest='dir_b', default='after') +parser.add_argument('--insane', help='Skip sanity check', action='store_true') +parser.add_argument('file', metavar='file', nargs='?') +config = parser.parse_args() + +gooddir=config.dir_a +baddir=config.dir_b + +BAD_FILES=find(baddir, "*") +GOOD_FILES=find(gooddir, "*") +NO_PREFIX=sorted([x[len(gooddir)+1:] for x in GOOD_FILES]) + +# "Checking whether build environment is sane ..." +if not config.insane: + announce_test("sanity check") + if not os.access(LINKTEST, os.X_OK): + error("Expect '%s' to be present and executable" % (LINKTEST,)) + exit(1) + + res = testrun(GOOD_FILES) + if not res: + # "build environment is grinning and holding a spatula. Guess not." + linkline="%s %s" % (LINKTEST, " ".join(GOOD_FILES),) + stderr.write("\n%s\n\n" % linkline) + stderr.write("Returned with exitcode != 0\n") + sys.exit(1) + +if config.file is not None: + # File exchange mode + goodfile = gooddir+"/"+config.file + badfile = baddir+"/"+config.file + check_functions_in_file(config.file, goodfile, badfile) +else: + # Function exchange mode + check_files() diff --git a/utils/abtest/mark_aarch64fns.py b/utils/abtest/mark_aarch64fns.py deleted file mode 100755 index 65201479284..00000000000 --- a/utils/abtest/mark_aarch64fns.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python -# -# Mark functions in an arm assembly file. This is done by surrounding the -# function with "# -- Begin Name" and "# -- End Name" -# (This script is designed for aarch64 ios assembly syntax) -import sys -import re - -inp = open(sys.argv[1], "r").readlines() - -# First pass -linenum = 0 -INVALID=-100 -last_align = INVALID -last_code = INVALID -last_globl = INVALID -last_globl_name = None -begin = INVALID -in_text_section = False -begins = dict() -for line in inp: - linenum += 1 - if re.search(r'.section\s+__TEXT,__text,regular,pure_instructions', line): - in_text_section = True - continue - elif ".section" in line: - in_text_section = False - continue - - if not in_text_section: - continue - - if ".align" in line: - last_align = linenum - gl = re.search(r'.globl\s+(\w+)', line) - if gl: - last_globl_name = gl.group(1) - last_globl = linenum - m = re.search(r'^(\w+):', line) - if m and begin == INVALID: - labelname = m.group(1) - if last_globl+2 == linenum and last_globl_name == labelname: - begin = last_globl - funcname = labelname - if line == "\n" and begin != INVALID: - end = linenum - triple = (funcname, begin, end) - begins[begin] = triple - begin = INVALID - -# Second pass: Mark -out = open(sys.argv[1], "w") -in_func = None -linenum = 0 -for line in inp: - linenum += 1 - if in_func is not None and linenum == end: - out.write("# -- End %s\n" % in_func) - in_func = None - - triple = begins.get(linenum) - if triple is not None: - in_func, begin, end = triple - out.write("# -- Begin %s\n" % in_func) - out.write(line) diff --git a/utils/abtest/mark_armfns.py b/utils/abtest/mark_armfns.py deleted file mode 100755 index 0edf42e8a83..00000000000 --- a/utils/abtest/mark_armfns.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python -# -# Mark functions in an arm assembly file. This is done by surrounding the -# function with "# -- Begin Name" and "# -- End Name" -# (This script is designed for arm ios assembly syntax) -import sys -import re - -inp = open(sys.argv[1], "r").readlines() - -# First pass -linenum = 0 -INVALID=-100 -last_align = INVALID -last_code = INVALID -last_globl = INVALID -begin = INVALID -begins = dict() -for line in inp: - linenum += 1 - if ".align" in line: - last_align = linenum - if ".code" in line: - last_code = linenum - if ".globl" in line: - last_globl = linenum - m = re.search(r'.thumb_func\s+(\w+)', line) - if m: - funcname = m.group(1) - if last_code == last_align+1 and (linenum - last_code) < 4: - begin = last_align - if last_globl+1 == last_align: - begin = last_globl - if line == "\n" and begin != INVALID: - end = linenum - triple = (funcname, begin, end) - begins[begin] = triple - begin = INVALID - -# Second pass: Mark -out = open(sys.argv[1], "w") -in_func = None -linenum = 0 -for line in inp: - linenum += 1 - if in_func is not None and linenum == end: - out.write("# -- End %s\n" % in_func) - in_func = None - - triple = begins.get(linenum) - if triple is not None: - in_func, begin, end = triple - out.write("# -- Begin %s\n" % in_func) - out.write(line)