Add an SkOpts target for Haswell+ Intel chips.

Haswell brought a whole slew of handy new instructions for us (AVX2, FMA, BMI1+BMI2) and also feature F16C, which came one generation earlier on Ivybridge.  We work with integers often enough that we really want to target AVX2 instead of AVX, and this means it's pretty practical to ask for all those other goodies along with it.

Chrome's GN files and Google3's BUILD file will need an update, before or after this CL.

BUG=skia:

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2840
CQ_INCLUDE_TRYBOTS=master.client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot

Change-Id: I826daf77b5104664c5d31ddaabee347e287b87a2
Reviewed-on: https://skia-review.googlesource.com/2840
Commit-Queue: Mike Klein <mtklein@chromium.org>
Reviewed-by: Herb Derby <herb@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 53f49ec..c138492 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -197,6 +197,18 @@
   cflags = [ "-mavx" ]
 }
 
+opts("hsw") {
+  enabled = is_x86
+  sources = skia_opts.hsw_sources
+  cflags = [
+    "-mavx2",
+    "-mbmi",
+    "-mbmi2",
+    "-mf16c",
+    "-mfma",
+  ]
+}
+
 opts("dsp") {
   enabled = current_cpu == "mipsel"
   sources = skia_opts.mips_dsp_sources
@@ -440,6 +452,7 @@
     ":fontmgr_fuchsia",
     ":gif",
     ":gpu",
+    ":hsw",
     ":jpeg",
     ":none",
     ":pdf",
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
index 0ed0957..73a40ee 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -134,13 +134,14 @@
 file (GLOB_RECURSE sse41_srcs ../src/*sse41*.cpp ../src/*SSE41*.cpp)
 file (GLOB_RECURSE sse42_srcs ../src/*sse42*.cpp ../src/*SSE42*.cpp)
 file (GLOB_RECURSE avx_srcs   ../src/*_avx.cpp)
-file (GLOB_RECURSE avx2_srcs  ../src/*_avx2.cpp)
+file (GLOB_RECURSE hsw_srcs   ../src/*_hsw.cpp)
 if (NOT WIN32)
     set_source_files_properties(${ssse3_srcs} PROPERTIES COMPILE_FLAGS -mssse3)
     set_source_files_properties(${sse41_srcs} PROPERTIES COMPILE_FLAGS -msse4.1)
     set_source_files_properties(${sse42_srcs} PROPERTIES COMPILE_FLAGS -msse4.2)
     set_source_files_properties(${avx_srcs}   PROPERTIES COMPILE_FLAGS -mavx)
-    set_source_files_properties(${avx2_srcs}  PROPERTIES COMPILE_FLAGS -mavx2)
+    set_source_files_properties(${hsw_srcs}   PROPERTIES COMPILE_FLAGS
+        -mavx2 -mbmi -mbmi2 -mf16c -mfma)
 endif()
 
 # Detect our optional dependencies.
diff --git a/gyp/opts.gyp b/gyp/opts.gyp
index 21edd85..f872083 100644
--- a/gyp/opts.gyp
+++ b/gyp/opts.gyp
@@ -34,7 +34,7 @@
       'conditions': [
         [ '"x86" in skia_arch_type and skia_os != "ios"', {
           'cflags': [ '-msse2' ],
-          'dependencies': [ 'opts_ssse3', 'opts_sse41', 'opts_sse42', 'opts_avx', 'opts_avx2' ],
+          'dependencies': [ 'opts_ssse3', 'opts_sse41', 'opts_sse42', 'opts_avx', 'opts_hsw' ],
           'sources': [ '<@(sse2_sources)' ],
         }],
 
@@ -171,8 +171,8 @@
       ],
     },
     {
-      'target_name': 'opts_avx2',
-      'product_name': 'skia_opts_avx2',
+      'target_name': 'opts_hsw',
+      'product_name': 'skia_opts_hsw',
       'type': 'static_library',
       'standalone_static_library': 1,
       'dependencies': [ 'core.gyp:*' ],
@@ -181,11 +181,15 @@
           '../src/core',
           '../src/utils',
       ],
-      'sources': [ '<@(avx2_sources)' ],
+      'sources': [ '<@(hsw_sources)' ],
       'msvs_settings': { 'VCCLCompilerTool': { 'EnableEnhancedInstructionSet': '5' } },
-      'xcode_settings': { 'OTHER_CPLUSPLUSFLAGS': [ '-mavx2' ] },
+      'xcode_settings': {
+          'OTHER_CPLUSPLUSFLAGS': [ '-mavx2', '-mbmi', '-mbmi2', '-mf16c', '-mfma' ]
+      },
       'conditions': [
-        [ 'not skia_android_framework', { 'cflags': [ '-mavx2' ] }],
+        [ 'not skia_android_framework', {
+            'cflags': [ '-mavx2', '-mbmi', '-mbmi2', '-mf16c', '-mfma' ]
+        }],
       ],
     },
     {
diff --git a/gyp/opts.gypi b/gyp/opts.gypi
index 9aeb7f3..530ff58 100644
--- a/gyp/opts.gypi
+++ b/gyp/opts.gypi
@@ -58,8 +58,12 @@
         'avx_sources': [
             '<(skia_src_path)/opts/SkOpts_avx.cpp',
         ],
-        # These targets are empty, but XCode doesn't like that, so add an empty file to each.
+        'hsw_sources': [
+            '<(skia_src_path)/opts/SkOpts_hsw.cpp',
+        ],
+
+        # TODO: clean up after updating Chrome build.
         'avx2_sources': [
-            '<(skia_src_path)/core/SkForceCPlusPlusLinking.cpp',
+            '<(skia_src_path)/opts/SkOpts_hsw.cpp',
         ],
 }
diff --git a/public.bzl b/public.bzl
index 5cfd7d5..5ba7e10 100644
--- a/public.bzl
+++ b/public.bzl
@@ -309,9 +309,16 @@
     ],
 )
 
+HSW_SRCS = struct(
+    include = [
+        "src/opts/*_hsw.cpp",
+    ],
+)
+
+# TODO: clean up after updating BUILD.
 AVX2_SRCS = struct(
     include = [
-        "src/opts/*_avx2.cpp",
+        "src/opts/*_hsw.cpp",
     ],
 )
 
diff --git a/src/core/SkCpu.cpp b/src/core/SkCpu.cpp
index 24333b7..e3e6152 100644
--- a/src/core/SkCpu.cpp
+++ b/src/core/SkCpu.cpp
@@ -52,6 +52,8 @@
 
             cpuid7(abcd);
             if (abcd[1] & (1<<5)) { features |= SkCpu::AVX2; }
+            if (abcd[1] & (1<<3)) { features |= SkCpu::BMI1; }
+            if (abcd[1] & (1<<8)) { features |= SkCpu::BMI2; }
         }
         return features;
     }
diff --git a/src/core/SkCpu.h b/src/core/SkCpu.h
index 4dbe065..34c19d2 100644
--- a/src/core/SkCpu.h
+++ b/src/core/SkCpu.h
@@ -22,6 +22,11 @@
         F16C  = 1 << 7,
         FMA   = 1 << 8,
         AVX2  = 1 << 9,
+        BMI1  = 1 << 10,
+        BMI2  = 1 << 11,
+
+        // Handy alias for all the cool Haswell+ instructions.
+        HSW = AVX2 | BMI1 | BMI2 | F16C | FMA,
     };
     enum {
         NEON     = 1 << 0,
diff --git a/src/core/SkOpts.cpp b/src/core/SkOpts.cpp
index 5cac8ec..4d60079 100644
--- a/src/core/SkOpts.cpp
+++ b/src/core/SkOpts.cpp
@@ -147,7 +147,7 @@
     void Init_sse41();
     void Init_sse42();
     void Init_avx();
-    void Init_avx2() {}
+    void Init_hsw();
     void Init_crc32();
 
     static void init() {
@@ -157,7 +157,7 @@
         if (SkCpu::Supports(SkCpu::SSE41)) { Init_sse41(); }
         if (SkCpu::Supports(SkCpu::SSE42)) { Init_sse42(); }
         if (SkCpu::Supports(SkCpu::AVX  )) { Init_avx();   }
-        if (SkCpu::Supports(SkCpu::AVX2 )) { Init_avx2();  }
+        if (SkCpu::Supports(SkCpu::HSW  )) { Init_hsw();   }
 
     #elif defined(SK_CPU_ARM64)
         if (SkCpu::Supports(SkCpu::CRC32)) { Init_crc32(); }
diff --git a/src/opts/SkOpts_hsw.cpp b/src/opts/SkOpts_hsw.cpp
new file mode 100644
index 0000000..53e2e5a
--- /dev/null
+++ b/src/opts/SkOpts_hsw.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkOpts.h"
+
+#define SK_OPTS_NS hsw
+
+namespace SkOpts {
+    void Init_hsw() { }
+}
+