# Copyright (C) 2007-2023 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with GCC; see the file COPYING3.  If not see
# <http://www.gnu.org/licenses/>.
# GCC testsuite that uses the `dg.exp' driver.
global torture_current_flags
set torture_current_flags ""
# Exit immediately if this isn't a s390 target.
if ![istarget s390*-*-*] then {
  return
}
# Load support procs.
load_lib gcc-dg.exp
load_lib target-supports.exp
load_lib gfortran-dg.exp
load_lib atomic-dg.exp
# Return 1 if the assembler understands .machine and .machinemode.  The
# target attribute needs that feature to work.
proc check_effective_target_target_attribute { } {
    if { ![check_runtime s390_check_machine_machinemode [subst {
	int main (void)
	{
	    asm (".machine push" : : );
	    asm (".machine pop" : : );
	    asm (".machinemode push" : : );
	    asm (".machinemode pop" : : );
	    return 0;
	}
    }] "" ] } { return 0 } else { return 1 }
}
# Return 1 if htm (etnd - extract nesting depth) instructions are
# understood by the assembler and can be executed.
proc check_effective_target_htm { } {
    if { ![check_runtime s390_check_htm [subst {
	int main (void)
	{
	    unsigned int nd;
	    asm ("etnd %0" : "=d" (nd));
	    return nd;
	}
    }] "-march=zEC12 -mzarch" ] } { return 0 } else { return 1 }
}
global s390_cached_flags
set s390_cached_flags ""
global s390_cached_value
set s390_cached_value ""
global s390_cached_value_noflags
set s390_cached_value_noflags ""
# Return 1 if a program using the full instruction set allowed by
# the compiler option can be executed.
proc check_effective_target_s390_useable_hw { } {
    global torture_current_flags
    global s390_cached_flags
    global s390_cached_value
    global s390_cached_value_noflags
    # Remove -Ox options and whitespace.
    set flags [regsub -all {[-]O[0-9s]} "$torture_current_flags" ""]
    set flags [regsub -all {[ \\t\\n]+} "$flags" " "]
    set flags [regsub -all {(^ )|( $)} "$flags" ""]
    if { "$s390_cached_flags" != "" && "$flags" == "$s390_cached_flags" } {
      return $s390_cached_value
    }
    # Extra cache for (frequent) calls with empty torture_current_flags.
    if { "$flags" == "" && $s390_cached_value_noflags != "" } {
      return $s390_cached_value_noflags
    }
    if { ![check_runtime_nocache s390_check_useable_hw [subst {
	int main (void)
	{
	    asm (".machinemode zarch" : : );
	#if __ARCH__ >= 13
	    asm ("ncrk %%r2,%%r2,%%r2" : : : "r2");
	#elif __ARCH__ >= 12
	    asm ("agh %%r2,0(%%r15)" : : : "r2");
	#elif __ARCH__ >= 11
	    asm ("lochiz %%r2,42" : : : "r2");
	#elif __ARCH__ >= 10
	    asm ("risbgn %%r2,%%r2,0,0,0" : : : "r2");
	#elif __ARCH__ >= 9
	    asm ("sgrk %%r2,%%r2,%%r2" : : : "r2");
	#elif __ARCH__ >= 8
	    asm ("rosbg %%r2,%%r2,0,0,0" : : : "r2");
	#elif __ARCH__ >= 7
	    asm ("nilf %%r2,0" : : : "r2");
	#elif __ARCH__ >= 6
	    asm ("lay %%r2,0(%%r15)" : : : "r2");
	#elif __ARCH__ >= 5
	    asm ("tam" : : );
	#endif
	#ifdef __HTM__
	  {
	    unsigned int nd;
	    asm ("etnd %0" : "=d" (nd));
	  }
	#endif
	#if defined (__VX__) && defined (__zarch__)
	    asm ("vzero %%v0" : : : "v0");
	#endif
	  return 0;
	}
    }] "$flags" ] } { set result 0 } else { set result 1 }
    if { "$flags" == "" } {
      set s390_cached_value_noflags "$result"
    } else {
      set s390_cached_flags "$flags"
      set s390_cached_value "$result"
    }
    return $result
}
# Return 1 if -march=... specific instructions are understood by
# the assembler and can be executed.
proc check_effective_target_s390_z900_hw { } {
    if { ![check_runtime s390_check_s390_z900_hw [subst {
	int main (void)
	{
	    asm ("tam" : : );
	    return 0;
	}
    }] "-march=z900 -m64 -mzarch" ] } { return 0 } else { return 1 }
}
proc check_effective_target_s390_z990_hw { } {
    if { ![check_runtime s390_check_s390_z990_hw [subst {
	int main (void)
	{
	    asm ("lay %%r2,0(%%r15)" : : );
	    return 0;
	}
    }] "-march=z990 -m64 -mzarch" ] } { return 0 } else { return 1 }
}
proc check_effective_target_s390_z9_ec_hw { } {
    if { ![check_runtime s390_check_s390_z9_ec_hw [subst {
	int main (void)
	{
	    asm ("nilf %%r2,0" : : );
	    return 0;
	}
    }] "-march=z9-ec -m64 -mzarch" ] } { return 0 } else { return 1 }
}
proc check_effective_target_s390_z10_hw { } {
    if { ![check_runtime s390_check_s390_z10_hw [subst {
	int main (void)
	{
	    asm ("rosbg %%r2,%%r2,0,0,0" : : );
	    return 0;
	}
    }] "-march=z10 -m64 -mzarch" ] } { return 0 } else { return 1 }
}
proc check_effective_target_s390_z196_hw { } {
    if { ![check_runtime s390_check_s390_z196_hw [subst {
	int main (void)
	{
	    asm ("sgrk %%r2,%%r2,%%r2" : : );
	    return 0;
	}
    }] "-march=z196 -m64 -mzarch" ] } { return 0 } else { return 1 }
}
proc check_effective_target_s390_zEC12_hw { } {
    if { ![check_runtime s390_check_s390_zEC12_hw [subst {
	int main (void)
	{
	    asm ("risbgn %%r2,%%r2,0,0,0" : : );
	    return 0;
	}
    }] "-march=zEC12 -m64 -mzarch" ] } { return 0 } else { return 1 }
}
proc check_effective_target_s390_z13_hw { } {
    if { ![check_runtime s390_check_s390_z13_hw [subst {
	int main (void)
	{
	    asm ("lcbb %%r2,0(%%r15),0" : : );
	    return 0;
	}
    }] "-march=z13 -m64 -mzarch" ] } { return 0 } else { return 1 }
}
proc check_effective_target_s390_z14_hw { } {
    if { ![check_runtime s390_check_s390_z14_hw [subst {
	int main (void)
	{
	    int x = 0;
	    asm ("msgrkc %0,%0,%0" : "+r" (x) : );
	    return x;
	}
    }] "-march=z14 -m64 -mzarch" ] } { return 0 } else { return 1 }
}
# Return 1 if the default compiler options enable z/Architecture mode
proc check_effective_target_s390_zarch { } {
    return [check_no_compiler_messages s390_zarch object {
	int dummy[sizeof (int __attribute__((__mode__(__word__)))) == 8
		  ? 1 : -1];
    }]
}
# If a testcase doesn't have special options, use these.
global DEFAULT_CFLAGS
if ![info exists DEFAULT_CFLAGS] then {
    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
}
global DEFAULT_FFLAGS
if ![info exists DEFAULT_FFLAGS] then {
    set DEFAULT_FFLAGS " -pedantic-errors"
}
# Initialize `dg'.
dg-init
set md_tests $srcdir/$subdir/md/*.c
# C++ tests belong into g++.dg with a target check.  Do NOT add C to
# these regexps!
# Main loop.
dg-runtest [lsort [prune [glob -nocomplain $srcdir/$subdir/*.{c,S}] \
			 $md_tests]] "" $DEFAULT_CFLAGS
dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*vector*/*.{c,S}]] \
	"" $DEFAULT_CFLAGS
dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*vector*/partial/*.{c,S}]] \
	"" $DEFAULT_CFLAGS
gfortran-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*vector*/*.F90]] \
	"" $DEFAULT_FFLAGS
dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/target-attribute/*.{c,S}]] \
	"" $DEFAULT_CFLAGS
dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/arch12/*.{c,S}]] \
	"" "-O3 -march=arch12 -mzarch"
dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/arch13/*.{c,S}]] \
	"" "-O3 -march=arch13 -mzarch"
dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/vxe/*.{c,S}]] \
	"" "-O3 -march=arch12 -mzarch"
# Some md tests require libatomic
atomic_init
dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/md/*.{c,S}]] \
	"" $DEFAULT_CFLAGS
# Additional hotpatch torture tests.
torture-init
set-torture-options [list -Os -O1 -O2 -O3]
gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/hotpatch-\[0-9\]*.c]] \
	"" $DEFAULT_CFLAGS
torture-finish
# Additional md torture tests.
# (Note: Split into a separate torture test for each -march= option to improve
# cacheability.)
torture-init
set MD_TEST_OPTS [list \
	{-Os} {-Os -march=z900} \
	{-O0} {-O0 -march=z900} \
	{-O1} {-O1 -march=z900} \
	{-O2} {-O2 -march=z900} \
	{-O3} {-O3 -march=z900} ]
set-torture-options $MD_TEST_OPTS
gcc-dg-runtest [lsort [glob -nocomplain $md_tests]] "" "$DEFAULT_CFLAGS"
torture-finish
torture-init
set MD_TEST_OPTS [list \
	{-Os -march=z13} \
	{-O0 -march=z13} \
	{-O1 -march=z13} \
	{-O2 -march=z13} \
	{-O3 -march=z13} ]
set-torture-options $MD_TEST_OPTS
gcc-dg-runtest [lsort [glob -nocomplain $md_tests]] "" "$DEFAULT_CFLAGS"
torture-finish
# Tests that should pass on all optimization levels.
foreach t [list $srcdir/$subdir/pr80080-3.c] {
	torture-init
	set-torture-options [list -O1 -O2 -O3 -O0 -Os -Ofast -Og]
	gcc-dg-runtest [list $t] \
		"" $DEFAULT_CFLAGS
	torture-finish
}
# All done.
atomic_finish
dg-finish