Merge remote-tracking branch 'aosp/upstream-master' into update-shaderc

Includes:
37422e9 Support building under CYGWIN
e0e4044 Update Travis notification emails
f8cc397 Generate spvasm.vim

Test: checkbuild.py on Linux; ran unit tests on Windows
Change-Id: If82c790d58064940397123732219bdffa29ab988
diff --git a/.travis.yml b/.travis.yml
index 0d2375b..c84cfb7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -81,8 +81,8 @@
     recipients:
       - antiagainst@google.com
       - awoloszyn@google.com
-      - deki@google.com
       - dneto@google.com
+      - ehsann@google.com
       - qining@google.com
     on_success: change
     on_failure: always
diff --git a/CHANGES b/CHANGES
index e9f2c8e..47b3c2f 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,10 @@
 Revision history for SPIRV-Tools
 
 v2016.7-dev 2016-12-13
+ - Add build target spirv-tools-vimsyntax to generate spvasm.vim, a SPIR-V
+   assembly syntax file for Vim.
+ - Fixes:
+   #508: Support compilation under CYGWIN
 
 v2016.6 2016-12-13
  - Published the C++ interface for assembling, disassembling, validation, and
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0f0d5ea..7765caf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -30,6 +30,8 @@
   add_definitions(-DSPIRV_LINUX)
 elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
   add_definitions(-DSPIRV_WINDOWS)
+elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN")
+  add_definitions(-DSPIRV_WINDOWS)
 elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
   add_definitions(-DSPIRV_MAC)
 elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Android")
diff --git a/README.md b/README.md
index 9ec348e..6fc589d 100644
--- a/README.md
+++ b/README.md
@@ -89,6 +89,13 @@
 For the latest list with detailed documentation, please refer to
 [`include/spirv-tools/optimizer.hpp`](include/spirv-tools/optimizer.hpp).
 
