gcc/gcc/testsuite/lib/target-supports.exp

9740 lines
276 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Copyright (C) 1999-2019 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/>.
# Please email any bugs, comments, and/or additions to this file to:
# gcc-patches@gcc.gnu.org
# This file defines procs for determining features supported by the target.
# Try to compile the code given by CONTENTS into an output file of
# type TYPE, where TYPE is as for target_compile. Return a list
# whose first element contains the compiler messages and whose
# second element is the name of the output file.
#
# BASENAME is a prefix to use for source and output files.
# If ARGS is not empty, its first element is a string that
# should be added to the command line.
#
# Assume by default that CONTENTS is C code.
# Otherwise, code should contain:
# "// C++" for c++,
# "// D" for D,
# "! Fortran" for Fortran code,
# "/* ObjC", for ObjC
# "// ObjC++" for ObjC++
# and "// Go" for Go
# If the tool is ObjC/ObjC++ then we overide the extension to .m/.mm to
# allow for ObjC/ObjC++ specific flags.
proc check_compile {basename type contents args} {
global tool
verbose "check_compile tool: $tool for $basename"
# Save additional_sources to avoid compiling testsuite's sources
# against check_compile's source.
global additional_sources
if [info exists additional_sources] {
set tmp_additional_sources "$additional_sources"
set additional_sources ""
}
if { [llength $args] > 0 } {
set options [list "additional_flags=[lindex $args 0]"]
} else {
set options ""
}
switch -glob -- $contents {
"*! Fortran*" { set src ${basename}[pid].f90 }
"*// C++*" { set src ${basename}[pid].cc }
"*// D*" { set src ${basename}[pid].d }
"*// ObjC++*" { set src ${basename}[pid].mm }
"*/* ObjC*" { set src ${basename}[pid].m }
"*// Go*" { set src ${basename}[pid].go }
default {
switch -- $tool {
"objc" { set src ${basename}[pid].m }
"obj-c++" { set src ${basename}[pid].mm }
default { set src ${basename}[pid].c }
}
}
}
set compile_type $type
switch -glob $type {
assembly { set output ${basename}[pid].s }
object { set output ${basename}[pid].o }
executable { set output ${basename}[pid].exe }
"rtl-*" {
set output ${basename}[pid].s
lappend options "additional_flags=-fdump-$type"
set compile_type assembly
}
}
set f [open $src "w"]
puts $f $contents
close $f
set lines [${tool}_target_compile $src $output $compile_type "$options"]
file delete $src
set scan_output $output
# Don't try folding this into the switch above; calling "glob" before the
# file is created won't work.
if [regexp "rtl-(.*)" $type dummy rtl_type] {
set scan_output "[glob $src.\[0-9\]\[0-9\]\[0-9\]r.$rtl_type]"
file delete $output
}
# Restore additional_sources.
if [info exists additional_sources] {
set additional_sources "$tmp_additional_sources"
}
return [list $lines $scan_output]
}
proc current_target_name { } {
global target_info
if [info exists target_info(target,name)] {
set answer $target_info(target,name)
} else {
set answer ""
}
return $answer
}
# Implement an effective-target check for property PROP by invoking
# the Tcl command ARGS and seeing if it returns true.
proc check_cached_effective_target { prop args } {
global et_cache
set target [current_target_name]
if {![info exists et_cache($prop,$target)]} {
verbose "check_cached_effective_target $prop: checking $target" 2
if {[string is true -strict $args] || [string is false -strict $args]} {
error {check_cached_effective_target condition already evaluated; did you pass [...] instead of the expected {...}?}
} else {
set code [catch {uplevel eval $args} result]
if {$code != 0 && $code != 2} {
return -code $code $result
}
set et_cache($prop,$target) $result
}
}
set value $et_cache($prop,$target)
verbose "check_cached_effective_target $prop: returning $value for $target" 2
return $value
}
# Implements a version of check_cached_effective_target that also takes et_index
# into account when creating the key for the cache.
proc check_cached_effective_target_indexed { prop args } {
global et_index
set key "$et_index $prop"
verbose "check_cached_effective_target_index $prop: returning $key" 2
return [check_cached_effective_target $key [list uplevel eval $args]]
}
# Clear effective-target cache. This is useful after testing
# effective-target features and overriding TEST_ALWAYS_FLAGS and/or
# ALWAYS_CXXFLAGS.
# If one changes ALWAYS_CXXFLAGS or TEST_ALWAYS_FLAGS then they should
# do a clear_effective_target_cache at the end as the target cache can
# make decisions based upon the flags, and those decisions need to be
# redone when the flags change. An example of this is the
# asan_init/asan_finish pair.
proc clear_effective_target_cache { } {
global et_cache
array unset et_cache
}
# Like check_compile, but delete the output file and return true if the
# compiler printed no messages.
proc check_no_compiler_messages_nocache {args} {
set result [eval check_compile $args]
set lines [lindex $result 0]
set output [lindex $result 1]
remote_file build delete $output
return [string match "" $lines]
}
# Like check_no_compiler_messages_nocache, but cache the result.
# PROP is the property we're checking, and doubles as a prefix for
# temporary filenames.
proc check_no_compiler_messages {prop args} {
return [check_cached_effective_target $prop {
eval [list check_no_compiler_messages_nocache $prop] $args
}]
}
# Like check_compile, but return true if the compiler printed no
# messages and if the contents of the output file satisfy PATTERN.
# If PATTERN has the form "!REGEXP", the contents satisfy it if they
# don't match regular expression REGEXP, otherwise they satisfy it
# if they do match regular expression PATTERN. (PATTERN can start
# with something like "[!]" if the regular expression needs to match
# "!" as the first character.)
#
# Delete the output file before returning. The other arguments are
# as for check_compile.
proc check_no_messages_and_pattern_nocache {basename pattern args} {
global tool
set result [eval [list check_compile $basename] $args]
set lines [lindex $result 0]
set output [lindex $result 1]
set ok 0
if { [string match "" $lines] } {
set chan [open "$output"]
set invert [regexp {^!(.*)} $pattern dummy pattern]
set ok [expr { [regexp $pattern [read $chan]] != $invert }]
close $chan
}
remote_file build delete $output
return $ok
}
# Like check_no_messages_and_pattern_nocache, but cache the result.
# PROP is the property we're checking, and doubles as a prefix for
# temporary filenames.
proc check_no_messages_and_pattern {prop pattern args} {
return [check_cached_effective_target $prop {
eval [list check_no_messages_and_pattern_nocache $prop $pattern] $args
}]
}
# Try to compile and run an executable from code CONTENTS. Return true
# if the compiler reports no messages and if execution "passes" in the
# usual DejaGNU sense. The arguments are as for check_compile, with
# TYPE implicitly being "executable".
proc check_runtime_nocache {basename contents args} {
global tool
set result [eval [list check_compile $basename executable $contents] $args]
set lines [lindex $result 0]
set output [lindex $result 1]
set ok 0
if { [string match "" $lines] } {
# No error messages, everything is OK.
set result [remote_load target "./$output" "" ""]
set status [lindex $result 0]
verbose "check_runtime_nocache $basename: status is <$status>" 2
if { $status == "pass" } {
set ok 1
}
}
remote_file build delete $output
return $ok
}
# Like check_runtime_nocache, but cache the result. PROP is the
# property we're checking, and doubles as a prefix for temporary
# filenames.
proc check_runtime {prop args} {
global tool
return [check_cached_effective_target $prop {
eval [list check_runtime_nocache $prop] $args
}]
}
# Return 1 if GCC was configured with $pattern.
proc check_configured_with { pattern } {
global tool
set gcc_output [${tool}_target_compile "-v" "" "none" ""]
if { [ regexp "Configured with: \[^\n\]*$pattern" $gcc_output ] } {
verbose "Matched: $pattern" 2
return 1
}
verbose "Failed to match: $pattern" 2
return 0
}
###############################
# proc check_weak_available { }
###############################
# weak symbols are only supported in some configs/object formats
# this proc returns 1 if they're supported, 0 if they're not, or -1 if unsure
proc check_weak_available { } {
global target_cpu
# All mips targets should support it
if { [ string first "mips" $target_cpu ] >= 0 } {
return 1
}
# All AIX targets should support it
if { [istarget *-*-aix*] } {
return 1
}
# All solaris2 targets should support it
if { [istarget *-*-solaris2*] } {
return 1
}
# Windows targets Cygwin and MingW32 support it
if { [istarget *-*-cygwin*] || [istarget *-*-mingw*] } {
return 1
}
# HP-UX 10.X doesn't support it
if { [istarget hppa*-*-hpux10*] } {
return 0
}
# nvptx (nearly) supports it
if { [istarget nvptx-*-*] } {
return 1
}
# pdp11 doesn't support it
if { [istarget pdp11*-*-*] } {
return 0
}
# ELF and ECOFF support it. a.out does with gas/gld but may also with
# other linkers, so we should try it
set objformat [gcc_target_object_format]
switch $objformat {
elf { return 1 }
ecoff { return 1 }
a.out { return 1 }
mach-o { return 1 }
som { return 1 }
unknown { return -1 }
default { return 0 }
}
}
# return 1 if weak undefined symbols are supported.
proc check_effective_target_weak_undefined { } {
if { [istarget hppa*-*-hpux*] } {
return 0
}
return [check_runtime weak_undefined {
extern void foo () __attribute__((weak));
int main (void) { if (foo) return 1; return 0; }
} ""]
}
###############################
# proc check_weak_override_available { }
###############################
# Like check_weak_available, but return 0 if weak symbol definitions
# cannot be overridden.
proc check_weak_override_available { } {
if { [istarget *-*-mingw*] } {
return 0
}
return [check_weak_available]
}
# The noinit attribute is only supported by some targets.
# This proc returns 1 if it's supported, 0 if it's not.
proc check_effective_target_noinit { } {
if { [istarget arm*-*-eabi]
|| [istarget msp430-*-*] } {
return 1
}
return 0
}
###############################
# proc check_visibility_available { what_kind }
###############################
# The visibility attribute is only support in some object formats
# This proc returns 1 if it is supported, 0 if not.
# The argument is the kind of visibility, default/protected/hidden/internal.
proc check_visibility_available { what_kind } {
if [string match "" $what_kind] { set what_kind "hidden" }
return [check_no_compiler_messages visibility_available_$what_kind object "
void f() __attribute__((visibility(\"$what_kind\")));
void f() {}
"]
}
###############################
# proc check_alias_available { }
###############################
# Determine if the target toolchain supports the alias attribute.
# Returns 2 if the target supports aliases. Returns 1 if the target
# only supports weak aliased. Returns 0 if the target does not
# support aliases at all. Returns -1 if support for aliases could not
# be determined.
proc check_alias_available { } {
global tool
return [check_cached_effective_target alias_available {
set src alias[pid].c
set obj alias[pid].o
verbose "check_alias_available compiling testfile $src" 2
set f [open $src "w"]
# Compile a small test program. The definition of "g" is
# necessary to keep the Solaris assembler from complaining
# about the program.
puts $f "#ifdef __cplusplus\nextern \"C\"\n#endif\n"
puts $f "void g() {} void f() __attribute__((alias(\"g\")));"
close $f
set lines [${tool}_target_compile $src $obj object ""]
file delete $src
remote_file build delete $obj
if [string match "" $lines] then {
# No error messages, everything is OK.
return 2
} else {
if [regexp "alias definitions not supported" $lines] {
verbose "check_alias_available target does not support aliases" 2
set objformat [gcc_target_object_format]
if { $objformat == "elf" } {
verbose "check_alias_available but target uses ELF format, so it ought to" 2
return -1
} else {
return 0
}
} else {
if [regexp "only weak aliases are supported" $lines] {
verbose "check_alias_available target supports only weak aliases" 2
return 1
} else {
return -1
}
}
}
}]
}
# Returns 1 if the target toolchain supports strong aliases, 0 otherwise.
proc check_effective_target_alias { } {
if { [check_alias_available] < 2 } {
return 0
} else {
return 1
}
}
# Returns 1 if the target toolchain supports ifunc, 0 otherwise.
proc check_ifunc_available { } {
return [check_no_compiler_messages ifunc_available object {
#ifdef __cplusplus
extern "C" {
#endif
extern void f_ ();
typedef void F (void);
F* g (void) { return &f_; }
void f () __attribute__ ((ifunc ("g")));
#ifdef __cplusplus
}
#endif
}]
}
# Returns true if --gc-sections is supported on the target.
proc check_gc_sections_available { } {
global tool
return [check_cached_effective_target gc_sections_available {
# Some targets don't support gc-sections despite whatever's
# advertised by ld's options.
if { [istarget alpha*-*-*]
|| [istarget ia64-*-*] } {
return 0
}
# elf2flt uses -q (--emit-relocs), which is incompatible with
# --gc-sections.
if { [board_info target exists ldflags]
&& [regexp " -elf2flt\[ =\]" " [board_info target ldflags] "] } {
return 0
}
# VxWorks kernel modules are relocatable objects linked with -r,
# while RTP executables are linked with -q (--emit-relocs).
# Both of these options are incompatible with --gc-sections.
if { [istarget *-*-vxworks*] } {
return 0
}
# Check if the ld used by gcc supports --gc-sections.
set gcc_ld [lindex [${tool}_target_compile "-print-prog-name=ld" "" "none" ""] 0]
set ld_output [remote_exec host "$gcc_ld" "--help"]
if { [ string first "--gc-sections" $ld_output ] >= 0 } {
return 1
} else {
return 0
}
}]
}
# Return 1 if according to target_info struct and explicit target list
# target is supposed to support trampolines.
proc check_effective_target_trampolines { } {
if [target_info exists gcc,no_trampolines] {
return 0
}
if { [istarget avr-*-*]
|| [istarget msp430-*-*]
|| [istarget nvptx-*-*]
|| [istarget hppa2.0w-hp-hpux11.23]
|| [istarget hppa64-hp-hpux11.23]
|| [istarget pru-*-*]
|| [istarget bpf-*-*] } {
return 0;
}
return 1
}
# Return 1 if target has limited stack size.
proc check_effective_target_stack_size { } {
if [target_info exists gcc,stack_size] {
return 1
}
return 0
}
# Return the value attribute of an effective target, otherwise return 0.
proc dg-effective-target-value { effective_target } {
if { "$effective_target" == "stack_size" } {
if [check_effective_target_stack_size] {
return [target_info gcc,stack_size]
}
}
return 0
}
# Return 1 if signal.h is supported.
proc check_effective_target_signal { } {
if [target_info exists gcc,signal_suppress] {
return 0
}
return 1
}
# Return 1 if according to target_info struct and explicit target list
# target disables -fdelete-null-pointer-checks. Targets should return 0
# if they simply default to -fno-delete-null-pointer-checks but obey
# -fdelete-null-pointer-checks when passed explicitly (and tests that
# depend on this option should do that).
proc check_effective_target_keeps_null_pointer_checks { } {
if [target_info exists keeps_null_pointer_checks] {
return 1
}
if { [istarget msp430-*-*] || [istarget cr16-*-*] } {
return 1;
}
return 0
}
# Return the autofdo profile wrapper
# Linux by default allows 516KB of perf event buffers
# in /proc/sys/kernel/perf_event_mlock_kb
# Each individual perf tries to grab it
# This causes problems with parallel test suite runs. Instead
# limit us to 8 pages (32K), which should be good enough
# for the small test programs. With the default settings
# this allows parallelism of 16 and higher of parallel gcc-auto-profile
proc profopt-perf-wrapper { } {
global srcdir
return "$srcdir/../config/i386/gcc-auto-profile -o perf.data -m8 "
}
# Return true if profiling is supported on the target.
proc check_profiling_available { test_what } {
verbose "Profiling argument is <$test_what>" 1
# These conditions depend on the argument so examine them before
# looking at the cache variable.
# Tree profiling requires TLS runtime support.
if { $test_what == "-fprofile-generate" } {
if { ![check_effective_target_tls_runtime] } {
return 0
}
}
if { $test_what == "-fauto-profile" } {
if { !([istarget i?86-*-linux*] || [istarget x86_64-*-linux*]) } {
verbose "autofdo only supported on linux"
return 0
}
# not cross compiling?
if { ![isnative] } {
verbose "autofdo not supported for non native builds"
return 0
}
set event [profopt-perf-wrapper]
if {$event == "" } {
verbose "autofdo not supported"
return 0
}
global srcdir
set status [remote_exec host "$srcdir/../config/i386/gcc-auto-profile" "true -v >/dev/null"]
if { [lindex $status 0] != 0 } {
verbose "autofdo not supported because perf does not work"
return 0
}
# no good way to check this in advance -- check later instead.
#set status [remote_exec host "create_gcov" "2>/dev/null"]
#if { [lindex $status 0] != 255 } {
# verbose "autofdo not supported due to missing create_gcov"
# return 0
#}
}
# Support for -p on solaris2 relies on mcrt1.o which comes with the
# vendor compiler. We cannot reliably predict the directory where the
# vendor compiler (and thus mcrt1.o) is installed so we can't
# necessarily find mcrt1.o even if we have it.
if { [istarget *-*-solaris2*] && $test_what == "-p" } {
return 0
}
# We don't yet support profiling for MIPS16.
if { [istarget mips*-*-*]
&& ![check_effective_target_nomips16]
&& ($test_what == "-p" || $test_what == "-pg") } {
return 0
}
# MinGW does not support -p.
if { [istarget *-*-mingw*] && $test_what == "-p" } {
return 0
}
# cygwin does not support -p.
if { [istarget *-*-cygwin*] && $test_what == "-p" } {
return 0
}
# uClibc does not have gcrt1.o.
if { [check_effective_target_uclibc]
&& ($test_what == "-p" || $test_what == "-pg") } {
return 0
}
# Now examine the cache variable.
set profiling_working \
[check_cached_effective_target profiling_available {
# Some targets don't have any implementation of __bb_init_func or are
# missing other needed machinery.
if {[istarget aarch64*-*-elf]
|| [istarget am3*-*-linux*]
|| [istarget amdgcn-*-*]
|| [istarget arm*-*-eabi*]
|| [istarget arm*-*-elf]
|| [istarget arm*-*-symbianelf*]
|| [istarget avr-*-*]
|| [istarget bfin-*-*]
|| [istarget cris-*-*]
|| [istarget crisv32-*-*]
|| [istarget csky-*-elf]
|| [istarget fido-*-elf]
|| [istarget h8300-*-*]
|| [istarget lm32-*-*]
|| [istarget m32c-*-elf]
|| [istarget m68k-*-elf]
|| [istarget m68k-*-uclinux*]
|| [istarget mips*-*-elf*]
|| [istarget mmix-*-*]
|| [istarget mn10300-*-elf*]
|| [istarget moxie-*-elf*]
|| [istarget msp430-*-*]
|| [istarget nds32*-*-elf]
|| [istarget nios2-*-elf]
|| [istarget nvptx-*-*]
|| [istarget powerpc-*-eabi*]
|| [istarget powerpc-*-elf]
|| [istarget pru-*-*]
|| [istarget rx-*-*]
|| [istarget tic6x-*-elf]
|| [istarget visium-*-*]
|| [istarget xstormy16-*]
|| [istarget xtensa*-*-elf]
|| [istarget *-*-rtems*]
|| [istarget *-*-vxworks*] } {
return 0
} else {
return 1
}
}]
# -pg link test result can't be cached since it may change between
# runs.
if { $profiling_working == 1
&& ![check_no_compiler_messages_nocache profiling executable {
int main() { return 0; } } "-pg"] } {
set profiling_working 0
}
return $profiling_working
}
# Check to see if a target is "freestanding". This is as per the definition
# in Section 4 of C99 standard. Effectively, it is a target which supports no
# extra headers or libraries other than what is considered essential.
proc check_effective_target_freestanding { } {
if { [istarget nvptx-*-*] } {
return 1
}
return 0
}
# Return 1 if target has packed layout of structure members by
# default, 0 otherwise. Note that this is slightly different than
# whether the target has "natural alignment": both attributes may be
# false.
proc check_effective_target_default_packed { } {
return [check_no_compiler_messages default_packed assembly {
struct x { char a; long b; } c;
int s[sizeof (c) == sizeof (char) + sizeof (long) ? 1 : -1];
}]
}
# Return 1 if target has PCC_BITFIELD_TYPE_MATTERS defined. See
# documentation, where the test also comes from.
proc check_effective_target_pcc_bitfield_type_matters { } {
# PCC_BITFIELD_TYPE_MATTERS isn't just about unnamed or empty
# bitfields, but let's stick to the example code from the docs.
return [check_no_compiler_messages pcc_bitfield_type_matters assembly {
struct foo1 { char x; char :0; char y; };
struct foo2 { char x; int :0; char y; };
int s[sizeof (struct foo1) != sizeof (struct foo2) ? 1 : -1];
}]
}
# Add to FLAGS all the target-specific flags needed to use thread-local storage.
proc add_options_for_tls { flags } {
# On Solaris 9, __tls_get_addr/___tls_get_addr only lives in
# libthread, so always pass -pthread for native TLS. Same for AIX.
# Need to duplicate native TLS check from
# check_effective_target_tls_native to avoid recursion.
if { ([istarget powerpc-ibm-aix*]) &&
[check_no_messages_and_pattern tls_native "!emutls" assembly {
__thread int i;
int f (void) { return i; }
void g (int j) { i = j; }
}] } {
return "-pthread [g++_link_flags [get_multilibs "-pthread"] ] $flags "
}
return $flags
}
# Return 1 if indirect jumps are supported, 0 otherwise.
proc check_effective_target_indirect_jumps {} {
if { [istarget nvptx-*-*] || [istarget bpf-*-*] } {
return 0
}
return 1
}
# Return 1 if nonlocal goto is supported, 0 otherwise.
proc check_effective_target_nonlocal_goto {} {
if { [istarget nvptx-*-*] || [istarget bpf-*-*] } {
return 0
}
return 1
}
# Return 1 if global constructors are supported, 0 otherwise.
proc check_effective_target_global_constructor {} {
if { [istarget nvptx-*-*]
|| [istarget amdgcn-*-*]
|| [istarget bpf-*-*] } {
return 0
}
return 1
}
# Return 1 if taking label values is supported, 0 otherwise.
proc check_effective_target_label_values {} {
if { [istarget nvptx-*-*] || [target_info exists gcc,no_label_values] } {
return 0
}
return 1
}
# Return 1 if builtin_return_address and builtin_frame_address are
# supported, 0 otherwise.
proc check_effective_target_return_address {} {
if { [istarget nvptx-*-*] } {
return 0
}
# No notion of return address in eBPF.
if { [istarget bpf-*-*] } {
return 0
}
# It could be supported on amdgcn, but isn't yet.
if { [istarget amdgcn*-*-*] } {
return 0
}
return 1
}
# Return 1 if the assembler does not verify function types against
# calls, 0 otherwise. Such verification will typically show up problems
# with K&R C function declarations.
proc check_effective_target_untyped_assembly {} {
if { [istarget nvptx-*-*] } {
return 0
}
return 1
}
# Return 1 if alloca is supported, 0 otherwise.
proc check_effective_target_alloca {} {
if { [istarget nvptx-*-*] } {
return [check_no_compiler_messages alloca assembly {
void f (void*);
void g (int n) { f (__builtin_alloca (n)); }
}]
}
return 1
}
# Return 1 if thread local storage (TLS) is supported, 0 otherwise.
proc check_effective_target_tls {} {
return [check_no_compiler_messages tls assembly {
__thread int i;
int f (void) { return i; }
void g (int j) { i = j; }
}]
}
# Return 1 if *native* thread local storage (TLS) is supported, 0 otherwise.
proc check_effective_target_tls_native {} {
# VxWorks uses emulated TLS machinery, but with non-standard helper
# functions, so we fail to automatically detect it.
if { [istarget *-*-vxworks*] } {
return 0
}
return [check_no_messages_and_pattern tls_native "!emutls" assembly {
__thread int i;
int f (void) { return i; }
void g (int j) { i = j; }
}]
}
# Return 1 if *emulated* thread local storage (TLS) is supported, 0 otherwise.
proc check_effective_target_tls_emulated {} {
# VxWorks uses emulated TLS machinery, but with non-standard helper
# functions, so we fail to automatically detect it.
if { [istarget *-*-vxworks*] } {
return 1
}
return [check_no_messages_and_pattern tls_emulated "emutls" assembly {
__thread int i;
int f (void) { return i; }
void g (int j) { i = j; }
}]
}
# Return 1 if TLS executables can run correctly, 0 otherwise.
proc check_effective_target_tls_runtime {} {
return [check_runtime tls_runtime {
__thread int thr __attribute__((tls_model("global-dynamic"))) = 0;
int main (void) { return thr; }
} [add_options_for_tls ""]]
}
# Return 1 if atomic compare-and-swap is supported on 'int'
proc check_effective_target_cas_char {} {
return [check_no_compiler_messages cas_char assembly {
#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
#error unsupported
#endif
} ""]
}
proc check_effective_target_cas_int {} {
return [check_no_compiler_messages cas_int assembly {
#if __INT_MAX__ == 0x7fff && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
/* ok */
#elif __INT_MAX__ == 0x7fffffff && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
/* ok */
#else
#error unsupported
#endif
} ""]
}
# Return 1 if -ffunction-sections is supported, 0 otherwise.
proc check_effective_target_function_sections {} {
# Darwin has its own scheme and silently accepts -ffunction-sections.
if { [istarget *-*-darwin*] } {
return 0
}
return [check_no_compiler_messages functionsections assembly {
void foo (void) { }
} "-ffunction-sections"]
}
# Return 1 if instruction scheduling is available, 0 otherwise.
proc check_effective_target_scheduling {} {
return [check_no_compiler_messages scheduling object {
void foo (void) { }
} "-fschedule-insns"]
}
# Return 1 if trapping arithmetic is available, 0 otherwise.
proc check_effective_target_trapping {} {
return [check_no_compiler_messages trapping object {
int add (int a, int b) { return a + b; }
} "-ftrapv"]
}
# Return 1 if compilation with -fgraphite is error-free for trivial
# code, 0 otherwise.
proc check_effective_target_fgraphite {} {
return [check_no_compiler_messages fgraphite object {
void foo (void) { }
} "-O1 -fgraphite"]
}
# Return 1 if compilation with -fopenacc is error-free for trivial
# code, 0 otherwise.
proc check_effective_target_fopenacc {} {
# nvptx/amdgcn can be built with the device-side bits of openacc, but it
# does not make sense to test it as an openacc host.
if [istarget nvptx-*-*] { return 0 }
if [istarget amdgcn-*-*] { return 0 }
return [check_no_compiler_messages fopenacc object {
void foo (void) { }
} "-fopenacc"]
}
# Return 1 if compilation with -fopenmp is error-free for trivial
# code, 0 otherwise.
proc check_effective_target_fopenmp {} {
# nvptx/amdgcn can be built with the device-side bits of libgomp, but it
# does not make sense to test it as an openmp host.
if [istarget nvptx-*-*] { return 0 }
if [istarget amdgcn-*-*] { return 0 }
return [check_no_compiler_messages fopenmp object {
void foo (void) { }
} "-fopenmp"]
}
# Return 1 if compilation with -fgnu-tm is error-free for trivial
# code, 0 otherwise.
proc check_effective_target_fgnu_tm {} {
return [check_no_compiler_messages fgnu_tm object {
void foo (void) { }
} "-fgnu-tm"]
}
# Return 1 if the target supports mmap, 0 otherwise.
proc check_effective_target_mmap {} {
return [check_function_available "mmap"]
}
# Return 1 if the target supports dlopen, 0 otherwise.
proc check_effective_target_dlopen {} {
return [check_no_compiler_messages dlopen executable {
#include <dlfcn.h>
int main(void) { dlopen ("dummy.so", RTLD_NOW); }
} [add_options_for_dlopen ""]]
}
proc add_options_for_dlopen { flags } {
return "$flags -ldl"
}
# Return 1 if the target supports clone, 0 otherwise.
proc check_effective_target_clone {} {
return [check_function_available "clone"]
}
# Return 1 if the target supports setrlimit, 0 otherwise.
proc check_effective_target_setrlimit {} {
# Darwin has non-posix compliant RLIMIT_AS
if { [istarget *-*-darwin*] } {
return 0
}
return [check_function_available "setrlimit"]
}
# Return 1 if the target supports gettimeofday, 0 otherwise.
proc check_effective_target_gettimeofday {} {
return [check_function_available "gettimeofday"]
}
# Return 1 if the target supports swapcontext, 0 otherwise.
proc check_effective_target_swapcontext {} {
return [check_no_compiler_messages swapcontext executable {
#include <ucontext.h>
int main (void)
{
ucontext_t orig_context,child_context;
if (swapcontext(&child_context, &orig_context) < 0) { }
}
}]
}
# Return 1 if the target supports POSIX threads, 0 otherwise.
proc check_effective_target_pthread {} {
return [check_no_compiler_messages pthread object {
#include <pthread.h>
void foo (void) { }
} "-pthread"]
}
# Return 1 if compilation with -gstabs is error-free for trivial
# code, 0 otherwise.
proc check_effective_target_stabs {} {
return [check_no_compiler_messages stabs object {
void foo (void) { }
} "-gstabs"]
}
# Return 1 if compilation with -mpe-aligned-commons is error-free
# for trivial code, 0 otherwise.
proc check_effective_target_pe_aligned_commons {} {
if { [istarget *-*-cygwin*] || [istarget *-*-mingw*] } {
return [check_no_compiler_messages pe_aligned_commons object {
int foo;
} "-mpe-aligned-commons"]
}
return 0
}
# Return 1 if the target supports -static
proc check_effective_target_static {} {
if { [istarget arm*-*-uclinuxfdpiceabi] } {
return 0;
}
return [check_no_compiler_messages static executable {
int main (void) { return 0; }
} "-static"]
}
# Return 1 if the target supports -fstack-protector
proc check_effective_target_fstack_protector {} {
return [check_runtime fstack_protector {
#include <string.h>
int main (int argc, char *argv[]) {
char buf[64];
return !strcpy (buf, strrchr (argv[0], '/'));
}
} "-fstack-protector"]
}
# Return 1 if the target supports -fstack-check or -fstack-check=$stack_kind
proc check_stack_check_available { stack_kind } {
if [string match "" $stack_kind] then {
set stack_opt "-fstack-check"
} else { set stack_opt "-fstack-check=$stack_kind" }
return [check_no_compiler_messages stack_check_$stack_kind executable {
int main (void) { return 0; }
} "$stack_opt"]
}
# Return 1 if compilation with -freorder-blocks-and-partition is error-free
# for trivial code, 0 otherwise. As some targets (ARM for example) only
# warn when -fprofile-use is also supplied we test that combination too.
proc check_effective_target_freorder {} {
if { [check_no_compiler_messages freorder object {
void foo (void) { }
} "-freorder-blocks-and-partition"]
&& [check_no_compiler_messages fprofile_use_freorder object {
void foo (void) { }
} "-fprofile-use -freorder-blocks-and-partition -Wno-missing-profile"] } {
return 1
}
return 0
}
# Return 1 if -fpic and -fPIC are supported, as in no warnings or errors
# emitted, 0 otherwise. Whether a shared library can actually be built is
# out of scope for this test.
proc check_effective_target_fpic { } {
# Note that M68K has a multilib that supports -fpic but not
# -fPIC, so we need to check both. We test with a program that
# requires GOT references.
foreach arg {fpic fPIC} {
if [check_no_compiler_messages $arg object {
extern int foo (void); extern int bar;
int baz (void) { return foo () + bar; }
} "-$arg"] {
return 1
}
}
return 0
}
# On AArch64, if -fpic is not supported, then we will fall back to -fPIC
# silently. So, we can't rely on above "check_effective_target_fpic" as it
# assumes compiler will give warning if -fpic not supported. Here we check
# whether binutils supports those new -fpic relocation modifiers, and assume
# -fpic is supported if there is binutils support. GCC configuration will
# enable -fpic for AArch64 in this case.
#
# "check_effective_target_aarch64_small_fpic" is dedicated for checking small
# memory model -fpic relocation types.
proc check_effective_target_aarch64_small_fpic { } {
if { [istarget aarch64*-*-*] } {
return [check_no_compiler_messages aarch64_small_fpic object {
void foo (void) { asm ("ldr x0, [x2, #:gotpage_lo15:globalsym]"); }
}]
} else {
return 0
}
}
# On AArch64, instruction sequence for TLS LE under -mtls-size=32 will utilize
# the relocation modifier "tprel_g0_nc" together with MOVK, it's only supported
# in binutils since 2015-03-04 as PR gas/17843.
#
# This test directive make sure binutils support all features needed by TLS LE
# under -mtls-size=32 on AArch64.
proc check_effective_target_aarch64_tlsle32 { } {
if { [istarget aarch64*-*-*] } {
return [check_no_compiler_messages aarch64_tlsle32 object {
void foo (void) { asm ("movk x1,#:tprel_g0_nc:t1"); }
}]
} else {
return 0
}
}
# Return 1 if -shared is supported, as in no warnings or errors
# emitted, 0 otherwise.
proc check_effective_target_shared { } {
# Note that M68K has a multilib that supports -fpic but not
# -fPIC, so we need to check both. We test with a program that
# requires GOT references.
return [check_no_compiler_messages shared executable {
extern int foo (void); extern int bar;
int baz (void) { return foo () + bar; }
} "-shared -fpic"]
}
# Return 1 if -pie, -fpie and -fPIE are supported, 0 otherwise.
proc check_effective_target_pie { } {
if { [istarget *-*-darwin\[912\]*]
|| [istarget *-*-dragonfly*]
|| [istarget *-*-freebsd*]
|| [istarget *-*-linux*]
|| [istarget arm*-*-uclinuxfdpiceabi]
|| [istarget *-*-gnu*]
|| [istarget *-*-amdhsa]} {
return 1;
}
if { [istarget *-*-solaris2.1\[1-9\]*] } {
# Full PIE support was added in Solaris 11.3, but gcc errors out
# if missing, so check for that.
return [check_no_compiler_messages pie executable {
int main (void) { return 0; }
} "-pie -fpie"]
}
return 0
}
# Return true if the target supports -mpaired-single (as used on MIPS).
proc check_effective_target_mpaired_single { } {
return [check_no_compiler_messages mpaired_single object {
void foo (void) { }
} "-mpaired-single"]
}
# Return true if the target has access to FPU instructions.
proc check_effective_target_hard_float { } {
if { [istarget mips*-*-*] } {
return [check_no_compiler_messages hard_float assembly {
#if (defined __mips_soft_float || defined __mips16)
#error __mips_soft_float || __mips16
#endif
}]
}
# This proc is actually checking the availabilty of FPU
# support for doubles, so on the RX we must fail if the
# 64-bit double multilib has been selected.
if { [istarget rx-*-*] } {
return 0
# return [check_no_compiler_messages hard_float assembly {
#if defined __RX_64_BIT_DOUBLES__
#error __RX_64_BIT_DOUBLES__
#endif
# }]
}
# The generic test doesn't work for C-SKY because some cores have
# hard float for single precision only.
if { [istarget csky*-*-*] } {
return [check_no_compiler_messages hard_float assembly {
#if defined __csky_soft_float__
#error __csky_soft_float__
#endif
}]
}
# The generic test equates hard_float with "no call for adding doubles".
return [check_no_messages_and_pattern hard_float "!\\(call" rtl-expand {
double a (double b, double c) { return b + c; }
}]
}
# Return true if the target is a 64-bit MIPS target.
proc check_effective_target_mips64 { } {
return [check_no_compiler_messages mips64 assembly {
#ifndef __mips64
#error !__mips64
#endif
}]
}
# Return true if the target is a MIPS target that does not produce
# MIPS16 code.
proc check_effective_target_nomips16 { } {
return [check_no_compiler_messages nomips16 object {
#ifndef __mips
#error !__mips
#else
/* A cheap way of testing for -mflip-mips16. */
void foo (void) { asm ("addiu $20,$20,1"); }
void bar (void) { asm ("addiu $20,$20,1"); }
#endif
}]
}
# Add the options needed for MIPS16 function attributes. At the moment,
# we don't support MIPS16 PIC.
proc add_options_for_mips16_attribute { flags } {
return "$flags -mno-abicalls -fno-pic -DMIPS16=__attribute__((mips16))"
}
# Return true if we can force a mode that allows MIPS16 code generation.
# We don't support MIPS16 PIC, and only support MIPS16 -mhard-float
# for o32 and o64.
proc check_effective_target_mips16_attribute { } {
return [check_no_compiler_messages mips16_attribute assembly {
#ifdef PIC
#error PIC
#endif
#if defined __mips_hard_float \
&& (!defined _ABIO32 || _MIPS_SIM != _ABIO32) \
&& (!defined _ABIO64 || _MIPS_SIM != _ABIO64)
#error __mips_hard_float && (!_ABIO32 || !_ABIO64)
#endif
} [add_options_for_mips16_attribute ""]]
}
# Return 1 if the target supports long double larger than double when
# using the new ABI, 0 otherwise.
proc check_effective_target_mips_newabi_large_long_double { } {
return [check_no_compiler_messages mips_newabi_large_long_double object {
int dummy[sizeof(long double) > sizeof(double) ? 1 : -1];
} "-mabi=64"]
}
# Return true if the target is a MIPS target that has access
# to the LL and SC instructions.
proc check_effective_target_mips_llsc { } {
if { ![istarget mips*-*-*] } {
return 0
}
# Assume that these instructions are always implemented for
# non-elf* targets, via emulation if necessary.
if { ![istarget *-*-elf*] } {
return 1
}
# Otherwise assume LL/SC support for everything but MIPS I.
return [check_no_compiler_messages mips_llsc assembly {
#if __mips == 1
#error __mips == 1
#endif
}]
}
# Return true if the target is a MIPS target that uses in-place relocations.
proc check_effective_target_mips_rel { } {
if { ![istarget mips*-*-*] } {
return 0
}
return [check_no_compiler_messages mips_rel object {
#if (defined _ABIN32 && _MIPS_SIM == _ABIN32) \
|| (defined _ABI64 && _MIPS_SIM == _ABI64)
#error _ABIN32 && (_ABIN32 || _ABI64)
#endif
}]
}
# Return true if the target is a MIPS target that uses the EABI.
proc check_effective_target_mips_eabi { } {
if { ![istarget mips*-*-*] } {
return 0
}
return [check_no_compiler_messages mips_eabi object {
#ifndef __mips_eabi
#error !__mips_eabi
#endif
}]
}
# Return 1 if the current multilib does not generate PIC by default.
proc check_effective_target_nonpic { } {
return [check_no_compiler_messages nonpic assembly {
#if __PIC__
#error __PIC__
#endif
}]
}
# Return 1 if the current multilib generates PIE by default.
proc check_effective_target_pie_enabled { } {
return [check_no_compiler_messages pie_enabled assembly {
#ifndef __PIE__
#error unsupported
#endif
}]
}
# Return 1 if the target generates -fstack-protector by default.
proc check_effective_target_fstack_protector_enabled {} {
return [ check_no_compiler_messages fstack_protector_enabled assembly {
#if !defined(__SSP__) && !defined(__SSP_ALL__) && \
!defined(__SSP_STRONG__) && !defined(__SSP_EXPICIT__)
#error unsupported
#endif
}]
}
# Return 1 if the target does not use a status wrapper.
proc check_effective_target_unwrapped { } {
if { [target_info needs_status_wrapper] != "" \
&& [target_info needs_status_wrapper] != "0" } {
return 0
}
return 1
}
# Return true if iconv is supported on the target. In particular IBM1047.
proc check_iconv_available { test_what } {
global libiconv
# If the tool configuration file has not set libiconv, try "-liconv"
if { ![info exists libiconv] } {
set libiconv "-liconv"
}
set test_what [lindex $test_what 1]
return [check_runtime_nocache $test_what [subst {
#include <iconv.h>
int main (void)
{
iconv_t cd;
cd = iconv_open ("$test_what", "UTF-8");
if (cd == (iconv_t) -1)
return 1;
return 0;
}
}] $libiconv]
}
# Return true if the atomic library is supported on the target.
proc check_effective_target_libatomic_available { } {
return [check_no_compiler_messages libatomic_available executable {
int main (void) { return 0; }
} "-latomic"]
}
# Return 1 if an ASCII locale is supported on this host, 0 otherwise.
proc check_ascii_locale_available { } {
return 1
}
# Return true if named sections are supported on this target.
proc check_named_sections_available { } {
return [check_no_compiler_messages named_sections assembly {
int __attribute__ ((section("whatever"))) foo;
}]
}
# Return true if the "naked" function attribute is supported on this target.
proc check_effective_target_naked_functions { } {
return [check_no_compiler_messages naked_functions assembly {
void f() __attribute__((naked));
}]
}
# Return 1 if the target supports Fortran real kinds larger than real(8),
# 0 otherwise.
#
# When the target name changes, replace the cached result.
proc check_effective_target_fortran_large_real { } {
return [check_no_compiler_messages fortran_large_real executable {
! Fortran
integer,parameter :: k = selected_real_kind (precision (0.0_8) + 1)
real(kind=k) :: x
x = cos (x)
end
}]
}
# Return 1 if the target supports Fortran real kind real(16),
# 0 otherwise. Contrary to check_effective_target_fortran_large_real
# this checks for Real(16) only; the other returned real(10) if
# both real(10) and real(16) are available.
#
# When the target name changes, replace the cached result.
proc check_effective_target_fortran_real_16 { } {
return [check_no_compiler_messages fortran_real_16 executable {
! Fortran
real(kind=16) :: x
x = cos (x)
end
}]
}
# Return 1 if the target supports Fortran real kind 10,
# 0 otherwise. Contrary to check_effective_target_fortran_large_real
# this checks for real(10) only.
#
# When the target name changes, replace the cached result.
proc check_effective_target_fortran_real_10 { } {
return [check_no_compiler_messages fortran_real_10 executable {
! Fortran
real(kind=10) :: x
x = cos (x)
end
}]
}
# Return 1 if the target supports Fortran's IEEE modules,
# 0 otherwise.
#
# When the target name changes, replace the cached result.
proc check_effective_target_fortran_ieee { flags } {
return [check_no_compiler_messages fortran_ieee executable {
! Fortran
use, intrinsic :: ieee_features
end
} $flags ]
}
# Return 1 if the target supports SQRT for the largest floating-point
# type. (Some targets lack the libm support for this FP type.)
# On most targets, this check effectively checks either whether sqrtl is
# available or on __float128 systems whether libquadmath is installed,
# which provides sqrtq.
#
# When the target name changes, replace the cached result.
proc check_effective_target_fortran_largest_fp_has_sqrt { } {
return [check_no_compiler_messages fortran_largest_fp_has_sqrt executable {
! Fortran
use iso_fortran_env, only: real_kinds
integer,parameter:: maxFP = real_kinds(ubound(real_kinds,dim=1))
real(kind=maxFP), volatile :: x
x = 2.0_maxFP
x = sqrt (x)
end
}]
}
# Return 1 if the target supports Fortran integer kinds larger than
# integer(8), 0 otherwise.
#
# When the target name changes, replace the cached result.
proc check_effective_target_fortran_large_int { } {
return [check_no_compiler_messages fortran_large_int executable {
! Fortran
integer,parameter :: k = selected_int_kind (range (0_8) + 1)
integer(kind=k) :: i
end
}]
}
# Return 1 if the target supports Fortran integer(16), 0 otherwise.
#
# When the target name changes, replace the cached result.
proc check_effective_target_fortran_integer_16 { } {
return [check_no_compiler_messages fortran_integer_16 executable {
! Fortran
integer(16) :: i
end
}]
}
# Return 1 if we can statically link libgfortran, 0 otherwise.
#
# When the target name changes, replace the cached result.
proc check_effective_target_static_libgfortran { } {
return [check_no_compiler_messages static_libgfortran executable {
! Fortran
print *, 'test'
end
} "-static"]
}
# Return 1 if we can use the -rdynamic option, 0 otherwise.
proc check_effective_target_rdynamic { } {
return [check_no_compiler_messages rdynamic executable {
int main() { return 0; }
} "-rdynamic"]
}
proc check_linker_plugin_available { } {
return [check_no_compiler_messages_nocache linker_plugin executable {
int main() { return 0; }
} "-flto -fuse-linker-plugin"]
}
# Return 1 if the target OS supports running SSE executables, 0
# otherwise. Cache the result.
proc check_sse_os_support_available { } {
return [check_cached_effective_target sse_os_support_available {
# If this is not the right target then we can skip the test.
if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
expr 0
} else {
expr 1
}
}]
}
# Return 1 if the target OS supports running AVX executables, 0
# otherwise. Cache the result.
proc check_avx_os_support_available { } {
return [check_cached_effective_target avx_os_support_available {
# If this is not the right target then we can skip the test.
if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
expr 0
} else {
# Check that OS has AVX and SSE saving enabled.
check_runtime_nocache avx_os_support_available {
int main ()
{
unsigned int eax, edx;
asm ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (0));
return (eax & 0x06) != 0x06;
}
} ""
}
}]
}
# Return 1 if the target OS supports running AVX executables, 0
# otherwise. Cache the result.
proc check_avx512_os_support_available { } {
return [check_cached_effective_target avx512_os_support_available {
# If this is not the right target then we can skip the test.
if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
expr 0
} else {
# Check that OS has AVX512, AVX and SSE saving enabled.
check_runtime_nocache avx512_os_support_available {
int main ()
{
unsigned int eax, edx;
asm ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (0));
return (eax & 0xe6) != 0xe6;
}
} ""
}
}]
}
# Return 1 if the target supports executing SSE instructions, 0
# otherwise. Cache the result.
proc check_sse_hw_available { } {
return [check_cached_effective_target sse_hw_available {
# If this is not the right target then we can skip the test.
if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
expr 0
} else {
check_runtime_nocache sse_hw_available {
#include "cpuid.h"
int main ()
{
unsigned int eax, ebx, ecx, edx;
if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
return 1;
return !(edx & bit_SSE);
}
} ""
}
}]
}
# Return 1 if the target supports executing SSE2 instructions, 0
# otherwise. Cache the result.
proc check_sse2_hw_available { } {
return [check_cached_effective_target sse2_hw_available {
# If this is not the right target then we can skip the test.
if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
expr 0
} else {
check_runtime_nocache sse2_hw_available {
#include "cpuid.h"
int main ()
{
unsigned int eax, ebx, ecx, edx;
if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
return 1;
return !(edx & bit_SSE2);
}
} ""
}
}]
}
# Return 1 if the target supports executing SSE4 instructions, 0
# otherwise. Cache the result.
proc check_sse4_hw_available { } {
return [check_cached_effective_target sse4_hw_available {
# If this is not the right target then we can skip the test.
if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
expr 0
} else {
check_runtime_nocache sse4_hw_available {
#include "cpuid.h"
int main ()
{
unsigned int eax, ebx, ecx, edx;
if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
return 1;
return !(ecx & bit_SSE4_2);
}
} ""
}
}]
}
# Return 1 if the target supports executing AVX instructions, 0
# otherwise. Cache the result.
proc check_avx_hw_available { } {
return [check_cached_effective_target avx_hw_available {
# If this is not the right target then we can skip the test.
if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
expr 0
} else {
check_runtime_nocache avx_hw_available {
#include "cpuid.h"
int main ()
{
unsigned int eax, ebx, ecx, edx;
if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
return 1;
return ((ecx & (bit_AVX | bit_OSXSAVE))
!= (bit_AVX | bit_OSXSAVE));
}
} ""
}
}]
}
# Return 1 if the target supports executing AVX2 instructions, 0
# otherwise. Cache the result.
proc check_avx2_hw_available { } {
return [check_cached_effective_target avx2_hw_available {
# If this is not the right target then we can skip the test.
if { !([istarget x86_64-*-*] || [istarget i?86-*-*]) } {
expr 0
} else {
check_runtime_nocache avx2_hw_available {
#include <stddef.h>
#include "cpuid.h"
int main ()
{
unsigned int eax, ebx, ecx, edx;
if (__get_cpuid_max (0, NULL) < 7)
return 1;
__cpuid (1, eax, ebx, ecx, edx);
if (!(ecx & bit_OSXSAVE))
return 1;
__cpuid_count (7, 0, eax, ebx, ecx, edx);
return !(ebx & bit_AVX2);
}
} ""
}
}]
}
# Return 1 if the target supports executing AVX512 foundation instructions, 0
# otherwise. Cache the result.
proc check_avx512f_hw_available { } {
return [check_cached_effective_target avx512f_hw_available {
# If this is not the right target then we can skip the test.
if { !([istarget x86_64-*-*] || [istarget i?86-*-*]) } {
expr 0
} else {
check_runtime_nocache avx512f_hw_available {
#include <stddef.h>
#include "cpuid.h"
int main ()
{
unsigned int eax, ebx, ecx, edx;
if (__get_cpuid_max (0, NULL) < 7)
return 1;
__cpuid (1, eax, ebx, ecx, edx);
if (!(ecx & bit_OSXSAVE))
return 1;
__cpuid_count (7, 0, eax, ebx, ecx, edx);
return !(ebx & bit_AVX512F);
}
} ""
}
}]
}
# Return 1 if the target supports running SSE executables, 0 otherwise.
proc check_effective_target_sse_runtime { } {
if { [check_effective_target_sse]
&& [check_sse_hw_available]
&& [check_sse_os_support_available] } {
return 1
}
return 0
}
# Return 1 if the target supports running SSE2 executables, 0 otherwise.
proc check_effective_target_sse2_runtime { } {
if { [check_effective_target_sse2]
&& [check_sse2_hw_available]
&& [check_sse_os_support_available] } {
return 1
}
return 0
}
# Return 1 if the target supports running SSE4 executables, 0 otherwise.
proc check_effective_target_sse4_runtime { } {
if { [check_effective_target_sse4]
&& [check_sse4_hw_available]
&& [check_sse_os_support_available] } {
return 1
}
return 0
}
# Return 1 if the target supports running AVX executables, 0 otherwise.
proc check_effective_target_avx_runtime { } {
if { [check_effective_target_avx]
&& [check_avx_hw_available]
&& [check_avx_os_support_available] } {
return 1
}
return 0
}
# Return 1 if the target supports running AVX2 executables, 0 otherwise.
proc check_effective_target_avx2_runtime { } {
if { [check_effective_target_avx2]
&& [check_avx2_hw_available]
&& [check_avx_os_support_available] } {
return 1
}
return 0
}
# Return 1 if the target supports running AVX512f executables, 0 otherwise.
proc check_effective_target_avx512f_runtime { } {
if { [check_effective_target_avx512f]
&& [check_avx512f_hw_available]
&& [check_avx512_os_support_available] } {
return 1
}
return 0
}
# Return 1 if bmi2 instructions can be compiled.
proc check_effective_target_bmi2 { } {
if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
return 0
}
return [check_no_compiler_messages bmi2 object {
unsigned int
_bzhi_u32 (unsigned int __X, unsigned int __Y)
{
return __builtin_ia32_bzhi_si (__X, __Y);
}
} "-mbmi2" ]
}
# Return 1 if the target supports executing MIPS Paired-Single instructions,
# 0 otherwise. Cache the result.
proc check_mpaired_single_hw_available { } {
return [check_cached_effective_target mpaired_single_hw_available {
# If this is not the right target then we can skip the test.
if { !([istarget mips*-*-*]) } {
expr 0
} else {
check_runtime_nocache mpaired_single_hw_available {
int main()
{
asm volatile ("pll.ps $f2,$f4,$f6");
return 0;
}
} ""
}
}]
}
# Return 1 if the target supports executing Loongson vector instructions,
# 0 otherwise. Cache the result.
proc check_mips_loongson_mmi_hw_available { } {
return [check_cached_effective_target mips_loongson_mmi_hw_available {
# If this is not the right target then we can skip the test.
if { !([istarget mips*-*-*]) } {
expr 0
} else {
check_runtime_nocache mips_loongson_mmi_hw_available {
#include <loongson-mmiintrin.h>
int main()
{
asm volatile ("paddw $f2,$f4,$f6");
return 0;
}
} "-mloongson-mmi"
}
}]
}
# Return 1 if the target supports executing MIPS MSA instructions, 0
# otherwise. Cache the result.
proc check_mips_msa_hw_available { } {
return [check_cached_effective_target mips_msa_hw_available {
# If this is not the right target then we can skip the test.
if { !([istarget mips*-*-*]) } {
expr 0
} else {
check_runtime_nocache mips_msa_hw_available {
#if !defined(__mips_msa)
#error "MSA NOT AVAIL"
#else
#if !(((__mips == 64) || (__mips == 32)) && (__mips_isa_rev >= 2))
#error "MSA NOT AVAIL FOR ISA REV < 2"
#endif
#if !defined(__mips_hard_float)
#error "MSA HARD_FLOAT REQUIRED"
#endif
#if __mips_fpr != 64
#error "MSA 64-bit FPR REQUIRED"
#endif
#include <msa.h>
int main()
{
v8i16 v = __builtin_msa_ldi_h (0);
v[0] = 0;
return v[0];
}
#endif
} "-mmsa"
}
}]
}
# Return 1 if the target supports running MIPS Paired-Single
# executables, 0 otherwise.
proc check_effective_target_mpaired_single_runtime { } {
if { [check_effective_target_mpaired_single]
&& [check_mpaired_single_hw_available] } {
return 1
}
return 0
}
# Return 1 if the target supports running Loongson executables, 0 otherwise.
proc check_effective_target_mips_loongson_mmi_runtime { } {
if { [check_effective_target_mips_loongson_mmi]
&& [check_mips_loongson_mmi_hw_available] } {
return 1
}
return 0
}
# Return 1 if the target supports running MIPS MSA executables, 0 otherwise.
proc check_effective_target_mips_msa_runtime { } {
if { [check_effective_target_mips_msa]
&& [check_mips_msa_hw_available] } {
return 1
}
return 0
}
# Return 1 if we are compiling for 64-bit PowerPC but we do not use direct
# move instructions for moves from GPR to FPR.
proc check_effective_target_powerpc64_no_dm { } {
# The "mulld" checks if we are generating PowerPC64 code. The "lfd"
# checks if we do not use direct moves, but use the old-fashioned
# slower move-via-the-stack.
return [check_no_messages_and_pattern powerpc64_no_dm \
{\mmulld\M.*\mlfd} assembly {
double f(long long x) { return x*x; }
} {-O2}]
}
# Return 1 if the target supports the __builtin_cpu_supports built-in,
# including having a new enough library to support the test. Cache the result.
# Require at least a power7 to run on.
proc check_ppc_cpu_supports_hw_available { } {
return [check_cached_effective_target ppc_cpu_supports_hw_available {
# Some simulators are known to not support VSX/power8 instructions.
# For now, disable on Darwin
if { [istarget powerpc-*-eabi]
|| [istarget powerpc*-*-eabispe]
|| [istarget *-*-darwin*]} {
expr 0
} else {
set options "-mvsx"
check_runtime_nocache ppc_cpu_supports_hw_available {
int main()
{
#ifdef __MACH__
asm volatile ("xxlor vs0,vs0,vs0");
#else
asm volatile ("xxlor 0,0,0");
#endif
if (!__builtin_cpu_supports ("vsx"))
return 1;
return 0;
}
} $options
}
}]
}
# Return 1 if the target supports executing 750CL paired-single instructions, 0
# otherwise. Cache the result.
proc check_750cl_hw_available { } {
return [check_cached_effective_target 750cl_hw_available {
# If this is not the right target then we can skip the test.
if { ![istarget powerpc-*paired*] } {
expr 0
} else {
check_runtime_nocache 750cl_hw_available {
int main()
{
#ifdef __MACH__
asm volatile ("ps_mul v0,v0,v0");
#else
asm volatile ("ps_mul 0,0,0");
#endif
return 0;
}
} "-mpaired"
}
}]
}
# Return 1 if the target supports executing power8 vector instructions, 0
# otherwise. Cache the result.
proc check_p8vector_hw_available { } {
return [check_cached_effective_target p8vector_hw_available {
# Some simulators are known to not support VSX/power8 instructions.
# For now, disable on Darwin
if { [istarget powerpc-*-eabi]
|| [istarget powerpc*-*-eabispe]
|| [istarget *-*-darwin*]} {
expr 0
} else {
set options "-mpower8-vector"
check_runtime_nocache p8vector_hw_available {
int main()
{
#ifdef __MACH__
asm volatile ("xxlorc vs0,vs0,vs0");
#else
asm volatile ("xxlorc 0,0,0");
#endif
return 0;
}
} $options
}
}]
}
# Return 1 if the target supports executing power9 vector instructions, 0
# otherwise. Cache the result.
proc check_p9vector_hw_available { } {
return [check_cached_effective_target p9vector_hw_available {
# Some simulators are known to not support VSX/power8/power9
# instructions. For now, disable on Darwin.
if { [istarget powerpc-*-eabi]
|| [istarget powerpc*-*-eabispe]
|| [istarget *-*-darwin*]} {
expr 0
} else {
set options "-mpower9-vector"
check_runtime_nocache p9vector_hw_available {
int main()
{
long e = -1;
vector double v = (vector double) { 0.0, 0.0 };
asm ("xsxexpdp %0,%1" : "+r" (e) : "wa" (v));
return e;
}
} $options
}
}]
}
# Return 1 if the target supports executing power9 modulo instructions, 0
# otherwise. Cache the result.
proc check_p9modulo_hw_available { } {
return [check_cached_effective_target p9modulo_hw_available {
# Some simulators are known to not support VSX/power8/power9
# instructions. For now, disable on Darwin.
if { [istarget powerpc-*-eabi]
|| [istarget powerpc*-*-eabispe]
|| [istarget *-*-darwin*]} {
expr 0
} else {
set options "-mmodulo"
check_runtime_nocache p9modulo_hw_available {
int main()
{
int i = 5, j = 3, r = -1;
asm ("modsw %0,%1,%2" : "+r" (r) : "r" (i), "r" (j));
return (r == 2);
}
} $options
}
}]
}
# Return 1 if the target supports executing FUTURE instructions, 0 otherwise.
# Cache the result. It is assumed that if a simulator does not support the
# FUTURE instructions, that it will generate an error and this test will fail.
proc check_powerpc_future_hw_available { } {
return [check_cached_effective_target powerpc_future_hw_available {
check_runtime_nocache powerpc_future_hw_available {
int main()
{
/* Set e first and use +r to check if pli actually works. */
long e = -1;
asm ("pli %0,%1" : "+r" (e) : "n" (0x12345));
return (e == 0x12345);
}
} "-mfuture"
}]
}
# Return 1 if the target supports executing __float128 on PowerPC via software
# emulation, 0 otherwise. Cache the result.
proc check_ppc_float128_sw_available { } {
return [check_cached_effective_target ppc_float128_sw_available {
# Some simulators are known to not support VSX/power8/power9
# instructions. For now, disable on Darwin.
if { [istarget powerpc-*-eabi]
|| [istarget powerpc*-*-eabispe]
|| [istarget *-*-darwin*]} {
expr 0
} else {
set options "-mfloat128 -mvsx"
check_runtime_nocache ppc_float128_sw_available {
volatile __float128 x = 1.0q;
volatile __float128 y = 2.0q;
int main()
{
__float128 z = x + y;
return (z != 3.0q);
}
} $options
}
}]
}
# Return 1 if the target supports executing __float128 on PowerPC via power9
# hardware instructions, 0 otherwise. Cache the result.
proc check_ppc_float128_hw_available { } {
return [check_cached_effective_target ppc_float128_hw_available {
# Some simulators are known to not support VSX/power8/power9
# instructions. For now, disable on Darwin.
if { [istarget powerpc-*-eabi]
|| [istarget powerpc*-*-eabispe]
|| [istarget *-*-darwin*]} {
expr 0
} else {
set options "-mfloat128 -mvsx -mfloat128-hardware -mpower9-vector"
check_runtime_nocache ppc_float128_hw_available {
volatile __float128 x = 1.0q;
volatile __float128 y = 2.0q;
int main()
{
__float128 z = x + y;
__float128 w = -1.0q;
__asm__ ("xsaddqp %0,%1,%2" : "+v" (w) : "v" (x), "v" (y));
return ((z != 3.0q) || (z != w));
}
} $options
}
}]
}
# Return 1 if the target supports executing VSX instructions, 0
# otherwise. Cache the result.
proc check_vsx_hw_available { } {
return [check_cached_effective_target vsx_hw_available {
# Some simulators are known to not support VSX instructions.
# For now, disable on Darwin
if { [istarget powerpc-*-eabi]
|| [istarget powerpc*-*-eabispe]
|| [istarget *-*-darwin*]} {
expr 0
} else {
set options "-mvsx"
check_runtime_nocache vsx_hw_available {
int main()
{
#ifdef __MACH__
asm volatile ("xxlor vs0,vs0,vs0");
#else
asm volatile ("xxlor 0,0,0");
#endif
return 0;
}
} $options
}
}]
}
# Return 1 if the target supports executing AltiVec instructions, 0
# otherwise. Cache the result.
proc check_vmx_hw_available { } {
return [check_cached_effective_target vmx_hw_available {
# Some simulators are known to not support VMX instructions.
if { [istarget powerpc-*-eabi] || [istarget powerpc*-*-eabispe] } {
expr 0
} else {
# Most targets don't require special flags for this test case, but
# Darwin does. Just to be sure, make sure VSX is not enabled for
# the altivec tests.
if { [istarget *-*-darwin*]
|| [istarget *-*-aix*] } {
set options "-maltivec -mno-vsx"
} else {
set options "-mno-vsx"
}
check_runtime_nocache vmx_hw_available {
int main()
{
#ifdef __MACH__
asm volatile ("vor v0,v0,v0");
#else
asm volatile ("vor 0,0,0");
#endif
return 0;
}
} $options
}
}]
}
proc check_ppc_recip_hw_available { } {
return [check_cached_effective_target ppc_recip_hw_available {
# Some simulators may not support FRE/FRES/FRSQRTE/FRSQRTES
# For now, disable on Darwin
if { [istarget powerpc-*-eabi] || [istarget powerpc*-*-eabispe] || [istarget *-*-darwin*]} {
expr 0
} else {
set options "-mpowerpc-gfxopt -mpowerpc-gpopt -mpopcntb"
check_runtime_nocache ppc_recip_hw_available {
volatile double d_recip, d_rsqrt, d_four = 4.0;
volatile float f_recip, f_rsqrt, f_four = 4.0f;
int main()
{
asm volatile ("fres %0,%1" : "=f" (f_recip) : "f" (f_four));
asm volatile ("fre %0,%1" : "=d" (d_recip) : "d" (d_four));
asm volatile ("frsqrtes %0,%1" : "=f" (f_rsqrt) : "f" (f_four));
asm volatile ("frsqrte %0,%1" : "=f" (d_rsqrt) : "d" (d_four));
return 0;
}
} $options
}
}]
}
# Return 1 if the target supports executing AltiVec and Cell PPU
# instructions, 0 otherwise. Cache the result.
proc check_effective_target_cell_hw { } {
return [check_cached_effective_target cell_hw_available {
# Some simulators are known to not support VMX and PPU instructions.
if { [istarget powerpc-*-eabi*] } {
expr 0
} else {
# Most targets don't require special flags for this test
# case, but Darwin and AIX do.
if { [istarget *-*-darwin*]
|| [istarget *-*-aix*] } {
set options "-maltivec -mcpu=cell"
} else {
set options "-mcpu=cell"
}
check_runtime_nocache cell_hw_available {
int main()
{
#ifdef __MACH__
asm volatile ("vor v0,v0,v0");
asm volatile ("lvlx v0,r0,r0");
#else
asm volatile ("vor 0,0,0");
asm volatile ("lvlx 0,0,0");
#endif
return 0;
}
} $options
}
}]
}
# Return 1 if the target supports executing 64-bit instructions, 0
# otherwise. Cache the result.
proc check_effective_target_powerpc64 { } {
global powerpc64_available_saved
global tool
if [info exists powerpc64_available_saved] {
verbose "check_effective_target_powerpc64 returning saved $powerpc64_available_saved" 2
} else {
set powerpc64_available_saved 0
# Some simulators are known to not support powerpc64 instructions.
if { [istarget powerpc-*-eabi*] || [istarget powerpc-ibm-aix*] } {
verbose "check_effective_target_powerpc64 returning 0" 2
return $powerpc64_available_saved
}
# Set up, compile, and execute a test program containing a 64-bit
# instruction. Include the current process ID in the file
# names to prevent conflicts with invocations for multiple
# testsuites.
set src ppc[pid].c
set exe ppc[pid].x
set f [open $src "w"]
puts $f "int main() {"
puts $f "#ifdef __MACH__"
puts $f " asm volatile (\"extsw r0,r0\");"
puts $f "#else"
puts $f " asm volatile (\"extsw 0,0\");"
puts $f "#endif"
puts $f " return 0; }"
close $f
set opts "additional_flags=-mcpu=G5"
verbose "check_effective_target_powerpc64 compiling testfile $src" 2
set lines [${tool}_target_compile $src $exe executable "$opts"]
file delete $src
if [string match "" $lines] then {
# No error message, compilation succeeded.
set result [${tool}_load "./$exe" "" ""]
set status [lindex $result 0]
remote_file build delete $exe
verbose "check_effective_target_powerpc64 testfile status is <$status>" 2
if { $status == "pass" } then {
set powerpc64_available_saved 1
}
} else {
verbose "check_effective_target_powerpc64 testfile compilation failed" 2
}
}
return $powerpc64_available_saved
}
# GCC 3.4.0 for powerpc64-*-linux* included an ABI fix for passing
# complex float arguments. This affects gfortran tests that call cabsf
# in libm built by an earlier compiler. Return 0 if libm uses the same
# argument passing as the compiler under test, 1 otherwise.
proc check_effective_target_broken_cplxf_arg { } {
# Skip the work for targets known not to be affected.
if { ![istarget powerpc*-*-linux*] || ![is-effective-target lp64] } {
return 0
}
return [check_cached_effective_target broken_cplxf_arg {
check_runtime_nocache broken_cplxf_arg {
#include <complex.h>
extern void abort (void);
float fabsf (float);
float cabsf (_Complex float);
int main ()
{
_Complex float cf;
float f;
cf = 3 + 4.0fi;
f = cabsf (cf);
if (fabsf (f - 5.0) > 0.0001)
/* Yes, it's broken. */
return 0;
/* All fine, not broken. */
return 1;
}
} "-lm"
}]
}
# Return 1 is this is a TI C6X target supporting C67X instructions
proc check_effective_target_ti_c67x { } {
return [check_no_compiler_messages ti_c67x assembly {
#if !defined(_TMS320C6700)
#error !_TMS320C6700
#endif
}]
}
# Return 1 is this is a TI C6X target supporting C64X+ instructions
proc check_effective_target_ti_c64xp { } {
return [check_no_compiler_messages ti_c64xp assembly {
#if !defined(_TMS320C6400_PLUS)
#error !_TMS320C6400_PLUS
#endif
}]
}
proc check_alpha_max_hw_available { } {
return [check_runtime alpha_max_hw_available {
int main() { return __builtin_alpha_amask(1<<8) != 0; }
}]
}
# Returns true iff the FUNCTION is available on the target system.
# (This is essentially a Tcl implementation of Autoconf's
# AC_CHECK_FUNC.)
proc check_function_available { function } {
return [check_no_compiler_messages ${function}_available \
executable [subst {
#ifdef __cplusplus
extern "C"
#endif
char $function ();
int main () { $function (); }
}] "-fno-builtin" ]
}
# Returns true iff "fork" is available on the target system.
proc check_fork_available {} {
return [check_function_available "fork"]
}
# Returns true iff "mkfifo" is available on the target system.
proc check_mkfifo_available {} {
if { [istarget *-*-cygwin*] } {
# Cygwin has mkfifo, but support is incomplete.
return 0
}
return [check_function_available "mkfifo"]
}
# Returns true iff "__cxa_atexit" is used on the target system.
proc check_cxa_atexit_available { } {
return [check_cached_effective_target cxa_atexit_available {
if { [istarget hppa*-*-hpux10*] } {
# HP-UX 10 doesn't have __cxa_atexit but subsequent test passes.
expr 0
} elseif { [istarget *-*-vxworks] } {
# vxworks doesn't have __cxa_atexit but subsequent test passes.
expr 0
} else {
check_runtime_nocache cxa_atexit_available {
// C++
#include <stdlib.h>
static unsigned int count;
struct X
{
X() { count = 1; }
~X()
{
if (count != 3)
exit(1);
count = 4;
}
};
void f()
{
static X x;
}
struct Y
{
Y() { f(); count = 2; }
~Y()
{
if (count != 2)
exit(1);
count = 3;
}
};
Y y;
int main() { return 0; }
}
}
}]
}
proc check_effective_target_objc2 { } {
return [check_no_compiler_messages objc2 object {
#ifdef __OBJC2__
int dummy[1];
#else
#error !__OBJC2__
#endif
}]
}
proc check_effective_target_next_runtime { } {
return [check_no_compiler_messages objc2 object {
#ifdef __NEXT_RUNTIME__
int dummy[1];
#else
#error !__NEXT_RUNTIME__
#endif
}]
}
# Return 1 if we're generating code for big-endian memory order.
proc check_effective_target_be { } {
return [check_no_compiler_messages be object {
int dummy[__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ? 1 : -1];
}]
}
# Return 1 if we're generating code for little-endian memory order.
proc check_effective_target_le { } {
return [check_no_compiler_messages le object {
int dummy[__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ? 1 : -1];
}]
}
# Return 1 if we're generating code for only power8 platforms.
proc check_effective_target_p8 { } {
return [check_no_compiler_messages_nocache p8 assembly {
#if !(!defined(_ARCH_PWR9) && defined(_ARCH_PWR8))
#error NO
#endif
} ""]
}
# Return 1 if we're generating code for power9 and future platforms.
proc check_effective_target_p9+ { } {
return [check_no_compiler_messages_nocache p9+ assembly {
#if !(defined(_ARCH_PWR9))
#error NO
#endif
} ""]
}
# Return 1 if we're generating 32-bit code using default options, 0
# otherwise.
proc check_effective_target_ilp32 { } {
return [check_no_compiler_messages ilp32 object {
int dummy[sizeof (int) == 4
&& sizeof (void *) == 4
&& sizeof (long) == 4 ? 1 : -1];
}]
}
# Return 1 if we're generating ia32 code using default options, 0
# otherwise.
proc check_effective_target_ia32 { } {
return [check_no_compiler_messages ia32 object {
int dummy[sizeof (int) == 4
&& sizeof (void *) == 4
&& sizeof (long) == 4 ? 1 : -1] = { __i386__ };
}]
}
# Return 1 if we're generating x32 code using default options, 0
# otherwise.
proc check_effective_target_x32 { } {
return [check_no_compiler_messages x32 object {
int dummy[sizeof (int) == 4
&& sizeof (void *) == 4
&& sizeof (long) == 4 ? 1 : -1] = { __x86_64__ };
}]
}
# Return 1 if we're generating 32-bit integers using default
# options, 0 otherwise.
proc check_effective_target_int32 { } {
return [check_no_compiler_messages int32 object {
int dummy[sizeof (int) == 4 ? 1 : -1];
}]
}
# Return 1 if we're generating 32-bit or larger integers using default
# options, 0 otherwise.
proc check_effective_target_int32plus { } {
return [check_no_compiler_messages int32plus object {
int dummy[sizeof (int) >= 4 ? 1 : -1];
}]
}
# Return 1 if we're generating 64-bit long long using default options,
# 0 otherwise.
proc check_effective_target_longlong64 { } {
return [check_no_compiler_messages longlong64 object {
int dummy[sizeof (long long) == 8 ? 1 : -1];
}]
}
# Return 1 if we're generating 32-bit or larger pointers using default
# options, 0 otherwise.
proc check_effective_target_ptr32plus { } {
# The msp430 has 16-bit or 20-bit pointers. The 20-bit pointer is stored
# in a 32-bit slot when in memory, so sizeof(void *) returns 4, but it
# cannot really hold a 32-bit address, so we always return false here.
if { [istarget msp430-*-*] } {
return 0
}
return [check_no_compiler_messages ptr32plus object {
int dummy[sizeof (void *) >= 4 ? 1 : -1];
}]
}
# Return 1 if we support 16-bit or larger array and structure sizes
# using default options, 0 otherwise.
# This implies at least a 20-bit address space, as no targets have an address
# space between 16 and 20 bits.
proc check_effective_target_size20plus { } {
return [check_no_compiler_messages size20plus object {
char dummy[65537L];
}]
}
# Return 1 if target supports function pointers, 0 otherwise.
proc check_effective_target_function_pointers { } {
if { [istarget pru-*-*] } {
return [check_no_compiler_messages func_ptr_avail assembly {
#ifdef __PRU_EABI_GNU__
#error unsupported
#endif
}]
}
return 1
}
# Return 1 if target supports arbitrarily large return values, 0 otherwise.
proc check_effective_target_large_return_values { } {
if { [istarget pru-*-*] } {
return [check_no_compiler_messages large_return_values assembly {
#ifdef __PRU_EABI_GNU__
#error unsupported
#endif
}]
}
return 1
}
# Return 1 if we support 24-bit or larger array and structure sizes
# using default options, 0 otherwise.
# This implies at least a 32-bit address space, as no targets have an address
# space between 24 and 32 bits.
proc check_effective_target_size32plus { } {
return [check_no_compiler_messages size32plus object {
char dummy[16777217L];
}]
}
# Returns 1 if we're generating 16-bit or smaller integers with the
# default options, 0 otherwise.
proc check_effective_target_int16 { } {
return [check_no_compiler_messages int16 object {
int dummy[sizeof (int) < 4 ? 1 : -1];
}]
}
# Return 1 if we're generating 64-bit code using default options, 0
# otherwise.
proc check_effective_target_lp64 { } {
return [check_no_compiler_messages lp64 object {
int dummy[sizeof (int) == 4
&& sizeof (void *) == 8
&& sizeof (long) == 8 ? 1 : -1];
}]
}
# Return 1 if we're generating 64-bit code using default llp64 options,
# 0 otherwise.
proc check_effective_target_llp64 { } {
return [check_no_compiler_messages llp64 object {
int dummy[sizeof (int) == 4
&& sizeof (void *) == 8
&& sizeof (long long) == 8
&& sizeof (long) == 4 ? 1 : -1];
}]
}
# Return 1 if long and int have different sizes,
# 0 otherwise.
proc check_effective_target_long_neq_int { } {
return [check_no_compiler_messages long_ne_int object {
int dummy[sizeof (int) != sizeof (long) ? 1 : -1];
}]
}
# Return 1 if int size is equal to float size,
# 0 otherwise.
proc check_effective_target_int_eq_float { } {
return [check_no_compiler_messages int_eq_float object {
int dummy[sizeof (int) >= sizeof (float) ? 1 : -1];
}]
}
# Return 1 if pointer size is equal to long size,
# 0 otherwise.
proc check_effective_target_ptr_eq_long { } {
# sizeof (void *) == 4 for msp430-elf -mlarge which is equal to
# sizeof (long). Avoid false positive.
if { [istarget msp430-*-*] } {
return 0
}
return [check_no_compiler_messages ptr_eq_long object {
int dummy[sizeof (void *) == sizeof (long) ? 1 : -1];
}]
}
# Return 1 if the target supports long double larger than double,
# 0 otherwise.
proc check_effective_target_large_long_double { } {
return [check_no_compiler_messages large_long_double object {
int dummy[sizeof(long double) > sizeof(double) ? 1 : -1];
}]
}
# Return 1 if the target supports double larger than float,
# 0 otherwise.
proc check_effective_target_large_double { } {
return [check_no_compiler_messages large_double object {
int dummy[sizeof(double) > sizeof(float) ? 1 : -1];
}]
}
# Return 1 if the target supports long double of 128 bits,
# 0 otherwise.
proc check_effective_target_longdouble128 { } {
return [check_no_compiler_messages longdouble128 object {
int dummy[sizeof(long double) == 16 ? 1 : -1];
}]
}
# Return 1 if the target supports long double of 64 bits,
# 0 otherwise.
proc check_effective_target_longdouble64 { } {
return [check_no_compiler_messages longdouble64 object {
int dummy[sizeof(long double) == 8 ? 1 : -1];
}]
}
# Return 1 if the target supports double of 64 bits,
# 0 otherwise.
proc check_effective_target_double64 { } {
return [check_no_compiler_messages double64 object {
int dummy[sizeof(double) == 8 ? 1 : -1];
}]
}
# Return 1 if the target supports double of at least 64 bits,
# 0 otherwise.
proc check_effective_target_double64plus { } {
return [check_no_compiler_messages double64plus object {
int dummy[sizeof(double) >= 8 ? 1 : -1];
}]
}
# Return 1 if the target supports 'w' suffix on floating constant
# 0 otherwise.
proc check_effective_target_has_w_floating_suffix { } {
set opts ""
if [check_effective_target_c++] {
append opts "-std=gnu++03"
}
return [check_no_compiler_messages w_fp_suffix object {
float dummy = 1.0w;
} "$opts"]
}
# Return 1 if the target supports 'q' suffix on floating constant
# 0 otherwise.
proc check_effective_target_has_q_floating_suffix { } {
set opts ""
if [check_effective_target_c++] {
append opts "-std=gnu++03"
}
return [check_no_compiler_messages q_fp_suffix object {
float dummy = 1.0q;
} "$opts"]
}
# Return 1 if the target supports the _FloatN / _FloatNx type
# indicated in the function name, 0 otherwise.
proc check_effective_target_float16 {} {
return [check_no_compiler_messages_nocache float16 object {
_Float16 x;
} [add_options_for_float16 ""]]
}
proc check_effective_target_float32 {} {
return [check_no_compiler_messages_nocache float32 object {
_Float32 x;
} [add_options_for_float32 ""]]
}
proc check_effective_target_float64 {} {
return [check_no_compiler_messages_nocache float64 object {
_Float64 x;
} [add_options_for_float64 ""]]
}
proc check_effective_target_float128 {} {
return [check_no_compiler_messages_nocache float128 object {
_Float128 x;
} [add_options_for_float128 ""]]
}
proc check_effective_target_float32x {} {
return [check_no_compiler_messages_nocache float32x object {
_Float32x x;
} [add_options_for_float32x ""]]
}
proc check_effective_target_float64x {} {
return [check_no_compiler_messages_nocache float64x object {
_Float64x x;
} [add_options_for_float64x ""]]
}
proc check_effective_target_float128x {} {
return [check_no_compiler_messages_nocache float128x object {
_Float128x x;
} [add_options_for_float128x ""]]
}
# Likewise, but runtime support for any special options used as well
# as compile-time support is required.
proc check_effective_target_float16_runtime {} {
return [check_effective_target_float16]
}
proc check_effective_target_float32_runtime {} {
return [check_effective_target_float32]
}
proc check_effective_target_float64_runtime {} {
return [check_effective_target_float64]
}
proc check_effective_target_float128_runtime {} {
if { ![check_effective_target_float128] } {
return 0
}
if { [istarget powerpc*-*-*] } {
return [check_effective_target_base_quadfloat_support]
}
return 1
}
proc check_effective_target_float32x_runtime {} {
return [check_effective_target_float32x]
}
proc check_effective_target_float64x_runtime {} {
if { ![check_effective_target_float64x] } {
return 0
}
if { [istarget powerpc*-*-*] } {
return [check_effective_target_base_quadfloat_support]
}
return 1
}
proc check_effective_target_float128x_runtime {} {
return [check_effective_target_float128x]
}
# Return 1 if the target hardware supports any options added for
# _FloatN and _FloatNx types, 0 otherwise.
proc check_effective_target_floatn_nx_runtime {} {
if { [istarget powerpc*-*-aix*] } {
return 0
}
if { [istarget powerpc*-*-*] } {
return [check_effective_target_base_quadfloat_support]
}
return 1
}
# Add options needed to use the _FloatN / _FloatNx type indicated in
# the function name.
proc add_options_for_float16 { flags } {
if { [istarget arm*-*-*] } {
return "$flags -mfp16-format=ieee"
}
return "$flags"
}
proc add_options_for_float32 { flags } {
return "$flags"
}
proc add_options_for_float64 { flags } {
return "$flags"
}
proc add_options_for_float128 { flags } {
return [add_options_for___float128 "$flags"]
}
proc add_options_for_float32x { flags } {
return "$flags"
}
proc add_options_for_float64x { flags } {
return [add_options_for___float128 "$flags"]
}
proc add_options_for_float128x { flags } {
return "$flags"
}
# Return 1 if the target supports __float128,
# 0 otherwise.
proc check_effective_target___float128 { } {
if { [istarget powerpc*-*-*] } {
return [check_ppc_float128_sw_available]
}
if { [istarget ia64-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*] } {
return 1
}
return 0
}
proc add_options_for___float128 { flags } {
if { [istarget powerpc*-*-*] } {
return "$flags -mfloat128 -mvsx"
}
return "$flags"
}
# Return 1 if the target supports any special run-time requirements
# for __float128 or _Float128,
# 0 otherwise.
proc check_effective_target_base_quadfloat_support { } {
if { [istarget powerpc*-*-*] } {
return [check_vsx_hw_available]
}
return 1
}
# Return 1 if the target supports all four forms of fused multiply-add
# (fma, fms, fnma, and fnms) for both float and double.
proc check_effective_target_scalar_all_fma { } {
return [istarget aarch64*-*-*]
}
# Return 1 if the target supports compiling fixed-point,
# 0 otherwise.
proc check_effective_target_fixed_point { } {
return [check_no_compiler_messages fixed_point object {
_Sat _Fract x; _Sat _Accum y;
}]
}
# Return 1 if the target supports compiling decimal floating point,
# 0 otherwise.
proc check_effective_target_dfp_nocache { } {
verbose "check_effective_target_dfp_nocache: compiling source" 2
set ret [check_no_compiler_messages_nocache dfp object {
float x __attribute__((mode(DD)));
}]
verbose "check_effective_target_dfp_nocache: returning $ret" 2
return $ret
}
proc check_effective_target_dfprt_nocache { } {
return [check_runtime_nocache dfprt {
typedef float d64 __attribute__((mode(DD)));
d64 x = 1.2df, y = 2.3dd, z;
int main () { z = x + y; return 0; }
}]
}
# Return 1 if the target supports compiling Decimal Floating Point,
# 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_dfp { } {
return [check_cached_effective_target dfp {
check_effective_target_dfp_nocache
}]
}
# Return 1 if the target supports linking and executing Decimal Floating
# Point, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_dfprt { } {
return [check_cached_effective_target dfprt {
check_effective_target_dfprt_nocache
}]
}
proc check_effective_target_powerpc_popcntb_ok { } {
return [check_cached_effective_target powerpc_popcntb_ok {
# Disable on Darwin.
if { [istarget powerpc-*-eabi] || [istarget powerpc*-*-eabispe] || [istarget *-*-darwin*]} {
expr 0
} else {
check_runtime_nocache powerpc_popcntb_ok {
volatile int r;
volatile int a = 0x12345678;
int main()
{
asm volatile ("popcntb %0,%1" : "=r" (r) : "r" (a));
return 0;
}
} "-mcpu=power5"
}
}]
}
# Return 1 if the target supports executing DFP hardware instructions,
# 0 otherwise. Cache the result.
proc check_dfp_hw_available { } {
return [check_cached_effective_target dfp_hw_available {
# For now, disable on Darwin
if { [istarget powerpc-*-eabi] || [istarget powerpc*-*-eabispe] || [istarget *-*-darwin*]} {
expr 0
} else {
check_runtime_nocache dfp_hw_available {
volatile _Decimal64 r;
volatile _Decimal64 a = 4.0DD;
volatile _Decimal64 b = 2.0DD;
int main()
{
asm volatile ("dadd %0,%1,%2" : "=d" (r) : "d" (a), "d" (b));
asm volatile ("dsub %0,%1,%2" : "=d" (r) : "d" (a), "d" (b));
asm volatile ("dmul %0,%1,%2" : "=d" (r) : "d" (a), "d" (b));
asm volatile ("ddiv %0,%1,%2" : "=d" (r) : "d" (a), "d" (b));
return 0;
}
} "-mcpu=power6 -mhard-float"
}
}]
}
# Return 1 if the target supports compiling and assembling UCN, 0 otherwise.
proc check_effective_target_ucn_nocache { } {
# -std=c99 is only valid for C
if [check_effective_target_c] {
set ucnopts "-std=c99"
} else {
set ucnopts ""
}
verbose "check_effective_target_ucn_nocache: compiling source" 2
set ret [check_no_compiler_messages_nocache ucn object {
int \u00C0;
} $ucnopts]
verbose "check_effective_target_ucn_nocache: returning $ret" 2
return $ret
}
# Return 1 if the target supports compiling and assembling UCN, 0 otherwise.
#
# This won't change for different subtargets, so cache the result.
proc check_effective_target_ucn { } {
return [check_cached_effective_target ucn {
check_effective_target_ucn_nocache
}]
}
# Return 1 if the target needs a command line argument to enable a SIMD
# instruction set.
proc check_effective_target_vect_cmdline_needed { } {
global et_vect_cmdline_needed_target_name
if { ![info exists et_vect_cmdline_needed_target_name] } {
set et_vect_cmdline_needed_target_name ""
}
# If the target has changed since we set the cached value, clear it.
set current_target [current_target_name]
if { $current_target != $et_vect_cmdline_needed_target_name } {
verbose "check_effective_target_vect_cmdline_needed: `$et_vect_cmdline_needed_target_name' `$current_target'" 2
set et_vect_cmdline_needed_target_name $current_target
if { [info exists et_vect_cmdline_needed_saved] } {
verbose "check_effective_target_vect_cmdline_needed: removing cached result" 2
unset et_vect_cmdline_needed_saved
}
}
return [check_cached_effective_target vect_cmdline_needed {
if { [istarget alpha*-*-*]
|| [istarget ia64-*-*]
|| (([istarget i?86-*-*] || [istarget x86_64-*-*])
&& ![is-effective-target ia32])
|| ([istarget powerpc*-*-*]
&& ([check_effective_target_powerpc_spe]
|| [check_effective_target_powerpc_altivec]))
|| ([istarget sparc*-*-*] && [check_effective_target_sparc_vis])
|| ([istarget arm*-*-*] && [check_effective_target_arm_neon])
|| [istarget aarch64*-*-*] } {
return 0
} else {
return 1
}}]
}
# Return 1 if the target supports hardware vectors of int, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_int { } {
return [check_cached_effective_target_indexed vect_int {
expr {
[istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
|| [istarget amdgcn-*-*]
|| [istarget sparc*-*-*]
|| [istarget alpha*-*-*]
|| [istarget ia64-*-*]
|| [istarget aarch64*-*-*]
|| [is-effective-target arm_neon]
|| ([istarget mips*-*-*]
&& ([et-is-effective-target mips_loongson_mmi]
|| [et-is-effective-target mips_msa]))
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
}}]
}
# Return 1 if the target supports signed int->float conversion
#
proc check_effective_target_vect_intfloat_cvt { } {
return [check_cached_effective_target_indexed vect_intfloat_cvt {
expr { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
|| [is-effective-target arm_neon]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports signed double->int conversion
#
proc check_effective_target_vect_doubleint_cvt { } {
return [check_cached_effective_target_indexed vect_doubleint_cvt {
expr { (([istarget i?86-*-*] || [istarget x86_64-*-*])
&& [check_no_compiler_messages vect_doubleint_cvt assembly {
#ifdef __tune_atom__
# error No double vectorizer support.
#endif
}])
|| [istarget aarch64*-*-*]
|| ([istarget powerpc*-*-*] && [check_vsx_hw_available])
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa]) }}]
}
# Return 1 if the target supports signed int->double conversion
#
proc check_effective_target_vect_intdouble_cvt { } {
return [check_cached_effective_target_indexed vect_intdouble_cvt {
expr { (([istarget i?86-*-*] || [istarget x86_64-*-*])
&& [check_no_compiler_messages vect_intdouble_cvt assembly {
#ifdef __tune_atom__
# error No double vectorizer support.
#endif
}])
|| [istarget aarch64*-*-*]
|| ([istarget powerpc*-*-*] && [check_vsx_hw_available])
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa]) }}]
}
#Return 1 if we're supporting __int128 for target, 0 otherwise.
proc check_effective_target_int128 { } {
return [check_no_compiler_messages int128 object {
int dummy[
#ifndef __SIZEOF_INT128__
-1
#else
1
#endif
];
}]
}
# Return 1 if the target supports unsigned int->float conversion
#
proc check_effective_target_vect_uintfloat_cvt { } {
return [check_cached_effective_target_indexed vect_uintfloat_cvt {
expr { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
|| [istarget aarch64*-*-*]
|| [is-effective-target arm_neon]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports signed float->int conversion
#
proc check_effective_target_vect_floatint_cvt { } {
return [check_cached_effective_target_indexed vect_floatint_cvt {
expr { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
|| [is-effective-target arm_neon]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports unsigned float->int conversion
#
proc check_effective_target_vect_floatuint_cvt { } {
return [check_cached_effective_target_indexed vect_floatuint_cvt {
expr { ([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
|| [is-effective-target arm_neon]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if peeling for alignment might be profitable on the target
#
proc check_effective_target_vect_peeling_profitable { } {
return [check_cached_effective_target_indexed vect_peeling_profitable {
expr { ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
|| [check_effective_target_vect_element_align_preferred] }}]
}
# Return 1 if the target supports #pragma omp declare simd, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_simd_clones { } {
# On i?86/x86_64 #pragma omp declare simd builds a sse2, avx,
# avx2 and avx512f clone. Only the right clone for the
# specified arch will be chosen, but still we need to at least
# be able to assemble avx512f.
return [check_cached_effective_target_indexed vect_simd_clones {
expr { (([istarget i?86-*-*] || [istarget x86_64-*-*])
&& [check_effective_target_avx512f])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if this is a AArch64 target supporting big endian
proc check_effective_target_aarch64_big_endian { } {
return [check_no_compiler_messages aarch64_big_endian assembly {
#if !defined(__aarch64__) || !defined(__AARCH64EB__)
#error !__aarch64__ || !__AARCH64EB__
#endif
}]
}
# Return 1 if this is a AArch64 target supporting little endian
proc check_effective_target_aarch64_little_endian { } {
if { ![istarget aarch64*-*-*] } {
return 0
}
return [check_no_compiler_messages aarch64_little_endian assembly {
#if !defined(__aarch64__) || defined(__AARCH64EB__)
#error FOO
#endif
}]
}
# Return 1 if this is an AArch64 target supporting SVE.
proc check_effective_target_aarch64_sve { } {
if { ![istarget aarch64*-*-*] } {
return 0
}
return [check_no_compiler_messages aarch64_sve assembly {
#if !defined (__ARM_FEATURE_SVE)
#error FOO
#endif
}]
}
# Return 1 if this is an AArch64 target supporting SVE2.
proc check_effective_target_aarch64_sve2 { } {
if { ![istarget aarch64*-*-*] } {
return 0
}
return [check_no_compiler_messages aarch64_sve2 assembly {
#if !defined (__ARM_FEATURE_SVE2)
#error FOO
#endif
}]
}
# Return 1 if this is an AArch64 target only supporting SVE (not SVE2).
proc check_effective_target_aarch64_sve1_only { } {
return [expr { [check_effective_target_aarch64_sve]
&& ![check_effective_target_aarch64_sve2] }]
}
# Return the size in bits of an SVE vector, or 0 if the size is variable.
proc aarch64_sve_bits { } {
return [check_cached_effective_target aarch64_sve_bits {
global tool
set src dummy[pid].c
set f [open $src "w"]
puts $f "int bits = __ARM_FEATURE_SVE_BITS;"
close $f
set output [${tool}_target_compile $src "" preprocess ""]
file delete $src
regsub {.*bits = ([^;]*);.*} $output {\1} bits
expr { $bits }
}]
}
# Return 1 if this is a compiler supporting ARC atomic operations
proc check_effective_target_arc_atomic { } {
return [check_no_compiler_messages arc_atomic assembly {
#if !defined(__ARC_ATOMIC__)
#error FOO
#endif
}]
}
# Return 1 if this is an arm target using 32-bit instructions
proc check_effective_target_arm32 { } {
if { ![istarget arm*-*-*] } {
return 0
}
return [check_no_compiler_messages arm32 assembly {
#if !defined(__arm__) || (defined(__thumb__) && !defined(__thumb2__))
#error !__arm || __thumb__ && !__thumb2__
#endif
}]
}
# Return 1 if this is an arm target not using Thumb
proc check_effective_target_arm_nothumb { } {
if { ![istarget arm*-*-*] } {
return 0
}
return [check_no_compiler_messages arm_nothumb assembly {
#if !defined(__arm__) || (defined(__thumb__) || defined(__thumb2__))
#error !__arm__ || __thumb || __thumb2__
#endif
}]
}
# Return 1 if this is a little-endian ARM target
proc check_effective_target_arm_little_endian { } {
if { ![istarget arm*-*-*] } {
return 0
}
return [check_no_compiler_messages arm_little_endian assembly {
#if !defined(__arm__) || !defined(__ARMEL__)
#error !__arm__ || !__ARMEL__
#endif
}]
}
# Return 1 if this is an ARM target that only supports aligned vector accesses
proc check_effective_target_arm_vect_no_misalign { } {
if { ![istarget arm*-*-*] } {
return 0
}
return [check_no_compiler_messages arm_vect_no_misalign assembly {
#if !defined(__arm__) \
|| (defined(__ARM_FEATURE_UNALIGNED) \
&& defined(__ARMEL__))
#error !__arm__ || (__ARMEL__ && __ARM_FEATURE_UNALIGNED)
#endif
}]
}
# Return 1 if this is an ARM target supporting -mfloat-abi=soft. Some
# multilibs may be incompatible with this option.
proc check_effective_target_arm_soft_ok { } {
if { [check_effective_target_arm32] } {
return [check_no_compiler_messages arm_soft_ok executable {
int main() { return 0;}
} "-mfloat-abi=soft"]
} else {
return 0
}
}
# Return 1 if this is an ARM target supporting -mfpu=vfp with an
# appropriate abi.
proc check_effective_target_arm_vfp_ok_nocache { } {
global et_arm_vfp_flags
set et_arm_vfp_flags ""
if { [check_effective_target_arm32] } {
foreach flags {"-mfpu=vfp" "-mfpu=vfp -mfloat-abi=softfp" "-mfpu=vfp -mfloat-abi=hard"} {
if { [check_no_compiler_messages_nocache arm_vfp_ok object {
#ifndef __ARM_FP
#error __ARM_FP not defined
#endif
} "$flags"] } {
set et_arm_vfp_flags $flags
return 1
}
}
}
return 0
}
proc check_effective_target_arm_vfp_ok { } {
return [check_cached_effective_target arm_vfp_ok \
check_effective_target_arm_vfp_ok_nocache]
}
# Add the options needed to compile code with -mfpu=vfp. We need either
# -mfloat-abi=softfp or -mfloat-abi=hard, but if one is already
# specified by the multilib, use it.
proc add_options_for_arm_vfp { flags } {
if { ! [check_effective_target_arm_vfp_ok] } {
return "$flags"
}
global et_arm_vfp_flags
return "$flags $et_arm_vfp_flags"
}
# Return 1 if this is an ARM target supporting -mfpu=vfp3
# -mfloat-abi=softfp.
proc check_effective_target_arm_vfp3_ok { } {
if { [check_effective_target_arm32] } {
return [check_no_compiler_messages arm_vfp3_ok object {
int dummy;
} "-mfpu=vfp3 -mfloat-abi=softfp"]
} else {
return 0
}
}
# Return 1 if this is an ARM target supporting -mfpu=fp-armv8
# -mfloat-abi=softfp.
proc check_effective_target_arm_v8_vfp_ok {} {
if { [check_effective_target_arm32] } {
return [check_no_compiler_messages arm_v8_vfp_ok object {
int foo (void)
{
__asm__ volatile ("vrinta.f32.f32 s0, s0");
return 0;
}
} "-mfpu=fp-armv8 -mfloat-abi=softfp"]
} else {
return 0
}
}
# Return 1 if this is an ARM target supporting -mfpu=vfp
# -mfloat-abi=hard. Some multilibs may be incompatible with these
# options.
proc check_effective_target_arm_hard_vfp_ok { } {
if { [check_effective_target_arm32]
&& ! [check-flags [list "" { *-*-* } { "-mfloat-abi=*" } { "-mfloat-abi=hard" }]] } {
return [check_no_compiler_messages arm_hard_vfp_ok executable {
int main() { return 0;}
} "-mfpu=vfp -mfloat-abi=hard"]
} else {
return 0
}
}
# Return 1 if this is an ARM target defining __ARM_FP. We may need
# -mfloat-abi=softfp or equivalent options. Some multilibs may be
# incompatible with these options. Also set et_arm_fp_flags to the
# best options to add.
proc check_effective_target_arm_fp_ok_nocache { } {
global et_arm_fp_flags
set et_arm_fp_flags ""
if { [check_effective_target_arm32] } {
foreach flags {"" "-mfloat-abi=softfp" "-mfloat-abi=hard"} {
if { [check_no_compiler_messages_nocache arm_fp_ok object {
#ifndef __ARM_FP
#error __ARM_FP not defined
#endif
} "$flags"] } {
set et_arm_fp_flags $flags
return 1
}
}
}
return 0
}
proc check_effective_target_arm_fp_ok { } {
return [check_cached_effective_target arm_fp_ok \
check_effective_target_arm_fp_ok_nocache]
}
# Add the options needed to define __ARM_FP. We need either
# -mfloat-abi=softfp or -mfloat-abi=hard, but if one is already
# specified by the multilib, use it.
proc add_options_for_arm_fp { flags } {
if { ! [check_effective_target_arm_fp_ok] } {
return "$flags"
}
global et_arm_fp_flags
return "$flags $et_arm_fp_flags"
}
# Return 1 if this is an ARM target that supports DSP multiply with
# current multilib flags.
proc check_effective_target_arm_dsp { } {
return [check_no_compiler_messages arm_dsp assembly {
#ifndef __ARM_FEATURE_DSP
#error not DSP
#endif
int i;
}]
}
# Return 1 if this is an ARM target that supports unaligned word/halfword
# load/store instructions.
proc check_effective_target_arm_unaligned { } {
return [check_no_compiler_messages arm_unaligned assembly {
#ifndef __ARM_FEATURE_UNALIGNED
#error no unaligned support
#endif
int i;
}]
}
# Return 1 if this is an ARM target supporting -mfpu=crypto-neon-fp-armv8
# -mfloat-abi=softfp or equivalent options. Some multilibs may be
# incompatible with these options. Also set et_arm_crypto_flags to the
# best options to add.
proc check_effective_target_arm_crypto_ok_nocache { } {
global et_arm_crypto_flags
set et_arm_crypto_flags ""
if { [check_effective_target_arm_v8_neon_ok] } {
foreach flags {"" "-mfloat-abi=softfp" "-mfpu=crypto-neon-fp-armv8" "-mfpu=crypto-neon-fp-armv8 -mfloat-abi=softfp"} {
if { [check_no_compiler_messages_nocache arm_crypto_ok object {
#include "arm_neon.h"
uint8x16_t
foo (uint8x16_t a, uint8x16_t b)
{
return vaeseq_u8 (a, b);
}
} "$flags"] } {
set et_arm_crypto_flags $flags
return 1
}
}
}
return 0
}
# Return 1 if this is an ARM target supporting -mfpu=crypto-neon-fp-armv8
proc check_effective_target_arm_crypto_ok { } {
return [check_cached_effective_target arm_crypto_ok \
check_effective_target_arm_crypto_ok_nocache]
}
# Add options for crypto extensions.
proc add_options_for_arm_crypto { flags } {
if { ! [check_effective_target_arm_crypto_ok] } {
return "$flags"
}
global et_arm_crypto_flags
return "$flags $et_arm_crypto_flags"
}
# Add the options needed for NEON. We need either -mfloat-abi=softfp
# or -mfloat-abi=hard, but if one is already specified by the
# multilib, use it. Similarly, if a -mfpu option already enables
# NEON, do not add -mfpu=neon.
proc add_options_for_arm_neon { flags } {
if { ! [check_effective_target_arm_neon_ok] } {
return "$flags"
}
global et_arm_neon_flags
return "$flags $et_arm_neon_flags"
}
proc add_options_for_arm_v8_vfp { flags } {
if { ! [check_effective_target_arm_v8_vfp_ok] } {
return "$flags"
}
return "$flags -mfpu=fp-armv8 -mfloat-abi=softfp"
}
proc add_options_for_arm_v8_neon { flags } {
if { ! [check_effective_target_arm_v8_neon_ok] } {
return "$flags"
}
global et_arm_v8_neon_flags
return "$flags $et_arm_v8_neon_flags -march=armv8-a"
}
# Add the options needed for ARMv8.1 Adv.SIMD. Also adds the ARMv8 NEON
# options for AArch64 and for ARM.
proc add_options_for_arm_v8_1a_neon { flags } {
if { ! [check_effective_target_arm_v8_1a_neon_ok] } {
return "$flags"
}
global et_arm_v8_1a_neon_flags
return "$flags $et_arm_v8_1a_neon_flags"
}
# Add the options needed for ARMv8.2 with the scalar FP16 extension.
# Also adds the ARMv8 FP options for ARM and for AArch64.
proc add_options_for_arm_v8_2a_fp16_scalar { flags } {
if { ! [check_effective_target_arm_v8_2a_fp16_scalar_ok] } {
return "$flags"
}
global et_arm_v8_2a_fp16_scalar_flags
return "$flags $et_arm_v8_2a_fp16_scalar_flags"
}
# Add the options needed for ARMv8.2 with the FP16 extension. Also adds
# the ARMv8 NEON options for ARM and for AArch64.
proc add_options_for_arm_v8_2a_fp16_neon { flags } {
if { ! [check_effective_target_arm_v8_2a_fp16_neon_ok] } {
return "$flags"
}
global et_arm_v8_2a_fp16_neon_flags
return "$flags $et_arm_v8_2a_fp16_neon_flags"
}
proc add_options_for_arm_crc { flags } {
if { ! [check_effective_target_arm_crc_ok] } {
return "$flags"
}
global et_arm_crc_flags
return "$flags $et_arm_crc_flags"
}
# Add the options needed for NEON. We need either -mfloat-abi=softfp
# or -mfloat-abi=hard, but if one is already specified by the
# multilib, use it. Similarly, if a -mfpu option already enables
# NEON, do not add -mfpu=neon.
proc add_options_for_arm_neonv2 { flags } {
if { ! [check_effective_target_arm_neonv2_ok] } {
return "$flags"
}
global et_arm_neonv2_flags
return "$flags $et_arm_neonv2_flags"
}
# Add the options needed for vfp3.
proc add_options_for_arm_vfp3 { flags } {
if { ! [check_effective_target_arm_vfp3_ok] } {
return "$flags"
}
return "$flags -mfpu=vfp3 -mfloat-abi=softfp"
}
# Return 1 if this is an ARM target supporting -mfpu=neon
# -mfloat-abi=softfp or equivalent options. Some multilibs may be
# incompatible with these options. Also set et_arm_neon_flags to the
# best options to add.
proc check_effective_target_arm_neon_ok_nocache { } {
global et_arm_neon_flags
set et_arm_neon_flags ""
if { [check_effective_target_arm32] } {
foreach flags {"" "-mfloat-abi=softfp" "-mfpu=neon" "-mfpu=neon -mfloat-abi=softfp" "-mfpu=neon -mfloat-abi=softfp -march=armv7-a" "-mfloat-abi=hard" "-mfpu=neon -mfloat-abi=hard" "-mfpu=neon -mfloat-abi=hard -march=armv7-a"} {
if { [check_no_compiler_messages_nocache arm_neon_ok object {
#include <arm_neon.h>
int dummy;
#ifndef __ARM_NEON__
#error not NEON
#endif
/* Avoid the case where a test adds -mfpu=neon, but the toolchain is
configured for -mcpu=arm926ej-s, for example. */
#if __ARM_ARCH < 7 || __ARM_ARCH_PROFILE == 'M'
#error Architecture does not support NEON.
#endif
} "$flags"] } {
set et_arm_neon_flags $flags
return 1
}
}
}
return 0
}
proc check_effective_target_arm_neon_ok { } {
return [check_cached_effective_target arm_neon_ok \
check_effective_target_arm_neon_ok_nocache]
}
# Return 1 if this is an ARM target supporting the SIMD32 intrinsics
# from arm_acle.h. Some multilibs may be incompatible with these options.
# Also set et_arm_simd32_flags to the best options to add.
# arm_acle.h includes stdint.h which can cause trouble with incompatible
# -mfloat-abi= options.
proc check_effective_target_arm_simd32_ok_nocache { } {
global et_arm_simd32_flags
set et_arm_simd32_flags ""
foreach flags {"" "-march=armv6" "-march=armv6 -mfloat-abi=softfp" "-march=armv6 -mfloat-abi=hard"} {
if { [check_no_compiler_messages_nocache arm_simd32_ok object {
#include <arm_acle.h>
int dummy;
#ifndef __ARM_FEATURE_SIMD32
#error not SIMD32
#endif
} "$flags"] } {
set et_arm_simd32_flags $flags
return 1
}
}
return 0
}
proc check_effective_target_arm_simd32_ok { } {
return [check_cached_effective_target arm_simd32_ok \
check_effective_target_arm_simd32_ok_nocache]
}
proc add_options_for_arm_simd32 { flags } {
if { ! [check_effective_target_arm_simd32_ok] } {
return "$flags"
}
global et_arm_simd32_flags
return "$flags $et_arm_simd32_flags"
}
# Return 1 if this is an ARM target supporting the saturation intrinsics
# from arm_acle.h. Some multilibs may be incompatible with these options.
# Also set et_arm_qbit_flags to the best options to add.
# arm_acle.h includes stdint.h which can cause trouble with incompatible
# -mfloat-abi= options.
proc check_effective_target_arm_qbit_ok_nocache { } {
global et_arm_qbit_flags
set et_arm_qbit_flags ""
foreach flags {"" "-march=armv5te" "-march=armv5te -mfloat-abi=softfp" "-march=armv5te -mfloat-abi=hard"} {
if { [check_no_compiler_messages_nocache et_arm_qbit_flags object {
#include <arm_acle.h>
int dummy;
#ifndef __ARM_FEATURE_QBIT
#error not QBIT
#endif
} "$flags"] } {
set et_arm_qbit_flags $flags
return 1
}
}
return 0
}
proc check_effective_target_arm_qbit_ok { } {
return [check_cached_effective_target et_arm_qbit_flags \
check_effective_target_arm_qbit_ok_nocache]
}
proc add_options_for_arm_qbit { flags } {
if { ! [check_effective_target_arm_qbit_ok] } {
return "$flags"
}
global et_arm_qbit_flags
return "$flags $et_arm_qbit_flags"
}
# Return 1 if this is an ARM target supporting -mfpu=neon without any
# -mfloat-abi= option. Useful in tests where add_options is not
# supported (such as lto tests).
proc check_effective_target_arm_neon_ok_no_float_abi_nocache { } {
if { [check_effective_target_arm32] } {
foreach flags {"-mfpu=neon"} {
if { [check_no_compiler_messages_nocache arm_neon_ok_no_float_abi object {
#include <arm_neon.h>
int dummy;
#ifndef __ARM_NEON__
#error not NEON
#endif
/* Avoid the case where a test adds -mfpu=neon, but the toolchain is
configured for -mcpu=arm926ej-s, for example. */
#if __ARM_ARCH < 7 || __ARM_ARCH_PROFILE == 'M'
#error Architecture does not support NEON.
#endif
} "$flags"] } {
return 1
}
}
}
return 0
}
proc check_effective_target_arm_neon_ok_no_float_abi { } {
return [check_cached_effective_target arm_neon_ok_no_float_abi \
check_effective_target_arm_neon_ok_no_float_abi_nocache]
}
proc check_effective_target_arm_crc_ok_nocache { } {
global et_arm_crc_flags
set et_arm_crc_flags "-march=armv8-a+crc"
return [check_no_compiler_messages_nocache arm_crc_ok object {
#if !defined (__ARM_FEATURE_CRC32)
#error FOO
#endif
} "$et_arm_crc_flags"]
}
proc check_effective_target_arm_crc_ok { } {
return [check_cached_effective_target arm_crc_ok \
check_effective_target_arm_crc_ok_nocache]
}
# Return 1 if this is an ARM target supporting -mfpu=neon-fp16
# -mfloat-abi=softfp or equivalent options. Some multilibs may be
# incompatible with these options. Also set et_arm_neon_fp16_flags to
# the best options to add.
proc check_effective_target_arm_neon_fp16_ok_nocache { } {
global et_arm_neon_fp16_flags
global et_arm_neon_flags
set et_arm_neon_fp16_flags ""
if { [check_effective_target_arm32]
&& [check_effective_target_arm_neon_ok] } {
foreach flags {"" "-mfloat-abi=softfp" "-mfpu=neon-fp16"
"-mfpu=neon-fp16 -mfloat-abi=softfp"
"-mfp16-format=ieee"
"-mfloat-abi=softfp -mfp16-format=ieee"
"-mfpu=neon-fp16 -mfp16-format=ieee"
"-mfpu=neon-fp16 -mfloat-abi=softfp -mfp16-format=ieee"} {
if { [check_no_compiler_messages_nocache arm_neon_fp16_ok object {
#include "arm_neon.h"
float16x4_t
foo (float32x4_t arg)
{
return vcvt_f16_f32 (arg);
}
} "$et_arm_neon_flags $flags"] } {
set et_arm_neon_fp16_flags [concat $et_arm_neon_flags $flags]
return 1
}
}
}
return 0
}
proc check_effective_target_arm_neon_fp16_ok { } {
return [check_cached_effective_target arm_neon_fp16_ok \
check_effective_target_arm_neon_fp16_ok_nocache]
}
# Return 1 if this is an ARM target supporting -mfpu=neon-fp16
# and -mfloat-abi=softfp together. Some multilibs may be
# incompatible with these options. Also set et_arm_neon_softfp_fp16_flags to
# the best options to add.
proc check_effective_target_arm_neon_softfp_fp16_ok_nocache { } {
global et_arm_neon_softfp_fp16_flags
global et_arm_neon_flags
set et_arm_neon_softfp_fp16_flags ""
if { [check_effective_target_arm32]
&& [check_effective_target_arm_neon_ok] } {
foreach flags {"-mfpu=neon-fp16 -mfloat-abi=softfp"
"-mfpu=neon-fp16 -mfloat-abi=softfp -mfp16-format=ieee"} {
if { [check_no_compiler_messages_nocache arm_neon_softfp_fp16_ok object {
#include "arm_neon.h"
float16x4_t
foo (float32x4_t arg)
{
return vcvt_f16_f32 (arg);
}
} "$et_arm_neon_flags $flags"] } {
set et_arm_neon_softfp_fp16_flags [concat $et_arm_neon_flags $flags]
return 1
}
}
}
return 0
}
proc check_effective_target_arm_neon_softfp_fp16_ok { } {
return [check_cached_effective_target arm_neon_softfp_fp16_ok \
check_effective_target_arm_neon_softfp_fp16_ok_nocache]
}
proc check_effective_target_arm_neon_fp16_hw { } {
if {! [check_effective_target_arm_neon_fp16_ok] } {
return 0
}
global et_arm_neon_fp16_flags
check_runtime arm_neon_fp16_hw {
int
main (int argc, char **argv)
{
asm ("vcvt.f32.f16 q1, d0");
return 0;
}
} $et_arm_neon_fp16_flags
}
proc add_options_for_arm_neon_fp16 { flags } {
if { ! [check_effective_target_arm_neon_fp16_ok] } {
return "$flags"
}
global et_arm_neon_fp16_flags
return "$flags $et_arm_neon_fp16_flags"
}
proc add_options_for_arm_neon_softfp_fp16 { flags } {
if { ! [check_effective_target_arm_neon_softfp_fp16_ok] } {
return "$flags"
}
global et_arm_neon_softfp_fp16_flags
return "$flags $et_arm_neon_softfp_fp16_flags"
}
proc add_options_for_aarch64_sve { flags } {
if { ![istarget aarch64*-*-*] || [check_effective_target_aarch64_sve] } {
return "$flags"
}
return "$flags -march=armv8.2-a+sve"
}
# Return 1 if this is an ARM target supporting the FP16 alternative
# format. Some multilibs may be incompatible with the options needed. Also
# set et_arm_neon_fp16_flags to the best options to add.
proc check_effective_target_arm_fp16_alternative_ok_nocache { } {
global et_arm_neon_fp16_flags
set et_arm_neon_fp16_flags ""
if { [check_effective_target_arm32] } {
foreach flags {"" "-mfloat-abi=softfp" "-mfpu=neon-fp16"
"-mfpu=neon-fp16 -mfloat-abi=softfp"} {
if { [check_no_compiler_messages_nocache \
arm_fp16_alternative_ok object {
#if !defined (__ARM_FP16_FORMAT_ALTERNATIVE)
#error __ARM_FP16_FORMAT_ALTERNATIVE not defined
#endif
} "$flags -mfp16-format=alternative"] } {
set et_arm_neon_fp16_flags "$flags -mfp16-format=alternative"
return 1
}
}
}
return 0
}
proc check_effective_target_arm_fp16_alternative_ok { } {
return [check_cached_effective_target arm_fp16_alternative_ok \
check_effective_target_arm_fp16_alternative_ok_nocache]
}
# Return 1 if this is an ARM target supports specifying the FP16 none
# format. Some multilibs may be incompatible with the options needed.
proc check_effective_target_arm_fp16_none_ok_nocache { } {
if { [check_effective_target_arm32] } {
foreach flags {"" "-mfloat-abi=softfp" "-mfpu=neon-fp16"
"-mfpu=neon-fp16 -mfloat-abi=softfp"} {
if { [check_no_compiler_messages_nocache \
arm_fp16_none_ok object {
#if defined (__ARM_FP16_FORMAT_ALTERNATIVE)
#error __ARM_FP16_FORMAT_ALTERNATIVE defined
#endif
#if defined (__ARM_FP16_FORMAT_IEEE)
#error __ARM_FP16_FORMAT_IEEE defined
#endif
} "$flags -mfp16-format=none"] } {
return 1
}
}
}
return 0
}
proc check_effective_target_arm_fp16_none_ok { } {
return [check_cached_effective_target arm_fp16_none_ok \
check_effective_target_arm_fp16_none_ok_nocache]
}
# Return 1 if this is an ARM target supporting -mfpu=neon-fp-armv8
# -mfloat-abi=softfp or equivalent options. Some multilibs may be
# incompatible with these options. Also set et_arm_v8_neon_flags to the
# best options to add.
proc check_effective_target_arm_v8_neon_ok_nocache { } {
global et_arm_v8_neon_flags
set et_arm_v8_neon_flags ""
if { [check_effective_target_arm32] } {
foreach flags {"" "-mfloat-abi=softfp" "-mfpu=neon-fp-armv8" "-mfpu=neon-fp-armv8 -mfloat-abi=softfp"} {
if { [check_no_compiler_messages_nocache arm_v8_neon_ok object {
#if __ARM_ARCH < 8
#error not armv8 or later
#endif
#include "arm_neon.h"
void
foo ()
{
__asm__ volatile ("vrintn.f32 q0, q0");
}
} "$flags -march=armv8-a"] } {
set et_arm_v8_neon_flags $flags
return 1
}
}
}
return 0
}
proc check_effective_target_arm_v8_neon_ok { } {
return [check_cached_effective_target arm_v8_neon_ok \
check_effective_target_arm_v8_neon_ok_nocache]
}
# Return 1 if this is an ARM target supporting -mfpu=neon-vfpv4
# -mfloat-abi=softfp or equivalent options. Some multilibs may be
# incompatible with these options. Also set et_arm_neonv2_flags to the
# best options to add.
proc check_effective_target_arm_neonv2_ok_nocache { } {
global et_arm_neonv2_flags
global et_arm_neon_flags
set et_arm_neonv2_flags ""
if { [check_effective_target_arm32]
&& [check_effective_target_arm_neon_ok] } {
foreach flags {"" "-mfloat-abi=softfp" "-mfpu=neon-vfpv4" "-mfpu=neon-vfpv4 -mfloat-abi=softfp"} {
if { [check_no_compiler_messages_nocache arm_neonv2_ok object {
#include "arm_neon.h"
float32x2_t
foo (float32x2_t a, float32x2_t b, float32x2_t c)
{
return vfma_f32 (a, b, c);
}
} "$et_arm_neon_flags $flags"] } {
set et_arm_neonv2_flags [concat $et_arm_neon_flags $flags]
return 1
}
}
}
return 0
}
proc check_effective_target_arm_neonv2_ok { } {
return [check_cached_effective_target arm_neonv2_ok \
check_effective_target_arm_neonv2_ok_nocache]
}
# Add the options needed for VFP FP16 support. We need either
# -mfloat-abi=softfp or -mfloat-abi=hard. If one is already specified by
# the multilib, use it.
proc add_options_for_arm_fp16 { flags } {
if { ! [check_effective_target_arm_fp16_ok] } {
return "$flags"
}
global et_arm_fp16_flags
return "$flags $et_arm_fp16_flags"
}
# Add the options needed to enable support for IEEE format
# half-precision support. This is valid for ARM targets.
proc add_options_for_arm_fp16_ieee { flags } {
if { ! [check_effective_target_arm_fp16_ok] } {
return "$flags"
}
global et_arm_fp16_flags
return "$flags $et_arm_fp16_flags -mfp16-format=ieee"
}
# Add the options needed to enable support for ARM Alternative format
# half-precision support. This is valid for ARM targets.
proc add_options_for_arm_fp16_alternative { flags } {
if { ! [check_effective_target_arm_fp16_ok] } {
return "$flags"
}
global et_arm_fp16_flags
return "$flags $et_arm_fp16_flags -mfp16-format=alternative"
}
# Return 1 if this is an ARM target that can support a VFP fp16 variant.
# Skip multilibs that are incompatible with these options and set
# et_arm_fp16_flags to the best options to add. This test is valid for
# ARM only.
proc check_effective_target_arm_fp16_ok_nocache { } {
global et_arm_fp16_flags
set et_arm_fp16_flags ""
if { ! [check_effective_target_arm32] } {
return 0;
}
if [check-flags \
[list "" { *-*-* } { "-mfpu=*" } \
{ "-mfpu=*fp16*" "-mfpu=*fpv[4-9]*" \
"-mfpu=*fpv[1-9][0-9]*" "-mfpu=*fp-armv8*" } ]] {
# Multilib flags would override -mfpu.
return 0
}
if [check-flags [list "" { *-*-* } { "-mfloat-abi=soft" } { "" } ]] {
# Must generate floating-point instructions.
return 0
}
if [check_effective_target_arm_hf_eabi] {
# Use existing float-abi and force an fpu which supports fp16
set et_arm_fp16_flags "-mfpu=vfpv4"
return 1;
}
if [check-flags [list "" { *-*-* } { "-mfpu=*" } { "" } ]] {
# The existing -mfpu value is OK; use it, but add softfp.
set et_arm_fp16_flags "-mfloat-abi=softfp"
return 1;
}
# Add -mfpu for a VFP fp16 variant since there is no preprocessor
# macro to check for this support.
set flags "-mfpu=vfpv4 -mfloat-abi=softfp"
if { [check_no_compiler_messages_nocache arm_fp16_ok assembly {
int dummy;
} "$flags"] } {
set et_arm_fp16_flags "$flags"
return 1
}
return 0
}
proc check_effective_target_arm_fp16_ok { } {
return [check_cached_effective_target arm_fp16_ok \
check_effective_target_arm_fp16_ok_nocache]
}
# Return 1 if the target supports executing VFP FP16 instructions, 0
# otherwise. This test is valid for ARM only.
proc check_effective_target_arm_fp16_hw { } {
if {! [check_effective_target_arm_fp16_ok] } {
return 0
}
global et_arm_fp16_flags
check_runtime arm_fp16_hw {
int
main (int argc, char **argv)
{
__fp16 a = 1.0;
float r;
asm ("vcvtb.f32.f16 %0, %1"
: "=w" (r) : "w" (a)
: /* No clobbers. */);
return (r == 1.0) ? 0 : 1;
}
} "$et_arm_fp16_flags -mfp16-format=ieee"
}
# Creates a series of routines that return 1 if the given architecture
# can be selected and a routine to give the flags to select that architecture
# Note: Extra flags may be added to disable options from newer compilers
# (Thumb in particular - but others may be added in the future).
# Warning: Do not use check_effective_target_arm_arch_*_ok for architecture
# extension (eg. ARMv8.1-A) since there is no macro defined for them. See
# how only __ARM_ARCH_8A__ is checked for ARMv8.1-A.
# Usage: /* { dg-require-effective-target arm_arch_v5_ok } */
# /* { dg-add-options arm_arch_v5t } */
# /* { dg-require-effective-target arm_arch_v5t_multilib } */
foreach { armfunc armflag armdefs } {
v4 "-march=armv4 -marm" __ARM_ARCH_4__
v4t "-march=armv4t -mfloat-abi=softfp" __ARM_ARCH_4T__
v4t_arm "-march=armv4t -marm" __ARM_ARCH_4T__
v4t_thumb "-march=armv4t -mthumb -mfloat-abi=softfp" __ARM_ARCH_4T__
v5t "-march=armv5t -mfloat-abi=softfp" __ARM_ARCH_5T__
v5t_arm "-march=armv5t -marm" __ARM_ARCH_5T__
v5t_thumb "-march=armv5t -mthumb -mfloat-abi=softfp" __ARM_ARCH_5T__
v5te "-march=armv5te -mfloat-abi=softfp" __ARM_ARCH_5TE__
v5te_arm "-march=armv5te -marm" __ARM_ARCH_5TE__
v5te_thumb "-march=armv5te -mthumb -mfloat-abi=softfp" __ARM_ARCH_5TE__
v6 "-march=armv6 -mfloat-abi=softfp" __ARM_ARCH_6__
v6_arm "-march=armv6 -marm" __ARM_ARCH_6__
v6_thumb "-march=armv6 -mthumb -mfloat-abi=softfp" __ARM_ARCH_6__
v6k "-march=armv6k -mfloat-abi=softfp" __ARM_ARCH_6K__
v6k_arm "-march=armv6k -marm" __ARM_ARCH_6K__
v6k_thumb "-march=armv6k -mthumb -mfloat-abi=softfp" __ARM_ARCH_6K__
v6t2 "-march=armv6t2" __ARM_ARCH_6T2__
v6z "-march=armv6z -mfloat-abi=softfp" __ARM_ARCH_6Z__
v6z_arm "-march=armv6z -marm" __ARM_ARCH_6Z__
v6z_thumb "-march=armv6z -mthumb -mfloat-abi=softfp" __ARM_ARCH_6Z__
v6m "-march=armv6-m -mthumb -mfloat-abi=soft" __ARM_ARCH_6M__
v7a "-march=armv7-a" __ARM_ARCH_7A__
v7r "-march=armv7-r" __ARM_ARCH_7R__
v7m "-march=armv7-m -mthumb" __ARM_ARCH_7M__
v7em "-march=armv7e-m -mthumb" __ARM_ARCH_7EM__
v7ve "-march=armv7ve -marm"
"__ARM_ARCH_7A__ && __ARM_FEATURE_IDIV"
v8a "-march=armv8-a" __ARM_ARCH_8A__
v8_1a "-march=armv8.1-a" __ARM_ARCH_8A__
v8_2a "-march=armv8.2-a" __ARM_ARCH_8A__
v8m_base "-march=armv8-m.base -mthumb -mfloat-abi=soft"
__ARM_ARCH_8M_BASE__
v8m_main "-march=armv8-m.main -mthumb" __ARM_ARCH_8M_MAIN__
v8r "-march=armv8-r" __ARM_ARCH_8R__ } {
eval [string map [list FUNC $armfunc FLAG $armflag DEFS $armdefs ] {
proc check_effective_target_arm_arch_FUNC_ok { } {
return [check_no_compiler_messages arm_arch_FUNC_ok assembly {
#if !(DEFS)
#error !(DEFS)
#endif
int
main (void)
{
return 0;
}
} "FLAG" ]
}
proc add_options_for_arm_arch_FUNC { flags } {
return "$flags FLAG"
}
proc check_effective_target_arm_arch_FUNC_multilib { } {
return [check_runtime arm_arch_FUNC_multilib {
int
main (void)
{
return 0;
}
} [add_options_for_arm_arch_FUNC ""]]
}
}]
}
# Return 1 if GCC was configured with --with-mode=
proc check_effective_target_default_mode { } {
return [check_configured_with "with-mode="]
}
# Return 1 if this is an ARM target where -marm causes ARM to be
# used (not Thumb)
proc check_effective_target_arm_arm_ok { } {
return [check_no_compiler_messages arm_arm_ok assembly {
#if !defined (__arm__) || defined (__thumb__) || defined (__thumb2__)
#error !__arm__ || __thumb__ || __thumb2__
#endif
} "-marm"]
}
# Return 1 is this is an ARM target where -mthumb causes Thumb-1 to be
# used.
proc check_effective_target_arm_thumb1_ok { } {
return [check_no_compiler_messages arm_thumb1_ok assembly {
#if !defined(__arm__) || !defined(__thumb__) || defined(__thumb2__)
#error !__arm__ || !__thumb__ || __thumb2__
#endif
int foo (int i) { return i; }
} "-mthumb"]
}
# Return 1 is this is an ARM target where -mthumb causes Thumb-2 to be
# used.
proc check_effective_target_arm_thumb2_ok { } {
return [check_no_compiler_messages arm_thumb2_ok assembly {
#if !defined(__thumb2__)
#error !__thumb2__
#endif
int foo (int i) { return i; }
} "-mthumb"]
}
# Return 1 if this is an ARM target where Thumb-1 is used without options
# added by the test.
proc check_effective_target_arm_thumb1 { } {
return [check_no_compiler_messages arm_thumb1 assembly {
#if !defined(__arm__) || !defined(__thumb__) || defined(__thumb2__)
#error !__arm__ || !__thumb__ || __thumb2__
#endif
int i;
} ""]
}
# Return 1 if this is an ARM target where Thumb-2 is used without options
# added by the test.
proc check_effective_target_arm_thumb2 { } {
return [check_no_compiler_messages arm_thumb2 assembly {
#if !defined(__thumb2__)
#error !__thumb2__
#endif
int i;
} ""]
}
# Return 1 if this is an ARM target where conditional execution is available.
proc check_effective_target_arm_cond_exec { } {
return [check_no_compiler_messages arm_cond_exec assembly {
#if defined(__arm__) && defined(__thumb__) && !defined(__thumb2__)
#error FOO
#endif
int i;
} ""]
}
# Return 1 if this is an ARM cortex-M profile cpu
proc check_effective_target_arm_cortex_m { } {
if { ![istarget arm*-*-*] } {
return 0
}
return [check_no_compiler_messages arm_cortex_m assembly {
#if defined(__ARM_ARCH_ISA_ARM)
#error __ARM_ARCH_ISA_ARM is defined
#endif
int i;
} "-mthumb"]
}
# Return 1 if this is an ARM target where -mthumb causes Thumb-1 to be
# used and MOVT/MOVW instructions to be available.
proc check_effective_target_arm_thumb1_movt_ok {} {
if [check_effective_target_arm_thumb1_ok] {
return [check_no_compiler_messages arm_movt object {
int
foo (void)
{
asm ("movt r0, #42");
}
} "-mthumb"]
} else {
return 0
}
}
# Return 1 if this is an ARM target where -mthumb causes Thumb-1 to be
# used and CBZ and CBNZ instructions are available.
proc check_effective_target_arm_thumb1_cbz_ok {} {
if [check_effective_target_arm_thumb1_ok] {
return [check_no_compiler_messages arm_movt object {
int
foo (void)
{
asm ("cbz r0, 2f\n2:");
}
} "-mthumb"]
} else {
return 0
}
}
# Return 1 if this is an ARM target where ARMv8-M Security Extensions is
# available.
proc check_effective_target_arm_cmse_ok {} {
return [check_no_compiler_messages arm_cmse object {
int
foo (void)
{
asm ("bxns r0");
}
} "-mcmse"];
}
# Return 1 if this compilation turns on string_ops_prefer_neon on.
proc check_effective_target_arm_tune_string_ops_prefer_neon { } {
return [check_no_messages_and_pattern arm_tune_string_ops_prefer_neon "@string_ops_prefer_neon:\t1" assembly {
int foo (void) { return 0; }
} "-O2 -mprint-tune-info" ]
}
# Return 1 if the target supports executing NEON instructions, 0
# otherwise. Cache the result.
proc check_effective_target_arm_neon_hw { } {
return [check_runtime arm_neon_hw_available {
int
main (void)
{
long long a = 0, b = 1;
asm ("vorr %P0, %P1, %P2"
: "=w" (a)
: "0" (a), "w" (b));
return (a != 1);
}
} [add_options_for_arm_neon ""]]
}
# Return true if this is an AArch64 target that can run SVE code.
proc check_effective_target_aarch64_sve_hw { } {
if { ![istarget aarch64*-*-*] } {
return 0
}
return [check_runtime aarch64_sve_hw_available {
int
main (void)
{
asm volatile ("ptrue p0.b");
return 0;
}
} [add_options_for_aarch64_sve ""]]
}
# Return true if this is an AArch64 target that can run SVE2 code.
proc check_effective_target_aarch64_sve2_hw { } {
if { ![istarget aarch64*-*-*] } {
return 0
}
return [check_runtime aarch64_sve2_hw_available {
int
main (void)
{
asm volatile ("addp z0.b, p0/m, z0.b, z1.b");
return 0;
}
}]
}
# Return true if this is an AArch64 target that can run SVE code and
# if its SVE vectors have exactly BITS bits.
proc aarch64_sve_hw_bits { bits } {
if { ![check_effective_target_aarch64_sve_hw] } {
return 0
}
return [check_runtime aarch64_sve${bits}_hw [subst {
int
main (void)
{
int res;
asm volatile ("cntd %0" : "=r" (res));
if (res * 64 != $bits)
__builtin_abort ();
return 0;
}
}] [add_options_for_aarch64_sve ""]]
}
# Return true if this is an AArch64 target that can run SVE code and
# if its SVE vectors have exactly 256 bits.
proc check_effective_target_aarch64_sve256_hw { } {
return [aarch64_sve_hw_bits 256]
}
proc check_effective_target_arm_neonv2_hw { } {
return [check_runtime arm_neon_hwv2_available {
#include "arm_neon.h"
int
main (void)
{
float32x2_t a, b, c;
asm ("vfma.f32 %P0, %P1, %P2"
: "=w" (a)
: "w" (b), "w" (c));
return 0;
}
} [add_options_for_arm_neonv2 ""]]
}
# ID_AA64PFR1_EL1.BT using bits[3:0] == 1 implies BTI implimented.
proc check_effective_target_aarch64_bti_hw { } {
if { ![istarget aarch64*-*-*] } {
return 0
}
return [check_runtime aarch64_bti_hw_available {
int
main (void)
{
int a;
asm volatile ("mrs %0, id_aa64pfr1_el1" : "=r" (a));
return !((a & 0xf) == 1);
}
} "-O2" ]
}
# Return 1 if GCC was configured with --enable-standard-branch-protection
proc check_effective_target_default_branch_protection { } {
return [check_configured_with "enable-standard-branch-protection"]
}
# Return 1 if the target supports the ARMv8.1 Adv.SIMD extension, 0
# otherwise. The test is valid for AArch64 and ARM. Record the command
# line options needed.
proc check_effective_target_arm_v8_1a_neon_ok_nocache { } {
global et_arm_v8_1a_neon_flags
set et_arm_v8_1a_neon_flags ""
if { ![istarget arm*-*-*] && ![istarget aarch64*-*-*] } {
return 0;
}
# Iterate through sets of options to find the compiler flags that
# need to be added to the -march option. Start with the empty set
# since AArch64 only needs the -march setting.
foreach flags {"" "-mfpu=neon-fp-armv8" "-mfloat-abi=softfp" \
"-mfpu=neon-fp-armv8 -mfloat-abi=softfp"} {
foreach arches { "-march=armv8-a+rdma" "-march=armv8.1-a" } {
if { [check_no_compiler_messages_nocache arm_v8_1a_neon_ok object {
#if !defined (__ARM_FEATURE_QRDMX)
#error "__ARM_FEATURE_QRDMX not defined"
#endif
} "$flags $arches"] } {
set et_arm_v8_1a_neon_flags "$flags $arches"
return 1
}
}
}
return 0;
}
proc check_effective_target_arm_v8_1a_neon_ok { } {
return [check_cached_effective_target arm_v8_1a_neon_ok \
check_effective_target_arm_v8_1a_neon_ok_nocache]
}
# Return 1 if the target supports ARMv8.2 scalar FP16 arithmetic
# instructions, 0 otherwise. The test is valid for ARM and for AArch64.
# Record the command line options needed.
proc check_effective_target_arm_v8_2a_fp16_scalar_ok_nocache { } {
global et_arm_v8_2a_fp16_scalar_flags
set et_arm_v8_2a_fp16_scalar_flags ""
if { ![istarget arm*-*-*] && ![istarget aarch64*-*-*] } {
return 0;
}
# Iterate through sets of options to find the compiler flags that
# need to be added to the -march option.
foreach flags {"" "-mfpu=fp-armv8" "-mfloat-abi=softfp" \
"-mfpu=fp-armv8 -mfloat-abi=softfp"} {
if { [check_no_compiler_messages_nocache \
arm_v8_2a_fp16_scalar_ok object {
#if !defined (__ARM_FEATURE_FP16_SCALAR_ARITHMETIC)
#error "__ARM_FEATURE_FP16_SCALAR_ARITHMETIC not defined"
#endif
} "$flags -march=armv8.2-a+fp16"] } {
set et_arm_v8_2a_fp16_scalar_flags "$flags -march=armv8.2-a+fp16"
return 1
}
}
return 0;
}
proc check_effective_target_arm_v8_2a_fp16_scalar_ok { } {
return [check_cached_effective_target arm_v8_2a_fp16_scalar_ok \
check_effective_target_arm_v8_2a_fp16_scalar_ok_nocache]
}
# Return 1 if the target supports ARMv8.2 Adv.SIMD FP16 arithmetic
# instructions, 0 otherwise. The test is valid for ARM and for AArch64.
# Record the command line options needed.
proc check_effective_target_arm_v8_2a_fp16_neon_ok_nocache { } {
global et_arm_v8_2a_fp16_neon_flags
set et_arm_v8_2a_fp16_neon_flags ""
if { ![istarget arm*-*-*] && ![istarget aarch64*-*-*] } {
return 0;
}
# Iterate through sets of options to find the compiler flags that
# need to be added to the -march option.
foreach flags {"" "-mfpu=neon-fp-armv8" "-mfloat-abi=softfp" \
"-mfpu=neon-fp-armv8 -mfloat-abi=softfp"} {
if { [check_no_compiler_messages_nocache \
arm_v8_2a_fp16_neon_ok object {
#if !defined (__ARM_FEATURE_FP16_VECTOR_ARITHMETIC)
#error "__ARM_FEATURE_FP16_VECTOR_ARITHMETIC not defined"
#endif
} "$flags -march=armv8.2-a+fp16"] } {
set et_arm_v8_2a_fp16_neon_flags "$flags -march=armv8.2-a+fp16"
return 1
}
}
return 0;
}
proc check_effective_target_arm_v8_2a_fp16_neon_ok { } {
return [check_cached_effective_target arm_v8_2a_fp16_neon_ok \
check_effective_target_arm_v8_2a_fp16_neon_ok_nocache]
}
# Return 1 if the target supports ARMv8.2 Adv.SIMD Dot Product
# instructions, 0 otherwise. The test is valid for ARM and for AArch64.
# Record the command line options needed.
proc check_effective_target_arm_v8_2a_dotprod_neon_ok_nocache { } {
global et_arm_v8_2a_dotprod_neon_flags
set et_arm_v8_2a_dotprod_neon_flags ""
if { ![istarget arm*-*-*] && ![istarget aarch64*-*-*] } {
return 0;
}
# Iterate through sets of options to find the compiler flags that
# need to be added to the -march option.
foreach flags {"" "-mfloat-abi=softfp -mfpu=neon-fp-armv8" "-mfloat-abi=hard -mfpu=neon-fp-armv8"} {
if { [check_no_compiler_messages_nocache \
arm_v8_2a_dotprod_neon_ok object {
#include <stdint.h>
#if !defined (__ARM_FEATURE_DOTPROD)
#error "__ARM_FEATURE_DOTPROD not defined"
#endif
} "$flags -march=armv8.2-a+dotprod"] } {
set et_arm_v8_2a_dotprod_neon_flags "$flags -march=armv8.2-a+dotprod"
return 1
}
}
return 0;
}
proc check_effective_target_arm_v8_2a_dotprod_neon_ok { } {
return [check_cached_effective_target arm_v8_2a_dotprod_neon_ok \
check_effective_target_arm_v8_2a_dotprod_neon_ok_nocache]
}
proc add_options_for_arm_v8_2a_dotprod_neon { flags } {
if { ! [check_effective_target_arm_v8_2a_dotprod_neon_ok] } {
return "$flags"
}
global et_arm_v8_2a_dotprod_neon_flags
return "$flags $et_arm_v8_2a_dotprod_neon_flags"
}
# Return 1 if the target supports FP16 VFMAL and VFMSL
# instructions, 0 otherwise.
# Record the command line options needed.
proc check_effective_target_arm_fp16fml_neon_ok_nocache { } {
global et_arm_fp16fml_neon_flags
set et_arm_fp16fml_neon_flags ""
if { ![istarget arm*-*-*] } {
return 0;
}
# Iterate through sets of options to find the compiler flags that
# need to be added to the -march option.
foreach flags {"" "-mfloat-abi=softfp -mfpu=neon-fp-armv8" "-mfloat-abi=hard -mfpu=neon-fp-armv8"} {
if { [check_no_compiler_messages_nocache \
arm_fp16fml_neon_ok assembly {
#include <arm_neon.h>
float32x2_t
foo (float32x2_t r, float16x4_t a, float16x4_t b)
{
return vfmlal_high_f16 (r, a, b);
}
} "$flags -march=armv8.2-a+fp16fml"] } {
set et_arm_fp16fml_neon_flags "$flags -march=armv8.2-a+fp16fml"
return 1
}
}
return 0;
}
proc check_effective_target_arm_fp16fml_neon_ok { } {
return [check_cached_effective_target arm_fp16fml_neon_ok \
check_effective_target_arm_fp16fml_neon_ok_nocache]
}
proc add_options_for_arm_fp16fml_neon { flags } {
if { ! [check_effective_target_arm_fp16fml_neon_ok] } {
return "$flags"
}
global et_arm_fp16fml_neon_flags
return "$flags $et_arm_fp16fml_neon_flags"
}
# Return 1 if the target supports executing ARMv8 NEON instructions, 0
# otherwise.
proc check_effective_target_arm_v8_neon_hw { } {
return [check_runtime arm_v8_neon_hw_available {
#include "arm_neon.h"
int
main (void)
{
float32x2_t a = { 1.0f, 2.0f };
#ifdef __ARM_ARCH_ISA_A64
asm ("frinta %0.2s, %1.2s"
: "=w" (a)
: "w" (a));
#else
asm ("vrinta.f32 %P0, %P1"
: "=w" (a)
: "0" (a));
#endif
return a[0] == 2.0f;
}
} [add_options_for_arm_v8_neon ""]]
}
# Return 1 if the target supports executing the ARMv8.1 Adv.SIMD extension, 0
# otherwise. The test is valid for AArch64 and ARM.
proc check_effective_target_arm_v8_1a_neon_hw { } {
if { ![check_effective_target_arm_v8_1a_neon_ok] } {
return 0;
}
return [check_runtime arm_v8_1a_neon_hw_available {
int
main (void)
{
#ifdef __ARM_ARCH_ISA_A64
__Int32x2_t a = {0, 1};
__Int32x2_t b = {0, 2};
__Int32x2_t result;
asm ("sqrdmlah %0.2s, %1.2s, %2.2s"
: "=w"(result)
: "w"(a), "w"(b)
: /* No clobbers. */);
#else
__simd64_int32_t a = {0, 1};
__simd64_int32_t b = {0, 2};
__simd64_int32_t result;
asm ("vqrdmlah.s32 %P0, %P1, %P2"
: "=w"(result)
: "w"(a), "w"(b)
: /* No clobbers. */);
#endif
return result[0];
}
} [add_options_for_arm_v8_1a_neon ""]]
}
# Return 1 if the target supports executing floating point instructions from
# ARMv8.2 with the FP16 extension, 0 otherwise. The test is valid for ARM and
# for AArch64.
proc check_effective_target_arm_v8_2a_fp16_scalar_hw { } {
if { ![check_effective_target_arm_v8_2a_fp16_scalar_ok] } {
return 0;
}
return [check_runtime arm_v8_2a_fp16_scalar_hw_available {
int
main (void)
{
__fp16 a = 1.0;
__fp16 result;
#ifdef __ARM_ARCH_ISA_A64
asm ("fabs %h0, %h1"
: "=w"(result)
: "w"(a)
: /* No clobbers. */);
#else
asm ("vabs.f16 %0, %1"
: "=w"(result)
: "w"(a)
: /* No clobbers. */);
#endif
return (result == 1.0) ? 0 : 1;
}
} [add_options_for_arm_v8_2a_fp16_scalar ""]]
}
# Return 1 if the target supports executing Adv.SIMD instructions from ARMv8.2
# with the FP16 extension, 0 otherwise. The test is valid for ARM and for
# AArch64.
proc check_effective_target_arm_v8_2a_fp16_neon_hw { } {
if { ![check_effective_target_arm_v8_2a_fp16_neon_ok] } {
return 0;
}
return [check_runtime arm_v8_2a_fp16_neon_hw_available {
int
main (void)
{
#ifdef __ARM_ARCH_ISA_A64
__Float16x4_t a = {1.0, -1.0, 1.0, -1.0};
__Float16x4_t result;
asm ("fabs %0.4h, %1.4h"
: "=w"(result)
: "w"(a)
: /* No clobbers. */);
#else
__simd64_float16_t a = {1.0, -1.0, 1.0, -1.0};
__simd64_float16_t result;
asm ("vabs.f16 %P0, %P1"
: "=w"(result)
: "w"(a)
: /* No clobbers. */);
#endif
return (result[0] == 1.0) ? 0 : 1;
}
} [add_options_for_arm_v8_2a_fp16_neon ""]]
}
# Return 1 if the target supports executing AdvSIMD instructions from ARMv8.2
# with the Dot Product extension, 0 otherwise. The test is valid for ARM and for
# AArch64.
proc check_effective_target_arm_v8_2a_dotprod_neon_hw { } {
if { ![check_effective_target_arm_v8_2a_dotprod_neon_ok] } {
return 0;
}
return [check_runtime arm_v8_2a_dotprod_neon_hw_available {
#include "arm_neon.h"
int
main (void)
{
uint32x2_t results = {0,0};
uint8x8_t a = {1,1,1,1,2,2,2,2};
uint8x8_t b = {2,2,2,2,3,3,3,3};
#ifdef __ARM_ARCH_ISA_A64
asm ("udot %0.2s, %1.8b, %2.8b"
: "=w"(results)
: "w"(a), "w"(b)
: /* No clobbers. */);
#else
asm ("vudot.u8 %P0, %P1, %P2"
: "=w"(results)
: "w"(a), "w"(b)
: /* No clobbers. */);
#endif
return (results[0] == 8 && results[1] == 24) ? 1 : 0;
}
} [add_options_for_arm_v8_2a_dotprod_neon ""]]
}
# Return 1 if this is a ARM target with NEON enabled.
proc check_effective_target_arm_neon { } {
if { [check_effective_target_arm32] } {
return [check_no_compiler_messages arm_neon object {
#ifndef __ARM_NEON__
#error not NEON
#else
int dummy;
#endif
}]
} else {
return 0
}
}
proc check_effective_target_arm_neonv2 { } {
if { [check_effective_target_arm32] } {
return [check_no_compiler_messages arm_neon object {
#ifndef __ARM_NEON__
#error not NEON
#else
#ifndef __ARM_FEATURE_FMA
#error not NEONv2
#else
int dummy;
#endif
#endif
}]
} else {
return 0
}
}
# Return 1 if this is an ARM target with load acquire and store release
# instructions for 8-, 16- and 32-bit types.
proc check_effective_target_arm_acq_rel { } {
return [check_no_compiler_messages arm_acq_rel object {
void
load_acquire_store_release (void)
{
asm ("lda r0, [r1]\n\t"
"stl r0, [r1]\n\t"
"ldah r0, [r1]\n\t"
"stlh r0, [r1]\n\t"
"ldab r0, [r1]\n\t"
"stlb r0, [r1]"
: : : "r0", "memory");
}
}]
}
# Add the options needed for MIPS Paired-Single.
proc add_options_for_mpaired_single { flags } {
if { ! [check_effective_target_mpaired_single] } {
return "$flags"
}
return "$flags -mpaired-single"
}
# Add the options needed for MIPS SIMD Architecture.
proc add_options_for_mips_msa { flags } {
if { ! [check_effective_target_mips_msa] } {
return "$flags"
}
return "$flags -mmsa"
}
# Add the options needed for MIPS Loongson MMI Architecture.
proc add_options_for_mips_loongson_mmi { flags } {
if { ! [check_effective_target_mips_loongson_mmi] } {
return "$flags"
}
return "$flags -mloongson-mmi"
}
# Return 1 if this a Loongson-2E or -2F target using an ABI that supports
# the Loongson vector modes.
proc check_effective_target_mips_loongson_mmi { } {
return [check_no_compiler_messages loongson assembly {
#if !defined(__mips_loongson_mmi)
#error !__mips_loongson_mmi
#endif
#if !defined(__mips_loongson_vector_rev)
#error !__mips_loongson_vector_rev
#endif
}]
}
# Return 1 if this is a MIPS target that supports the legacy NAN.
proc check_effective_target_mips_nanlegacy { } {
return [check_no_compiler_messages nanlegacy assembly {
#include <stdlib.h>
int main () { return 0; }
} "-mnan=legacy"]
}
# Return 1 if an MSA program can be compiled to object
proc check_effective_target_mips_msa { } {
if ![check_effective_target_nomips16] {
return 0
}
return [check_no_compiler_messages msa object {
#if !defined(__mips_msa)
#error "MSA NOT AVAIL"
#else
#if !(((__mips == 64) || (__mips == 32)) && (__mips_isa_rev >= 2))
#error "MSA NOT AVAIL FOR ISA REV < 2"
#endif
#if !defined(__mips_hard_float)
#error "MSA HARD_FLOAT REQUIRED"
#endif
#if __mips_fpr != 64
#error "MSA 64-bit FPR REQUIRED"
#endif
#include <msa.h>
int main()
{
v8i16 v = __builtin_msa_ldi_h (1);
return v[0];
}
#endif
} "-mmsa" ]
}
# Return 1 if this is an ARM target that adheres to the ABI for the ARM
# Architecture.
proc check_effective_target_arm_eabi { } {
return [check_no_compiler_messages arm_eabi object {
#ifndef __ARM_EABI__
#error not EABI
#else
int dummy;
#endif
}]
}
# Return 1 if this is an ARM target that adheres to the hard-float variant of
# the ABI for the ARM Architecture (e.g. -mfloat-abi=hard).
proc check_effective_target_arm_hf_eabi { } {
return [check_no_compiler_messages arm_hf_eabi object {
#if !defined(__ARM_EABI__) || !defined(__ARM_PCS_VFP)
#error not hard-float EABI
#else
int dummy;
#endif
}]
}
# Return 1 if this is an ARM target that uses the soft float ABI
# with no floating-point instructions at all (e.g. -mfloat-abi=soft).
proc check_effective_target_arm_softfloat { } {
return [check_no_compiler_messages arm_softfloat object {
#if !defined(__SOFTFP__)
#error not soft-float EABI
#else
int dummy;
#endif
}]
}
# Return 1 if this is an ARM target supporting -mcpu=iwmmxt.
# Some multilibs may be incompatible with this option.
proc check_effective_target_arm_iwmmxt_ok { } {
if { [check_effective_target_arm32] } {
return [check_no_compiler_messages arm_iwmmxt_ok object {
int dummy;
} "-mcpu=iwmmxt"]
} else {
return 0
}
}
# Return true if LDRD/STRD instructions are prefered over LDM/STM instructions
# for an ARM target.
proc check_effective_target_arm_prefer_ldrd_strd { } {
if { ![check_effective_target_arm32] } {
return 0;
}
return [check_no_messages_and_pattern arm_prefer_ldrd_strd "strd\tr" assembly {
void foo (void) { __asm__ ("" ::: "r4", "r5"); }
} "-O2 -mthumb" ]
}
# Return true if LDRD/STRD instructions are available on this target.
proc check_effective_target_arm_ldrd_strd_ok { } {
if { ![check_effective_target_arm32] } {
return 0;
}
return [check_no_compiler_messages arm_ldrd_strd_ok object {
int main(void)
{
__UINT64_TYPE__ a = 1, b = 10;
__UINT64_TYPE__ *c = &b;
// `a` will be in a valid register since it's a DImode quantity.
asm ("ldrd %0, %1"
: "=r" (a)
: "m" (c));
return a == 10;
}
}]
}
# Return 1 if this is a PowerPC target supporting -meabi.
proc check_effective_target_powerpc_eabi_ok { } {
if { [istarget powerpc*-*-*] } {
return [check_no_compiler_messages powerpc_eabi_ok object {
int dummy;
} "-meabi"]
} else {
return 0
}
}
# Return 1 if this is a PowerPC target with floating-point registers.
proc check_effective_target_powerpc_fprs { } {
if { [istarget powerpc*-*-*]
|| [istarget rs6000-*-*] } {
return [check_no_compiler_messages powerpc_fprs object {
#ifdef __NO_FPRS__
#error no FPRs
#else
int dummy;
#endif
}]
} else {
return 0
}
}
# Return 1 if this is a PowerPC target with hardware double-precision
# floating point.
proc check_effective_target_powerpc_hard_double { } {
if { [istarget powerpc*-*-*]
|| [istarget rs6000-*-*] } {
return [check_no_compiler_messages powerpc_hard_double object {
#ifdef _SOFT_DOUBLE
#error soft double
#else
int dummy;
#endif
}]
} else {
return 0
}
}
# Return 1 if this is a PowerPC target supporting -maltivec.
proc check_effective_target_powerpc_altivec_ok { } {
if { ([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
|| [istarget rs6000-*-*] } {
# AltiVec is not supported on AIX before 5.3.
if { [istarget powerpc*-*-aix4*]
|| [istarget powerpc*-*-aix5.1*]
|| [istarget powerpc*-*-aix5.2*] } {
return 0
}
return [check_no_compiler_messages powerpc_altivec_ok object {
int dummy;
} "-maltivec"]
} else {
return 0
}
}
# Return 1 if this is a PowerPC target supporting -mpower8-vector
proc check_effective_target_powerpc_p8vector_ok { } {
if { ([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
|| [istarget rs6000-*-*] } {
# AltiVec is not supported on AIX before 5.3.
if { [istarget powerpc*-*-aix4*]
|| [istarget powerpc*-*-aix5.1*]
|| [istarget powerpc*-*-aix5.2*] } {
return 0
}
# Darwin doesn't run on power8, so far.
if { [istarget *-*-darwin*] } {
return 0
}
return [check_no_compiler_messages powerpc_p8vector_ok object {
int main (void) {
asm volatile ("xxlorc 0,0,0");
return 0;
}
} "-mpower8-vector"]
} else {
return 0
}
}
# Return 1 if this is a PowerPC target supporting -mpower9-vector
proc check_effective_target_powerpc_p9vector_ok { } {
if { ([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
|| [istarget rs6000-*-*] } {
# AltiVec is not supported on AIX before 5.3.
if { [istarget powerpc*-*-aix4*]
|| [istarget powerpc*-*-aix5.1*]
|| [istarget powerpc*-*-aix5.2*] } {
return 0
}
# Darwin doesn't run on power9, so far.
if { [istarget *-*-darwin*] } {
return 0
}
return [check_no_compiler_messages powerpc_p9vector_ok object {
int main (void) {
long e = -1;
vector double v = (vector double) { 0.0, 0.0 };
asm ("xsxexpdp %0,%1" : "+r" (e) : "wa" (v));
return e;
}
} "-mpower9-vector"]
} else {
return 0
}
}
# Return 1 if this is a PowerPC target supporting -mmodulo
proc check_effective_target_powerpc_p9modulo_ok { } {
if { ([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
|| [istarget rs6000-*-*] } {
# AltiVec is not supported on AIX before 5.3.
if { [istarget powerpc*-*-aix4*]
|| [istarget powerpc*-*-aix5.1*]
|| [istarget powerpc*-*-aix5.2*] } {
return 0
}
return [check_no_compiler_messages powerpc_p9modulo_ok object {
int main (void) {
int i = 5, j = 3, r = -1;
asm ("modsw %0,%1,%2" : "+r" (r) : "r" (i), "r" (j));
return (r == 2);
}
} "-mmodulo"]
} else {
return 0
}
}
# Return 1 if this is a PowerPC target supporting -mfuture.
# Limit this to 64-bit linux systems for now until other
# targets support FUTURE.
proc check_effective_target_powerpc_future_ok { } {
if { ([istarget powerpc64*-*-linux*]) } {
return [check_no_compiler_messages powerpc_future_ok object {
int main (void) {
long e;
asm ("pli %0,%1" : "=r" (e) : "n" (0x12345));
return e;
}
} "-mfuture"]
} else {
return 0
}
}
# Return 1 if this is a PowerPC target supporting -mfloat128 via either
# software emulation on power7/power8 systems or hardware support on power9.
proc check_effective_target_powerpc_float128_sw_ok { } {
if { ([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
|| [istarget rs6000-*-*] } {
# AltiVec is not supported on AIX before 5.3.
if { [istarget powerpc*-*-aix4*]
|| [istarget powerpc*-*-aix5.1*]
|| [istarget powerpc*-*-aix5.2*] } {
return 0
}
# Darwin doesn't have VSX, so no soft support for float128.
if { [istarget *-*-darwin*] } {
return 0
}
return [check_no_compiler_messages powerpc_float128_sw_ok object {
volatile __float128 x = 1.0q;
volatile __float128 y = 2.0q;
int main() {
__float128 z = x + y;
return (z == 3.0q);
}
} "-mfloat128 -mvsx"]
} else {
return 0
}
}
# Return 1 if this is a PowerPC target supporting -mfloat128 via hardware
# support on power9.
proc check_effective_target_powerpc_float128_hw_ok { } {
if { ([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
|| [istarget rs6000-*-*] } {
# AltiVec is not supported on AIX before 5.3.
if { [istarget powerpc*-*-aix4*]
|| [istarget powerpc*-*-aix5.1*]
|| [istarget powerpc*-*-aix5.2*] } {
return 0
}
# Darwin doesn't run on any machine with float128 h/w so far.
if { [istarget *-*-darwin*] } {
return 0
}
return [check_no_compiler_messages powerpc_float128_hw_ok object {
volatile __float128 x = 1.0q;
volatile __float128 y = 2.0q;
int main() {
__float128 z;
__asm__ ("xsaddqp %0,%1,%2" : "=v" (z) : "v" (x), "v" (y));
return (z == 3.0q);
}
} "-mfloat128-hardware"]
} else {
return 0
}
}
# Return 1 if current options define float128, 0 otherwise.
proc check_effective_target_ppc_float128 { } {
return [check_no_compiler_messages_nocache ppc_float128 object {
#ifndef __FLOAT128__
nope no good
#endif
}]
}
# Return 1 if current options generate float128 insns, 0 otherwise.
proc check_effective_target_ppc_float128_insns { } {
return [check_no_compiler_messages_nocache ppc_float128 object {
#ifndef __FLOAT128_HARDWARE__
nope no good
#endif
}]
}
# Return 1 if current options generate VSX instructions, 0 otherwise.
proc check_effective_target_powerpc_vsx { } {
return [check_no_compiler_messages_nocache powerpc_vsx object {
#ifndef __VSX__
nope no vsx
#endif
}]
}
# Return 1 if this is a PowerPC target supporting -mvsx
proc check_effective_target_powerpc_vsx_ok { } {
if { ([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
|| [istarget rs6000-*-*] } {
# VSX is not supported on AIX before 7.1.
if { [istarget powerpc*-*-aix4*]
|| [istarget powerpc*-*-aix5*]
|| [istarget powerpc*-*-aix6*] } {
return 0
}
# Darwin doesn't have VSX, even if it's used with an assembler
# which recognises the insns.
if { [istarget *-*-darwin*] } {
return 0
}
return [check_no_compiler_messages powerpc_vsx_ok object {
int main (void) {
asm volatile ("xxlor 0,0,0");
return 0;
}
} "-mvsx"]
} else {
return 0
}
}
# Return 1 if this is a PowerPC target supporting -mhtm
proc check_effective_target_powerpc_htm_ok { } {
if { ([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
|| [istarget rs6000-*-*] } {
# HTM is not supported on AIX yet.
if { [istarget powerpc*-*-aix*] } {
return 0
}
return [check_no_compiler_messages powerpc_htm_ok object {
int main (void) {
asm volatile ("tbegin. 0");
return 0;
}
} "-mhtm"]
} else {
return 0
}
}
# Return 1 if the target supports executing HTM hardware instructions,
# 0 otherwise. Cache the result.
proc check_htm_hw_available { } {
return [check_cached_effective_target htm_hw_available {
# For now, disable on Darwin
if { [istarget powerpc-*-eabi] || [istarget powerpc*-*-eabispe] || [istarget *-*-darwin*]} {
expr 0
} else {
check_runtime_nocache htm_hw_available {
int main()
{
__builtin_ttest ();
return 0;
}
} "-mhtm"
}
}]
}
# Return 1 if this is a PowerPC target supporting -mcpu=cell.
proc check_effective_target_powerpc_ppu_ok { } {
if [check_effective_target_powerpc_altivec_ok] {
return [check_no_compiler_messages cell_asm_available object {
int main (void) {
#ifdef __MACH__
asm volatile ("lvlx v0,v0,v0");
#else
asm volatile ("lvlx 0,0,0");
#endif
return 0;
}
}]
} else {
return 0
}
}
# Return 1 if this is a PowerPC target that supports SPU.
proc check_effective_target_powerpc_spu { } {
if { [istarget powerpc*-*-linux*] } {
return [check_effective_target_powerpc_altivec_ok]
} else {
return 0
}
}
# Return 1 if this is a PowerPC SPE target. The check includes options
# specified by dg-options for this test, so don't cache the result.
proc check_effective_target_powerpc_spe_nocache { } {
if { [istarget powerpc*-*-*] } {
return [check_no_compiler_messages_nocache powerpc_spe object {
#ifndef __SPE__
#error not SPE
#else
int dummy;
#endif
} [current_compiler_flags]]
} else {
return 0
}
}
# Return 1 if this is a PowerPC target with SPE enabled.
proc check_effective_target_powerpc_spe { } {
if { [istarget powerpc*-*-*] } {
return [check_no_compiler_messages powerpc_spe object {
#ifndef __SPE__
#error not SPE
#else
int dummy;
#endif
}]
} else {
return 0
}
}
# Return 1 if this is a PowerPC target with Altivec enabled.
proc check_effective_target_powerpc_altivec { } {
if { [istarget powerpc*-*-*] } {
return [check_no_compiler_messages powerpc_altivec object {
#ifndef __ALTIVEC__
#error not Altivec
#else
int dummy;
#endif
}]
} else {
return 0
}
}
# Return 1 if this is a PowerPC 405 target. The check includes options
# specified by dg-options for this test, so don't cache the result.
proc check_effective_target_powerpc_405_nocache { } {
if { [istarget powerpc*-*-*] || [istarget rs6000-*-*] } {
return [check_no_compiler_messages_nocache powerpc_405 object {
#ifdef __PPC405__
int dummy;
#else
#error not a PPC405
#endif
} [current_compiler_flags]]
} else {
return 0
}
}
# Return 1 if this is a PowerPC target using the ELFv2 ABI.
proc check_effective_target_powerpc_elfv2 { } {
if { [istarget powerpc*-*-*] } {
return [check_no_compiler_messages powerpc_elfv2 object {
#if _CALL_ELF != 2
#error not ELF v2 ABI
#else
int dummy;
#endif
}]
} else {
return 0
}
}
# The VxWorks SPARC simulator accepts only EM_SPARC executables and
# chokes on EM_SPARC32PLUS or EM_SPARCV9 executables. Return 1 if the
# test environment appears to run executables on such a simulator.
proc check_effective_target_ultrasparc_hw { } {
return [check_runtime ultrasparc_hw {
int main() { return 0; }
} "-mcpu=ultrasparc"]
}
# Return 1 if the test environment supports executing UltraSPARC VIS2
# instructions. We check this by attempting: "bmask %g0, %g0, %g0"
proc check_effective_target_ultrasparc_vis2_hw { } {
return [check_runtime ultrasparc_vis2_hw {
int main() { __asm__(".word 0x81b00320"); return 0; }
} "-mcpu=ultrasparc3"]
}
# Return 1 if the test environment supports executing UltraSPARC VIS3
# instructions. We check this by attempting: "addxc %g0, %g0, %g0"
proc check_effective_target_ultrasparc_vis3_hw { } {
return [check_runtime ultrasparc_vis3_hw {
int main() { __asm__(".word 0x81b00220"); return 0; }
} "-mcpu=niagara3"]
}
# Return 1 if this is a SPARC-V9 target.
proc check_effective_target_sparc_v9 { } {
if { [istarget sparc*-*-*] } {
return [check_no_compiler_messages sparc_v9 object {
int main (void) {
asm volatile ("return %i7+8");
return 0;
}
}]
} else {
return 0
}
}
# Return 1 if this is a SPARC target with VIS enabled.
proc check_effective_target_sparc_vis { } {
if { [istarget sparc*-*-*] } {
return [check_no_compiler_messages sparc_vis object {
#ifndef __VIS__
#error not VIS
#else
int dummy;
#endif
}]
} else {
return 0
}
}
# Return 1 if the target supports hardware vector shift operation.
proc check_effective_target_vect_shift { } {
return [check_cached_effective_target_indexed vect_shift {
expr {([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
|| [istarget ia64-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget aarch64*-*-*]
|| [is-effective-target arm_neon]
|| ([istarget mips*-*-*]
&& ([et-is-effective-target mips_msa]
|| [et-is-effective-target mips_loongson_mmi]))
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports hardware vector shift by register operation.
proc check_effective_target_vect_var_shift { } {
return [check_cached_effective_target_indexed vect_var_shift {
expr {(([istarget i?86-*-*] || [istarget x86_64-*-*])
&& [check_avx2_available])
}}]
}
proc check_effective_target_whole_vector_shift { } {
if { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget ia64-*-*]
|| [istarget aarch64*-*-*]
|| [istarget powerpc64*-*-*]
|| ([is-effective-target arm_neon]
&& [check_effective_target_arm_little_endian])
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_loongson_mmi])
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
|| [istarget amdgcn-*-*] } {
set answer 1
} else {
set answer 0
}
verbose "check_effective_target_vect_long: returning $answer" 2
return $answer
}
# Return 1 if the target supports vector bswap operations.
proc check_effective_target_vect_bswap { } {
return [check_cached_effective_target_indexed vect_bswap {
expr { [istarget aarch64*-*-*]
|| [is-effective-target arm_neon]
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports comparison of bool vectors for at
# least one vector length.
proc check_effective_target_vect_bool_cmp { } {
return [check_cached_effective_target_indexed vect_bool_cmp {
expr { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget aarch64*-*-*]
|| [is-effective-target arm_neon] }}]
}
# Return 1 if the target supports addition of char vectors for at least
# one vector length.
proc check_effective_target_vect_char_add { } {
return [check_cached_effective_target_indexed vect_char_add {
expr {
[istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
|| [istarget amdgcn-*-*]
|| [istarget ia64-*-*]
|| [istarget aarch64*-*-*]
|| [is-effective-target arm_neon]
|| ([istarget mips*-*-*]
&& ([et-is-effective-target mips_loongson_mmi]
|| [et-is-effective-target mips_msa]))
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
}}]
}
# Return 1 if the target supports hardware vector shift operation for char.
proc check_effective_target_vect_shift_char { } {
return [check_cached_effective_target_indexed vect_shift_char {
expr { ([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
|| [is-effective-target arm_neon]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports hardware vectors of long, 0 otherwise.
#
# This can change for different subtargets so do not cache the result.
proc check_effective_target_vect_long { } {
if { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| (([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
&& [check_effective_target_ilp32])
|| [is-effective-target arm_neon]
|| ([istarget sparc*-*-*] && [check_effective_target_ilp32])
|| [istarget aarch64*-*-*]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
|| [istarget amdgcn-*-*] } {
set answer 1
} else {
set answer 0
}
verbose "check_effective_target_vect_long: returning $answer" 2
return $answer
}
# Return 1 if the target supports hardware vectors of float when
# -funsafe-math-optimizations is enabled, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_float { } {
return [check_cached_effective_target_indexed vect_float {
expr { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget powerpc*-*-*]
|| [istarget mips-sde-elf]
|| [istarget mipsisa64*-*-*]
|| [istarget ia64-*-*]
|| [istarget aarch64*-*-*]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| [is-effective-target arm_neon]
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vxe])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports hardware vectors of float without
# -funsafe-math-optimizations being enabled, 0 otherwise.
proc check_effective_target_vect_float_strict { } {
return [expr { [check_effective_target_vect_float]
&& ![istarget arm*-*-*] }]
}
# Return 1 if the target supports hardware vectors of double, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_double { } {
return [check_cached_effective_target_indexed vect_double {
expr { (([istarget i?86-*-*] || [istarget x86_64-*-*])
&& [check_no_compiler_messages vect_double assembly {
#ifdef __tune_atom__
# error No double vectorizer support.
#endif
}])
|| [istarget aarch64*-*-*]
|| ([istarget powerpc*-*-*] && [check_vsx_hw_available])
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
|| [istarget amdgcn-*-*]} }]
}
# Return 1 if the target supports conditional addition, subtraction,
# multiplication, division, minimum and maximum on vectors of double,
# via the cond_ optabs. Return 0 otherwise.
proc check_effective_target_vect_double_cond_arith { } {
return [check_effective_target_aarch64_sve]
}
# Return 1 if the target supports hardware vectors of long long, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_long_long { } {
return [check_cached_effective_target_indexed vect_long_long {
expr { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx]) }}]
}
# Return 1 if the target plus current options does not support a vector
# max instruction on "int", 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_no_int_min_max { } {
return [check_cached_effective_target_indexed vect_no_int_min_max {
expr { [istarget sparc*-*-*]
|| [istarget alpha*-*-*]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_loongson_mmi]) }}]
}
# Return 1 if the target plus current options does not support a vector
# add instruction on "int", 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_no_int_add { } {
# Alpha only supports vector add on V8QI and V4HI.
return [check_cached_effective_target_indexed vect_no_int_add {
expr { [istarget alpha*-*-*] }}]
}
# Return 1 if the target plus current options does not support vector
# bitwise instructions, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_no_bitwise { } {
return [check_cached_effective_target_indexed vect_no_bitwise { return 0 }]
}
# Return 1 if the target plus current options supports vector permutation,
# 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_perm { } {
return [check_cached_effective_target_indexed vect_perm {
expr { [is-effective-target arm_neon]
|| [istarget aarch64*-*-*]
|| [istarget powerpc*-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([istarget mips*-*-*]
&& ([et-is-effective-target mpaired_single]
|| [et-is-effective-target mips_msa]))
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if, for some VF:
#
# - the target's default vector size is VF * ELEMENT_BITS bits
#
# - it is possible to implement the equivalent of:
#
# int<ELEMENT_BITS>_t s1[COUNT][COUNT * VF], s2[COUNT * VF];
# for (int i = 0; i < COUNT; ++i)
# for (int j = 0; j < COUNT * VF; ++j)
# s1[i][j] = s2[j - j % COUNT + i]
#
# using only a single 2-vector permute for each vector in s1.
#
# E.g. for COUNT == 3 and vector length 4, the two arrays would be:
#
# s2 | a0 a1 a2 a3 | b0 b1 b2 b3 | c0 c1 c2 c3
# ------+-------------+-------------+------------
# s1[0] | a0 a0 a0 a3 | a3 a3 b2 b2 | b2 c1 c1 c1
# s1[1] | a1 a1 a1 b0 | b0 b0 b3 b3 | b3 c2 c2 c2
# s1[2] | a2 a2 a2 b1 | b1 b1 c0 c0 | c0 c3 c3 c3
#
# Each s1 permute requires only two of a, b and c.
#
# The distance between the start of vector n in s1[0] and the start
# of vector n in s2 is:
#
# A = (n * VF) % COUNT
#
# The corresponding value for the end of vector n is:
#
# B = (n * VF + VF - 1) % COUNT
#
# Subtracting i from each value gives the corresponding difference
# for s1[i]. The condition being tested by this function is false
# iff A - i > 0 and B - i < 0 for some i and n, such that the first
# element for s1[i] comes from vector n - 1 of s2 and the last element
# comes from vector n + 1 of s2. The condition is therefore true iff
# A <= B for all n. This is turn means the condition is true iff:
#
# (n * VF) % COUNT + (VF - 1) % COUNT < COUNT
#
# for all n. COUNT - (n * VF) % COUNT is bounded by gcd (VF, COUNT),
# and will be that value for at least one n in [0, COUNT), so we want:
#
# (VF - 1) % COUNT < gcd (VF, COUNT)
proc vect_perm_supported { count element_bits } {
set vector_bits [lindex [available_vector_sizes] 0]
# The number of vectors has to be a power of 2 when permuting
# variable-length vectors.
if { $vector_bits <= 0 && ($count & -$count) != $count } {
return 0
}
set vf [expr { $vector_bits / $element_bits }]
# Compute gcd (VF, COUNT).
set gcd $vf
set temp1 $count
while { $temp1 > 0 } {
set temp2 [expr { $gcd % $temp1 }]
set gcd $temp1
set temp1 $temp2
}
return [expr { ($vf - 1) % $count < $gcd }]
}
# Return 1 if the target supports SLP permutation of 3 vectors when each
# element has 32 bits.
proc check_effective_target_vect_perm3_int { } {
return [expr { [check_effective_target_vect_perm]
&& [vect_perm_supported 3 32] }]
}
# Return 1 if the target plus current options supports vector permutation
# on byte-sized elements, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_perm_byte { } {
return [check_cached_effective_target_indexed vect_perm_byte {
expr { ([is-effective-target arm_neon]
&& [is-effective-target arm_little_endian])
|| ([istarget aarch64*-*-*]
&& [is-effective-target aarch64_little_endian])
|| [istarget powerpc*-*-*]
|| ([istarget mips-*.*]
&& [et-is-effective-target mips_msa])
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports SLP permutation of 3 vectors when each
# element has 8 bits.
proc check_effective_target_vect_perm3_byte { } {
return [expr { [check_effective_target_vect_perm_byte]
&& [vect_perm_supported 3 8] }]
}
# Return 1 if the target plus current options supports vector permutation
# on short-sized elements, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_perm_short { } {
return [check_cached_effective_target_indexed vect_perm_short {
expr { ([is-effective-target arm_neon]
&& [is-effective-target arm_little_endian])
|| ([istarget aarch64*-*-*]
&& [is-effective-target aarch64_little_endian])
|| [istarget powerpc*-*-*]
|| (([istarget i?86-*-*] || [istarget x86_64-*-*])
&& [check_ssse3_available])
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports SLP permutation of 3 vectors when each
# element has 16 bits.
proc check_effective_target_vect_perm3_short { } {
return [expr { [check_effective_target_vect_perm_short]
&& [vect_perm_supported 3 16] }]
}
# Return 1 if the target plus current options supports folding of
# copysign into XORSIGN.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_xorsign { } {
return [check_cached_effective_target_indexed xorsign {
expr { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget aarch64*-*-*] || [istarget arm*-*-*] }}]
}
# Return 1 if the target plus current options supports a vector
# widening summation of *short* args into *int* result, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_widen_sum_hi_to_si_pattern { } {
return [check_cached_effective_target_indexed vect_widen_sum_hi_to_si_pattern {
expr { [istarget powerpc*-*-*]
|| ([istarget aarch64*-*-*]
&& ![check_effective_target_aarch64_sve])
|| [is-effective-target arm_neon]
|| [istarget ia64-*-*] }}]
}
# Return 1 if the target plus current options supports a vector
# widening summation of *short* args into *int* result, 0 otherwise.
# A target can also support this widening summation if it can support
# promotion (unpacking) from shorts to ints.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_widen_sum_hi_to_si { } {
return [check_cached_effective_target_indexed vect_widen_sum_hi_to_si {
expr { [check_effective_target_vect_unpack]
|| [istarget powerpc*-*-*]
|| [istarget ia64-*-*] }}]
}
# Return 1 if the target plus current options supports a vector
# widening summation of *char* args into *short* result, 0 otherwise.
# A target can also support this widening summation if it can support
# promotion (unpacking) from chars to shorts.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_widen_sum_qi_to_hi { } {
return [check_cached_effective_target_indexed vect_widen_sum_qi_to_hi {
expr { [check_effective_target_vect_unpack]
|| [is-effective-target arm_neon]
|| [istarget ia64-*-*] }}]
}
# Return 1 if the target plus current options supports a vector
# widening summation of *char* args into *int* result, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_widen_sum_qi_to_si { } {
return [check_cached_effective_target_indexed vect_widen_sum_qi_to_si {
expr { [istarget powerpc*-*-*] }}]
}
# Return 1 if the target plus current options supports a vector
# widening multiplication of *char* args into *short* result, 0 otherwise.
# A target can also support this widening multplication if it can support
# promotion (unpacking) from chars to shorts, and vect_short_mult (non-widening
# multiplication of shorts).
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_widen_mult_qi_to_hi { } {
return [check_cached_effective_target_indexed vect_widen_mult_qi_to_hi {
expr { ([check_effective_target_vect_unpack]
&& [check_effective_target_vect_short_mult])
|| ([istarget powerpc*-*-*]
|| ([istarget aarch64*-*-*]
&& ![check_effective_target_aarch64_sve])
|| [is-effective-target arm_neon]
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx]))
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target plus current options supports a vector
# widening multiplication of *short* args into *int* result, 0 otherwise.
# A target can also support this widening multplication if it can support
# promotion (unpacking) from shorts to ints, and vect_int_mult (non-widening
# multiplication of ints).
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_widen_mult_hi_to_si { } {
return [check_cached_effective_target_indexed vect_widen_mult_hi_to_si {
expr { ([check_effective_target_vect_unpack]
&& [check_effective_target_vect_int_mult])
|| ([istarget powerpc*-*-*]
|| [istarget ia64-*-*]
|| ([istarget aarch64*-*-*]
&& ![check_effective_target_aarch64_sve])
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [is-effective-target arm_neon]
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx]))
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target plus current options supports a vector
# widening multiplication of *char* args into *short* result, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_widen_mult_qi_to_hi_pattern { } {
return [check_cached_effective_target_indexed vect_widen_mult_qi_to_hi_pattern {
expr { [istarget powerpc*-*-*]
|| ([is-effective-target arm_neon]
&& [check_effective_target_arm_little_endian])
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target plus current options supports a vector
# widening multiplication of *short* args into *int* result, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_widen_mult_hi_to_si_pattern { } {
return [check_cached_effective_target_indexed vect_widen_mult_hi_to_si_pattern {
expr { [istarget powerpc*-*-*]
|| [istarget ia64-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([is-effective-target arm_neon]
&& [check_effective_target_arm_little_endian])
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target plus current options supports a vector
# widening multiplication of *int* args into *long* result, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_widen_mult_si_to_di_pattern { } {
return [check_cached_effective_target_indexed vect_widen_mult_si_to_di_pattern {
expr { [istarget ia64-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx]) }}]
}
# Return 1 if the target plus current options supports a vector
# widening shift, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_widen_shift { } {
return [check_cached_effective_target_indexed vect_widen_shift {
expr { [is-effective-target arm_neon] }}]
}
# Return 1 if the target plus current options supports a vector
# dot-product of signed chars, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_sdot_qi { } {
return [check_cached_effective_target_indexed vect_sdot_qi {
expr { [istarget ia64-*-*]
|| [istarget aarch64*-*-*]
|| [istarget arm*-*-*]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa]) }}]
}
# Return 1 if the target plus current options supports a vector
# dot-product of unsigned chars, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_udot_qi { } {
return [check_cached_effective_target_indexed vect_udot_qi {
expr { [istarget powerpc*-*-*]
|| [istarget aarch64*-*-*]
|| [istarget arm*-*-*]
|| [istarget ia64-*-*]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa]) }}]
}
# Return 1 if the target plus current options supports a vector
# dot-product of signed shorts, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_sdot_hi { } {
return [check_cached_effective_target_indexed vect_sdot_hi {
expr { ([istarget powerpc*-*-*] && ![istarget powerpc-*-linux*paired*])
|| [istarget ia64-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa]) }}]
}
# Return 1 if the target plus current options supports a vector
# dot-product of unsigned shorts, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_udot_hi { } {
return [check_cached_effective_target_indexed vect_udot_hi {
expr { ([istarget powerpc*-*-*] && ![istarget powerpc-*-linux*paired*])
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa]) }}]
}
# Return 1 if the target plus current options supports a vector
# sad operation of unsigned chars, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_usad_char { } {
return [check_cached_effective_target_indexed vect_usad_char {
expr { [istarget i?86-*-*]
|| [istarget x86_64-*-*]
|| ([istarget aarch64*-*-*]
&& ![check_effective_target_aarch64_sve])
|| ([istarget powerpc*-*-*]
&& [check_p9vector_hw_available])}}]
}
# Return 1 if the target plus current options supports both signed
# and unsigned average operations on vectors of bytes.
proc check_effective_target_vect_avg_qi {} {
return [expr { [istarget aarch64*-*-*]
&& ![check_effective_target_aarch64_sve1_only] }]
}
# Return 1 if the target plus current options supports both signed
# and unsigned multiply-high-with-round-and-scale operations
# on vectors of half-words.
proc check_effective_target_vect_mulhrs_hi {} {
return [expr { [istarget aarch64*-*-*]
&& [check_effective_target_aarch64_sve2] }]
}
# Return 1 if the target plus current options supports signed division
# by power-of-2 operations on vectors of 4-byte integers.
proc check_effective_target_vect_sdiv_pow2_si {} {
return [expr { [istarget aarch64*-*-*]
&& [check_effective_target_aarch64_sve] }]
}
# Return 1 if the target plus current options supports a vector
# demotion (packing) of shorts (to chars) and ints (to shorts)
# using modulo arithmetic, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_pack_trunc { } {
return [check_cached_effective_target_indexed vect_pack_trunc {
expr { ([istarget powerpc*-*-*] && ![istarget powerpc-*-linux*paired*])
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget aarch64*-*-*]
|| ([istarget arm*-*-*] && [check_effective_target_arm_neon_ok]
&& [check_effective_target_arm_little_endian])
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx]) }}]
}
# Return 1 if the target plus current options supports a vector
# promotion (unpacking) of chars (to shorts) and shorts (to ints), 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_unpack { } {
return [check_cached_effective_target_indexed vect_unpack {
expr { ([istarget powerpc*-*-*] && ![istarget powerpc-*paired*])
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget ia64-*-*]
|| [istarget aarch64*-*-*]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| ([istarget arm*-*-*] && [check_effective_target_arm_neon_ok]
&& [check_effective_target_arm_little_endian])
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx]) }}]
}
# Return 1 if the target plus current options does not guarantee
# that its STACK_BOUNDARY is >= the reguired vector alignment.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_unaligned_stack { } {
return [check_cached_effective_target_indexed unaligned_stack { expr 0 }]
}
# Return 1 if the target plus current options does not support a vector
# alignment mechanism, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_no_align { } {
return [check_cached_effective_target_indexed vect_no_align {
expr { [istarget mipsisa64*-*-*]
|| [istarget mips-sde-elf]
|| [istarget sparc*-*-*]
|| [istarget ia64-*-*]
|| [check_effective_target_arm_vect_no_misalign]
|| ([istarget powerpc*-*-*] && [check_p8vector_hw_available])
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_loongson_mmi]) }}]
}
# Return 1 if the target supports a vector misalign access, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_vect_hw_misalign { } {
return [check_cached_effective_target_indexed vect_hw_misalign {
if { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([istarget powerpc*-*-*] && [check_p8vector_hw_available])
|| [istarget aarch64*-*-*]
|| ([istarget mips*-*-*] && [et-is-effective-target mips_msa])
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx]) } {
return 1
}
if { [istarget arm*-*-*]
&& ![check_effective_target_arm_vect_no_misalign] } {
return 1
}
return 0
}]
}
# Return 1 if arrays are aligned to the vector alignment
# boundary, 0 otherwise.
proc check_effective_target_vect_aligned_arrays { } {
set et_vect_aligned_arrays 0
if { (([istarget i?86-*-*] || [istarget x86_64-*-*])
&& !([is-effective-target ia32]
|| ([check_avx_available] && ![check_prefer_avx128]))) } {
set et_vect_aligned_arrays 1
}
verbose "check_effective_target_vect_aligned_arrays:\
returning $et_vect_aligned_arrays" 2
return $et_vect_aligned_arrays
}
# Return 1 if types of size 32 bit or less are naturally aligned
# (aligned to their type-size), 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_natural_alignment_32 { } {
# FIXME: 32bit powerpc: guaranteed only if MASK_ALIGN_NATURAL/POWER.
# FIXME: m68k has -malign-int
return [check_cached_effective_target_indexed natural_alignment_32 {
if { ([istarget *-*-darwin*] && [is-effective-target lp64])
|| [istarget avr-*-*]
|| [istarget m68k-*-linux*]
|| [istarget pru-*-*]
|| [istarget stormy16-*-*]
|| [istarget rl78-*-*]
|| [istarget pdp11-*-*]
|| [istarget msp430-*-*]
|| [istarget m32c-*-*]
|| [istarget cris-*-*] } {
return 0
} else {
return 1
}
}]
}
# Return 1 if types of size 64 bit or less are naturally aligned (aligned to their
# type-size), 0 otherwise.
#
# This won't change for different subtargets so cache the result.
proc check_effective_target_natural_alignment_64 { } {
return [check_cached_effective_target_indexed natural_alignment_64 {
expr { [is-effective-target natural_alignment_32]
&& [is-effective-target lp64] && ![istarget *-*-darwin*] }
}]
}
# Return 1 if all vector types are naturally aligned (aligned to their
# type-size), 0 otherwise.
proc check_effective_target_vect_natural_alignment { } {
set et_vect_natural_alignment 1
if { [check_effective_target_arm_eabi]
|| [istarget nvptx-*-*]
|| [istarget s390*-*-*]
|| [istarget amdgcn-*-*] } {
set et_vect_natural_alignment 0
}
verbose "check_effective_target_vect_natural_alignment:\
returning $et_vect_natural_alignment" 2
return $et_vect_natural_alignment
}
# Return true if the target supports the check_raw_ptrs and check_war_ptrs
# optabs on vectors.
proc check_effective_target_vect_check_ptrs { } {
return [check_effective_target_aarch64_sve2]
}
# Return true if fully-masked loops are supported.
proc check_effective_target_vect_fully_masked { } {
return [expr { [check_effective_target_aarch64_sve]
|| [istarget amdgcn*-*-*] }]
}
# Return 1 if the target doesn't prefer any alignment beyond element
# alignment during vectorization.
proc check_effective_target_vect_element_align_preferred { } {
return [expr { [check_effective_target_aarch64_sve]
&& [check_effective_target_vect_variable_length] }]
}
# Return 1 if we can align stack data to the preferred vector alignment.
proc check_effective_target_vect_align_stack_vars { } {
if { [check_effective_target_aarch64_sve] } {
return [check_effective_target_vect_variable_length]
}
return 1
}
# Return 1 if vector alignment (for types of size 32 bit or less) is reachable, 0 otherwise.
proc check_effective_target_vector_alignment_reachable { } {
set et_vector_alignment_reachable 0
if { [check_effective_target_vect_aligned_arrays]
|| [check_effective_target_natural_alignment_32] } {
set et_vector_alignment_reachable 1
}
verbose "check_effective_target_vector_alignment_reachable:\
returning $et_vector_alignment_reachable" 2
return $et_vector_alignment_reachable
}
# Return 1 if vector alignment for 64 bit is reachable, 0 otherwise.
proc check_effective_target_vector_alignment_reachable_for_64bit { } {
set et_vector_alignment_reachable_for_64bit 0
if { [check_effective_target_vect_aligned_arrays]
|| [check_effective_target_natural_alignment_64] } {
set et_vector_alignment_reachable_for_64bit 1
}
verbose "check_effective_target_vector_alignment_reachable_for_64bit:\
returning $et_vector_alignment_reachable_for_64bit" 2
return $et_vector_alignment_reachable_for_64bit
}
# Return 1 if the target only requires element alignment for vector accesses
proc check_effective_target_vect_element_align { } {
return [check_cached_effective_target_indexed vect_element_align {
expr { ([istarget arm*-*-*]
&& ![check_effective_target_arm_vect_no_misalign])
|| [check_effective_target_vect_hw_misalign]
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if we expect to see unaligned accesses in at least some
# vector dumps.
proc check_effective_target_vect_unaligned_possible { } {
return [expr { ![check_effective_target_vect_element_align_preferred]
&& (![check_effective_target_vect_no_align]
|| [check_effective_target_vect_hw_misalign]) }]
}
# Return 1 if the target supports vector LOAD_LANES operations, 0 otherwise.
proc check_effective_target_vect_load_lanes { } {
# We don't support load_lanes correctly on big-endian arm.
return [check_cached_effective_target vect_load_lanes {
expr { ([check_effective_target_arm_little_endian]
&& [check_effective_target_arm_neon_ok])
|| [istarget aarch64*-*-*] }}]
}
# Return 1 if the target supports vector masked stores.
proc check_effective_target_vect_masked_store { } {
return [expr { [check_effective_target_aarch64_sve]
|| [istarget amdgcn*-*-*] }]
}
# Return 1 if the target supports vector scatter stores.
proc check_effective_target_vect_scatter_store { } {
return [expr { [check_effective_target_aarch64_sve]
|| [istarget amdgcn*-*-*] }]
}
# Return 1 if the target supports vector conditional operations, 0 otherwise.
proc check_effective_target_vect_condition { } {
return [check_cached_effective_target_indexed vect_condition {
expr { [istarget aarch64*-*-*]
|| [istarget powerpc*-*-*]
|| [istarget ia64-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| ([istarget arm*-*-*]
&& [check_effective_target_arm_neon_ok])
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports vector conditional operations where
# the comparison has different type from the lhs, 0 otherwise.
proc check_effective_target_vect_cond_mixed { } {
return [check_cached_effective_target_indexed vect_cond_mixed {
expr { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget aarch64*-*-*]
|| [istarget powerpc*-*-*]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports vector char multiplication, 0 otherwise.
proc check_effective_target_vect_char_mult { } {
return [check_cached_effective_target_indexed vect_char_mult {
expr { [istarget aarch64*-*-*]
|| [istarget ia64-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [check_effective_target_arm32]
|| [check_effective_target_powerpc_altivec]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports vector short multiplication, 0 otherwise.
proc check_effective_target_vect_short_mult { } {
return [check_cached_effective_target_indexed vect_short_mult {
expr { [istarget ia64-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget powerpc*-*-*]
|| [istarget aarch64*-*-*]
|| [check_effective_target_arm32]
|| ([istarget mips*-*-*]
&& ([et-is-effective-target mips_msa]
|| [et-is-effective-target mips_loongson_mmi]))
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports vector int multiplication, 0 otherwise.
proc check_effective_target_vect_int_mult { } {
return [check_cached_effective_target_indexed vect_int_mult {
expr { ([istarget powerpc*-*-*] && ![istarget powerpc-*-linux*paired*])
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget ia64-*-*]
|| [istarget aarch64*-*-*]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| [check_effective_target_arm32]
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports 64 bit hardware vector
# multiplication of long operands with a long result, 0 otherwise.
#
# This can change for different subtargets so do not cache the result.
proc check_effective_target_vect_long_mult { } {
if { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| (([istarget powerpc*-*-*]
&& ![istarget powerpc-*-linux*paired*])
&& [check_effective_target_ilp32])
|| [is-effective-target arm_neon]
|| ([istarget sparc*-*-*] && [check_effective_target_ilp32])
|| [istarget aarch64*-*-*]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa]) } {
set answer 1
} else {
set answer 0
}
verbose "check_effective_target_vect_long_mult: returning $answer" 2
return $answer
}
# Return 1 if the target supports vector even/odd elements extraction, 0 otherwise.
proc check_effective_target_vect_extract_even_odd { } {
return [check_cached_effective_target_indexed extract_even_odd {
expr { [istarget aarch64*-*-*]
|| [istarget powerpc*-*-*]
|| [is-effective-target arm_neon]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget ia64-*-*]
|| ([istarget mips*-*-*]
&& ([et-is-effective-target mips_msa]
|| [et-is-effective-target mpaired_single]))
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx]) }}]
}
# Return 1 if the target supports vector interleaving, 0 otherwise.
proc check_effective_target_vect_interleave { } {
return [check_cached_effective_target_indexed vect_interleave {
expr { [istarget aarch64*-*-*]
|| [istarget powerpc*-*-*]
|| [is-effective-target arm_neon]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget ia64-*-*]
|| ([istarget mips*-*-*]
&& ([et-is-effective-target mpaired_single]
|| [et-is-effective-target mips_msa]))
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx]) }}]
}
foreach N {2 3 4 8} {
eval [string map [list N $N] {
# Return 1 if the target supports 2-vector interleaving
proc check_effective_target_vect_stridedN { } {
return [check_cached_effective_target_indexed vect_stridedN {
if { (N & -N) == N
&& [check_effective_target_vect_interleave]
&& [check_effective_target_vect_extract_even_odd] } {
return 1
}
if { ([istarget arm*-*-*]
|| [istarget aarch64*-*-*]) && N >= 2 && N <= 4 } {
return 1
}
if [check_effective_target_vect_fully_masked] {
return 1
}
return 0
}]
}
}]
}
# Return the list of vector sizes (in bits) that each target supports.
# A vector length of "0" indicates variable-length vectors.
proc available_vector_sizes { } {
set result {}
if { [istarget aarch64*-*-*] } {
if { [check_effective_target_aarch64_sve] } {
lappend result [aarch64_sve_bits]
}
lappend result 128 64
} elseif { [istarget arm*-*-*]
&& [check_effective_target_arm_neon_ok] } {
lappend result 128 64
} elseif { [istarget i?86-*-*] || [istarget x86_64-*-*] } {
if { [check_avx_available] && ![check_prefer_avx128] } {
lappend result 256
}
lappend result 128
if { ![is-effective-target ia32] } {
lappend result 64
}
} elseif { [istarget sparc*-*-*] } {
lappend result 64
} else {
# The traditional default asumption.
lappend result 128
}
return $result
}
# Return 1 if the target supports multiple vector sizes
proc check_effective_target_vect_multiple_sizes { } {
return [expr { [llength [available_vector_sizes]] > 1 }]
}
# Return true if variable-length vectors are supported.
proc check_effective_target_vect_variable_length { } {
return [expr { [lindex [available_vector_sizes] 0] == 0 }]
}
# Return 1 if the target supports vectors of 64 bits.
proc check_effective_target_vect64 { } {
return [expr { [lsearch -exact [available_vector_sizes] 64] >= 0 }]
}
# Return 1 if the target supports vector copysignf calls.
proc check_effective_target_vect_call_copysignf { } {
return [check_cached_effective_target_indexed vect_call_copysignf {
expr { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget powerpc*-*-*]
|| [istarget aarch64*-*-*] }}]
}
# Return 1 if the target supports hardware square root instructions.
proc check_effective_target_sqrt_insn { } {
return [check_cached_effective_target sqrt_insn {
expr { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget powerpc*-*-*]
|| [istarget aarch64*-*-*]
|| ([istarget arm*-*-*] && [check_effective_target_arm_vfp_ok])
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx])
|| [istarget amdgcn-*-*] }}]
}
# Return any additional options to enable square root intructions.
proc add_options_for_sqrt_insn { flags } {
if { [istarget amdgcn*-*-*] } {
return "$flags -ffast-math"
}
if { [istarget arm*-*-*] } {
return [add_options_for_arm_vfp "$flags"]
}
return $flags
}
# Return 1 if the target supports vector sqrtf calls.
proc check_effective_target_vect_call_sqrtf { } {
return [check_cached_effective_target_indexed vect_call_sqrtf {
expr { [istarget aarch64*-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([istarget powerpc*-*-*] && [check_vsx_hw_available])
|| ([istarget s390*-*-*]
&& [check_effective_target_s390_vx]) }}]
}
# Return 1 if the target supports vector lrint calls.
proc check_effective_target_vect_call_lrint { } {
set et_vect_call_lrint 0
if { (([istarget i?86-*-*] || [istarget x86_64-*-*])
&& [check_effective_target_ilp32])
|| [istarget amdgcn-*-*] } {
set et_vect_call_lrint 1
}
verbose "check_effective_target_vect_call_lrint: returning $et_vect_call_lrint" 2
return $et_vect_call_lrint
}
# Return 1 if the target supports vector btrunc calls.
proc check_effective_target_vect_call_btrunc { } {
return [check_cached_effective_target_indexed vect_call_btrunc {
expr { [istarget aarch64*-*-*]
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports vector btruncf calls.
proc check_effective_target_vect_call_btruncf { } {
return [check_cached_effective_target_indexed vect_call_btruncf {
expr { [istarget aarch64*-*-*]
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports vector ceil calls.
proc check_effective_target_vect_call_ceil { } {
return [check_cached_effective_target_indexed vect_call_ceil {
expr { [istarget aarch64*-*-*]
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports vector ceilf calls.
proc check_effective_target_vect_call_ceilf { } {
return [check_cached_effective_target_indexed vect_call_ceilf {
expr { [istarget aarch64*-*-*] }}]
}
# Return 1 if the target supports vector floor calls.
proc check_effective_target_vect_call_floor { } {
return [check_cached_effective_target_indexed vect_call_floor {
expr { [istarget aarch64*-*-*] }}]
}
# Return 1 if the target supports vector floorf calls.
proc check_effective_target_vect_call_floorf { } {
return [check_cached_effective_target_indexed vect_call_floorf {
expr { [istarget aarch64*-*-*]
|| [istarget amdgcn-*-*] }}]
}
# Return 1 if the target supports vector lceil calls.
proc check_effective_target_vect_call_lceil { } {
return [check_cached_effective_target_indexed vect_call_lceil {
expr { [istarget aarch64*-*-*] }}]
}
# Return 1 if the target supports vector lfloor calls.
proc check_effective_target_vect_call_lfloor { } {
return [check_cached_effective_target_indexed vect_call_lfloor {
expr { [istarget aarch64*-*-*] }}]
}
# Return 1 if the target supports vector nearbyint calls.
proc check_effective_target_vect_call_nearbyint { } {
return [check_cached_effective_target_indexed vect_call_nearbyint {
expr { [istarget aarch64*-*-*] }}]
}
# Return 1 if the target supports vector nearbyintf calls.
proc check_effective_target_vect_call_nearbyintf { } {
return [check_cached_effective_target_indexed vect_call_nearbyintf {
expr { [istarget aarch64*-*-*] }}]
}
# Return 1 if the target supports vector round calls.
proc check_effective_target_vect_call_round { } {
return [check_cached_effective_target_indexed vect_call_round {
expr { [istarget aarch64*-*-*] }}]
}
# Return 1 if the target supports vector roundf calls.
proc check_effective_target_vect_call_roundf { } {
return [check_cached_effective_target_indexed vect_call_roundf {
expr { [istarget aarch64*-*-*] }}]
}
# Return 1 if the target supports AND, OR and XOR reduction.
proc check_effective_target_vect_logical_reduc { } {
return [check_effective_target_aarch64_sve]
}
# Return 1 if the target supports the fold_extract_last optab.
proc check_effective_target_vect_fold_extract_last { } {
return [check_effective_target_aarch64_sve]
}
# Return 1 if the target supports section-anchors
proc check_effective_target_section_anchors { } {
return [check_cached_effective_target section_anchors {
expr { [istarget powerpc*-*-*]
|| [istarget arm*-*-*]
|| [istarget aarch64*-*-*] }}]
}
# Return 1 if the target supports atomic operations on "int_128" values.
proc check_effective_target_sync_int_128 { } {
return 0
}
# Return 1 if the target supports atomic operations on "int_128" values
# and can execute them.
# This requires support for both compare-and-swap and true atomic loads.
proc check_effective_target_sync_int_128_runtime { } {
return 0
}
# Return 1 if the target supports atomic operations on "long long".
#
# Note: 32bit x86 targets require -march=pentium in dg-options.
# Note: 32bit s390 targets require -mzarch in dg-options.
proc check_effective_target_sync_long_long { } {
if { [istarget i?86-*-*] || [istarget x86_64-*-*])
|| [istarget aarch64*-*-*]
|| [istarget arm*-*-*]
|| [istarget alpha*-*-*]
|| ([istarget sparc*-*-*] && [check_effective_target_lp64])
|| [istarget s390*-*-*] } {
return 1
} else {
return 0
}
}
# Return 1 if the target supports popcount on long.
proc check_effective_target_popcountl { } {
return [check_no_messages_and_pattern popcountl "!\\(call" rtl-expand {
int foo (long b)
{
return __builtin_popcountl (b);
}
} "" ]
}
# Return 1 if the target supports popcount on long long.
proc check_effective_target_popcountll { } {
return [check_no_messages_and_pattern popcountll "!\\(call" rtl-expand {
int foo (long long b)
{
return __builtin_popcountll (b);
}
} "" ]
}
# Return 1 if the target supports popcount on int.
proc check_effective_target_popcount { } {
return [check_no_messages_and_pattern popcount "!\\(call" rtl-expand {
int foo (int b)
{
return __builtin_popcount (b);
}
} "" ]
}
# Return 1 if the target supports atomic operations on "long long"
# and can execute them.
#
# Note: 32bit x86 targets require -march=pentium in dg-options.
proc check_effective_target_sync_long_long_runtime { } {
if { (([istarget x86_64-*-*] || [istarget i?86-*-*])
&& [check_cached_effective_target sync_long_long_available {
check_runtime_nocache sync_long_long_available {
#include "cpuid.h"
int main ()
{
unsigned int eax, ebx, ecx, edx;
if (__get_cpuid (1, &eax, &ebx, &ecx, &edx))
return !(edx & bit_CMPXCHG8B);
return 1;
}
} ""
}])
|| [istarget aarch64*-*-*]
|| [istarget arm*-*-uclinuxfdpiceabi]
|| ([istarget arm*-*-linux-*]
&& [check_runtime sync_longlong_runtime {
#include <stdlib.h>
int main ()
{
long long l1;
if (sizeof (long long) != 8)
exit (1);
/* Just check for native;
checking for kernel fallback is tricky. */
asm volatile ("ldrexd r0,r1, [%0]"
: : "r" (&l1) : "r0", "r1");
exit (0);
}
} "" ])
|| [istarget alpha*-*-*]
|| ([istarget sparc*-*-*]
&& [check_effective_target_lp64]
&& [check_effective_target_ultrasparc_hw])
|| ([istarget powerpc*-*-*] && [check_effective_target_lp64]) } {
return 1
} else {
return 0
}
}
# Return 1 if the target supports byte swap instructions.
proc check_effective_target_bswap { } {
return [check_cached_effective_target bswap {
expr { [istarget aarch64*-*-*]
|| [istarget alpha*-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget m68k-*-*]
|| [istarget powerpc*-*-*]
|| [istarget rs6000-*-*]
|| [istarget s390*-*-*]
|| ([istarget arm*-*-*]
&& [check_no_compiler_messages_nocache arm_v6_or_later object {
#if __ARM_ARCH < 6
#error not armv6 or later
#endif
int i;
} ""]) }}]
}
# Return 1 if the target supports atomic operations on "int" and "long".
proc check_effective_target_sync_int_long { } {
# This is intentionally powerpc but not rs6000, rs6000 doesn't have the
# load-reserved/store-conditional instructions.
return [check_cached_effective_target sync_int_long {
expr { [istarget ia64-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget aarch64*-*-*]
|| [istarget alpha*-*-*]
|| [istarget arm*-*-linux-*]
|| [istarget arm*-*-uclinuxfdpiceabi]
|| ([istarget arm*-*-*]
&& [check_effective_target_arm_acq_rel])
|| [istarget bfin*-*linux*]
|| [istarget hppa*-*linux*]
|| [istarget s390*-*-*]
|| [istarget powerpc*-*-*]
|| [istarget crisv32-*-*] || [istarget cris-*-*]
|| ([istarget sparc*-*-*] && [check_effective_target_sparc_v9])
|| ([istarget arc*-*-*] && [check_effective_target_arc_atomic])
|| [check_effective_target_mips_llsc] }}]
}
# Return 1 if the target supports atomic operations on "char" and "short".
proc check_effective_target_sync_char_short { } {
# This is intentionally powerpc but not rs6000, rs6000 doesn't have the
# load-reserved/store-conditional instructions.
return [check_cached_effective_target sync_char_short {
expr { [istarget aarch64*-*-*]
|| [istarget ia64-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget alpha*-*-*]
|| [istarget arm*-*-linux-*]
|| [istarget arm*-*-uclinuxfdpiceabi]
|| ([istarget arm*-*-*]
&& [check_effective_target_arm_acq_rel])
|| [istarget hppa*-*linux*]
|| [istarget s390*-*-*]
|| [istarget powerpc*-*-*]
|| [istarget crisv32-*-*] || [istarget cris-*-*]
|| ([istarget sparc*-*-*] && [check_effective_target_sparc_v9])
|| ([istarget arc*-*-*] && [check_effective_target_arc_atomic])
|| [check_effective_target_mips_llsc] }}]
}
# Return 1 if the target uses a ColdFire FPU.
proc check_effective_target_coldfire_fpu { } {
return [check_no_compiler_messages coldfire_fpu assembly {
#ifndef __mcffpu__
#error !__mcffpu__
#endif
}]
}
# Return true if this is a uClibc target.
proc check_effective_target_uclibc {} {
return [check_no_compiler_messages uclibc object {
#include <features.h>
#if !defined (__UCLIBC__)
#error !__UCLIBC__
#endif
}]
}
# Return true if this is a uclibc target and if the uclibc feature
# described by __$feature__ is not present.
proc check_missing_uclibc_feature {feature} {
return [check_no_compiler_messages $feature object "
#include <features.h>
#if !defined (__UCLIBC) || defined (__${feature}__)
#error FOO
#endif
"]
}
# Return true if this is a Newlib target.
proc check_effective_target_newlib {} {
return [check_no_compiler_messages newlib object {
#include <newlib.h>
}]
}
# Return true if GCC was configured with --enable-newlib-nano-formatted-io
proc check_effective_target_newlib_nano_io { } {
return [check_configured_with "--enable-newlib-nano-formatted-io"]
}
# Some newlib versions don't provide a frexpl and instead depend
# on frexp to implement long double conversions in their printf-like
# functions. This leads to broken results. Detect such versions here.
proc check_effective_target_newlib_broken_long_double_io {} {
if { [is-effective-target newlib] && ![is-effective-target frexpl] } {
return 1
}
return 0
}
# Return true if this is NOT a Bionic target.
proc check_effective_target_non_bionic {} {
return [check_no_compiler_messages non_bionic object {
#include <ctype.h>
#if defined (__BIONIC__)
#error FOO
#endif
}]
}
# Return true if this target has error.h header.
proc check_effective_target_error_h {} {
return [check_no_compiler_messages error_h object {
#include <error.h>
}]
}
# Return true if this target has tgmath.h header.
proc check_effective_target_tgmath_h {} {
return [check_no_compiler_messages tgmath_h object {
#include <tgmath.h>
}]
}
# Return true if target's libc supports complex functions.
proc check_effective_target_libc_has_complex_functions {} {
return [check_no_compiler_messages libc_has_complex_functions object {
#include <complex.h>
}]
}
# Return 1 if
# (a) an error of a few ULP is expected in string to floating-point
# conversion functions; and
# (b) overflow is not always detected correctly by those functions.
proc check_effective_target_lax_strtofp {} {
# By default, assume that all uClibc targets suffer from this.
return [check_effective_target_uclibc]
}
# Return 1 if this is a target for which wcsftime is a dummy
# function that always returns 0.
proc check_effective_target_dummy_wcsftime {} {
# By default, assume that all uClibc targets suffer from this.
return [check_effective_target_uclibc]
}
# Return 1 if constructors with initialization priority arguments are
# supposed on this target.
proc check_effective_target_init_priority {} {
return [check_no_compiler_messages init_priority assembly "
void f() __attribute__((constructor (1000)));
void f() \{\}
"]
}
# Return 1 if the target matches the effective target 'arg', 0 otherwise.
# This can be used with any check_* proc that takes no argument and
# returns only 1 or 0. It could be used with check_* procs that take
# arguments with keywords that pass particular arguments.
proc is-effective-target { arg } {
global et_index
set selected 0
if { ![info exists et_index] } {
# Initialize the effective target index that is used in some
# check_effective_target_* procs.
set et_index 0
}
if { [info procs check_effective_target_${arg}] != [list] } {
set selected [check_effective_target_${arg}]
} else {
switch $arg {
"vmx_hw" { set selected [check_vmx_hw_available] }
"vsx_hw" { set selected [check_vsx_hw_available] }
"p8vector_hw" { set selected [check_p8vector_hw_available] }
"p9vector_hw" { set selected [check_p9vector_hw_available] }
"p9modulo_hw" { set selected [check_p9modulo_hw_available] }
"ppc_float128_sw" { set selected [check_ppc_float128_sw_available] }
"ppc_float128_hw" { set selected [check_ppc_float128_hw_available] }
"ppc_recip_hw" { set selected [check_ppc_recip_hw_available] }
"ppc_cpu_supports_hw" { set selected [check_ppc_cpu_supports_hw_available] }
"dfp_hw" { set selected [check_dfp_hw_available] }
"htm_hw" { set selected [check_htm_hw_available] }
"named_sections" { set selected [check_named_sections_available] }
"gc_sections" { set selected [check_gc_sections_available] }
"cxa_atexit" { set selected [check_cxa_atexit_available] }
default { error "unknown effective target keyword `$arg'" }
}
}
verbose "is-effective-target: $arg $selected" 2
return $selected
}
# Return 1 if the argument is an effective-target keyword, 0 otherwise.
proc is-effective-target-keyword { arg } {
if { [info procs check_effective_target_${arg}] != [list] } {
return 1
} else {
# These have different names for their check_* procs.
switch $arg {
"vmx_hw" { return 1 }
"vsx_hw" { return 1 }
"p8vector_hw" { return 1 }
"p9vector_hw" { return 1 }
"p9modulo_hw" { return 1 }
"ppc_float128_sw" { return 1 }
"ppc_float128_hw" { return 1 }
"ppc_recip_hw" { return 1 }
"dfp_hw" { return 1 }
"htm_hw" { return 1 }
"named_sections" { return 1 }
"gc_sections" { return 1 }
"cxa_atexit" { return 1 }
default { return 0 }
}
}
}
# Execute tests for all targets in EFFECTIVE_TARGETS list. Set et_index to
# indicate what target is currently being processed. This is for
# the vectorizer tests, e.g. vect_int, to keep track what target supports
# a given feature.
proc et-dg-runtest { runtest testcases flags default-extra-flags } {
global dg-do-what-default
global EFFECTIVE_TARGETS
global et_index
if { [llength $EFFECTIVE_TARGETS] > 0 } {
foreach target $EFFECTIVE_TARGETS {
set target_flags $flags
set dg-do-what-default compile
set et_index [lsearch -exact $EFFECTIVE_TARGETS $target]
if { [info procs add_options_for_${target}] != [list] } {
set target_flags [add_options_for_${target} "$flags"]
}
if { [info procs check_effective_target_${target}_runtime]
!= [list] && [check_effective_target_${target}_runtime] } {
set dg-do-what-default run
}
$runtest $testcases $target_flags ${default-extra-flags}
}
} else {
set et_index 0
$runtest $testcases $flags ${default-extra-flags}
}
}
# Return 1 if a target matches the target in EFFECTIVE_TARGETS at index
# et_index, 0 otherwise.
proc et-is-effective-target { target } {
global EFFECTIVE_TARGETS
global et_index
if { [llength $EFFECTIVE_TARGETS] > $et_index
&& [lindex $EFFECTIVE_TARGETS $et_index] == $target } {
return 1
}
return 0
}
# Return 1 if target default to short enums
proc check_effective_target_short_enums { } {
return [check_no_compiler_messages short_enums assembly {
enum foo { bar };
int s[sizeof (enum foo) == 1 ? 1 : -1];
}]
}
# Return 1 if target supports merging string constants at link time.
proc check_effective_target_string_merging { } {
return [check_no_messages_and_pattern string_merging \
"rodata\\.str" assembly {
const char *var = "String";
} {-O2}]
}
# Return 1 if target has the basic signed and unsigned types in
# <stdint.h>, 0 otherwise. This will be obsolete when GCC ensures a
# working <stdint.h> for all targets.
proc check_effective_target_stdint_types { } {
return [check_no_compiler_messages stdint_types assembly {
#include <stdint.h>
int8_t a; int16_t b; int32_t c; int64_t d;
uint8_t e; uint16_t f; uint32_t g; uint64_t h;
}]
}
# Return 1 if target has the basic signed and unsigned types in
# <inttypes.h>, 0 otherwise. This is for tests that GCC's notions of
# these types agree with those in the header, as some systems have
# only <inttypes.h>.
proc check_effective_target_inttypes_types { } {
return [check_no_compiler_messages inttypes_types assembly {
#include <inttypes.h>
int8_t a; int16_t b; int32_t c; int64_t d;
uint8_t e; uint16_t f; uint32_t g; uint64_t h;
}]
}
# Return 1 if programs are intended to be run on a simulator
# (i.e. slowly) rather than hardware (i.e. fast).
proc check_effective_target_simulator { } {
# All "src/sim" simulators set this one.
if [board_info target exists is_simulator] {
return [board_info target is_simulator]
}
# The "sid" simulators don't set that one, but at least they set
# this one.
if [board_info target exists slow_simulator] {
return [board_info target slow_simulator]
}
return 0
}
# Return 1 if programs are intended to be run on hardware rather than
# on a simulator
proc check_effective_target_hw { } {
# All "src/sim" simulators set this one.
if [board_info target exists is_simulator] {
if [board_info target is_simulator] {
return 0
} else {
return 1
}
}
# The "sid" simulators don't set that one, but at least they set
# this one.
if [board_info target exists slow_simulator] {
if [board_info target slow_simulator] {
return 0
} else {
return 1
}
}
return 1
}
# Return 1 if the target is a VxWorks kernel.
proc check_effective_target_vxworks_kernel { } {
return [check_no_compiler_messages vxworks_kernel assembly {
#if !defined __vxworks || defined __RTP__
#error NO
#endif
}]
}
# Return 1 if the target is a VxWorks RTP.
proc check_effective_target_vxworks_rtp { } {
return [check_no_compiler_messages vxworks_rtp assembly {
#if !defined __vxworks || !defined __RTP__
#error NO
#endif
}]
}
# Return 1 if the target is expected to provide wide character support.
proc check_effective_target_wchar { } {
if {[check_missing_uclibc_feature UCLIBC_HAS_WCHAR]} {
return 0
}
return [check_no_compiler_messages wchar assembly {
#include <wchar.h>
}]
}
# Return 1 if the target has <pthread.h>.
proc check_effective_target_pthread_h { } {
return [check_no_compiler_messages pthread_h assembly {
#include <pthread.h>
}]
}
# Return 1 if the target can truncate a file from a file-descriptor,
# as used by libgfortran/io/unix.c:fd_truncate; i.e. ftruncate or
# chsize. We test for a trivially functional truncation; no stubs.
# As libgfortran uses _FILE_OFFSET_BITS 64, we do too; it'll cause a
# different function to be used.
proc check_effective_target_fd_truncate { } {
set prog {
#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ()
{
FILE *f = fopen ("tst.tmp", "wb");
int fd;
const char t[] = "test writing more than ten characters";
char s[11];
int status = 0;
fd = fileno (f);
write (fd, t, sizeof (t) - 1);
lseek (fd, 0, 0);
if (ftruncate (fd, 10) != 0)
status = 1;
close (fd);
fclose (f);
if (status)
{
unlink ("tst.tmp");
exit (status);
}
f = fopen ("tst.tmp", "rb");
if (fread (s, 1, sizeof (s), f) != 10 || strncmp (s, t, 10) != 0)
status = 1;
fclose (f);
unlink ("tst.tmp");
exit (status);
}
}
if { [check_runtime ftruncate $prog] } {
return 1;
}
regsub "ftruncate" $prog "chsize" prog
return [check_runtime chsize $prog]
}
# Add to FLAGS all the target-specific flags needed to enable
# full IEEE compliance mode.
proc add_options_for_ieee { flags } {
if { [istarget alpha*-*-*]
|| [istarget sh*-*-*] } {
return "$flags -mieee"
}
if { [istarget rx-*-*] } {
return "$flags -mnofpu"
}
return $flags
}
if {![info exists flags_to_postpone]} {
set flags_to_postpone ""
}
# Add to FLAGS the flags needed to enable functions to bind locally
# when using pic/PIC passes in the testsuite.
proc add_options_for_bind_pic_locally { flags } {
global flags_to_postpone
# Instead of returning 'flags' with the -fPIE or -fpie appended, we save it
# in 'flags_to_postpone' and append it later in gcc_target_compile procedure in
# order to make sure that the multilib_flags doesn't override this.
if {[check_no_compiler_messages using_pic2 assembly {
#if __PIC__ != 2
#error __PIC__ != 2
#endif
}]} {
set flags_to_postpone "-fPIE"
return $flags
}
if {[check_no_compiler_messages using_pic1 assembly {
#if __PIC__ != 1
#error __PIC__ != 1
#endif
}]} {
set flags_to_postpone "-fpie"
return $flags
}
return $flags
}
# Add to FLAGS the flags needed to enable 64-bit vectors.
proc add_options_for_double_vectors { flags } {
if [is-effective-target arm_neon_ok] {
return "$flags -mvectorize-with-neon-double"
}
return $flags
}
# Add to FLAGS the flags needed to define the STACK_SIZE macro.
proc add_options_for_stack_size { flags } {
if [is-effective-target stack_size] {
set stack_size [dg-effective-target-value stack_size]
return "$flags -DSTACK_SIZE=$stack_size"
}
return $flags
}
# Return 1 if the target provides a full C99 runtime.
proc check_effective_target_c99_runtime { } {
return [check_cached_effective_target c99_runtime {
global srcdir
set file [open "$srcdir/gcc.dg/builtins-config.h"]
set contents [read $file]
close $file
append contents {
#ifndef HAVE_C99_RUNTIME
#error !HAVE_C99_RUNTIME
#endif
}
check_no_compiler_messages_nocache c99_runtime assembly $contents
}]
}
# Return 1 if the target provides the D runtime.
proc check_effective_target_d_runtime { } {
return [check_no_compiler_messages d_runtime executable {
// D
module mod;
extern(C) int main() {
return 0;
}
}]
}
# Return 1 if target wchar_t is at least 4 bytes.
proc check_effective_target_4byte_wchar_t { } {
return [check_no_compiler_messages 4byte_wchar_t object {
int dummy[sizeof (__WCHAR_TYPE__) >= 4 ? 1 : -1];
}]
}
# Return 1 if the target supports automatic stack alignment.
proc check_effective_target_automatic_stack_alignment { } {
# Ordinarily x86 supports automatic stack alignment ...
if { [istarget i?86*-*-*] || [istarget x86_64-*-*] } then {
if { [istarget *-*-mingw*] || [istarget *-*-cygwin*] } {
# ... except Win64 SEH doesn't. Succeed for Win32 though.
return [check_effective_target_ilp32];
}
return 1;
}
return 0;
}
# Return true if we are compiling for AVX target.
proc check_avx_available { } {
if { [check_no_compiler_messages avx_available assembly {
#ifndef __AVX__
#error unsupported
#endif
} ""] } {
return 1;
}
return 0;
}
# Return true if we are compiling for AVX2 target.
proc check_avx2_available { } {
if { [check_no_compiler_messages avx2_available assembly {
#ifndef __AVX2__
#error unsupported
#endif
} ""] } {
return 1;
}
return 0;
}
# Return true if we are compiling for SSSE3 target.
proc check_ssse3_available { } {
if { [check_no_compiler_messages sse3a_available assembly {
#ifndef __SSSE3__
#error unsupported
#endif
} ""] } {
return 1;
}
return 0;
}
# Return true if 32- and 16-bytes vectors are available.
proc check_effective_target_vect_sizes_32B_16B { } {
return [expr { [available_vector_sizes] == [list 256 128] }]
}
# Return true if 16- and 8-bytes vectors are available.
proc check_effective_target_vect_sizes_16B_8B { } {
if { [check_avx_available]
|| [is-effective-target arm_neon]
|| [istarget aarch64*-*-*] } {
return 1;
} else {
return 0;
}
}
# Return true if 128-bits vectors are preferred even if 256-bits vectors
# are available.
proc check_prefer_avx128 { } {
if ![check_avx_available] {
return 0;
}
return [check_no_messages_and_pattern avx_explicit "xmm" assembly {
float a[1024],b[1024],c[1024];
void foo (void) { int i; for (i = 0; i < 1024; i++) a[i]=b[i]+c[i];}
} "-O2 -ftree-vectorize"]
}
# Return 1 if avx512f instructions can be compiled.
proc check_effective_target_avx512f { } {
return [check_no_compiler_messages avx512f object {
typedef double __m512d __attribute__ ((__vector_size__ (64)));
typedef double __m128d __attribute__ ((__vector_size__ (16)));
__m512d _mm512_add (__m512d a)
{
return __builtin_ia32_addpd512_mask (a, a, a, 1, 4);
}
__m128d _mm128_add (__m128d a)
{
return __builtin_ia32_addsd_round (a, a, 8);
}
__m128d _mm128_getmant (__m128d a)
{
return __builtin_ia32_getmantsd_round (a, a, 0, 8);
}
} "-O2 -mavx512f" ]
}
# Return 1 if avx instructions can be compiled.
proc check_effective_target_avx { } {
if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
return 0
}
return [check_no_compiler_messages avx object {
void _mm256_zeroall (void)
{
__builtin_ia32_vzeroall ();
}
} "-O2 -mavx" ]
}
# Return 1 if avx2 instructions can be compiled.
proc check_effective_target_avx2 { } {
return [check_no_compiler_messages avx2 object {
typedef long long __v4di __attribute__ ((__vector_size__ (32)));
__v4di
mm256_is32_andnotsi256 (__v4di __X, __v4di __Y)
{
return __builtin_ia32_andnotsi256 (__X, __Y);
}
} "-O0 -mavx2" ]
}
# Return 1 if sse instructions can be compiled.
proc check_effective_target_sse { } {
return [check_no_compiler_messages sse object {
int main ()
{
__builtin_ia32_stmxcsr ();
return 0;
}
} "-O2 -msse" ]
}
# Return 1 if sse2 instructions can be compiled.
proc check_effective_target_sse2 { } {
return [check_no_compiler_messages sse2 object {
typedef long long __m128i __attribute__ ((__vector_size__ (16)));
__m128i _mm_srli_si128 (__m128i __A, int __N)
{
return (__m128i)__builtin_ia32_psrldqi128 (__A, 8);
}
} "-O2 -msse2" ]
}
# Return 1 if sse4.1 instructions can be compiled.
proc check_effective_target_sse4 { } {
return [check_no_compiler_messages sse4.1 object {
typedef long long __m128i __attribute__ ((__vector_size__ (16)));
typedef int __v4si __attribute__ ((__vector_size__ (16)));
__m128i _mm_mullo_epi32 (__m128i __X, __m128i __Y)
{
return (__m128i) __builtin_ia32_pmulld128 ((__v4si)__X,
(__v4si)__Y);
}
} "-O2 -msse4.1" ]
}
# Return 1 if F16C instructions can be compiled.
proc check_effective_target_f16c { } {
return [check_no_compiler_messages f16c object {
#include "immintrin.h"
float
foo (unsigned short val)
{
return _cvtsh_ss (val);
}
} "-O2 -mf16c" ]
}
proc check_effective_target_ms_hook_prologue { } {
if { [check_no_compiler_messages ms_hook_prologue object {
void __attribute__ ((__ms_hook_prologue__)) foo ();
} ""] } {
return 1
} else {
return 0
}
}
# Return 1 if 3dnow instructions can be compiled.
proc check_effective_target_3dnow { } {
return [check_no_compiler_messages 3dnow object {
typedef int __m64 __attribute__ ((__vector_size__ (8)));
typedef float __v2sf __attribute__ ((__vector_size__ (8)));
__m64 _m_pfadd (__m64 __A, __m64 __B)
{
return (__m64) __builtin_ia32_pfadd ((__v2sf)__A, (__v2sf)__B);
}
} "-O2 -m3dnow" ]
}
# Return 1 if sse3 instructions can be compiled.
proc check_effective_target_sse3 { } {
return [check_no_compiler_messages sse3 object {
typedef double __m128d __attribute__ ((__vector_size__ (16)));
typedef double __v2df __attribute__ ((__vector_size__ (16)));
__m128d _mm_addsub_pd (__m128d __X, __m128d __Y)
{
return (__m128d) __builtin_ia32_addsubpd ((__v2df)__X, (__v2df)__Y);
}
} "-O2 -msse3" ]
}
# Return 1 if ssse3 instructions can be compiled.
proc check_effective_target_ssse3 { } {
return [check_no_compiler_messages ssse3 object {
typedef long long __m128i __attribute__ ((__vector_size__ (16)));
typedef int __v4si __attribute__ ((__vector_size__ (16)));
__m128i _mm_abs_epi32 (__m128i __X)
{
return (__m128i) __builtin_ia32_pabsd128 ((__v4si)__X);
}
} "-O2 -mssse3" ]
}
# Return 1 if aes instructions can be compiled.
proc check_effective_target_aes { } {
return [check_no_compiler_messages aes object {
typedef long long __m128i __attribute__ ((__vector_size__ (16)));
typedef long long __v2di __attribute__ ((__vector_size__ (16)));
__m128i _mm_aesimc_si128 (__m128i __X)
{
return (__m128i) __builtin_ia32_aesimc128 ((__v2di)__X);
}
} "-O2 -maes" ]
}
# Return 1 if vaes instructions can be compiled.
proc check_effective_target_vaes { } {
return [check_no_compiler_messages vaes object {
typedef long long __m128i __attribute__ ((__vector_size__ (16)));
typedef long long __v2di __attribute__ ((__vector_size__ (16)));
__m128i _mm_aesimc_si128 (__m128i __X)
{
return (__m128i) __builtin_ia32_aesimc128 ((__v2di)__X);
}
} "-O2 -maes -mavx" ]
}
# Return 1 if pclmul instructions can be compiled.
proc check_effective_target_pclmul { } {
return [check_no_compiler_messages pclmul object {
typedef long long __m128i __attribute__ ((__vector_size__ (16)));
typedef long long __v2di __attribute__ ((__vector_size__ (16)));
__m128i pclmulqdq_test (__m128i __X, __m128i __Y)
{
return (__m128i) __builtin_ia32_pclmulqdq128 ((__v2di)__X,
(__v2di)__Y,
1);
}
} "-O2 -mpclmul" ]
}
# Return 1 if vpclmul instructions can be compiled.
proc check_effective_target_vpclmul { } {
return [check_no_compiler_messages vpclmul object {
typedef long long __m128i __attribute__ ((__vector_size__ (16)));
typedef long long __v2di __attribute__ ((__vector_size__ (16)));
__m128i pclmulqdq_test (__m128i __X, __m128i __Y)
{
return (__m128i) __builtin_ia32_pclmulqdq128 ((__v2di)__X,
(__v2di)__Y,
1);
}
} "-O2 -mpclmul -mavx" ]
}
# Return 1 if sse4a instructions can be compiled.
proc check_effective_target_sse4a { } {
return [check_no_compiler_messages sse4a object {
typedef long long __m128i __attribute__ ((__vector_size__ (16)));
typedef long long __v2di __attribute__ ((__vector_size__ (16)));
__m128i _mm_insert_si64 (__m128i __X,__m128i __Y)
{
return (__m128i) __builtin_ia32_insertq ((__v2di)__X, (__v2di)__Y);
}
} "-O2 -msse4a" ]
}
# Return 1 if fma4 instructions can be compiled.
proc check_effective_target_fma4 { } {
return [check_no_compiler_messages fma4 object {
typedef float __m128 __attribute__ ((__vector_size__ (16)));
typedef float __v4sf __attribute__ ((__vector_size__ (16)));
__m128 _mm_macc_ps(__m128 __A, __m128 __B, __m128 __C)
{
return (__m128) __builtin_ia32_vfmaddps ((__v4sf)__A,
(__v4sf)__B,
(__v4sf)__C);
}
} "-O2 -mfma4" ]
}
# Return 1 if fma instructions can be compiled.
proc check_effective_target_fma { } {
return [check_no_compiler_messages fma object {
typedef float __m128 __attribute__ ((__vector_size__ (16)));
typedef float __v4sf __attribute__ ((__vector_size__ (16)));
__m128 _mm_macc_ps(__m128 __A, __m128 __B, __m128 __C)
{
return (__m128) __builtin_ia32_vfmaddps ((__v4sf)__A,
(__v4sf)__B,
(__v4sf)__C);
}
} "-O2 -mfma" ]
}
# Return 1 if xop instructions can be compiled.
proc check_effective_target_xop { } {
return [check_no_compiler_messages xop object {
typedef long long __m128i __attribute__ ((__vector_size__ (16)));
typedef short __v8hi __attribute__ ((__vector_size__ (16)));
__m128i _mm_maccs_epi16(__m128i __A, __m128i __B, __m128i __C)
{
return (__m128i) __builtin_ia32_vpmacssww ((__v8hi)__A,
(__v8hi)__B,
(__v8hi)__C);
}
} "-O2 -mxop" ]
}
# Return 1 if lzcnt instruction can be compiled.
proc check_effective_target_lzcnt { } {
return [check_no_compiler_messages lzcnt object {
unsigned short _lzcnt (unsigned short __X)
{
return __builtin_clzs (__X);
}
} "-mlzcnt" ]
}
# Return 1 if bmi instructions can be compiled.
proc check_effective_target_bmi { } {
return [check_no_compiler_messages bmi object {
unsigned int __bextr_u32 (unsigned int __X, unsigned int __Y)
{
return __builtin_ia32_bextr_u32 (__X, __Y);
}
} "-mbmi" ]
}
# Return 1 if ADX instructions can be compiled.
proc check_effective_target_adx { } {
return [check_no_compiler_messages adx object {
unsigned char
_adxcarry_u32 (unsigned char __CF, unsigned int __X,
unsigned int __Y, unsigned int *__P)
{
return __builtin_ia32_addcarryx_u32 (__CF, __X, __Y, __P);
}
} "-madx" ]
}
# Return 1 if rtm instructions can be compiled.
proc check_effective_target_rtm { } {
return [check_no_compiler_messages rtm object {
void
_rtm_xend (void)
{
return __builtin_ia32_xend ();
}
} "-mrtm" ]
}
# Return 1 if avx512vl instructions can be compiled.
proc check_effective_target_avx512vl { } {
return [check_no_compiler_messages avx512vl object {
typedef long long __v4di __attribute__ ((__vector_size__ (32)));
__v4di
mm256_and_epi64 (__v4di __X, __v4di __Y)
{
__v4di __W;
return __builtin_ia32_pandq256_mask (__X, __Y, __W, -1);
}
} "-mavx512vl" ]
}
# Return 1 if avx512cd instructions can be compiled.
proc check_effective_target_avx512cd { } {
return [check_no_compiler_messages avx512cd_trans object {
typedef long long __v8di __attribute__ ((__vector_size__ (64)));
__v8di
_mm512_conflict_epi64 (__v8di __W, __v8di __A)
{
return (__v8di) __builtin_ia32_vpconflictdi_512_mask ((__v8di) __A,
(__v8di) __W,
-1);
}
} "-Wno-psabi -mavx512cd" ]
}
# Return 1 if avx512er instructions can be compiled.
proc check_effective_target_avx512er { } {
return [check_no_compiler_messages avx512er_trans object {
typedef float __v16sf __attribute__ ((__vector_size__ (64)));
__v16sf
mm512_exp2a23_ps (__v16sf __X)
{
return __builtin_ia32_exp2ps_mask (__X, __X, -1, 4);
}
} "-Wno-psabi -mavx512er" ]
}
# Return 1 if sha instructions can be compiled.
proc check_effective_target_sha { } {
return [check_no_compiler_messages sha object {
typedef long long __m128i __attribute__ ((__vector_size__ (16)));
typedef int __v4si __attribute__ ((__vector_size__ (16)));
__m128i _mm_sha1msg1_epu32 (__m128i __X, __m128i __Y)
{
return (__m128i) __builtin_ia32_sha1msg1 ((__v4si)__X,
(__v4si)__Y);
}
} "-O2 -msha" ]
}
# Return 1 if avx512dq instructions can be compiled.
proc check_effective_target_avx512dq { } {
return [check_no_compiler_messages avx512dq object {
typedef long long __v8di __attribute__ ((__vector_size__ (64)));
__v8di
_mm512_mask_mullo_epi64 (__v8di __W, __v8di __A, __v8di __B)
{
return (__v8di) __builtin_ia32_pmullq512_mask ((__v8di) __A,
(__v8di) __B,
(__v8di) __W,
-1);
}
} "-mavx512dq" ]
}
# Return 1 if avx512bw instructions can be compiled.
proc check_effective_target_avx512bw { } {
return [check_no_compiler_messages avx512bw object {
typedef short __v32hi __attribute__ ((__vector_size__ (64)));
__v32hi
_mm512_mask_mulhrs_epi16 (__v32hi __W, __v32hi __A, __v32hi __B)
{
return (__v32hi) __builtin_ia32_pmulhrsw512_mask ((__v32hi) __A,
(__v32hi) __B,
(__v32hi) __W,
-1);
}
} "-mavx512bw" ]
}
# Return 1 if avx512vp2intersect instructions can be compiled.
proc check_effective_target_avx512vp2intersect { } {
return [check_no_compiler_messages avx512vp2intersect object {
typedef int __v16si __attribute__ ((__vector_size__ (64)));
typedef short __mmask16;
void
_mm512_2intersect_epi32 (__v16si __A, __v16si __B, __mmask16 *__U,
__mmask16 *__M)
{
__builtin_ia32_2intersectd512 (__U, __M, (__v16si) __A, (__v16si) __B);
}
} "-mavx512vp2intersect" ]
}
# Return 1 if avx512ifma instructions can be compiled.
proc check_effective_target_avx512ifma { } {
return [check_no_compiler_messages avx512ifma object {
typedef long long __v8di __attribute__ ((__vector_size__ (64)));
__v8di
_mm512_madd52lo_epu64 (__v8di __X, __v8di __Y, __v8di __Z)
{
return (__v8di) __builtin_ia32_vpmadd52luq512_mask ((__v8di) __X,
(__v8di) __Y,
(__v8di) __Z,
-1);
}
} "-mavx512ifma" ]
}
# Return 1 if avx512vbmi instructions can be compiled.
proc check_effective_target_avx512vbmi { } {
return [check_no_compiler_messages avx512vbmi object {
typedef char __v64qi __attribute__ ((__vector_size__ (64)));
__v64qi
_mm512_multishift_epi64_epi8 (__v64qi __X, __v64qi __Y)
{
return (__v64qi) __builtin_ia32_vpmultishiftqb512_mask ((__v64qi) __X,
(__v64qi) __Y,
(__v64qi) __Y,
-1);
}
} "-mavx512vbmi" ]
}
# Return 1 if avx512_4fmaps instructions can be compiled.
proc check_effective_target_avx5124fmaps { } {
return [check_no_compiler_messages avx5124fmaps object {
typedef float __v16sf __attribute__ ((__vector_size__ (64)));
typedef float __v4sf __attribute__ ((__vector_size__ (16)));
__v16sf
_mm512_mask_4fmadd_ps (__v16sf __DEST, __v16sf __A, __v16sf __B, __v16sf __C,
__v16sf __D, __v16sf __E, __v4sf *__F)
{
return (__v16sf) __builtin_ia32_4fmaddps_mask ((__v16sf) __A,
(__v16sf) __B,
(__v16sf) __C,
(__v16sf) __D,
(__v16sf) __E,
(const __v4sf *) __F,
(__v16sf) __DEST,
0xffff);
}
} "-mavx5124fmaps" ]
}
# Return 1 if avx512_4vnniw instructions can be compiled.
proc check_effective_target_avx5124vnniw { } {
return [check_no_compiler_messages avx5124vnniw object {
typedef int __v16si __attribute__ ((__vector_size__ (64)));
typedef int __v4si __attribute__ ((__vector_size__ (16)));
__v16si
_mm512_4dpwssd_epi32 (__v16si __A, __v16si __B, __v16si __C,
__v16si __D, __v16si __E, __v4si *__F)
{
return (__v16si) __builtin_ia32_vp4dpwssd ((__v16si) __B,
(__v16si) __C,
(__v16si) __D,
(__v16si) __E,
(__v16si) __A,
(const __v4si *) __F);
}
} "-mavx5124vnniw" ]
}
# Return 1 if avx512_vpopcntdq instructions can be compiled.
proc check_effective_target_avx512vpopcntdq { } {
return [check_no_compiler_messages avx512vpopcntdq object {
typedef int __v16si __attribute__ ((__vector_size__ (64)));
__v16si
_mm512_popcnt_epi32 (__v16si __A)
{
return (__v16si) __builtin_ia32_vpopcountd_v16si ((__v16si) __A);
}
} "-mavx512vpopcntdq" ]
}
# Return 1 if 128 or 256-bit avx512_vpopcntdq instructions can be compiled.
proc check_effective_target_avx512vpopcntdqvl { } {
return [check_no_compiler_messages avx512vpopcntdqvl object {
typedef int __v8si __attribute__ ((__vector_size__ (32)));
__v8si
_mm256_popcnt_epi32 (__v8si __A)
{
return (__v8si) __builtin_ia32_vpopcountd_v8si ((__v8si) __A);
}
} "-mavx512vpopcntdq -mavx512vl" ]
}
# Return 1 if gfni instructions can be compiled.
proc check_effective_target_gfni { } {
return [check_no_compiler_messages gfni object {
typedef char __v16qi __attribute__ ((__vector_size__ (16)));
__v16qi
_mm_gf2p8affineinv_epi64_epi8 (__v16qi __A, __v16qi __B, const int __C)
{
return (__v16qi) __builtin_ia32_vgf2p8affineinvqb_v16qi ((__v16qi) __A,
(__v16qi) __B,
0);
}
} "-mgfni" ]
}
# Return 1 if avx512vbmi2 instructions can be compiled.
proc check_effective_target_avx512vbmi2 { } {
return [check_no_compiler_messages avx512vbmi2 object {
typedef char __v16qi __attribute__ ((__vector_size__ (16)));
typedef unsigned long long __mmask16;
__v16qi
_mm_mask_compress_epi8 (__v16qi __A, __mmask16 __B, __v16qi __C)
{
return (__v16qi) __builtin_ia32_compressqi128_mask((__v16qi)__C,
(__v16qi)__A,
(__mmask16)__B);
}
} "-mavx512vbmi2 -mavx512vl" ]
}
# Return 1 if avx512vbmi2 instructions can be compiled.
proc check_effective_target_avx512vnni { } {
return [check_no_compiler_messages avx512vnni object {
typedef int __v16si __attribute__ ((__vector_size__ (64)));
__v16si
_mm_mask_compress_epi8 (__v16si __A, __v16si __B, __v16si __C)
{
return (__v16si) __builtin_ia32_vpdpbusd_v16si ((__v16si)__A,
(__v16si)__B,
(__v16si)__C);
}
} "-mavx512vnni -mavx512f" ]
}
# Return 1 if vaes instructions can be compiled.
proc check_effective_target_avx512vaes { } {
return [check_no_compiler_messages avx512vaes object {
typedef int __v16si __attribute__ ((__vector_size__ (64)));
__v32qi
_mm256_aesdec_epi128 (__v32qi __A, __v32qi __B)
{
return (__v32qi)__builtin_ia32_vaesdec_v32qi ((__v32qi) __A, (__v32qi) __B);
}
} "-mvaes" ]
}
# Return 1 if vpclmulqdq instructions can be compiled.
proc check_effective_target_vpclmulqdq { } {
return [check_no_compiler_messages vpclmulqdq object {
typedef long long __v4di __attribute__ ((__vector_size__ (32)));
__v4di
_mm256_clmulepi64_epi128 (__v4di __A, __v4di __B)
{
return (__v4di) __builtin_ia32_vpclmulqdq_v4di (__A, __B, 0);
}
} "-mvpclmulqdq -mavx512vl" ]
}
# Return 1 if avx512_bitalg instructions can be compiled.
proc check_effective_target_avx512bitalg { } {
return [check_no_compiler_messages avx512bitalg object {
typedef short int __v32hi __attribute__ ((__vector_size__ (64)));
__v32hi
_mm512_popcnt_epi16 (__v32hi __A)
{
return (__v32hi) __builtin_ia32_vpopcountw_v32hi ((__v32hi) __A);
}
} "-mavx512bitalg" ]
}
# Return 1 if C wchar_t type is compatible with char16_t.
proc check_effective_target_wchar_t_char16_t_compatible { } {
return [check_no_compiler_messages wchar_t_char16_t object {
__WCHAR_TYPE__ wc;
__CHAR16_TYPE__ *p16 = &wc;
char t[(((__CHAR16_TYPE__) -1) < 0 == ((__WCHAR_TYPE__) -1) < 0) ? 1 : -1];
}]
}
# Return 1 if C wchar_t type is compatible with char32_t.
proc check_effective_target_wchar_t_char32_t_compatible { } {
return [check_no_compiler_messages wchar_t_char32_t object {
__WCHAR_TYPE__ wc;
__CHAR32_TYPE__ *p32 = &wc;
char t[(((__CHAR32_TYPE__) -1) < 0 == ((__WCHAR_TYPE__) -1) < 0) ? 1 : -1];
}]
}
# Return 1 if pow10 function exists.
proc check_effective_target_pow10 { } {
return [check_runtime pow10 {
#include <math.h>
int main () {
double x;
x = pow10 (1);
return 0;
}
} "-lm" ]
}
# Return 1 if frexpl function exists.
proc check_effective_target_frexpl { } {
return [check_runtime frexpl {
#include <math.h>
int main () {
long double x;
int y;
x = frexpl (5.0, &y);
return 0;
}
} "-lm" ]
}
# Return 1 if issignaling function exists.
proc check_effective_target_issignaling {} {
return [check_runtime issignaling {
#define _GNU_SOURCE
#include <math.h>
int main ()
{
return issignaling (0.0);
}
} "-lm" ]
}
# Return 1 if current options generate DFP instructions, 0 otherwise.
proc check_effective_target_hard_dfp {} {
return [check_no_messages_and_pattern hard_dfp "!adddd3" assembly {
typedef float d64 __attribute__((mode(DD)));
d64 x, y, z;
void foo (void) { z = x + y; }
}]
}
# Return 1 if string.h and wchar.h headers provide C++ requires overloads
# for strchr etc. functions.
proc check_effective_target_correct_iso_cpp_string_wchar_protos { } {
return [check_no_compiler_messages correct_iso_cpp_string_wchar_protos assembly {
#include <string.h>
#include <wchar.h>
#if !defined(__cplusplus) \
|| !defined(__CORRECT_ISO_CPP_STRING_H_PROTO) \
|| !defined(__CORRECT_ISO_CPP_WCHAR_H_PROTO)
ISO C++ correct string.h and wchar.h protos not supported.
#else
int i;
#endif
}]
}
# Return 1 if GNU as is used.
proc check_effective_target_gas { } {
global use_gas_saved
global tool
if {![info exists use_gas_saved]} {
# Check if the as used by gcc is GNU as.
set gcc_as [lindex [${tool}_target_compile "-print-prog-name=as" "" "none" ""] 0]
# Provide /dev/null as input, otherwise gas times out reading from
# stdin.
set status [remote_exec host "$gcc_as" "-v /dev/null"]
set as_output [lindex $status 1]
if { [ string first "GNU" $as_output ] >= 0 } {
set use_gas_saved 1
} else {
set use_gas_saved 0
}
}
return $use_gas_saved
}
# Return 1 if GNU ld is used.
proc check_effective_target_gld { } {
global use_gld_saved
global tool
if {![info exists use_gld_saved]} {
# Check if the ld used by gcc is GNU ld.
set gcc_ld [lindex [${tool}_target_compile "-print-prog-name=ld" "" "none" ""] 0]
set status [remote_exec host "$gcc_ld" "--version"]
set ld_output [lindex $status 1]
if { [ string first "GNU" $ld_output ] >= 0 } {
set use_gld_saved 1
} else {
set use_gld_saved 0
}
}
return $use_gld_saved
}
# Return 1 if the compiler has been configure with link-time optimization
# (LTO) support.
proc check_effective_target_lto { } {
if { [istarget nvptx-*-*]
|| [istarget amdgcn-*-*] } {
return 0;
}
return [check_no_compiler_messages lto object {
void foo (void) { }
} "-flto"]
}
# Return 1 if the compiler and linker support incremental link-time
# optimization.
proc check_effective_target_lto_incremental { } {
if ![check_effective_target_lto] {
return 0
}
return [check_no_compiler_messages lto_incremental executable {
int main () { return 0; }
} "-flto -r -nostdlib"]
}
# Return 1 if -mx32 -maddress-mode=short can compile, 0 otherwise.
proc check_effective_target_maybe_x32 { } {
return [check_no_compiler_messages maybe_x32 object {
void foo (void) {}
} "-mx32 -maddress-mode=short"]
}
# Return 1 if this target supports the -fsplit-stack option, 0
# otherwise.
proc check_effective_target_split_stack {} {
return [check_no_compiler_messages split_stack object {
void foo (void) { }
} "-fsplit-stack"]
}
# Return 1 if this target supports the -masm=intel option, 0
# otherwise
proc check_effective_target_masm_intel {} {
return [check_no_compiler_messages masm_intel object {
extern void abort (void);
} "-masm=intel"]
}
# Return 1 if the language for the compiler under test is C.
proc check_effective_target_c { } {
global tool
if [string match $tool "gcc"] {
return 1
}
return 0
}
# Return 1 if the language for the compiler under test is C++.
proc check_effective_target_c++ { } {
global tool
if { [string match $tool "g++"] || [string match $tool "libstdc++"] } {
return 1
}
return 0
}
set cxx_default "c++14"
# Check whether the current active language standard supports the features
# of C++11/C++14 by checking for the presence of one of the -std flags.
# This assumes that the default for the compiler is $cxx_default, and that
# there will never be multiple -std= arguments on the command line.
proc check_effective_target_c++11_only { } {
global cxx_default
if ![check_effective_target_c++] {
return 0
}
if [check-flags { { } { } { -std=c++0x -std=gnu++0x -std=c++11 -std=gnu++11 } }] {
return 1
}
if { $cxx_default == "c++11" && [check-flags { { } { } { } { -std=* } }] } {
return 1
}
return 0
}
proc check_effective_target_c++11 { } {
if [check_effective_target_c++11_only] {
return 1
}
return [check_effective_target_c++14]
}
proc check_effective_target_c++11_down { } {
if ![check_effective_target_c++] {
return 0
}
return [expr ![check_effective_target_c++14] ]
}
proc check_effective_target_c++14_only { } {
global cxx_default
if ![check_effective_target_c++] {
return 0
}
if [check-flags { { } { } { -std=c++14 -std=gnu++14 -std=c++14 -std=gnu++14 } }] {
return 1
}
if { $cxx_default == "c++14" && [check-flags { { } { } { } { -std=* } }] } {
return 1
}
return 0
}
proc check_effective_target_c++14 { } {
if [check_effective_target_c++14_only] {
return 1
}
return [check_effective_target_c++17]
}
proc check_effective_target_c++14_down { } {
if ![check_effective_target_c++] {
return 0
}
return [expr ![check_effective_target_c++17] ]
}
proc check_effective_target_c++98_only { } {
global cxx_default
if ![check_effective_target_c++] {
return 0
}
if [check-flags { { } { } { -std=c++98 -std=gnu++98 -std=c++03 -std=gnu++03 } }] {
return 1
}
if { $cxx_default == "c++98" && [check-flags { { } { } { } { -std=* } }] } {
return 1
}
return 0
}
proc check_effective_target_c++17_only { } {
global cxx_default
if ![check_effective_target_c++] {
return 0
}
if [check-flags { { } { } { -std=c++17 -std=gnu++17 -std=c++1z -std=gnu++1z } }] {
return 1
}
if { $cxx_default == "c++17" && [check-flags { { } { } { } { -std=* } }] } {
return 1
}
return 0
}
proc check_effective_target_c++17 { } {
if [check_effective_target_c++17_only] {
return 1
}
return [check_effective_target_c++2a]
}
proc check_effective_target_c++17_down { } {
if ![check_effective_target_c++] {
return 0
}
return [expr ![check_effective_target_c++2a] ]
}
proc check_effective_target_c++2a_only { } {
global cxx_default
if ![check_effective_target_c++] {
return 0
}
if [check-flags { { } { } { -std=c++2a -std=gnu++2a } }] {
return 1
}
if { $cxx_default == "c++20" && [check-flags { { } { } { } { -std=* } }] } {
return 1
}
return 0
}
proc check_effective_target_c++2a { } {
return [check_effective_target_c++2a_only]
}
# Check for C++ Concepts TS support, i.e. -fconcepts flag.
proc check_effective_target_concepts { } {
return [check-flags { "" { } { -fconcepts -std=*2a } }]
}
# Return 1 if expensive testcases should be run.
proc check_effective_target_run_expensive_tests { } {
if { [getenv GCC_TEST_RUN_EXPENSIVE] != "" } {
return 1
}
return 0
}
# Returns 1 if "mempcpy" is available on the target system.
proc check_effective_target_mempcpy {} {
return [check_function_available "mempcpy"]
}
# Returns 1 if "stpcpy" is available on the target system.
proc check_effective_target_stpcpy {} {
return [check_function_available "stpcpy"]
}
# Check whether the vectorizer tests are supported by the target and
# append additional target-dependent compile flags to DEFAULT_VECTCFLAGS.
# If a port wants to execute the tests more than once it should append
# the supported target to EFFECTIVE_TARGETS instead, and the compile flags
# will be added by a call to add_options_for_<target>.
# Set dg-do-what-default to either compile or run, depending on target
# capabilities. Do not set this if the supported target is appended to
# EFFECTIVE_TARGETS. Flags and this variable will be set by et-dg-runtest
# automatically. Return the number of effective targets if vectorizer tests
# are supported, 0 otherwise.
proc check_vect_support_and_set_flags { } {
global DEFAULT_VECTCFLAGS
global dg-do-what-default
global EFFECTIVE_TARGETS
if [istarget powerpc-*paired*] {
lappend DEFAULT_VECTCFLAGS "-mpaired"
if [check_750cl_hw_available] {
set dg-do-what-default run
} else {
set dg-do-what-default compile
}
} elseif [istarget powerpc*-*-*] {
# Skip targets not supporting -maltivec.
if ![is-effective-target powerpc_altivec_ok] {
return 0
}
lappend DEFAULT_VECTCFLAGS "-maltivec"
if [check_p9vector_hw_available] {
lappend DEFAULT_VECTCFLAGS "-mpower9-vector"
} elseif [check_p8vector_hw_available] {
lappend DEFAULT_VECTCFLAGS "-mpower8-vector"
} elseif [check_vsx_hw_available] {
lappend DEFAULT_VECTCFLAGS "-mvsx" "-mno-allow-movmisalign"
}
if [check_vmx_hw_available] {
set dg-do-what-default run
} else {
if [is-effective-target ilp32] {
# Specify a cpu that supports VMX for compile-only tests.
lappend DEFAULT_VECTCFLAGS "-mcpu=970"
}
set dg-do-what-default compile
}
} elseif { [istarget i?86-*-*] || [istarget x86_64-*-*] } {
lappend DEFAULT_VECTCFLAGS "-msse2"
if { [check_effective_target_sse2_runtime] } {
set dg-do-what-default run
} else {
set dg-do-what-default compile
}
} elseif { [istarget mips*-*-*]
&& [check_effective_target_nomips16] } {
if { [check_effective_target_mpaired_single] } {
lappend EFFECTIVE_TARGETS mpaired_single
}
if { [check_effective_target_mips_loongson_mmi] } {
lappend EFFECTIVE_TARGETS mips_loongson_mmi
}
if { [check_effective_target_mips_msa] } {
lappend EFFECTIVE_TARGETS mips_msa
}
return [llength $EFFECTIVE_TARGETS]
} elseif [istarget sparc*-*-*] {
lappend DEFAULT_VECTCFLAGS "-mcpu=ultrasparc" "-mvis"
if [check_effective_target_ultrasparc_hw] {
set dg-do-what-default run
} else {
set dg-do-what-default compile
}
} elseif [istarget alpha*-*-*] {
# Alpha's vectorization capabilities are extremely limited.
# It's more effort than its worth disabling all of the tests
# that it cannot pass. But if you actually want to see what
# does work, command out the return.
return 0
lappend DEFAULT_VECTCFLAGS "-mmax"
if [check_alpha_max_hw_available] {
set dg-do-what-default run
} else {
set dg-do-what-default compile
}
} elseif [istarget ia64-*-*] {
set dg-do-what-default run
} elseif [is-effective-target arm_neon_ok] {
eval lappend DEFAULT_VECTCFLAGS [add_options_for_arm_neon ""]
# NEON does not support denormals, so is not used for vectorization by
# default to avoid loss of precision. We must pass -ffast-math to test
# vectorization of float operations.
lappend DEFAULT_VECTCFLAGS "-ffast-math"
if [is-effective-target arm_neon_hw] {
set dg-do-what-default run
} else {
set dg-do-what-default compile
}
} elseif [istarget "aarch64*-*-*"] {
set dg-do-what-default run
} elseif [istarget s390*-*-*] {
# The S/390 backend set a default of 2 for that value.
# Override it to have the same situation as with other
# targets.
lappend DEFAULT_VECTCFLAGS "--param" "min-vect-loop-bound=1"
lappend DEFAULT_VECTCFLAGS "--param" "max-unrolled-insns=200"
lappend DEFAULT_VECTCFLAGS "--param" "max-unroll-times=8"
lappend DEFAULT_VECTCFLAGS "--param" "max-completely-peeled-insns=200"
lappend DEFAULT_VECTCFLAGS "--param" "max-completely-peel-times=16"
if [check_effective_target_s390_vxe] {
lappend DEFAULT_VECTCFLAGS "-march=z14" "-mzarch"
set dg-do-what-default run
} elseif [check_effective_target_s390_vx] {
lappend DEFAULT_VECTCFLAGS "-march=z13" "-mzarch"
set dg-do-what-default run
} else {
lappend DEFAULT_VECTCFLAGS "-march=z14" "-mzarch"
set dg-do-what-default compile
}
} elseif [istarget amdgcn-*-*] {
set dg-do-what-default run
} else {
return 0
}
return 1
}
# Return 1 if the target does *not* require strict alignment.
proc check_effective_target_non_strict_align {} {
# On ARM, the default is to use STRICT_ALIGNMENT, but there
# are interfaces defined for misaligned access and thus
# depending on the architecture levels unaligned access is
# available.
if [istarget "arm*-*-*"] {
return [check_effective_target_arm_unaligned]
}
return [check_no_compiler_messages non_strict_align assembly {
char *y;
typedef char __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__))) c;
c *z;
void foo(void) { z = (c *) y; }
} "-Wcast-align"]
}
# Return 1 if the target has <ucontext.h>.
proc check_effective_target_ucontext_h { } {
return [check_no_compiler_messages ucontext_h assembly {
#include <ucontext.h>
}]
}
proc check_effective_target_aarch64_tiny { } {
if { [istarget aarch64*-*-*] } {
return [check_no_compiler_messages aarch64_tiny object {
#ifdef __AARCH64_CMODEL_TINY__
int dummy;
#else
#error target not AArch64 tiny code model
#endif
}]
} else {
return 0
}
}
# Create functions to check that the AArch64 assembler supports the
# various architecture extensions via the .arch_extension pseudo-op.
foreach { aarch64_ext } { "fp" "simd" "crypto" "crc" "lse" "dotprod" "sve"} {
eval [string map [list FUNC $aarch64_ext] {
proc check_effective_target_aarch64_asm_FUNC_ok { } {
if { [istarget aarch64*-*-*] } {
return [check_no_compiler_messages aarch64_FUNC_assembler object {
__asm__ (".arch_extension FUNC");
} "-march=armv8-a+FUNC"]
} else {
return 0
}
}
}]
}
proc check_effective_target_aarch64_small { } {
if { [istarget aarch64*-*-*] } {
return [check_no_compiler_messages aarch64_small object {
#ifdef __AARCH64_CMODEL_SMALL__
int dummy;
#else
#error target not AArch64 small code model
#endif
}]
} else {
return 0
}
}
proc check_effective_target_aarch64_large { } {
if { [istarget aarch64*-*-*] } {
return [check_no_compiler_messages aarch64_large object {
#ifdef __AARCH64_CMODEL_LARGE__
int dummy;
#else
#error target not AArch64 large code model
#endif
}]
} else {
return 0
}
}
# Return 1 if the assembler accepts the aarch64 .variant_pcs directive.
proc check_effective_target_aarch64_variant_pcs { } {
if { [istarget aarch64*-*-*] } {
return [check_no_compiler_messages aarch64_variant_pcs object {
__asm__ (".variant_pcs foo");
}]
} else {
return 0
}
}
# Return 1 if this is a reduced AVR Tiny core. Such cores have different
# register set, instruction set, addressing capabilities and ABI.
proc check_effective_target_avr_tiny { } {
if { [istarget avr*-*-*] } {
return [check_no_compiler_messages avr_tiny object {
#ifdef __AVR_TINY__
int dummy;
#else
#error target not a reduced AVR Tiny core
#endif
}]
} else {
return 0
}
}
# Return 1 if <fenv.h> is available.
proc check_effective_target_fenv {} {
return [check_no_compiler_messages fenv object {
#include <fenv.h>
} [add_options_for_ieee "-std=gnu99"]]
}
# Return 1 if <fenv.h> is available with all the standard IEEE
# exceptions and floating-point exceptions are raised by arithmetic
# operations. (If the target requires special options for "inexact"
# exceptions, those need to be specified in the testcases.)
proc check_effective_target_fenv_exceptions {} {
return [check_runtime fenv_exceptions {
#include <fenv.h>
#include <stdlib.h>
#ifndef FE_DIVBYZERO
# error Missing FE_DIVBYZERO
#endif
#ifndef FE_INEXACT
# error Missing FE_INEXACT
#endif
#ifndef FE_INVALID
# error Missing FE_INVALID
#endif
#ifndef FE_OVERFLOW
# error Missing FE_OVERFLOW
#endif
#ifndef FE_UNDERFLOW
# error Missing FE_UNDERFLOW
#endif
volatile float a = 0.0f, r;
int
main (void)
{
r = a / a;
if (fetestexcept (FE_INVALID))
exit (0);
else
abort ();
}
} [add_options_for_ieee "-std=gnu99"]]
}
# Return 1 if -fexceptions is supported.
proc check_effective_target_exceptions {} {
if { [istarget amdgcn*-*-*] } {
return 0
}
return 1
}
# Used to check if the testing configuration supports exceptions.
# Returns 0 if exceptions are unsupported or disabled (e.g. by passing
# -fno-exceptions). Returns 1 if exceptions are enabled.
proc check_effective_target_exceptions_enabled {} {
return [check_cached_effective_target exceptions_enabled {
if { [check_effective_target_exceptions] } {
return [check_no_compiler_messages exceptions_enabled assembly {
void foo (void)
{
throw 1;
}
}]
} else {
# If exceptions aren't supported, then they're not enabled.
return 0
}
}]
}
proc check_effective_target_tiny {} {
return [check_cached_effective_target tiny {
if { [istarget aarch64*-*-*]
&& [check_effective_target_aarch64_tiny] } {
return 1
}
if { [istarget avr-*-*]
&& [check_effective_target_avr_tiny] } {
return 1
}
# PRU Program Counter is 16-bits, and trampolines are not supported.
# Hence directly declare as a tiny target.
if [istarget pru-*-*] {
return 1
}
return 0
}]
}
# Return 1 if the target supports -mbranch-cost=N option.
proc check_effective_target_branch_cost {} {
if { [ istarget arm*-*-*]
|| [istarget avr*-*-*]
|| [istarget csky*-*-*]
|| [istarget epiphany*-*-*]
|| [istarget frv*-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget mips*-*-*]
|| [istarget s390*-*-*]
|| [istarget riscv*-*-*]
|| [istarget sh*-*-*] } {
return 1
}
return 0
}
# Record that dg-final test TEST requires convential compilation.
proc force_conventional_output_for { test } {
if { [info proc $test] == "" } {
perror "$test does not exist"
exit 1
}
proc ${test}_required_options {} {
global gcc_force_conventional_output
upvar 1 extra_tool_flags extra_tool_flags
if {[regexp -- "^scan-assembler" [info level 0]]
&& ![string match "*-fident*" $extra_tool_flags]} {
# Do not let .ident confuse assembler scan tests
return [list $gcc_force_conventional_output "-fno-ident"]
}
return $gcc_force_conventional_output
}
}
# Record that dg-final test scan-ltrans-tree-dump* requires -flto-partition=one
# in order to force a single partition, allowing scan-ltrans-tree-dump* to scan
# a dump file *.exe.ltrans0.*.
proc scan-ltrans-tree-dump_required_options {} {
return "-flto-partition=one"
}
proc scan-ltrans-tree-dump-times_required_options {} {
return "-flto-partition=one"
}
proc scan-ltrans-tree-dump-not_required_options {} {
return "-flto-partition=one"
}
proc scan-ltrans-tree-dump-dem_required_options {} {
return "-flto-partition=one"
}
proc scan-ltrans-tree-dump-dem-not_required_options {} {
return "-flto-partition=one"
}
# Return 1 if the x86-64 target supports PIE with copy reloc, 0
# otherwise. Cache the result.
proc check_effective_target_pie_copyreloc { } {
global tool
global GCC_UNDER_TEST
if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
return 0
}
# Need auto-host.h to check linker support.
if { ![file exists ../../auto-host.h ] } {
return 0
}
return [check_cached_effective_target pie_copyreloc {
# Set up and compile to see if linker supports PIE with copy
# reloc. Include the current process ID in the file names to
# prevent conflicts with invocations for multiple testsuites.
set src pie[pid].c
set obj pie[pid].o
set f [open $src "w"]
puts $f "#include \"../../auto-host.h\""
puts $f "#if HAVE_LD_PIE_COPYRELOC == 0"
puts $f "# error Linker does not support PIE with copy reloc."
puts $f "#endif"
close $f
verbose "check_effective_target_pie_copyreloc compiling testfile $src" 2
set lines [${tool}_target_compile $src $obj object ""]
file delete $src
file delete $obj
if [string match "" $lines] then {
verbose "check_effective_target_pie_copyreloc testfile compilation passed" 2
return 1
} else {
verbose "check_effective_target_pie_copyreloc testfile compilation failed" 2
return 0
}
}]
}
# Return 1 if the x86 target supports R_386_GOT32X relocation, 0
# otherwise. Cache the result.
proc check_effective_target_got32x_reloc { } {
global tool
global GCC_UNDER_TEST
if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
return 0
}
# Need auto-host.h to check linker support.
if { ![file exists ../../auto-host.h ] } {
return 0
}
return [check_cached_effective_target got32x_reloc {
# Include the current process ID in the file names to prevent
# conflicts with invocations for multiple testsuites.
set src got32x[pid].c
set obj got32x[pid].o
set f [open $src "w"]
puts $f "#include \"../../auto-host.h\""
puts $f "#if HAVE_AS_IX86_GOT32X == 0"
puts $f "# error Assembler does not support R_386_GOT32X."
puts $f "#endif"
close $f
verbose "check_effective_target_got32x_reloc compiling testfile $src" 2
set lines [${tool}_target_compile $src $obj object ""]
file delete $src
file delete $obj
if [string match "" $lines] then {
verbose "check_effective_target_got32x_reloc testfile compilation passed" 2
return 1
} else {
verbose "check_effective_target_got32x_reloc testfile compilation failed" 2
return 0
}
}]
return $got32x_reloc_available_saved
}
# Return 1 if the x86 target supports calling ___tls_get_addr via GOT,
# 0 otherwise. Cache the result.
proc check_effective_target_tls_get_addr_via_got { } {
global tool
global GCC_UNDER_TEST
if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
return 0
}
# Need auto-host.h to check linker support.
if { ![file exists ../../auto-host.h ] } {
return 0
}
return [check_cached_effective_target tls_get_addr_via_got {
# Include the current process ID in the file names to prevent
# conflicts with invocations for multiple testsuites.
set src tls_get_addr_via_got[pid].c
set obj tls_get_addr_via_got[pid].o
set f [open $src "w"]
puts $f "#include \"../../auto-host.h\""
puts $f "#if HAVE_AS_IX86_TLS_GET_ADDR_GOT == 0"
puts $f "# error Assembler/linker do not support calling ___tls_get_addr via GOT."
puts $f "#endif"
close $f
verbose "check_effective_target_tls_get_addr_via_got compiling testfile $src" 2
set lines [${tool}_target_compile $src $obj object ""]
file delete $src
file delete $obj
if [string match "" $lines] then {
verbose "check_effective_target_tls_get_addr_via_got testfile compilation passed" 2
return 1
} else {
verbose "check_effective_target_tls_get_addr_via_got testfile compilation failed" 2
return 0
}
}]
}
# Return 1 if the target uses comdat groups.
proc check_effective_target_comdat_group {} {
return [check_no_messages_and_pattern comdat_group "\.section\[^\n\r]*,comdat|\.group\[^\n\r]*,#comdat" assembly {
// C++
inline int foo () { return 1; }
int (*fn) () = foo;
}]
}
# Return 1 if target supports __builtin_eh_return
proc check_effective_target_builtin_eh_return { } {
return [check_no_compiler_messages builtin_eh_return object {
void test (long l, void *p)
{
__builtin_eh_return (l, p);
}
} "" ]
}
# Return 1 if the target supports max reduction for vectors.
proc check_effective_target_vect_max_reduc { } {
if { [istarget aarch64*-*-*] || [is-effective-target arm_neon] } {
return 1
}
return 0
}
# Return 1 if the compiler has been configured with hsa offloading.
proc check_effective_target_offload_hsa { } {
return [check_no_compiler_messages offload_hsa assembly {
int main () {return 0;}
} "-foffload=hsa" ]
}
# Return 1 if the compiler has been configured with hsa offloading.
proc check_effective_target_offload_gcn { } {
return [check_no_compiler_messages offload_gcn assembly {
int main () {return 0;}
} "-foffload=amdgcn-unknown-amdhsa" ]
}
# Return 1 if the target support -fprofile-update=atomic
proc check_effective_target_profile_update_atomic {} {
return [check_no_compiler_messages profile_update_atomic assembly {
int main (void) { return 0; }
} "-fprofile-update=atomic -fprofile-generate"]
}
# Return 1 if vector (va - vector add) instructions are understood by
# the assembler and can be executed. This also covers checking for
# the VX kernel feature. A kernel without that feature does not
# enable the vector facility and the following check will die with a
# signal.
proc check_effective_target_s390_vx { } {
if ![istarget s390*-*-*] then {
return 0;
}
return [check_runtime s390_check_vx {
int main (void)
{
asm ("va %%v24, %%v26, %%v28, 3" : : : "v24", "v26", "v28");
return 0;
}
} "-march=z13 -mzarch" ]
}
# Same as above but for the z14 vector enhancement facility. Test
# is performed with the vector nand instruction.
proc check_effective_target_s390_vxe { } {
if ![istarget s390*-*-*] then {
return 0;
}
return [check_runtime s390_check_vxe {
int main (void)
{
asm ("vnn %%v24, %%v26, %%v28" : : : "v24", "v26", "v28");
return 0;
}
} "-march=z14 -mzarch" ]
}
# Same as above but for the arch13 vector enhancement facility. Test
# is performed with the vector shift left double by bit instruction.
proc check_effective_target_s390_vxe2 { } {
if ![istarget s390*-*-*] then {
return 0;
}
return [check_runtime s390_check_vxe2 {
int main (void)
{
asm ("vsld %%v24, %%v26, %%v28, 3" : : : "v24", "v26", "v28");
return 0;
}
} "-march=arch13 -mzarch" ]
}
#For versions of ARM architectures that have hardware div insn,
#disable the divmod transform
proc check_effective_target_arm_divmod_simode { } {
return [check_no_compiler_messages arm_divmod assembly {
#ifdef __ARM_ARCH_EXT_IDIV__
#error has div insn
#endif
int i;
}]
}
# Return 1 if target supports divmod hardware insn or divmod libcall.
proc check_effective_target_divmod { } {
#TODO: Add checks for all targets that have either hardware divmod insn
# or define libfunc for divmod.
if { [istarget arm*-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*] } {
return 1
}
return 0
}
# Return 1 if target supports divmod for SImode. The reason for
# separating this from check_effective_target_divmod is that
# some versions of ARM architecture define div instruction
# only for simode, and for these archs, we do not want to enable
# divmod transform for simode.
proc check_effective_target_divmod_simode { } {
if { [istarget arm*-*-*] } {
return [check_effective_target_arm_divmod_simode]
}
return [check_effective_target_divmod]
}
# Return 1 if store merging optimization is applicable for target.
# Store merging is not profitable for targets like the avr which
# can load/store only one byte at a time. Use int size as a proxy
# for the number of bytes the target can write, and skip for targets
# with a smallish (< 32) size.
proc check_effective_target_store_merge { } {
if { [is-effective-target non_strict_align ] && [is-effective-target int32plus] } {
return 1
}
return 0
}
# Return 1 if we're able to assemble rdrand
proc check_effective_target_rdrand { } {
return [check_no_compiler_messages_nocache rdrand object {
unsigned int
__foo(void)
{
unsigned int val;
__builtin_ia32_rdrand32_step(&val);
return val;
}
} "-mrdrnd" ]
}
# Return 1 if the target supports coprocessor instructions: cdp, ldc, ldcl,
# stc, stcl, mcr and mrc.
proc check_effective_target_arm_coproc1_ok_nocache { } {
if { ![istarget arm*-*-*] } {
return 0
}
return [check_no_compiler_messages_nocache arm_coproc1_ok assembly {
#if (__thumb__ && !__thumb2__) || __ARM_ARCH < 4
#error FOO
#endif
}]
}
proc check_effective_target_arm_coproc1_ok { } {
return [check_cached_effective_target arm_coproc1_ok \
check_effective_target_arm_coproc1_ok_nocache]
}
# Return 1 if the target supports all coprocessor instructions checked by
# check_effective_target_arm_coproc1_ok in addition to the following: cdp2,
# ldc2, ldc2l, stc2, stc2l, mcr2 and mrc2.
proc check_effective_target_arm_coproc2_ok_nocache { } {
if { ![check_effective_target_arm_coproc1_ok] } {
return 0
}
return [check_no_compiler_messages_nocache arm_coproc2_ok assembly {
#if (__thumb__ && !__thumb2__) || __ARM_ARCH < 5
#error FOO
#endif
}]
}
proc check_effective_target_arm_coproc2_ok { } {
return [check_cached_effective_target arm_coproc2_ok \
check_effective_target_arm_coproc2_ok_nocache]
}
# Return 1 if the target supports all coprocessor instructions checked by
# check_effective_target_arm_coproc2_ok in addition the following: mcrr and
# mrrc.
proc check_effective_target_arm_coproc3_ok_nocache { } {
if { ![check_effective_target_arm_coproc2_ok] } {
return 0
}
return [check_no_compiler_messages_nocache arm_coproc3_ok assembly {
#if (__thumb__ && !__thumb2__) \
|| (__ARM_ARCH < 6 && !defined (__ARM_ARCH_5TE__))
#error FOO
#endif
}]
}
proc check_effective_target_arm_coproc3_ok { } {
return [check_cached_effective_target arm_coproc3_ok \
check_effective_target_arm_coproc3_ok_nocache]
}
# Return 1 if the target supports all coprocessor instructions checked by
# check_effective_target_arm_coproc3_ok in addition the following: mcrr2 and
# mrcc2.
proc check_effective_target_arm_coproc4_ok_nocache { } {
if { ![check_effective_target_arm_coproc3_ok] } {
return 0
}
return [check_no_compiler_messages_nocache arm_coproc4_ok assembly {
#if (__thumb__ && !__thumb2__) || __ARM_ARCH < 6
#error FOO
#endif
}]
}
proc check_effective_target_arm_coproc4_ok { } {
return [check_cached_effective_target arm_coproc4_ok \
check_effective_target_arm_coproc4_ok_nocache]
}
# Return 1 if the target supports the auto_inc_dec optimization pass.
proc check_effective_target_autoincdec { } {
if { ![check_no_compiler_messages auto_incdec assembly { void f () { }
} "-O2 -fdump-rtl-auto_inc_dec" ] } {
return 0
}
set dumpfile [glob -nocomplain "auto_incdec[pid].c.\[0-9\]\[0-9\]\[0-9\]r.auto_inc_dec"]
if { [file exists $dumpfile ] } {
file delete $dumpfile
return 1
}
return 0
}
# Return 1 if the target has support for stack probing designed
# to avoid stack-clash style attacks.
#
# This is used to restrict the stack-clash mitigation tests to
# just those targets that have been explicitly supported.
#
# In addition to the prologue work on those targets, each target's
# properties should be described in the functions below so that
# tests do not become a mess of unreadable target conditions.
#
proc check_effective_target_supports_stack_clash_protection { } {
if { [istarget x86_64-*-*] || [istarget i?86-*-*]
|| [istarget powerpc*-*-*] || [istarget rs6000*-*-*]
|| [istarget aarch64*-**] || [istarget s390*-*-*] } {
return 1
}
return 0
}
# Return 1 if the target creates a frame pointer for non-leaf functions
# Note we ignore cases where we apply tail call optimization here.
proc check_effective_target_frame_pointer_for_non_leaf { } {
# Solaris/x86 defaults to -fno-omit-frame-pointer.
if { [istarget i?86-*-solaris*] || [istarget x86_64-*-solaris*] } {
return 1
}
return 0
}
# Return 1 if the target's calling sequence or its ABI
# create implicit stack probes at or prior to function entry.
proc check_effective_target_caller_implicit_probes { } {
# On x86/x86_64 the call instruction itself pushes the return
# address onto the stack. That is an implicit probe of *sp.
if { [istarget x86_64-*-*] || [istarget i?86-*-*] } {
return 1
}
# On PPC, the ABI mandates that the address of the outer
# frame be stored at *sp. Thus each allocation of stack
# space is itself an implicit probe of *sp.
if { [istarget powerpc*-*-*] || [istarget rs6000*-*-*] } {
return 1
}
# s390's ABI has a register save area allocated by the
# caller for use by the callee. The mere existence does
# not constitute a probe by the caller, but when the slots
# used by the callee those stores are implicit probes.
if { [istarget s390*-*-*] } {
return 1
}
# Not strictly true on aarch64, but we have agreed that we will
# consider any function that pushes SP more than 3kbytes into
# the guard page as broken. This essentially means that we can
# consider the aarch64 as having a caller implicit probe at
# *(sp + 1k).
if { [istarget aarch64*-*-*] } {
return 1;
}
return 0
}
# Targets that potentially realign the stack pointer often cause residual
# stack allocations and make it difficult to elimination loops or residual
# allocations for dynamic stack allocations
proc check_effective_target_callee_realigns_stack { } {
if { [istarget x86_64-*-*] || [istarget i?86-*-*] } {
return 1
}
return 0
}
# Return 1 if CET instructions can be compiled.
proc check_effective_target_cet { } {
if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
return 0
}
return [check_no_compiler_messages cet object {
void foo (void)
{
asm ("setssbsy");
}
} "-O2 -fcf-protection" ]
}
# Return 1 if target supports floating point "infinite"
proc check_effective_target_inf { } {
return [check_no_compiler_messages supports_inf assembly {
const double pinf = __builtin_inf ();
}]
}
# Return 1 if the target supports ARMv8.3 Adv.SIMD Complex instructions
# instructions, 0 otherwise. The test is valid for ARM and for AArch64.
# Record the command line options needed.
proc check_effective_target_arm_v8_3a_complex_neon_ok_nocache { } {
global et_arm_v8_3a_complex_neon_flags
set et_arm_v8_3a_complex_neon_flags ""
if { ![istarget arm*-*-*] && ![istarget aarch64*-*-*] } {
return 0;
}
# Iterate through sets of options to find the compiler flags that
# need to be added to the -march option.
foreach flags {"" "-mfloat-abi=softfp -mfpu=auto" "-mfloat-abi=hard -mfpu=auto"} {
if { [check_no_compiler_messages_nocache \
arm_v8_3a_complex_neon_ok object {
#if !defined (__ARM_FEATURE_COMPLEX)
#error "__ARM_FEATURE_COMPLEX not defined"
#endif
} "$flags -march=armv8.3-a"] } {
set et_arm_v8_3a_complex_neon_flags "$flags -march=armv8.3-a"
return 1
}
}
return 0;
}
proc check_effective_target_arm_v8_3a_complex_neon_ok { } {
return [check_cached_effective_target arm_v8_3a_complex_neon_ok \
check_effective_target_arm_v8_3a_complex_neon_ok_nocache]
}
proc add_options_for_arm_v8_3a_complex_neon { flags } {
if { ! [check_effective_target_arm_v8_3a_complex_neon_ok] } {
return "$flags"
}
global et_arm_v8_3a_complex_neon_flags
return "$flags $et_arm_v8_3a_complex_neon_flags"
}
# Return 1 if the target supports executing AdvSIMD instructions from ARMv8.3
# with the complex instruction extension, 0 otherwise. The test is valid for
# ARM and for AArch64.
proc check_effective_target_arm_v8_3a_complex_neon_hw { } {
if { ![check_effective_target_arm_v8_3a_complex_neon_ok] } {
return 0;
}
return [check_runtime arm_v8_3a_complex_neon_hw_available {
#include "arm_neon.h"
int
main (void)
{
float32x2_t results = {-4.0,5.0};
float32x2_t a = {1.0,3.0};
float32x2_t b = {2.0,5.0};
#ifdef __ARM_ARCH_ISA_A64
asm ("fcadd %0.2s, %1.2s, %2.2s, #90"
: "=w"(results)
: "w"(a), "w"(b)
: /* No clobbers. */);
#else
asm ("vcadd.f32 %P0, %P1, %P2, #90"
: "=w"(results)
: "w"(a), "w"(b)
: /* No clobbers. */);
#endif
return (results[0] == 8 && results[1] == 24) ? 1 : 0;
}
} [add_options_for_arm_v8_3a_complex_neon ""]]
}
# Return 1 if the assembler supports assembling the Armv8.3 pointer authentication B key directive
proc check_effective_target_arm_v8_3a_bkey_directive { } {
return [check_no_compiler_messages cet object {
int main(void) {
asm (".cfi_b_key_frame");
return 0;
}
}]
}
# Returns 1 if the target is using glibc, 0 otherwise.
proc check_effective_target_glibc { } {
return [check_no_compiler_messages glibc_object assembly {
#include <stdlib.h>
#if !defined(__GLIBC__)
#error undefined
#endif
}]
}
# Return 1 if the target plus current options supports a vector
# complex addition with rotate of half and single float modes, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
foreach N {hf sf} {
eval [string map [list N $N] {
proc check_effective_target_vect_complex_rot_N { } {
return [check_cached_effective_target_indexed vect_complex_rot_N {
expr { [istarget aarch64*-*-*]
|| [istarget arm*-*-*] }}]
}
}]
}
# Return 1 if the target plus current options supports a vector
# complex addition with rotate of double float modes, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
foreach N {df} {
eval [string map [list N $N] {
proc check_effective_target_vect_complex_rot_N { } {
return [check_cached_effective_target_indexed vect_complex_rot_N {
expr { [istarget aarch64*-*-*] }}]
}
}]
}
# Return 1 if this target uses an LLVM assembler and/or linker
proc check_effective_target_llvm_binutils { } {
return [check_cached_effective_target llvm_binutils {
expr { [istarget amdgcn*-*-*]
|| [check_effective_target_offload_gcn] }}]
}
# Return 1 if the compiler supports '-mfentry'.
proc check_effective_target_mfentry { } {
if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
return 0
}
return [check_no_compiler_messages mfentry object {
void foo (void) { }
} "-mfentry"]
}
# Return 1 if this target supports indirect calls
proc check_effective_target_indirect_calls { } {
if { [istarget bpf-*-*] } {
return 0
}
return 1
}