1# Test code for libgccjit.so
2#
3# We will compile each of jit.dg/test-*.c into an executable
4# dynamically linked against libgccjit.so, and then run each
5# such executable.
6#
7# These executables call into the libgccjit.so API to create
8# code, compile it, and run it, verifying that the results
9# are as expected.  See harness.h for shared code used by all
10# such executables.
11#
12# The executables call into DejaGnu's unit testing C API to
13# report PASS/FAIL results, which this script gathers back
14# up into the Tcl world, reporting a summary of all results
15# across all of the executables.
16
17# Kludge alert:
18# We need g++_init so that it can find the stdlib include path.
19#
20# g++_init (in lib/g++.exp) uses g++_maybe_build_wrapper,
21# which normally comes from the definition of
22# ${tool}_maybe_build_wrapper within lib/wrapper.exp.
23#
24# However, for us, ${tool} is "jit".
25# Hence we load wrapper.exp with tool == "g++", so that
26# g++_maybe_build_wrapper is defined.
27set tool g++
28load_lib wrapper.exp
29set tool jit
30
31load_lib dg.exp
32load_lib prune.exp
33load_lib target-supports.exp
34load_lib gcc-defs.exp
35load_lib timeout.exp
36load_lib target-libpath.exp
37load_lib gcc.exp
38load_lib g++.exp
39load_lib dejagnu.exp
40
41# Look for lines of the form:
42#   definitely lost: 11,316 bytes in 235 blocks
43#   indirectly lost: 352 bytes in 4 blocks
44# Ideally these would report zero bytes lost (which is a PASS);
45# for now, report non-zero leaks as XFAILs.
46proc report_leak {kind name logfile line} {
47    set match [regexp "$kind lost: .*" $line result]
48    if $match {
49	verbose "Saw \"$result\" within \"$line\"" 4
50	# Extract bytes and blocks.
51	# These can contain commas as well as numerals,
52	# but we only care about whether we have zero.
53	regexp "$kind lost: (.+) bytes in (.+) blocks" \
54	    $result -> bytes blocks
55	verbose "bytes: '$bytes'" 4
56	verbose "blocks: '$blocks'" 4
57	if { $bytes == 0 } {
58	    pass "$name: $logfile: $result"
59	} else {
60	    xfail "$name: $logfile: $result"
61	}
62    }
63}
64
65proc parse_valgrind_logfile {name logfile} {
66    verbose "parse_valgrind_logfile: $logfile" 2
67    if [catch {set f [open $logfile]}] {
68	fail "$name: unable to read $logfile"
69	return
70    }
71
72    while { [gets $f line] >= 0 } {
73	# Strip off the PID prefix e.g. ==7675==
74	set line [regsub "==\[0-9\]*== " $line ""]
75	verbose $line 2
76
77	report_leak "definitely" $name $logfile $line
78	report_leak "indirectly" $name $logfile $line
79    }
80    close $f
81}
82
83# Given WRES, the result from "wait", issue a PASS
84# if the spawnee exited cleanly, or a FAIL for various kinds of
85# unexpected exits.
86
87proc verify_exit_status { executable wres } {
88    lassign $wres pid spawnid os_error_flag value
89    verbose "pid: $pid" 3
90    verbose "spawnid: $spawnid" 3
91    verbose "os_error_flag: $os_error_flag" 3
92    verbose "value: $value" 3
93
94    # Detect segfaults etc:
95    if { [llength $wres] > 4 } {
96	if { [lindex $wres 4] == "CHILDKILLED" } {
97	    fail "$executable killed: $wres"
98	    return
99	}
100    }
101    if { $os_error_flag != 0 } {
102	fail "$executable: OS error: $wres"
103	return
104    }
105    if { $value != 0 } {
106	fail "$executable: non-zero exit code: $wres"
107	return
108    }
109    pass "$executable exited cleanly"
110}
111
112# This is host_execute from dejagnu.exp commit
113#   126a089777158a7891ff975473939f08c0e31a1c
114# with the following patch applied, and renaming to "fixed_host_execute".
115# See the discussion at
116#  http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00000.html
117#
118#  --- /usr/share/dejagnu/dejagnu.exp.old  2014-10-08 13:38:57.274068541 -0400
119#  +++ /usr/share/dejagnu/dejagnu.exp      2014-10-10 12:27:51.113813659 -0400
120#  @@ -113,8 +113,6 @@ proc host_execute {args} {
121#       set timetol 0
122#       set arguments ""
123#
124#  -    expect_before buffer_full { perror "Buffer full" }
125#  -
126#       if { [llength $args] == 0} {
127#          set executable $args
128#       } else {
129
130
131# Execute the executable file, and anaylyse the output for the
132# test state keywords.
133#    Returns:
134#	A "" (empty) string if everything worked, or an error message
135#	if there was a problem.
136#
137proc fixed_host_execute {args} {
138    global env
139    global text
140    global spawn_id
141
142    verbose "fixed_host_execute: $args"
143
144    set timeoutmsg "Timed out: Never got started, "
145    set timeout 100
146    set file all
147    set timetol 0
148    set arguments ""
149
150    if { [llength $args] == 0} {
151	set executable $args
152    } else {
153	set executable [lindex $args 0]
154	set params [lindex $args 1]
155    }
156
157    verbose "The executable is $executable" 2
158    if {![file exists ${executable}]} {
159	perror "The executable, \"$executable\" is missing" 0
160	return "No source file found"
161    }
162
163    verbose "params: $params" 2
164
165    # spawn the executable and look for the DejaGnu output messages from the
166    # test case.
167    # spawn -noecho -open [open "|./${executable}" "r"]
168
169    # Run under valgrind if RUN_UNDER_VALGRIND is present in the environment.
170    # Note that it's best to configure gcc with --enable-valgrind-annotations
171    # when testing under valgrind.
172    set run_under_valgrind [info exists env(RUN_UNDER_VALGRIND)]
173    if $run_under_valgrind {
174	set valgrind_logfile "${executable}.valgrind.txt"
175	set valgrind_params {"valgrind"}
176	lappend valgrind_params "--leak-check=full"
177	lappend valgrind_params "--log-file=${valgrind_logfile}"
178    } else {
179	set valgrind_params {}
180    }
181    verbose "valgrind_params: $valgrind_params" 2
182
183    set args ${valgrind_params}
184    lappend args "./${executable}"
185    set args [concat $args ${params}]
186    verbose "args: $args" 2
187
188    eval spawn -noecho $args
189
190    expect_after full_buffer {	error "got full_buffer" }
191
192    set prefix "\[^\r\n\]*"
193    expect {
194	-re "^$prefix\[0-9\]\[0-9\]:..:..:${text}*\r\n" {
195	    regsub "\[\n\r\t\]*NOTE: $text\r\n" $expect_out(0,string) "" output
196	    verbose "$output" 3
197	    set timetol 0
198	    exp_continue
199	}
200	-re "^$prefix\tNOTE:${text}*" {
201	    regsub "\[\n\r\t\]*NOTE: $text\r\n" $expect_out(0,string) "" output
202	    set output [string range $output 6 end]
203	    verbose "$output" 2
204	    set timetol 0
205	    exp_continue
206	}
207	-re "^$prefix\tPASSED:${text}*" {
208	    regsub "\[\n\r\t\]*PASSED: $text\r\n" $expect_out(0,string) "" output
209	    set output [string range $output 8 end]
210	    pass "$output"
211	    set timetol 0
212	    exp_continue
213	}
214	-re "^$prefix\tFAILED:${text}*" {
215	    regsub "\[\n\r\t\]*FAILED: $text\r\n" $expect_out(0,string) "" output
216	    set output [string range $output 8 end]
217	    fail "$output"
218	    set timetol 0
219	    exp_continue
220	}
221	-re "^$prefix\tUNTESTED:${text}*" {
222	    regsub "\[\n\r\t\]*TESTED: $text\r\n" $expect_out(0,string) "" output
223	    set output [string range $output 8 end]
224	    untested "$output"
225	    set timetol 0
226	    exp_continue
227	}
228	-re "^$prefix\tUNRESOLVED:${text}*" {
229	    regsub "\[\n\r\t\]*UNRESOLVED: $text\r\n" $expect_out(0,string) "" output
230	    set output [string range $output 8 end]
231	    unresolved "$output"
232	    set timetol 0
233	    exp_continue
234	}
235	-re "^Totals" {
236	    verbose "All done" 2
237	}
238	eof {
239	    #	    unresolved "${executable} died prematurely"
240	    #	    catch close
241	    #	    return "${executable} died prematurely"
242	}
243	timeout {
244	    warning "Timed out executing test case"
245	    if { $timetol <= 2 } {
246		incr timetol
247		exp_continue
248	    } else {
249		catch close
250		return "Timed out executing test case"
251	    }
252	}
253	-re "^$prefix\r\n" {
254	    exp_continue
255	}
256    }
257
258    # Use "wait" before "close": valgrind might not have finished
259    # writing the log out before we parse it, so we need to wait for
260    # the spawnee to finish.
261
262    catch wait wres
263    verbose "wres: $wres" 2
264    verify_exit_status $executable $wres
265
266    if $run_under_valgrind {
267	upvar 2 name name
268	parse_valgrind_logfile $name $valgrind_logfile
269    }
270
271    # force a close of the executable to be safe.
272    catch close
273
274    return ""
275}
276
277# (end of code from dejagnu.exp)
278
279# GCC_UNDER_TEST is needed by gcc_target_compile
280global GCC_UNDER_TEST
281if ![info exists GCC_UNDER_TEST] {
282    set GCC_UNDER_TEST "[find_gcc]"
283}
284
285g++_init
286
287# Initialize dg.
288dg-init
289
290# Gather a list of all tests.
291
292# C tests within the testsuite: gcc/testsuite/jit.dg/test-*.c
293set tests [find $srcdir/$subdir test-*.c]
294
295# C++ tests within the testsuite: gcc/testsuite/jit.dg/test-*.cc
296set tests [concat $tests [find $srcdir/$subdir test-*.cc]]
297
298# We also test the examples within the documentation, to ensure that
299# they compile:
300set tests [concat $tests [find $srcdir/../jit/docs/examples *.c]]
301set tests [concat $tests [find $srcdir/../jit/docs/examples *.cc]]
302
303set tests [lsort $tests]
304
305verbose "tests: $tests"
306
307# Is testcase NAME meant to generate a reproducer?
308proc is_testcase_meant_to_generate_a_reproducer {name} {
309    # We expect most testcases to generate a reproducer.
310    # The exceptions are the tutorials (which don't have a "test-"
311    # prefix), and test-threads.c and test-benchmark.c (which are each
312    # unique).
313    verbose "is_testcase_meant_to_generate_a_reproducer: $name"
314    if { [string match "*test-*" $name] } {
315	if { [string match "*test-threads.c" $name] } {
316	    return 0
317	}
318	if { [string match "*test-benchmark.c" $name] } {
319	    return 0
320	}
321	return 1
322    }
323    return 0
324}
325
326# libgloss has found the driver (as "xgcc" or "gcc) and stored
327# its full path as GCC_UNDER_TEST.
328proc get_path_of_driver {} {
329    global GCC_UNDER_TEST
330
331    verbose "GCC_UNDER_TEST: $GCC_UNDER_TEST"
332    set binary [lindex $GCC_UNDER_TEST 0]
333    verbose "binary: $binary"
334
335    return [file dirname $binary]
336}
337
338# Expand "SRCDIR" within ARG to the location of the top-level
339# src directory
340
341proc jit-expand-vars {arg} {
342    verbose "jit-expand-vars: $arg"
343    global srcdir
344    verbose " srcdir: $srcdir"
345    # "srcdir" is that of the gcc/testsuite directory, so
346    # we need to go up two levels.
347    set arg [string map [list "SRCDIR" $srcdir/../..] $arg]
348    verbose " new arg: $arg"
349    return $arg
350}
351
352# Parameters used when invoking the executables built from the test cases.
353
354global jit-exe-params
355set jit-exe-params {}
356
357# Set "jit-exe-params", expanding "SRCDIR" in each arg to the location of
358# the top-level srcdir.
359
360proc dg-jit-set-exe-params { args } {
361    verbose "dg-jit-set-exe-params: $args"
362
363    global jit-exe-params
364    set jit-exe-params {}
365    # Skip initial arg (line number)
366    foreach arg [lrange $args 1 [llength $args] ] {
367	lappend jit-exe-params [jit-expand-vars $arg]
368    }
369}
370
371proc jit-dg-test { prog do_what extra_tool_flags } {
372    verbose "within jit-dg-test..."
373    verbose "  prog: $prog"
374    verbose "  do_what: $do_what"
375    verbose "  extra_tool_flags: $extra_tool_flags"
376
377    # test-threads.c needs to be linked against pthreads
378    if {[string match "*test-threads.c" $prog]} {
379	append extra_tool_flags " -lpthread"
380    }
381
382    # Any test case that uses jit-verify-output-file-was-created
383    # needs to call jit-setup-compile-to-file here.
384    # (is there a better way to handle setup/finish pairs in dg?)
385    set tmp [grep $prog "jit-verify-output-file-was-created"]
386    if {![string match "" $tmp]} {
387	jit-setup-compile-to-file $prog
388    }
389
390    # Determine what to name the built executable.
391    #
392    # We simply append .exe to the filename, e.g.
393    #  "test-foo.c.exe"
394    # since some testcases exist in both
395    #  "test-foo.c" and
396    #  "test-foo.cc"
397    # variants, and we don't want them to clobber each other's
398    # executables.
399    #
400    # This also ensures that the source name makes it into the
401    # pass/fail output, so that we can distinguish e.g. which test-foo
402    # is failing.
403    set output_file "[file tail $prog].exe"
404    verbose "output_file: $output_file"
405
406    # Create the test executable:
407    set extension [file extension $prog]
408    if {$extension == ".cc"} {
409	set compilation_function "g++_target_compile"
410	set options "{additional_flags=$extra_tool_flags}"
411    } else {
412	set compilation_function "gcc_target_compile"
413	# Until recently, <dejagnu.h> assumed -fgnu89-inline
414	# Ideally we should fixincludes it (PR other/63613), but
415	# for now add -fgnu89-inline when compiling C JIT testcases.
416	# See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63613
417	# and http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00011.html
418	set options "{additional_flags=$extra_tool_flags -fgnu89-inline}"
419    }
420    verbose "compilation_function=$compilation_function"
421    verbose "options=$options"
422
423    set comp_output [$compilation_function $prog $output_file \
424			 "executable" $options]
425    upvar 1 name name
426    if ![jit_check_compile "$name" "initial compilation" \
427	    $output_file $comp_output] then {
428      return
429    }
430
431    # Most of the test cases use gcc_jit_context_dump_reproducer_to_file
432    # as they run to write out a .c file that reproduces their behavior,
433    # exercising that API.
434    set generated_reproducer "${output_file}.reproducer.c"
435
436    # Delete any such generated .c file from a previous run.
437    catch "exec rm -f $generated_reproducer"
438
439    # Run the test executable, capturing the PASS/FAIL textual output
440    # from the C API, converting it into the Tcl API.
441
442    # We need to set LD_LIBRARY_PATH so that the test files can find
443    # libgccjit.so
444    # Do this using set_ld_library_path_env_vars from target-libpath.exp
445    # We will restore the old value later using
446    # restore_ld_library_path_env_vars.
447
448    # Unfortunately this API only supports a single saved value, rather
449    # than a stack, and g++_init has already called into this API,
450    # injecting the appropriate value for LD_LIBRARY_PATH for finding
451    # the built copy of libstdc++.
452    # Hence the call to restore_ld_library_path_env_vars would restore
453    # the *initial* value of LD_LIBRARY_PATH, and attempts to run
454    # a C++ testcase after running any prior testcases would thus look
455    # in the wrong place for libstdc++.  This led to failures at startup
456    # of the form:
457    #   ./tut01-hello-world.cc.exe: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by ./tut01-hello-world.cc.exe)
458    # when the built libstdc++ is more recent that the system libstdc++.
459    #
460    # As a workaround, reset the variable "orig_environment_saved" within
461    # target-libpath.exp, so that the {set|restore}_ld_library_path_env_vars
462    # API saves/restores the current value of LD_LIBRARY_PATH (as set up
463    # by g++_init).
464    global orig_environment_saved
465    set orig_environment_saved 0
466
467    global ld_library_path
468    global base_dir
469    set ld_library_path "$base_dir/../../"
470    set_ld_library_path_env_vars
471
472    # libgccjit uses the driver to convert .s files to .so libraries
473    # via its *installed* name, FULL_DRIVER_NAME
474    #   ${target_noncanonical}-gcc-${gcc_BASEVER}${exeext}
475    # e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0"
476    # looking for it on PATH.  Hence we need to prepend the location of
477    # that executable to PATH when running the tests
478    set dir_containing_driver [get_path_of_driver ]
479    verbose "dir_containing_driver: $dir_containing_driver"
480    global env
481    set old_path $env(PATH)
482    setenv "PATH" $dir_containing_driver:$old_path
483    verbose -log "PATH=[getenv PATH]"
484
485    # We have:
486    #   test-executables
487    #     linked to -> libgccjit.so
488    #                    -> invokes driver:
489    #                         -> invokes the assembler
490    #                         -> invokes the linker
491    # We want to be able to run this from the builddir without installing
492    # but the linker needs to be able to locate various libraries, or we
493    # get:
494    #   ld: cannot find crtbeginS.o: No such file or directory
495    #   ld: cannot find -lgcc
496    #   ld: cannot find -lgcc_s
497    # These can be found in the "gcc" subdir of the build.
498    # Hence to be able to run the testsuite without installing, we need
499    # to set or prepend the "gcc" subdir of the build to LIBRARY_PATH:
500    if { [info exists env(LIBRARY_PATH) ] } {
501	set old_library_path $env(LIBRARY_PATH)
502	setenv "LIBRARY_PATH" $dir_containing_driver:$old_library_path
503    } else {
504	setenv "LIBRARY_PATH" $dir_containing_driver
505    }
506    verbose -log "LIBRARY_PATH=[getenv LIBRARY_PATH]"
507
508    # dejagnu.exp's host_execute has code to scrape out test results
509    # from the DejaGnu C API and bring back into the tcl world, so we
510    # use that to invoke the built code.
511    # However, it appears to be buggy; see:
512    #  http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00000.html
513    # We instead call a patched local copy, "fixed_host_execute", defined
514    # above.
515
516    global jit-exe-params
517    set args ${jit-exe-params}
518    set jit-exe-params {}
519
520    set result [fixed_host_execute $output_file $args ]
521    verbose "result: $result"
522
523    # Restore PATH
524    setenv "PATH" $old_path
525
526    # Restore LIBRARY_PATH
527    if { [info exists old_library_path] } {
528	setenv "LIBRARY_PATH" $old_library_path
529    } else {
530	unsetenv "LIBRARY_PATH"
531    }
532
533    restore_ld_library_path_env_vars
534
535    # Most of the test cases use gcc_jit_context_dump_reproducer_to_file
536    # as they run to write out a .c file that reproduces their behavior,
537    # exercising that API.
538
539    if { [is_testcase_meant_to_generate_a_reproducer $name] } {
540	verbose "$name is meant to generate a reproducer"
541	# Verify that a reproducer was generated
542	if { [file exists $generated_reproducer] == 1} {
543	    pass "found generated reproducer: $generated_reproducer"
544	    set output_file "${generated_reproducer}.exe"
545	    # (this overwrites output_file)
546
547	    # Try to compile the generated reproducer
548	    verbose "compilation_function=$compilation_function"
549
550	    # The .c file written by gcc_jit_context_dump_reproducer_to_file
551	    # assigns the result of each API call to a unique variable, and not
552	    # all are necessarily used, so we need -Wno-unused-variable.
553	    set options \
554		"{additional_flags=$extra_tool_flags -Wno-unused-variable}"
555	    verbose "options=$options"
556
557	    set comp_output2 [$compilation_function $generated_reproducer \
558				  $output_file "executable" $options]
559	    if ![jit_check_compile "generated reproducer from $name" "initial compilation" \
560		     $output_file $comp_output2] then {
561			 return
562		     }
563
564	    # The caller, dg-test, will verify comp_output, which contains
565	    # the output from compiling the testcase and will issue a fail
566	    # if it's non-empty (e.g. containing warnings, the
567	    # "test for excess errors").
568	    #
569	    # Append the output from compiling the reproducer, so that this is also
570	    # verified:
571	    append comp_output $comp_output2
572
573	    # TODO: we should try to run the built executable
574	    # It's not quite a quine, since it embeds ptrs which could change
575	    # from run to run.
576	} else {
577	    fail "did not find a generated reproducer: $generated_reproducer"
578	}
579    } else {
580	verbose "$name is not meant to generate a reproducer"
581    }
582
583    # Normally we would return $comp_output and $output_file to the
584    # caller, which would delete $output_file, the generated executable.
585    # If we need to debug, it's handy to be able to suppress this behavior,
586    # keeping the executable around.
587    set preserve_executables [info exists env(PRESERVE_EXECUTABLES)]
588    if $preserve_executables {
589	set output_file ""
590    }
591
592    return [list $comp_output $output_file]
593}
594
595# Given source file PROG, scrape out the value of
596#   #define OUTPUT_FILENAME
597# failing if it's not found.
598
599proc jit-get-output-filename {prog} {
600    set tmp [grep $prog "#define OUTPUT_FILENAME (.*)"]
601    if {![string match "" $tmp]} {
602	foreach i $tmp {
603	    verbose "i: $i"
604	    if {[regexp "^\#define OUTPUT_FILENAME\[ \t\]\+\"(.*)\"$" $i i group] } {
605		verbose "group: '$group'"
606		return $group
607	    } else {
608		fail "Unable to parse line: $i"
609	    }
610	}
611    }
612    fail "Unable to locate OUTPUT_FILENAME"
613    return ""
614}
615
616# For testcases that use jit-verify-output-file-was-created
617# delete OUTPUT_FILENAME beforehand, to ensure that the
618# testcase is indeed creating it.
619
620proc jit-setup-compile-to-file { prog } {
621    verbose "jit-setup-compile-to-file: $prog"
622    set output_filename [jit-get-output-filename $prog]
623    verbose "  output_filename: $output_filename"
624    if {![string match "" $output_filename]} {
625	verbose "  deleting any $output_filename"
626	catch "exec rm -f $output_filename"
627    }
628}
629
630proc jit-verify-output-file-was-created { args } {
631    verbose "jit-verify-output-file-was-created: $args"
632
633    upvar 2 prog prog
634    verbose "prog: $prog"
635    set output_filename [jit-get-output-filename $prog]
636    verbose "  output_filename: $output_filename"
637
638    # Verify that the expected file was written out
639    if { [file exists $output_filename] == 1} {
640	pass "$output_filename exists"
641    } else {
642	fail "$output_filename does not exist"
643    }
644}
645
646# Verify that the given file exists, and is executable.
647# Attempt to execute it, and verify that its stdout matches
648# the given regex.
649
650proc jit-run-executable { args } {
651    verbose "jit-run-executable: $args"
652
653    set executable-name [lindex $args 0]
654    verbose "executable-name: ${executable-name}"
655
656    set dg-output-text [lindex $args 1]
657    verbose "dg-output-text: ${dg-output-text}"
658
659    if { [file executable ${executable-name}] } {
660	pass "${executable-name} has executable bit set"
661    } else {
662	fail "${executable-name} does not have executable bit set"
663    }
664
665    # Attempt to run the executable; adapted from dg.exp's dg-test
666    set status -1
667    set result [jit_load ./${executable-name}]
668    set status [lindex $result 0]
669    set output [lindex $result 1]
670    verbose "  status: $status"
671    verbose "  output: $output"
672    # send_user "After exec, status: $status\n"
673    if { "$status" == "pass" } {
674	pass "${executable-name} execution test"
675	verbose "Exec succeeded." 3
676	set texttmp ${dg-output-text}
677	if { ![regexp $texttmp ${output}] } {
678	    fail "${executable-name} output pattern test, is ${output}, should match $texttmp"
679	    verbose "Failed test for output pattern $texttmp" 3
680	} else {
681	    pass "${executable-name} output pattern test, $texttmp"
682	    verbose "Passed test for output pattern $texttmp" 3
683	}
684	unset texttmp
685    } elseif { "$status" == "fail" } {
686	# It would be nice to get some info out of errorCode.
687	if {[info exists errorCode]} {
688	    verbose "Exec failed, errorCode: $errorCode" 3
689	} else {
690	    verbose "Exec failed, errorCode not defined!" 3
691	}
692	fail "${executable-name} execution test"
693    } else {
694	$status "${executable-name} execution test"
695    }
696}
697
698# Assuming that a .s file has been written out named
699# OUTPUT_FILENAME, invoke the driver to try to turn it into
700# an executable, and try to run the result.
701# For use by the test-compile-to-assembler.c testcase.
702proc jit-verify-assembler { args } {
703    verbose "jit-verify-assembler: $args"
704
705    set dg-output-text [lindex $args 0]
706    verbose "dg-output-text: ${dg-output-text}"
707
708    upvar 2 name name
709    verbose "name: $name"
710
711    upvar 2 prog prog
712    verbose "prog: $prog"
713    set asm_filename [jit-get-output-filename $prog]
714    verbose "  asm_filename: ${asm_filename}"
715
716    # Name the built executable as OUTPUT_FILENAME with
717    # ".exe" appended.
718    set executable_from_asm ${asm_filename}.exe
719    verbose "  executable_from_asm: ${executable_from_asm}"
720
721    # Invoke the driver to assemble/link the .s file to the .exe
722    set comp_output [gcc_target_compile \
723			 ${asm_filename} \
724			 ${executable_from_asm} \
725			 "executable" \
726			 "{}"]
727    if ![jit_check_compile \
728	     "$name" \
729	     "assemble/link of ${asm_filename}" \
730	     ${executable_from_asm} \
731	     $comp_output] then {
732      return
733    }
734
735    # Verify that the executable was created.
736    if { [file exists $executable_from_asm] == 1} {
737	pass "$executable_from_asm exists"
738    } else {
739	fail "$executable_from_asm does not exist"
740    }
741
742    # Run it and verify that the output matches the regex.
743    jit-run-executable ${executable_from_asm} ${dg-output-text}
744}
745
746# Assuming that a .o file has been written out named
747# OUTPUT_FILENAME, invoke the driver to try to turn it into
748# an executable, and try to run the result.
749# For use by the test-compile-to-object.c testcase.
750proc jit-verify-object { args } {
751    verbose "jit-verify-object: $args"
752
753    set dg-output-text [lindex $args 0]
754    verbose "dg-output-text: ${dg-output-text}"
755
756    upvar 2 name name
757    verbose "name: $name"
758
759    upvar 2 prog prog
760    verbose "prog: $prog"
761    set obj_filename [jit-get-output-filename $prog]
762    verbose "  obj_filename: ${obj_filename}"
763
764    # Name the linked executable as OUTPUT_FILENAME with
765    # ".exe" appended.
766    set executable_from_obj ${obj_filename}.exe
767    verbose "  executable_from_obj: ${executable_from_obj}"
768
769    # Invoke the driver to link the .o file to the .exe
770    set comp_output [gcc_target_compile \
771			 ${obj_filename} \
772			 ${executable_from_obj} \
773			 "executable" \
774			 "{}"]
775    if ![jit_check_compile \
776	     "$name" \
777	     "link of ${obj_filename}" \
778	     ${executable_from_obj} \
779	     $comp_output] then {
780      return
781    }
782
783    # Verify that the executable was created.
784    if { [file exists $executable_from_obj] == 1} {
785	pass "$executable_from_obj exists"
786    } else {
787	fail "$executable_from_obj does not exist"
788    }
789
790    # Run it and verify that the output matches the regex.
791    jit-run-executable ${executable_from_obj} ${dg-output-text}
792}
793
794# Assuming that a .so file has been written out named
795# OUTPUT_FILENAME, build a test executable to use it,
796# and try to run the result.
797# For use by the test-compile-to-dynamic-library.c testcase.
798proc jit-verify-dynamic-library { args } {
799    verbose "jit-verify-object: $args"
800
801    global srcdir
802    global subdir
803
804    set dg-output-text [lindex $args 0]
805    verbose "dg-output-text: ${dg-output-text}"
806
807    upvar 2 name name
808    verbose "name: $name"
809
810    upvar 2 prog prog
811    verbose "prog: $prog"
812    set obj_filename [jit-get-output-filename $prog]
813    verbose "  obj_filename: ${obj_filename}"
814
815    # Build a test executable from
816    # verify-dynamic-library.c
817    set test_src "verify-dynamic-library.c"
818    set test_executable ${test_src}.exe
819    verbose "  test_executable: ${test_executable}"
820
821    # Invoke the driver to build the test executable
822    set comp_output [gcc_target_compile \
823			 $srcdir/$subdir/${test_src} \
824			 ${test_executable} \
825			 "executable" \
826			 "{additional_flags=-ldl}"]
827    if ![jit_check_compile \
828	     "$name" \
829	     "build of ${test_executable}" \
830	     ${test_executable} \
831	     $comp_output] then {
832      return
833    }
834
835    # Verify that the test executable was created.
836    if { [file exists $test_executable] == 1} {
837	pass "$test_executable exists"
838    } else {
839	fail "$test_executable does not exist"
840    }
841
842    # Run it and verify that the output matches the regex.
843    jit-run-executable ${test_executable} ${dg-output-text}
844}
845
846# A way to invoke "jit-run-executable" with the given regex,
847# using OUTPUT_FILENAME within the testcase to determine
848# the name of the executable to run.
849# For use by the test-compile-to-executable.c testcase.
850
851proc jit-verify-executable { args } {
852    verbose "jit-verify-executable: $args"
853
854    set dg-output-text [lindex $args 0]
855    verbose "dg-output-text: ${dg-output-text}"
856
857    upvar 2 name name
858    verbose "name: $name"
859
860    upvar 2 prog prog
861    verbose "prog: $prog"
862    set output_filename [jit-get-output-filename $prog]
863    verbose "  output_filename: $output_filename"
864
865    jit-run-executable $output_filename ${dg-output-text}
866}
867
868# We need to link with --export-dynamic for test-calling-external-function.c
869# so that the JIT-built code can call into functions from the main program.
870set DEFAULT_CFLAGS "-I$srcdir/../jit -lgccjit -g -Wall -Werror -Wl,--export-dynamic"
871
872# Main loop.  This will invoke jig-dg-test on each test-*.c file.
873dg-runtest $tests "" $DEFAULT_CFLAGS
874
875# All done.
876dg-finish
877