+### Extras
+
+* [Utility filters](#utility-filters)
+* Build target `spirv-tools-vimsyntax` generates file `spvasm.vim`.
+  Copy that file into your `$HOME/.vim/syntax` directory to get SPIR-V assembly syntax
+  highlighting in Vim.  This build target is not built by default.
+
 ## Source code
 
 The SPIR-V Tools are maintained by members of the The Khronos Group Inc.,
@@ -332,6 +339,9 @@
 ## Future Work
 <a name="future"></a>
 
+_See the [projects pages](https://github.com/KhronosGroup/SPIRV-Tools/projects)
+for more information._
+
 ### Assembler and disassembler
 
 * The disassembler could emit helpful annotations in comments.  For example:
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index 3a6b9a2..67e712e 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -13,6 +13,7 @@
 # limitations under the License.
 
 set(GRAMMAR_PROCESSING_SCRIPT "${spirv-tools_SOURCE_DIR}/utils/generate_grammar_tables.py")
+set(VIMSYNTAX_PROCESSING_SCRIPT "${spirv-tools_SOURCE_DIR}/utils/generate_vim_syntax.py")
 set(XML_REGISTRY_PROCESSING_SCRIPT "${spirv-tools_SOURCE_DIR}/utils/generate_registry_tables.py")
 
 # macro() definitions are used in the following because we need to append .inc
@@ -34,6 +35,22 @@
   list(APPEND OPERAND_CPP_DEPENDS ${GRAMMAR_KINDS_INC_FILE})
 endmacro(spvtools_core_tables)
 
+macro(spvtools_vimsyntax VERSION CLVERSION)
+  set(GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${VERSION}/spirv.core.grammar.json")
+  set(GLSL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${VERSION}/extinst.glsl.std.450.grammar.json")
+  set(OPENCL_GRAMMAR_JSON_FILE "${CMAKE_CURRENT_SOURCE_DIR}/extinst-1.0.opencl.std.grammar.json")
+  set(VIMSYNTAX_FILE "${spirv-tools_BINARY_DIR}/spvasm.vim")
+  add_custom_command(OUTPUT ${VIMSYNTAX_FILE}
+      COMMAND ${PYTHON_EXECUTABLE} ${VIMSYNTAX_PROCESSING_SCRIPT}
+      --spirv-core-grammar=${GRAMMAR_JSON_FILE}
+      --extinst-glsl-grammar=${GLSL_GRAMMAR_JSON_FILE}
+      --extinst-opencl-grammar=${OPENCL_GRAMMAR_JSON_FILE}
+      >${VIMSYNTAX_FILE}
+    DEPENDS ${VIMSYNTAX_PROCESSING_SCRIPT} ${GRAMMAR_JSON_FILE}
+            ${GLSL_GRAMMAR_JSON_FILE} ${OPENCL_GRAMMAR_JSON_FILE}
+    COMMENT "Generate spvasm.vim: Vim syntax file for SPIR-V assembly.")
+endmacro(spvtools_vimsyntax)
+
 macro(spvtools_glsl_tables VERSION)
   set(CORE_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${VERSION}/spirv.core.grammar.json")
   set(GLSL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${VERSION}/extinst.glsl.std.450.grammar.json")
@@ -67,6 +84,9 @@
 spvtools_opencl_tables("1.0")
 spvtools_glsl_tables("1.0")
 
+spvtools_vimsyntax("1.1" "1.0")
+add_custom_target(spirv-tools-vimsyntax DEPENDS ${VIMSYNTAX_FILE})
+
 
 # Extract the list of known generators from the SPIR-V XML registry file.
 set(GENERATOR_INC_FILE ${spirv-tools_BINARY_DIR}/generators.inc)
diff --git a/source/binary.cpp b/source/binary.cpp
index 689937f..cdd2eab 100644
--- a/source/binary.cpp
+++ b/source/binary.cpp
@@ -550,7 +550,7 @@
       const size_t remaining_input_bytes =
           sizeof(uint32_t) * (_.num_words - _.word_index);
       const size_t string_num_content_bytes =
-          strnlen(string, remaining_input_bytes);
+          spv_strnlen_s(string, remaining_input_bytes);
       // If there was no terminating null byte, then that's an end-of-input
       // error.
       if (string_num_content_bytes == remaining_input_bytes)
@@ -770,3 +770,11 @@
   delete[] binary->code;
   delete binary;
 }
+
+size_t spv_strnlen_s(const char* str, size_t strsz) {
+  if (!str) return 0;
+  for (size_t i = 0; i < strsz; i++) {
+    if (!str[i]) return i;
+  }
+  return strsz;
+}
diff --git a/source/binary.h b/source/binary.h
index 375e010..f6237e3 100644
--- a/source/binary.h
+++ b/source/binary.h
@@ -27,4 +27,10 @@
                                 const spv_endianness_t endian,
                                 spv_header_t* header);
 
+// Returns the number of non-null characters in str before the first null
+// character, or strsz if there is no null character.  Examines at most the
+// first strsz characters in str.  Returns 0 if str is nullptr.  This is a
+// replacement for C11's strnlen_s which might not exist in all environments.
+size_t spv_strnlen_s(const char* str, size_t strsz);
+
 #endif  // LIBSPIRV_BINARY_H_
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 891828b..6017793 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -71,6 +71,7 @@
   binary_endianness_test.cpp
   binary_header_get_test.cpp
   binary_parse_test.cpp
+  binary_strnlen_s_test.cpp
   binary_to_text_test.cpp
   binary_to_text.literal_test.cpp
   capability_set_test.cpp
diff --git a/test/binary_strnlen_s_test.cpp b/test/binary_strnlen_s_test.cpp
new file mode 100644
index 0000000..2d2170b
--- /dev/null
+++ b/test/binary_strnlen_s_test.cpp
@@ -0,0 +1,30 @@
+// Copyright (c) 2016 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "unit_spirv.h"
+
+namespace {
+
+TEST(Strnlen, Samples) {
+  EXPECT_EQ(0u, spv_strnlen_s(nullptr, 0));
+  EXPECT_EQ(0u, spv_strnlen_s(nullptr, 5));
+  EXPECT_EQ(0u, spv_strnlen_s("abc", 0));
+  EXPECT_EQ(1u, spv_strnlen_s("abc", 1));
+  EXPECT_EQ(3u, spv_strnlen_s("abc", 3));
+  EXPECT_EQ(3u, spv_strnlen_s("abc\0", 5));
+  EXPECT_EQ(0u, spv_strnlen_s("\0", 5));
+  EXPECT_EQ(1u, spv_strnlen_s("a\0c", 5));
+}
+
+}  // anonymous namespace
diff --git a/utils/generate_vim_syntax.py b/utils/generate_vim_syntax.py
new file mode 100755
index 0000000..837afa6
--- /dev/null
+++ b/utils/generate_vim_syntax.py
@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+# Copyright (c) 2016 Google Inc.
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Generates Vim syntax rules for SPIR-V assembly (.spvasm) files"""
+
+from __future__ import print_function
+
+import json
+
+PREAMBLE="""" Vim syntax file
+" Language:   spvasm
+" Generated by SPIRV-Tools
+
+if version < 600
+  syntax clear
+elseif exists("b:current_syntax")
+  finish
+endif
+
+syn case match
+"""
+
+POSTAMBLE="""
+
+syntax keyword spvasmTodo TODO FIXME contained
+
+syn match   spvasmIdNumber /%\d\+\>/
+
+" The assembler treats the leading minus sign as part of the number token.
+" This applies to integers, and to floats below.
+syn match   spvasmNumber /-\?\<\d\+\>/
+
+" Floating point literals.
+" In general, C++ requires at least digit in the mantissa, and the
+" floating point is optional.  This applies to both the regular decimal float
+" case and the hex float case.
+
+" First case: digits before the optional decimal, no trailing digits.
+syn match   spvasmFloat  /-\?\d\+\.\?\(e[+-]\d\+\)\?/
+" Second case: optional digits before decimal, trailing digits
+syn match   spvasmFloat  /-\?\d*\.\d\+\(e[+-]\d\+\)\?/
+
+" First case: hex digits before the optional decimal, no trailing hex digits.
+syn match   spvasmFloat  /-\?0[xX]\\x\+\.\?p[-+]\d\+/
+" Second case: optional hex digits before decimal, trailing hex digits
+syn match   spvasmFloat  /-\?0[xX]\\x*\.\\x\+p[-+]\d\+/
+
+syn match   spvasmComment /;.*$/ contains=spvasmTodo
+syn region  spvasmString start=/"/ skip=/\\\\"/ end=/"/
+syn match   spvasmId /%[a-zA-Z_][a-zA-Z_0-9]*/
+
+" Highlight unknown constants and statements as errors
+syn match   spvasmError /[a-zA-Z][a-zA-Z_0-9]*/
+
+
+if version >= 508 || !exists("did_c_syn_inits")
+  if version < 508
+    let did_c_syn_inits = 1
+    command -nargs=+ HiLink hi link <args>
+  else
+    command -nargs=+ HiLink hi def link <args>
+  endif
+
+  HiLink spvasmStatement Statement
+  HiLink spvasmNumber Number
+  HiLink spvasmComment Comment
+  HiLink spvasmString String
+  HiLink spvasmFloat Float
+  HiLink spvasmConstant Constant
+  HiLink spvasmIdNumber Identifier
+  HiLink spvasmId Identifier
+  HiLink spvasmTodo Todo
+
+  delcommand HiLink
+endif
+
+let b:current_syntax = "spvasm"
+"""
+
+# This list is taken from the description of OpSpecConstantOp in SPIR-V 1.1.
+# TODO(dneto): Propose that this information be embedded in the grammar file.
+SPEC_CONSTANT_OP_OPCODES = """
+        OpSConvert, OpFConvert
+        OpSNegate, OpNot
+        OpIAdd, OpISub
+        OpIMul, OpUDiv, OpSDiv, OpUMod, OpSRem, OpSMod
+        OpShiftRightLogical, OpShiftRightArithmetic, OpShiftLeftLogical
+        OpBitwiseOr, OpBitwiseXor, OpBitwiseAnd
+        OpVectorShuffle, OpCompositeExtract, OpCompositeInsert
+        OpLogicalOr, OpLogicalAnd, OpLogicalNot,
+        OpLogicalEqual, OpLogicalNotEqual
+        OpSelect
+        OpIEqual, OpINotEqual
+        OpULessThan, OpSLessThan
+        OpUGreaterThan, OpSGreaterThan
+        OpULessThanEqual, OpSLessThanEqual
+        OpUGreaterThanEqual, OpSGreaterThanEqual
+
+        OpQuantizeToF16
+
+        OpConvertFToS, OpConvertSToF
+        OpConvertFToU, OpConvertUToF
+        OpUConvert
+        OpConvertPtrToU, OpConvertUToPtr
+        OpGenericCastToPtr, OpPtrCastToGeneric
+        OpBitcast
+        OpFNegate
+        OpFAdd, OpFSub
+        OpFMul, OpFDiv
+        OpFRem, OpFMod
+        OpAccessChain, OpInBoundsAccessChain
+        OpPtrAccessChain, OpInBoundsPtrAccessChain"""
+
+
+def EmitAsStatement(name):
+    """Emits the given name as a statement token"""
+    print('syn keyword spvasmStatement', name)
+
+
+def EmitAsEnumerant(name):
+    """Emits the given name as an named operand token"""
+    print('syn keyword spvasmConstant', name)
+
+
+def main():
+    """Parses arguments, then generates the Vim syntax rules for SPIR-V assembly
+    on stdout."""
+    import argparse
+    parser = argparse.ArgumentParser(description='Generate SPIR-V info tables')
+    parser.add_argument('--spirv-core-grammar', metavar='<path>',
+                        type=str, required=True,
+                        help='input JSON grammar file for core SPIR-V '
+                        'instructions')
+    parser.add_argument('--extinst-glsl-grammar', metavar='<path>',
+                        type=str, required=False, default=None,
+                        help='input JSON grammar file for GLSL extended '
+                        'instruction set')
+    parser.add_argument('--extinst-opencl-grammar', metavar='<path>',
+                        type=str, required=False, default=None,
+                        help='input JSON grammar file for OpenGL extended '
+                        'instruction set')
+    args = parser.parse_args()
+
+    # Generate the syntax rules.
+    print(PREAMBLE)
+
+    core = json.loads(open(args.spirv_core_grammar).read())
+    print('\n" Core instructions')
+    for inst in core["instructions"]:
+        EmitAsStatement(inst['opname'])
+    print('\n" Core operand enums')
+    for operand_kind in core["operand_kinds"]:
+        if 'enumerants' in operand_kind:
+            for e in operand_kind['enumerants']:
+                EmitAsEnumerant(e['enumerant'])
+
+    if args.extinst_glsl_grammar is not None:
+        print('\n" GLSL.std.450 extended instructions')
+        glsl = json.loads(open(args.extinst_glsl_grammar).read())
+        # These opcodes are really enumerant operands for the OpExtInst
+        # instruction.
+        for inst in glsl["instructions"]:
+            EmitAsEnumerant(inst['opname'])
+
+    if args.extinst_opencl_grammar is not None:
+        print('\n" OpenCL.std extended instructions')
+        opencl = json.loads(open(args.extinst_opencl_grammar).read())
+        for inst in opencl["instructions"]:
+            EmitAsEnumerant(inst['opname'])
+
+    print('\n" OpSpecConstantOp opcodes')
+    for word in SPEC_CONSTANT_OP_OPCODES.split(' '):
+        stripped = word.strip('\n,')
+        if stripped != "":
+            # Treat as an enumerant, but without the leading "Op"
+            EmitAsEnumerant(stripped[2:])
+    print(POSTAMBLE)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/utils/update_build_version.py b/utils/update_build_version.py
index ae55694..95e4237 100755
--- a/utils/update_build_version.py
+++ b/utils/update_build_version.py
@@ -78,7 +78,7 @@
 
     pattern = re.compile(r'(v\d+\.\d+(-dev)?) \d\d\d\d-\d\d-\d\d$')
     changes_file = os.path.join(directory, 'CHANGES')
-    with open(changes_file) as f:
+    with open(changes_file, mode='rU') as f:
         for line in f.readlines():
             match = pattern.match(line)
             if match: