1 #!/bin/sh 2 self=$0 3 4 usage() { 5 cat <<EOF >&2 6 Usage: $self [options] FILE 7 8 Reads the Run Time CPU Detections definitions from FILE and generates a 9 C header file on stdout. 10 11 Options: 12 --arch=ARCH Architecture to generate defs for (required) 13 --disable-EXT Disable support for EXT extensions 14 --require-EXT Require support for EXT extensions 15 --sym=SYMBOL Unique symbol to use for RTCD initialization function 16 --config=FILE File with CONFIG_FOO=yes lines to parse 17 EOF 18 exit 1 19 } 20 21 die() { 22 echo "$@" >&2 23 exit 1 24 } 25 26 die_argument_required() { 27 die "Option $opt requires argument" 28 } 29 30 for opt; do 31 optval="${opt#*=}" 32 case "$opt" in 33 --arch) die_argument_required;; 34 --arch=*) arch=${optval};; 35 --disable-*) eval "disable_${opt#--disable-}=true";; 36 --require-*) REQUIRES="${REQUIRES}${opt#--require-} ";; 37 --sym) die_argument_required;; 38 --sym=*) symbol=${optval};; 39 --config=*) config_file=${optval};; 40 -h|--help) 41 usage 42 ;; 43 -*) 44 die "Unrecognized option: ${opt%%=*}" 45 ;; 46 *) 47 defs_file="$defs_file $opt" 48 ;; 49 esac 50 shift 51 done 52 for f in $defs_file; do [ -f "$f" ] || usage; done 53 [ -n "$arch" ] || usage 54 55 # Import the configuration 56 [ -f "$config_file" ] && eval $(grep CONFIG_ "$config_file") 57 58 # 59 # Routines for the RTCD DSL to call 60 # 61 prototype() { 62 rtyp="" 63 case "$1" in 64 unsigned) rtyp="$1 "; shift;; 65 esac 66 rtyp="${rtyp}$1" 67 fn="$2" 68 args="$3" 69 70 eval "${2}_rtyp='$rtyp'" 71 eval "${2}_args='$3'" 72 ALL_FUNCS="$ALL_FUNCS $fn" 73 specialize $fn c 74 } 75 76 specialize() { 77 fn="$1" 78 shift 79 for opt in "$@"; do 80 eval "${fn}_${opt}=${fn}_${opt}" 81 done 82 } 83 84 require() { 85 for fn in $ALL_FUNCS; do 86 for opt in "$@"; do 87 ofn=$(eval "echo \$${fn}_${opt}") 88 [ -z "$ofn" ] && continue 89 90 # if we already have a default, then we can disable it, as we know 91 # we can do better. 92 best=$(eval "echo \$${fn}_default") 93 best_ofn=$(eval "echo \$${best}") 94 [ -n "$best" ] && [ "$best_ofn" != "$ofn" ] && eval "${best}_link=false" 95 eval "${fn}_default=${fn}_${opt}" 96 eval "${fn}_${opt}_link=true" 97 done 98 done 99 } 100 101 forward_decls() { 102 ALL_FORWARD_DECLS="$ALL_FORWARD_DECLS $1" 103 } 104 105 # 106 # Include the user's directives 107 # 108 for f in $defs_file; do 109 . $f 110 done 111 112 # 113 # Process the directives according to the command line 114 # 115 process_forward_decls() { 116 for fn in $ALL_FORWARD_DECLS; do 117 eval $fn 118 done 119 } 120 121 determine_indirection() { 122 [ "$CONFIG_RUNTIME_CPU_DETECT" = "yes" ] || require $ALL_ARCHS 123 for fn in $ALL_FUNCS; do 124 n="" 125 rtyp="$(eval "echo \$${fn}_rtyp")" 126 args="$(eval "echo \"\$${fn}_args\"")" 127 dfn="$(eval "echo \$${fn}_default")" 128 dfn=$(eval "echo \$${dfn}") 129 for opt in "$@"; do 130 ofn=$(eval "echo \$${fn}_${opt}") 131 [ -z "$ofn" ] && continue 132 link=$(eval "echo \$${fn}_${opt}_link") 133 [ "$link" = "false" ] && continue 134 n="${n}x" 135 done 136 if [ "$n" = "x" ]; then 137 eval "${fn}_indirect=false" 138 else 139 eval "${fn}_indirect=true" 140 fi 141 done 142 } 143 144 declare_function_pointers() { 145 for fn in $ALL_FUNCS; do 146 rtyp="$(eval "echo \$${fn}_rtyp")" 147 args="$(eval "echo \"\$${fn}_args\"")" 148 dfn="$(eval "echo \$${fn}_default")" 149 dfn=$(eval "echo \$${dfn}") 150 for opt in "$@"; do 151 ofn=$(eval "echo \$${fn}_${opt}") 152 [ -z "$ofn" ] && continue 153 echo "$rtyp ${ofn}($args);" 154 done 155 if [ "$(eval "echo \$${fn}_indirect")" = "false" ]; then 156 echo "#define ${fn} ${dfn}" 157 else 158 echo "RTCD_EXTERN $rtyp (*${fn})($args);" 159 fi 160 echo 161 done 162 } 163 164 set_function_pointers() { 165 for fn in $ALL_FUNCS; do 166 n="" 167 rtyp="$(eval "echo \$${fn}_rtyp")" 168 args="$(eval "echo \"\$${fn}_args\"")" 169 dfn="$(eval "echo \$${fn}_default")" 170 dfn=$(eval "echo \$${dfn}") 171 if $(eval "echo \$${fn}_indirect"); then 172 echo " $fn = $dfn;" 173 for opt in "$@"; do 174 ofn=$(eval "echo \$${fn}_${opt}") 175 [ -z "$ofn" ] && continue 176 [ "$ofn" = "$dfn" ] && continue; 177 link=$(eval "echo \$${fn}_${opt}_link") 178 [ "$link" = "false" ] && continue 179 cond="$(eval "echo \$have_${opt}")" 180 echo " if (${cond}) $fn = $ofn;" 181 done 182 fi 183 echo 184 done 185 } 186 187 filter() { 188 filtered="" 189 for opt in "$@"; do 190 [ -z $(eval "echo \$disable_${opt}") ] && filtered="$filtered $opt" 191 done 192 echo $filtered 193 } 194 195 # 196 # Helper functions for generating the arch specific RTCD files 197 # 198 common_top() { 199 outfile_basename=$(basename ${symbol:-rtcd}) 200 include_guard=$(echo $outfile_basename | tr '[a-z]' '[A-Z]' | \ 201 tr -c '[A-Z0-9]' _)H_ 202 cat <<EOF 203 #ifndef ${include_guard} 204 #define ${include_guard} 205 206 #ifdef RTCD_C 207 #define RTCD_EXTERN 208 #else 209 #define RTCD_EXTERN extern 210 #endif 211 212 $(process_forward_decls) 213 214 $(declare_function_pointers c $ALL_ARCHS) 215 216 void ${symbol:-rtcd}(void); 217 EOF 218 } 219 220 common_bottom() { 221 cat <<EOF 222 #endif 223 EOF 224 } 225 226 x86() { 227 determine_indirection c $ALL_ARCHS 228 229 # Assign the helper variable for each enabled extension 230 for opt in $ALL_ARCHS; do 231 uc=$(echo $opt | tr '[a-z]' '[A-Z]') 232 eval "have_${opt}=\"flags & HAS_${uc}\"" 233 done 234 235 cat <<EOF 236 $(common_top) 237 238 #ifdef RTCD_C 239 #include "vpx_ports/x86.h" 240 static void setup_rtcd_internal(void) 241 { 242 int flags = x86_simd_caps(); 243 244 (void)flags; 245 246 $(set_function_pointers c $ALL_ARCHS) 247 } 248 #endif 249 $(common_bottom) 250 EOF 251 } 252 253 arm() { 254 determine_indirection c $ALL_ARCHS 255 256 # Assign the helper variable for each enabled extension 257 for opt in $ALL_ARCHS; do 258 uc=$(echo $opt | tr '[a-z]' '[A-Z]') 259 eval "have_${opt}=\"flags & HAS_${uc}\"" 260 done 261 262 cat <<EOF 263 $(common_top) 264 #include "vpx_config.h" 265 266 #ifdef RTCD_C 267 #include "vpx_ports/arm.h" 268 static void setup_rtcd_internal(void) 269 { 270 int flags = arm_cpu_caps(); 271 272 (void)flags; 273 274 $(set_function_pointers c $ALL_ARCHS) 275 } 276 #endif 277 $(common_bottom) 278 EOF 279 } 280 281 282 mips() { 283 determine_indirection c $ALL_ARCHS 284 cat <<EOF 285 $(common_top) 286 #include "vpx_config.h" 287 288 #ifdef RTCD_C 289 static void setup_rtcd_internal(void) 290 { 291 $(set_function_pointers c $ALL_ARCHS) 292 #if HAVE_DSPR2 293 #if CONFIG_VP8 294 void dsputil_static_init(); 295 dsputil_static_init(); 296 #endif 297 #if CONFIG_VP9 298 void vp9_dsputil_static_init(); 299 vp9_dsputil_static_init(); 300 #endif 301 #endif 302 } 303 #endif 304 $(common_bottom) 305 EOF 306 } 307 308 unoptimized() { 309 determine_indirection c 310 cat <<EOF 311 $(common_top) 312 #include "vpx_config.h" 313 314 #ifdef RTCD_C 315 static void setup_rtcd_internal(void) 316 { 317 $(set_function_pointers c) 318 } 319 #endif 320 $(common_bottom) 321 EOF 322 323 } 324 # 325 # Main Driver 326 # 327 require c 328 case $arch in 329 x86) 330 ALL_ARCHS=$(filter mmx sse sse2 sse3 ssse3 sse4_1 avx avx2) 331 x86 332 ;; 333 x86_64) 334 ALL_ARCHS=$(filter mmx sse sse2 sse3 ssse3 sse4_1 avx avx2) 335 REQUIRES=${REQUIRES:-mmx sse sse2} 336 require $(filter $REQUIRES) 337 x86 338 ;; 339 mips32) 340 ALL_ARCHS=$(filter mips32) 341 dspr2=$([ -f "$config_file" ] && eval echo $(grep HAVE_DSPR2 "$config_file")) 342 HAVE_DSPR2="${dspr2#*=}" 343 if [ "$HAVE_DSPR2" = "yes" ]; then 344 ALL_ARCHS=$(filter mips32 dspr2) 345 fi 346 mips 347 ;; 348 armv5te) 349 ALL_ARCHS=$(filter edsp) 350 arm 351 ;; 352 armv6) 353 ALL_ARCHS=$(filter edsp media) 354 arm 355 ;; 356 armv7) 357 ALL_ARCHS=$(filter edsp media neon) 358 arm 359 ;; 360 *) 361 unoptimized 362 ;; 363 esac 364