diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,3 @@
+# Changelog for pcre2
+
+## Unreleased changes
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,66 @@
+# pcre2
+
+Regular expressions for Haskell.
+
+## Teasers
+```haskell
+embeddedLicensePlate :: Text -> Maybe Text
+embeddedLicensePlate = match "[A-Z]{3}[0-9]{3,4}"
+```
+```haskell
+case "The quick brown fox" of
+    [regex|brown\s+(?<animal>\S+)|] -> Text.putStrLn animal
+    _                               -> error "nothing brown"
+```
+```haskell
+let kv'd = lined . packed . [_regex|^\s*(.*?)\s*[=:]\s*(.*)|]
+
+forMOf kv'd file $ execStateT $ do
+    k <- gets $ capture @1
+    v <- gets $ capture @2
+    liftIO $ Text.putStrLn $ "found " <> k <> " set to " <> v
+
+    case myMap ^. at k of
+        Just v' | v /= v' -> do
+            liftIO $ Text.putStrLn $ "setting " <> k <> " to " <> v'
+            _capture @2 .= v'
+        _ -> liftIO $ Text.putStrLn "no change"
+```
+
+## Features
+* Low-surface API covering most use cases.
+* Quiet functions with simple types&mdash;for the most part it's  
+`Text` _(pattern)_ `-> Text` _(subject)_ `-> result`.
+* Use partial application to create performant, compile-once-match-many code.
+* Low cognitive overhead&mdash;there's just one custom datatype for both compile
+  and match options, the `Option` monoid.
+* `Text` everywhere for interop with both C and the broader Haskell ecosystem.
+* Match failures expressed via `Alternative` or pattern match failures.
+* Opt-in Template Haskell facilities for compile-time verification of patterns,
+  indexing captures, and memoizing inline regexes.
+* Opt-in `lens` support.
+* No failure monads to express compile errors, preferring pure functions and
+  throwing imprecise exceptions with pretty `Show` instances.  Write simple
+  code and debug it.  Or, don't, and use the Template Haskell features instead.
+  Both are first-class.
+* Vast presentation of PCRE2 functionality.  We can even register Haskell
+  callbacks to run during matching!
+* No dependencies that aren't distributed with GHC.
+* Bundled, statically-linked UTF-16 build of ~~up-to-date~~ PCRE2 (version
+  10.35), with a complete, exposed Haskell binding.
+
+## TODO
+* Global matching.  (We already have global substitution.)
+* Many performance optimizations.  Currently we are 2&ndash;3&times; slower
+  than other libraries doing everything (a few &mu;s).
+* Make use of DFA and JIT compilation.
+* Establish automated builds.
+* Improve PCRE2 C compile time.
+* PCRE2 10.36 is out already.
+
+## License
+[Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.html).  
+PCRE2 is distributed under the [3-clause BSD](https://www.pcre.org/licence.txt) license.
+
+## Author
+&copy;2020 Shlomo Shuck
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/bench/Bench.hs b/bench/Bench.hs
new file mode 100644
--- /dev/null
+++ b/bench/Bench.hs
@@ -0,0 +1,114 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE ViewPatterns #-}
+
+module Main where
+
+import           Criterion.Main
+import           Data.List.NonEmpty          (NonEmpty(..))
+import qualified Data.Text                   as Text
+import           Lens.Micro.Platform
+import           System.IO.Unsafe            (unsafePerformIO)
+import qualified Text.Regex.PCRE
+import qualified Text.Regex.PCRE.Light.Char8
+import qualified Text.Regex.PCRE.String
+import qualified Text.Regex.PCRE.Text
+import           Text.Regex.Pcre2
+
+main :: IO ()
+main = defaultMain [
+    bgroup "creating single-use regexes" [
+        bench "pcre2" $ flip nf strings $ \(patt, subj) ->
+            let Just (_ :| [bar]) = capturesA (Text.pack patt) (Text.pack subj)
+            in Text.unpack bar,
+
+        bench "regex-pcre-builtin" $ flip nf strings $ \(patt, subj) ->
+            let r = Text.Regex.PCRE.makeRegex patt :: Text.Regex.PCRE.Regex
+                results :: (String, String, String)
+                results@(_, result, _) = Text.Regex.PCRE.match r subj
+            in result,
+
+        bench "pcre-light" $ flip nf strings $ \(patt, subj) ->
+            let r = Text.Regex.PCRE.Light.Char8.compile patt []
+                Just [_, bar] = Text.Regex.PCRE.Light.Char8.match r subj []
+            in bar],
+    
+    bgroup "strings" [
+        let r = capturesA $ Text.pack stringPattern
+        in bench "pcre2" $ flip nf stringSubject $ \subj ->
+            let Just (_ :| [bar]) = r $ Text.pack subj in Text.unpack bar,
+
+        let r = mkRegexBaseR stringPattern
+        in bench "regex-pcre-builtin" $ nfIO $ do
+            Right (Just (_, _, _, [bar])) <-
+                Text.Regex.PCRE.String.regexec r stringSubject
+            return bar,
+
+        let r = Text.Regex.PCRE.Light.Char8.compile stringPattern []
+        in bench "pcre-light" $ flip nf stringSubject $ \subj ->
+            let Just [_, bar] = Text.Regex.PCRE.Light.Char8.match r subj []
+            in bar],
+
+    bgroup "texts" [
+        bgroupTexts "short" strings,
+
+        bgroupTexts "long" (
+            "foo (ba*r) baz",
+            "foo b" ++ replicate 1000 'a' ++ "r baz")],
+
+    bgroup "Template Haskell" [
+        bench "pattern with named capture" $ flip nf textSubject $ \subj ->
+            let [regex|foo (?<bar>bar) baz|] = subj in bar,
+
+        bench "expression with capture" $ flip nf textSubject $ \subj ->
+            let Just cs = [regex|foo (?<bar>bar) baz|] subj
+            in capture @"bar" cs],
+
+    bgroup "substitutions" [
+        bench "PCRE2-native" $ flip nf textSubject $
+            sub (Text.pack "(?<=foo )bar(?= baz)") (Text.pack "quux"),
+
+        let quux = Text.pack "quux"
+        in bench "lens-powered" $ flip nf textSubject $
+            set ([_regex|foo (bar) baz|] . _capture @1) quux]]
+
+stringPattern = "foo (bar) baz"
+stringSubject = "foo bar baz"
+strings = (stringPattern, stringSubject)
+
+textPattern = Text.pack "foo (bar) baz"
+textSubject = Text.pack "foo bar baz"
+
+mkRegexBaseR :: String -> Text.Regex.PCRE.Regex
+mkRegexBaseR patt = unsafePerformIO $ do
+    Right r <- Text.Regex.PCRE.String.compile 0 0 patt
+    return r
+
+bgroupTexts :: String -> (String, String) -> Benchmark
+bgroupTexts label (patt, subj) = bgroup label [
+    bench "pcre2" $ flip nf textSubject $ \subj ->
+        let Just (_ :| [bar]) = pcre2R subj in bar,
+
+    bench "regex-pcre-builtin" $ nfIO $ do
+        Text.Regex.PCRE.Text.regexec regexBaseR textSubject >>= \case
+            Right (Just (_, _, _, [bar])) -> return bar
+            x                             -> do
+                print x
+                error "BUG!",
+
+    bench "pcre-light" $ flip nf textSubject $ \subj ->
+        let Just [_, bar] = Text.Regex.PCRE.Light.Char8.match
+                pcreLightR
+                (Text.unpack subj)
+                []
+        in bar]
+
+    where
+    textPattern = Text.pack patt
+    textSubject = Text.pack subj
+    pcre2R = capturesA textPattern
+    regexBaseR = mkRegexBaseR patt
+    pcreLightR = Text.Regex.PCRE.Light.Char8.compile patt []
diff --git a/pcre2.cabal b/pcre2.cabal
new file mode 100644
--- /dev/null
+++ b/pcre2.cabal
@@ -0,0 +1,186 @@
+cabal-version:      1.12
+name:               pcre2
+version:            1.0.0
+license:            Apache-2.0
+license-file:       LICENSE
+copyright:          2020 Shlomo Shuck
+maintainer:         stevenjshuck@gmail.com
+author:             Shlomo Shuck
+homepage:           https://github.com/sjshuck/hs-pcre2#readme
+bug-reports:        https://github.com/sjshuck/hs-pcre2/issues
+synopsis:           Regular expressions via the PCRE2 C library (included)
+description:
+    Please see the README on GitHub at <https://github.com/sjshuck/hs-pcre2>
+
+category:           Text
+build-type:         Simple
+extra-source-files:
+    README.md
+    ChangeLog.md
+    src/c/config.h
+    src/c/getters.h
+    src/c/pcre2.h
+    src/c/pcre2/src/pcre2_internal.h
+    src/c/pcre2/src/pcre2_intmodedep.h
+    src/c/pcre2/src/pcre2_jit_neon_inc.h
+    src/c/pcre2/src/pcre2_jit_simd_inc.h
+    src/c/pcre2/src/pcre2_ucp.h
+    src/c/pcre2/src/pcre2posix.h
+    src/c/pcre2/src/sljit/sljitConfig.h
+    src/c/pcre2/src/sljit/sljitConfigInternal.h
+    src/c/pcre2/src/sljit/sljitLir.h
+    src/c/pcre2/maint/ucptest.c
+    src/c/pcre2/maint/utf8.c
+    src/c/pcre2/src/pcre2_auto_possess.c
+    src/c/pcre2/src/pcre2_compile.c
+    src/c/pcre2/src/pcre2_config.c
+    src/c/pcre2/src/pcre2_context.c
+    src/c/pcre2/src/pcre2_convert.c
+    src/c/pcre2/src/pcre2_dfa_match.c
+    src/c/pcre2/src/pcre2_dftables.c
+    src/c/pcre2/src/pcre2_error.c
+    src/c/pcre2/src/pcre2_extuni.c
+    src/c/pcre2/src/pcre2_find_bracket.c
+    src/c/pcre2/src/pcre2_fuzzsupport.c
+    src/c/pcre2/src/pcre2_jit_compile.c
+    src/c/pcre2/src/pcre2_jit_match.c
+    src/c/pcre2/src/pcre2_jit_misc.c
+    src/c/pcre2/src/pcre2_jit_test.c
+    src/c/pcre2/src/pcre2_maketables.c
+    src/c/pcre2/src/pcre2_match.c
+    src/c/pcre2/src/pcre2_match_data.c
+    src/c/pcre2/src/pcre2_newline.c
+    src/c/pcre2/src/pcre2_ord2utf.c
+    src/c/pcre2/src/pcre2_pattern_info.c
+    src/c/pcre2/src/pcre2_printint.c
+    src/c/pcre2/src/pcre2_script_run.c
+    src/c/pcre2/src/pcre2_serialize.c
+    src/c/pcre2/src/pcre2_string_utils.c
+    src/c/pcre2/src/pcre2_study.c
+    src/c/pcre2/src/pcre2_substitute.c
+    src/c/pcre2/src/pcre2_substring.c
+    src/c/pcre2/src/pcre2_tables.c
+    src/c/pcre2/src/pcre2_ucd.c
+    src/c/pcre2/src/pcre2_valid_utf.c
+    src/c/pcre2/src/pcre2_xclass.c
+    src/c/pcre2/src/pcre2demo.c
+    src/c/pcre2/src/pcre2grep.c
+    src/c/pcre2/src/pcre2posix.c
+    src/c/pcre2/src/pcre2test.c
+    src/c/pcre2/src/sljit/sljitExecAllocator.c
+    src/c/pcre2/src/sljit/sljitLir.c
+    src/c/pcre2/src/sljit/sljitNativeARM_32.c
+    src/c/pcre2/src/sljit/sljitNativeARM_64.c
+    src/c/pcre2/src/sljit/sljitNativeARM_T2_32.c
+    src/c/pcre2/src/sljit/sljitNativeMIPS_32.c
+    src/c/pcre2/src/sljit/sljitNativeMIPS_64.c
+    src/c/pcre2/src/sljit/sljitNativeMIPS_common.c
+    src/c/pcre2/src/sljit/sljitNativePPC_32.c
+    src/c/pcre2/src/sljit/sljitNativePPC_64.c
+    src/c/pcre2/src/sljit/sljitNativePPC_common.c
+    src/c/pcre2/src/sljit/sljitNativeSPARC_32.c
+    src/c/pcre2/src/sljit/sljitNativeSPARC_common.c
+    src/c/pcre2/src/sljit/sljitNativeTILEGX-encoder.c
+    src/c/pcre2/src/sljit/sljitNativeTILEGX_64.c
+    src/c/pcre2/src/sljit/sljitNativeX86_32.c
+    src/c/pcre2/src/sljit/sljitNativeX86_64.c
+    src/c/pcre2/src/sljit/sljitNativeX86_common.c
+    src/c/pcre2/src/sljit/sljitProtExecAllocator.c
+    src/c/pcre2/src/sljit/sljitUtils.c
+    src/c/pcre2/src/sljit/sljitWXExecAllocator.c
+    src/c/pcre2_chartables.c
+
+source-repository head
+    type:     git
+    location: https://github.com/sjshuck/hs-pcre2
+
+library
+    exposed-modules:
+        Text.Regex.Pcre2
+        Text.Regex.Pcre2.Foreign
+
+    cc-options:       -DHAVE_CONFIG_H -DPCRE2_CODE_UNIT_WIDTH=16
+    c-sources:
+        src/c/pcre2/src/pcre2_auto_possess.c
+        src/c/pcre2_chartables.c
+        src/c/pcre2/src/pcre2_compile.c
+        src/c/pcre2/src/pcre2_config.c
+        src/c/pcre2/src/pcre2_context.c
+        src/c/pcre2/src/pcre2_convert.c
+        src/c/pcre2/src/pcre2_dfa_match.c
+        src/c/pcre2/src/pcre2_error.c
+        src/c/pcre2/src/pcre2_extuni.c
+        src/c/pcre2/src/pcre2_find_bracket.c
+        src/c/pcre2/src/pcre2_jit_compile.c
+        src/c/pcre2/src/pcre2_maketables.c
+        src/c/pcre2/src/pcre2_match.c
+        src/c/pcre2/src/pcre2_match_data.c
+        src/c/pcre2/src/pcre2_newline.c
+        src/c/pcre2/src/pcre2_ord2utf.c
+        src/c/pcre2/src/pcre2_pattern_info.c
+        src/c/pcre2/src/pcre2_script_run.c
+        src/c/pcre2/src/pcre2_serialize.c
+        src/c/pcre2/src/pcre2_string_utils.c
+        src/c/pcre2/src/pcre2_study.c
+        src/c/pcre2/src/pcre2_substitute.c
+        src/c/pcre2/src/pcre2_substring.c
+        src/c/pcre2/src/pcre2_tables.c
+        src/c/pcre2/src/pcre2_ucd.c
+        src/c/pcre2/src/pcre2_valid_utf.c
+        src/c/pcre2/src/pcre2_xclass.c
+
+    hs-source-dirs:   src/hs
+    other-modules:
+        Text.Regex.Pcre2.Foreign.TH
+        Text.Regex.Pcre2.Internal
+        Text.Regex.Pcre2.TH
+        Paths_pcre2
+
+    default-language: Haskell2010
+    include-dirs:     src/c src/c/pcre2/src
+    ghc-options:
+        -optc=-DPCRE2_CODE_UNIT_WIDTH=16 -optc=-Wno-discarded-qualifiers
+        -optc=-Wno-incompatible-pointer-types
+
+    build-depends:
+        base >=4.7 && <5,
+        containers >=0.6.2.1 && <0.7,
+        mtl >=2.2.2 && <2.3,
+        template-haskell >=2.15.0.0 && <2.16,
+        text >=1.2.4.0 && <1.3
+
+test-suite pcre2-test
+    type:             exitcode-stdio-1.0
+    main-is:          Spec.hs
+    hs-source-dirs:   test
+    other-modules:    Paths_pcre2
+    default-language: Haskell2010
+    ghc-options:      -threaded -rtsopts -with-rtsopts=-N
+    build-depends:
+        base >=4.7 && <5,
+        containers >=0.6.2.1 && <0.7,
+        hspec >=2.7.4 && <2.8,
+        microlens-platform >=0.4.2 && <0.5,
+        mtl >=2.2.2 && <2.3,
+        pcre2 -any,
+        template-haskell >=2.15.0.0 && <2.16,
+        text >=1.2.4.0 && <1.3
+
+benchmark pcre2-benchmarks
+    type:             exitcode-stdio-1.0
+    main-is:          Bench.hs
+    hs-source-dirs:   bench
+    other-modules:    Paths_pcre2
+    default-language: Haskell2010
+    ghc-options:      -threaded -rtsopts -with-rtsopts=-N
+    build-depends:
+        base >=4.7 && <5,
+        containers >=0.6.2.1 && <0.7,
+        criterion >=1.5.7.0 && <1.6,
+        microlens-platform >=0.4.2 && <0.5,
+        mtl >=2.2.2 && <2.3,
+        pcre-light >=0.4.1.0 && <0.5,
+        pcre2 -any,
+        regex-pcre-builtin >=0.95.1.3.8.43 && <0.96,
+        template-haskell >=2.15.0.0 && <2.16,
+        text >=1.2.4.0 && <1.3
diff --git a/src/c/config.h b/src/c/config.h
new file mode 100644
--- /dev/null
+++ b/src/c/config.h
@@ -0,0 +1,380 @@
+// Copied and edited per the PCRE2 source's NON-AUTOTOOLS-BUILD instructions.
+
+/* PCRE2 is written in Standard C, but there are a few non-standard things it
+can cope with, allowing it to run on SunOS4 and other "close to standard"
+systems.
+
+In environments that support the GNU autotools, config.h.in is converted into
+config.h by the "configure" script. In environments that use CMake,
+config-cmake.in is converted into config.h. If you are going to build PCRE2 "by
+hand" without using "configure" or CMake, you should copy the distributed
+config.h.generic to config.h, and edit the macro definitions to be the way you
+need them. You must then add -DHAVE_CONFIG_H to all of your compile commands,
+so that config.h is included at the start of every source.
+
+Alternatively, you can avoid editing by using -D on the compiler command line
+to set the macro values. In this case, you do not have to set -DHAVE_CONFIG_H,
+but if you do, default values will be taken from config.h for non-boolean
+macros that are not defined on the command line.
+
+Boolean macros such as HAVE_STDLIB_H and SUPPORT_PCRE2_8 should either be
+defined (conventionally to 1) for TRUE, and not defined at all for FALSE. All
+such macros are listed as a commented #undef in config.h.generic. Macros such
+as MATCH_LIMIT, whose actual value is relevant, have defaults defined, but are
+surrounded by #ifndef/#endif lines so that the value can be overridden by -D.
+
+PCRE2 uses memmove() if HAVE_MEMMOVE is defined; otherwise it uses bcopy() if
+HAVE_BCOPY is defined. If your system has neither bcopy() nor memmove(), make
+sure both macros are undefined; an emulation function will then be used. */
+
+/* By default, the \R escape sequence matches any Unicode line ending
+   character or sequence of characters. If BSR_ANYCRLF is defined (to any
+   value), this is changed so that backslash-R matches only CR, LF, or CRLF.
+   The build-time default can be overridden by the user of PCRE2 at runtime.
+   */
+/* #undef BSR_ANYCRLF */
+
+/* Define to any value to disable the use of the z and t modifiers in
+   formatting settings such as %zu or %td (this is rarely needed). */
+/* #undef DISABLE_PERCENT_ZT */
+
+/* If you are compiling for a system that uses EBCDIC instead of ASCII
+   character codes, define this macro to any value. When EBCDIC is set, PCRE2
+   assumes that all input strings are in EBCDIC. If you do not define this
+   macro, PCRE2 will assume input strings are ASCII or UTF-8/16/32 Unicode. It
+   is not possible to build a version of PCRE2 that supports both EBCDIC and
+   UTF-8/16/32. */
+/* #undef EBCDIC */
+
+/* In an EBCDIC environment, define this macro to any value to arrange for the
+   NL character to be 0x25 instead of the default 0x15. NL plays the role that
+   LF does in an ASCII/Unicode environment. */
+/* #undef EBCDIC_NL25 */
+
+/* Define this if your compiler supports __attribute__((uninitialized)) */
+/* #undef HAVE_ATTRIBUTE_UNINITIALIZED */
+
+/* Define to 1 if you have the `bcopy' function. */
+/* #undef HAVE_BCOPY */
+
+/* Define to 1 if you have the <bzlib.h> header file. */
+/* #undef HAVE_BZLIB_H */
+
+/* Define to 1 if you have the <dirent.h> header file. */
+/* #undef HAVE_DIRENT_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+/* #undef HAVE_DLFCN_H */
+
+/* Define to 1 if you have the <editline/readline.h> header file. */
+/* #undef HAVE_EDITLINE_READLINE_H */
+
+/* Define to 1 if you have the <edit/readline/readline.h> header file. */
+/* #undef HAVE_EDIT_READLINE_READLINE_H */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the `memfd_create' function. */
+/* #undef HAVE_MEMFD_CREATE */
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+/* #undef HAVE_MEMORY_H */
+
+/* Define to 1 if you have the `mkostemp' function. */
+/* #undef HAVE_MKOSTEMP */
+
+/* Define if you have POSIX threads libraries and header files. */
+/* #undef HAVE_PTHREAD */
+
+/* Have PTHREAD_PRIO_INHERIT. */
+/* #undef HAVE_PTHREAD_PRIO_INHERIT */
+
+/* Define to 1 if you have the <readline/history.h> header file. */
+/* #undef HAVE_READLINE_HISTORY_H */
+
+/* Define to 1 if you have the <readline/readline.h> header file. */
+/* #undef HAVE_READLINE_READLINE_H */
+
+/* Define to 1 if you have the `secure_getenv' function. */
+/* #undef HAVE_SECURE_GETENV */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+/* #undef HAVE_STRINGS_H */
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+/* #undef HAVE_SYS_STAT_H */
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+/* #undef HAVE_SYS_TYPES_H */
+
+/* Define to 1 if you have the <sys/wait.h> header file. */
+/* #undef HAVE_SYS_WAIT_H */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+/* #undef HAVE_UNISTD_H */
+
+/* Define to 1 if the compiler supports simple visibility declarations. */
+/* #undef HAVE_VISIBILITY */
+
+/* Define to 1 if you have the <windows.h> header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the <zlib.h> header file. */
+/* #undef HAVE_ZLIB_H */
+
+/* This limits the amount of memory that may be used while matching a pattern.
+   It applies to both pcre2_match() and pcre2_dfa_match(). It does not apply
+   to JIT matching. The value is in kibibytes (units of 1024 bytes). */
+#ifndef HEAP_LIMIT
+#define HEAP_LIMIT 20000000
+#endif
+
+/* The value of LINK_SIZE determines the number of bytes used to store links
+   as offsets within the compiled regex. The default is 2, which allows for
+   compiled patterns up to 65535 code units long. This covers the vast
+   majority of cases. However, PCRE2 can also be compiled to use 3 or 4 bytes
+   instead. This allows for longer patterns in extreme cases. */
+#ifndef LINK_SIZE
+#define LINK_SIZE 2
+#endif
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+/* This is ignored unless you are using libtool. */
+#ifndef LT_OBJDIR
+#define LT_OBJDIR ".libs/"
+#endif
+
+/* The value of MATCH_LIMIT determines the default number of times the
+   pcre2_match() function can record a backtrack position during a single
+   matching attempt. The value is also used to limit a loop counter in
+   pcre2_dfa_match(). There is a runtime interface for setting a different
+   limit. The limit exists in order to catch runaway regular expressions that
+   take for ever to determine that they do not match. The default is set very
+   large so that it does not accidentally catch legitimate cases. */
+#ifndef MATCH_LIMIT
+#define MATCH_LIMIT 10000000
+#endif
+
+/* The above limit applies to all backtracks, whether or not they are nested.
+   In some environments it is desirable to limit the nesting of backtracking
+   (that is, the depth of tree that is searched) more strictly, in order to
+   restrict the maximum amount of heap memory that is used. The value of
+   MATCH_LIMIT_DEPTH provides this facility. To have any useful effect, it
+   must be less than the value of MATCH_LIMIT. The default is to use the same
+   value as MATCH_LIMIT. There is a runtime method for setting a different
+   limit. In the case of pcre2_dfa_match(), this limit controls the depth of
+   the internal nested function calls that are used for pattern recursions,
+   lookarounds, and atomic groups. */
+#ifndef MATCH_LIMIT_DEPTH
+#define MATCH_LIMIT_DEPTH MATCH_LIMIT
+#endif
+
+/* This limit is parameterized just in case anybody ever wants to change it.
+   Care must be taken if it is increased, because it guards against integer
+   overflow caused by enormously large patterns. */
+#ifndef MAX_NAME_COUNT
+#define MAX_NAME_COUNT 10000
+#endif
+
+/* This limit is parameterized just in case anybody ever wants to change it.
+   Care must be taken if it is increased, because it guards against integer
+   overflow caused by enormously large patterns. */
+#ifndef MAX_NAME_SIZE
+#define MAX_NAME_SIZE 32
+#endif
+
+/* Defining NEVER_BACKSLASH_C locks out the use of \C in all patterns. */
+/* #undef NEVER_BACKSLASH_C */
+
+/* The value of NEWLINE_DEFAULT determines the default newline character
+   sequence. PCRE2 client programs can override this by selecting other values
+   at run time. The valid values are 1 (CR), 2 (LF), 3 (CRLF), 4 (ANY), 5
+   (ANYCRLF), and 6 (NUL). */
+#ifndef NEWLINE_DEFAULT
+#define NEWLINE_DEFAULT 2
+#endif
+
+/* Name of package */
+#define PACKAGE "pcre2"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "PCRE2"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "PCRE2 10.35"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "pcre2"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "10.35"
+
+/* The value of PARENS_NEST_LIMIT specifies the maximum depth of nested
+   parentheses (of any kind) in a pattern. This limits the amount of system
+   stack that is used while compiling a pattern. */
+#ifndef PARENS_NEST_LIMIT
+#define PARENS_NEST_LIMIT 250
+#endif
+
+/* The value of PCRE2GREP_BUFSIZE is the starting size of the buffer used by
+   pcre2grep to hold parts of the file it is searching. The buffer will be
+   expanded up to PCRE2GREP_MAX_BUFSIZE if necessary, for files containing
+   very long lines. The actual amount of memory used by pcre2grep is three
+   times this number, because it allows for the buffering of "before" and
+   "after" lines. */
+#ifndef PCRE2GREP_BUFSIZE
+#define PCRE2GREP_BUFSIZE 20480
+#endif
+
+/* The value of PCRE2GREP_MAX_BUFSIZE specifies the maximum size of the buffer
+   used by pcre2grep to hold parts of the file it is searching. The actual
+   amount of memory used by pcre2grep is three times this number, because it
+   allows for the buffering of "before" and "after" lines. */
+#ifndef PCRE2GREP_MAX_BUFSIZE
+#define PCRE2GREP_MAX_BUFSIZE 1048576
+#endif
+
+/* Define to any value to include debugging code. */
+/* #undef PCRE2_DEBUG */
+
+/* If you are compiling for a system other than a Unix-like system or
+   Win32, and it needs some magic to be inserted before the definition
+   of a function that is exported by the library, define this macro to
+   contain the relevant magic. If you do not define this macro, a suitable
+    __declspec value is used for Windows systems; in other environments
+   "extern" is used for a C compiler and "extern C" for a C++ compiler.
+   This macro apears at the start of every exported function that is part
+   of the external API. It does not appear on functions that are "external"
+   in the C sense, but which are internal to the library. */
+/* #undef PCRE2_EXP_DEFN */
+
+/* Define to any value if linking statically (TODO: make nice with Libtool) */
+#define PCRE2_STATIC 1
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+   your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* Define to any non-zero number to enable support for SELinux compatible
+   executable memory allocator in JIT. Note that this will have no effect
+   unless SUPPORT_JIT is also defined. */
+/* #undef SLJIT_PROT_EXECUTABLE_ALLOCATOR */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to any value to enable support for Just-In-Time compiling. */
+#define SUPPORT_JIT 1
+
+/* Define to any value to allow pcre2grep to be linked with libbz2, so that it
+   is able to handle .bz2 files. */
+/* #undef SUPPORT_LIBBZ2 */
+
+/* Define to any value to allow pcre2test to be linked with libedit. */
+/* #undef SUPPORT_LIBEDIT */
+
+/* Define to any value to allow pcre2test to be linked with libreadline. */
+/* #undef SUPPORT_LIBREADLINE */
+
+/* Define to any value to allow pcre2grep to be linked with libz, so that it
+   is able to handle .gz files. */
+/* #undef SUPPORT_LIBZ */
+
+/* Define to any value to enable callout script support in pcre2grep. */
+/* #undef SUPPORT_PCRE2GREP_CALLOUT */
+
+/* Define to any value to enable fork support in pcre2grep callout scripts.
+   This will have no effect unless SUPPORT_PCRE2GREP_CALLOUT is also defined.
+   */
+/* #undef SUPPORT_PCRE2GREP_CALLOUT_FORK */
+
+/* Define to any value to enable JIT support in pcre2grep. Note that this will
+   have no effect unless SUPPORT_JIT is also defined. */
+/* #undef SUPPORT_PCRE2GREP_JIT */
+
+/* Define to any value to enable the 16 bit PCRE2 library. */
+#define SUPPORT_PCRE2_16 1
+
+/* Define to any value to enable the 32 bit PCRE2 library. */
+/* #undef SUPPORT_PCRE2_32 */
+
+/* Define to any value to enable the 8 bit PCRE2 library. */
+/* #undef SUPPORT_PCRE2_8 */
+
+/* Define to any value to enable support for Unicode and UTF encoding. This
+   will work even in an EBCDIC environment, but it is incompatible with the
+   EBCDIC macro. That is, PCRE2 can support *either* EBCDIC code *or*
+   ASCII/Unicode, but not both at once. */
+#define SUPPORT_UNICODE 1
+
+/* Define to any value for valgrind support to find invalid memory reads. */
+/* #undef SUPPORT_VALGRIND */
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+/* Version number of package */
+#define VERSION "10.35"
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to the type of a signed integer type of width exactly 64 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef int64_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
diff --git a/src/c/getters.h b/src/c/getters.h
new file mode 100644
--- /dev/null
+++ b/src/c/getters.h
@@ -0,0 +1,60 @@
+// Functions to get PCRE2 struct fields.
+
+#include <pcre2.h>
+
+#ifndef GETTERS_H
+#define GETTERS_H
+
+#ifdef GETTER
+#error GETTER already defined
+#endif
+#define GETTER(src, field, ret) \
+    ret pcre2_##src##_##field(pcre2_##src *block) \
+    { \
+        return block->field; \
+    }
+
+/*
+    For example, the first of these produces the following code:
+
+    uint32_t pcre2_callout_block_version(pcre2_callout_block *block)
+    {
+        return block->version;
+    }
+*/
+GETTER(callout_block, version,               uint32_t)
+GETTER(callout_block, callout_number,        uint32_t)
+GETTER(callout_block, capture_top,           uint32_t)
+GETTER(callout_block, capture_last,          uint32_t)
+GETTER(callout_block, callout_flags,         uint32_t)
+GETTER(callout_block, offset_vector,         PCRE2_SIZE *)
+GETTER(callout_block, mark,                  PCRE2_SPTR)
+GETTER(callout_block, subject,               PCRE2_SPTR)
+GETTER(callout_block, subject_length,        PCRE2_SIZE)
+GETTER(callout_block, start_match,           PCRE2_SIZE)
+GETTER(callout_block, current_position,      PCRE2_SIZE)
+GETTER(callout_block, pattern_position,      PCRE2_SIZE)
+GETTER(callout_block, next_item_length,      PCRE2_SIZE)
+GETTER(callout_block, callout_string_offset, PCRE2_SIZE)
+GETTER(callout_block, callout_string_length, PCRE2_SIZE)
+GETTER(callout_block, callout_string,        PCRE2_SPTR)
+
+GETTER(callout_enumerate_block, version,               uint32_t)
+GETTER(callout_enumerate_block, pattern_position,      PCRE2_SIZE)
+GETTER(callout_enumerate_block, next_item_length,      PCRE2_SIZE)
+GETTER(callout_enumerate_block, callout_number,        uint32_t)
+GETTER(callout_enumerate_block, callout_string_offset, PCRE2_SIZE)
+GETTER(callout_enumerate_block, callout_string_length, PCRE2_SIZE)
+GETTER(callout_enumerate_block, callout_string,        PCRE2_SPTR)
+
+GETTER(substitute_callout_block, version,        uint32_t)
+GETTER(substitute_callout_block, subscount,      uint32_t)
+GETTER(substitute_callout_block, input,          PCRE2_SPTR)
+GETTER(substitute_callout_block, output,         PCRE2_SPTR)
+GETTER(substitute_callout_block, ovector,        PCRE2_SIZE *)
+GETTER(substitute_callout_block, oveccount,      uint32_t)
+GETTER(substitute_callout_block, output_offsets, PCRE2_SIZE *) // array of 2
+
+#undef GETTER
+
+#endif
diff --git a/src/c/pcre2.h b/src/c/pcre2.h
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2.h
@@ -0,0 +1,993 @@
+// Copied per the PCRE2 source's NON-AUTOTOOLS-BUILD instructions.
+
+/*************************************************
+*       Perl-Compatible Regular Expressions      *
+*************************************************/
+
+/* This is the public header file for the PCRE library, second API, to be
+#included by applications that call PCRE2 functions.
+
+           Copyright (c) 2016-2020 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifndef PCRE2_H_IDEMPOTENT_GUARD
+#define PCRE2_H_IDEMPOTENT_GUARD
+
+/* The current PCRE version information. */
+
+#define PCRE2_MAJOR           10
+#define PCRE2_MINOR           35
+#define PCRE2_PRERELEASE      
+#define PCRE2_DATE            2020-05-09
+
+/* When an application links to a PCRE DLL in Windows, the symbols that are
+imported have to be identified as such. When building PCRE2, the appropriate
+export setting is defined in pcre2_internal.h, which includes this file. So we
+don't change existing definitions of PCRE2_EXP_DECL. */
+
+#if defined(_WIN32) && !defined(PCRE2_STATIC)
+#  ifndef PCRE2_EXP_DECL
+#    define PCRE2_EXP_DECL  extern __declspec(dllimport)
+#  endif
+#endif
+
+/* By default, we use the standard "extern" declarations. */
+
+#ifndef PCRE2_EXP_DECL
+#  ifdef __cplusplus
+#    define PCRE2_EXP_DECL  extern "C"
+#  else
+#    define PCRE2_EXP_DECL  extern
+#  endif
+#endif
+
+/* When compiling with the MSVC compiler, it is sometimes necessary to include
+a "calling convention" before exported function names. (This is secondhand
+information; I know nothing about MSVC myself). For example, something like
+
+  void __cdecl function(....)
+
+might be needed. In order so make this easy, all the exported functions have
+PCRE2_CALL_CONVENTION just before their names. It is rarely needed; if not
+set, we ensure here that it has no effect. */
+
+#ifndef PCRE2_CALL_CONVENTION
+#define PCRE2_CALL_CONVENTION
+#endif
+
+/* Have to include limits.h, stdlib.h, and inttypes.h to ensure that size_t and
+uint8_t, UCHAR_MAX, etc are defined. Some systems that do have inttypes.h do
+not have stdint.h, which is why we use inttypes.h, which according to the C
+standard is a superset of stdint.h. If none of these headers are available,
+the relevant values must be provided by some other means. */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+/* Allow for C++ users compiling this directly. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The following option bits can be passed to pcre2_compile(), pcre2_match(),
+or pcre2_dfa_match(). PCRE2_NO_UTF_CHECK affects only the function to which it
+is passed. Put these bits at the most significant end of the options word so
+others can be added next to them */
+
+#define PCRE2_ANCHORED            0x80000000u
+#define PCRE2_NO_UTF_CHECK        0x40000000u
+#define PCRE2_ENDANCHORED         0x20000000u
+
+/* The following option bits can be passed only to pcre2_compile(). However,
+they may affect compilation, JIT compilation, and/or interpretive execution.
+The following tags indicate which:
+
+C   alters what is compiled by pcre2_compile()
+J   alters what is compiled by pcre2_jit_compile()
+M   is inspected during pcre2_match() execution
+D   is inspected during pcre2_dfa_match() execution
+*/
+
+#define PCRE2_ALLOW_EMPTY_CLASS   0x00000001u  /* C       */
+#define PCRE2_ALT_BSUX            0x00000002u  /* C       */
+#define PCRE2_AUTO_CALLOUT        0x00000004u  /* C       */
+#define PCRE2_CASELESS            0x00000008u  /* C       */
+#define PCRE2_DOLLAR_ENDONLY      0x00000010u  /*   J M D */
+#define PCRE2_DOTALL              0x00000020u  /* C       */
+#define PCRE2_DUPNAMES            0x00000040u  /* C       */
+#define PCRE2_EXTENDED            0x00000080u  /* C       */
+#define PCRE2_FIRSTLINE           0x00000100u  /*   J M D */
+#define PCRE2_MATCH_UNSET_BACKREF 0x00000200u  /* C J M   */
+#define PCRE2_MULTILINE           0x00000400u  /* C       */
+#define PCRE2_NEVER_UCP           0x00000800u  /* C       */
+#define PCRE2_NEVER_UTF           0x00001000u  /* C       */
+#define PCRE2_NO_AUTO_CAPTURE     0x00002000u  /* C       */
+#define PCRE2_NO_AUTO_POSSESS     0x00004000u  /* C       */
+#define PCRE2_NO_DOTSTAR_ANCHOR   0x00008000u  /* C       */
+#define PCRE2_NO_START_OPTIMIZE   0x00010000u  /*   J M D */
+#define PCRE2_UCP                 0x00020000u  /* C J M D */
+#define PCRE2_UNGREEDY            0x00040000u  /* C       */
+#define PCRE2_UTF                 0x00080000u  /* C J M D */
+#define PCRE2_NEVER_BACKSLASH_C   0x00100000u  /* C       */
+#define PCRE2_ALT_CIRCUMFLEX      0x00200000u  /*   J M D */
+#define PCRE2_ALT_VERBNAMES       0x00400000u  /* C       */
+#define PCRE2_USE_OFFSET_LIMIT    0x00800000u  /*   J M D */
+#define PCRE2_EXTENDED_MORE       0x01000000u  /* C       */
+#define PCRE2_LITERAL             0x02000000u  /* C       */
+#define PCRE2_MATCH_INVALID_UTF   0x04000000u  /*   J M D */
+
+/* An additional compile options word is available in the compile context. */
+
+#define PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES  0x00000001u  /* C */
+#define PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL    0x00000002u  /* C */
+#define PCRE2_EXTRA_MATCH_WORD               0x00000004u  /* C */
+#define PCRE2_EXTRA_MATCH_LINE               0x00000008u  /* C */
+#define PCRE2_EXTRA_ESCAPED_CR_IS_LF         0x00000010u  /* C */
+#define PCRE2_EXTRA_ALT_BSUX                 0x00000020u  /* C */
+
+/* These are for pcre2_jit_compile(). */
+
+#define PCRE2_JIT_COMPLETE        0x00000001u  /* For full matching */
+#define PCRE2_JIT_PARTIAL_SOFT    0x00000002u
+#define PCRE2_JIT_PARTIAL_HARD    0x00000004u
+#define PCRE2_JIT_INVALID_UTF     0x00000100u
+
+/* These are for pcre2_match(), pcre2_dfa_match(), pcre2_jit_match(), and
+pcre2_substitute(). Some are allowed only for one of the functions, and in
+these cases it is noted below. Note that PCRE2_ANCHORED, PCRE2_ENDANCHORED and
+PCRE2_NO_UTF_CHECK can also be passed to these functions (though
+pcre2_jit_match() ignores the latter since it bypasses all sanity checks). */
+
+#define PCRE2_NOTBOL                      0x00000001u
+#define PCRE2_NOTEOL                      0x00000002u
+#define PCRE2_NOTEMPTY                    0x00000004u  /* ) These two must be kept */
+#define PCRE2_NOTEMPTY_ATSTART            0x00000008u  /* ) adjacent to each other. */
+#define PCRE2_PARTIAL_SOFT                0x00000010u
+#define PCRE2_PARTIAL_HARD                0x00000020u
+#define PCRE2_DFA_RESTART                 0x00000040u  /* pcre2_dfa_match() only */
+#define PCRE2_DFA_SHORTEST                0x00000080u  /* pcre2_dfa_match() only */
+#define PCRE2_SUBSTITUTE_GLOBAL           0x00000100u  /* pcre2_substitute() only */
+#define PCRE2_SUBSTITUTE_EXTENDED         0x00000200u  /* pcre2_substitute() only */
+#define PCRE2_SUBSTITUTE_UNSET_EMPTY      0x00000400u  /* pcre2_substitute() only */
+#define PCRE2_SUBSTITUTE_UNKNOWN_UNSET    0x00000800u  /* pcre2_substitute() only */
+#define PCRE2_SUBSTITUTE_OVERFLOW_LENGTH  0x00001000u  /* pcre2_substitute() only */
+#define PCRE2_NO_JIT                      0x00002000u  /* Not for pcre2_dfa_match() */
+#define PCRE2_COPY_MATCHED_SUBJECT        0x00004000u
+#define PCRE2_SUBSTITUTE_LITERAL          0x00008000u  /* pcre2_substitute() only */
+#define PCRE2_SUBSTITUTE_MATCHED          0x00010000u  /* pcre2_substitute() only */
+#define PCRE2_SUBSTITUTE_REPLACEMENT_ONLY 0x00020000u  /* pcre2_substitute() only */
+
+/* Options for pcre2_pattern_convert(). */
+
+#define PCRE2_CONVERT_UTF                    0x00000001u
+#define PCRE2_CONVERT_NO_UTF_CHECK           0x00000002u
+#define PCRE2_CONVERT_POSIX_BASIC            0x00000004u
+#define PCRE2_CONVERT_POSIX_EXTENDED         0x00000008u
+#define PCRE2_CONVERT_GLOB                   0x00000010u
+#define PCRE2_CONVERT_GLOB_NO_WILD_SEPARATOR 0x00000030u
+#define PCRE2_CONVERT_GLOB_NO_STARSTAR       0x00000050u
+
+/* Newline and \R settings, for use in compile contexts. The newline values
+must be kept in step with values set in config.h and both sets must all be
+greater than zero. */
+
+#define PCRE2_NEWLINE_CR          1
+#define PCRE2_NEWLINE_LF          2
+#define PCRE2_NEWLINE_CRLF        3
+#define PCRE2_NEWLINE_ANY         4
+#define PCRE2_NEWLINE_ANYCRLF     5
+#define PCRE2_NEWLINE_NUL         6
+
+#define PCRE2_BSR_UNICODE         1
+#define PCRE2_BSR_ANYCRLF         2
+
+/* Error codes for pcre2_compile(). Some of these are also used by
+pcre2_pattern_convert(). */
+
+#define PCRE2_ERROR_END_BACKSLASH                  101
+#define PCRE2_ERROR_END_BACKSLASH_C                102
+#define PCRE2_ERROR_UNKNOWN_ESCAPE                 103
+#define PCRE2_ERROR_QUANTIFIER_OUT_OF_ORDER        104
+#define PCRE2_ERROR_QUANTIFIER_TOO_BIG             105
+#define PCRE2_ERROR_MISSING_SQUARE_BRACKET         106
+#define PCRE2_ERROR_ESCAPE_INVALID_IN_CLASS        107
+#define PCRE2_ERROR_CLASS_RANGE_ORDER              108
+#define PCRE2_ERROR_QUANTIFIER_INVALID             109
+#define PCRE2_ERROR_INTERNAL_UNEXPECTED_REPEAT     110
+#define PCRE2_ERROR_INVALID_AFTER_PARENS_QUERY     111
+#define PCRE2_ERROR_POSIX_CLASS_NOT_IN_CLASS       112
+#define PCRE2_ERROR_POSIX_NO_SUPPORT_COLLATING     113
+#define PCRE2_ERROR_MISSING_CLOSING_PARENTHESIS    114
+#define PCRE2_ERROR_BAD_SUBPATTERN_REFERENCE       115
+#define PCRE2_ERROR_NULL_PATTERN                   116
+#define PCRE2_ERROR_BAD_OPTIONS                    117
+#define PCRE2_ERROR_MISSING_COMMENT_CLOSING        118
+#define PCRE2_ERROR_PARENTHESES_NEST_TOO_DEEP      119
+#define PCRE2_ERROR_PATTERN_TOO_LARGE              120
+#define PCRE2_ERROR_HEAP_FAILED                    121
+#define PCRE2_ERROR_UNMATCHED_CLOSING_PARENTHESIS  122
+#define PCRE2_ERROR_INTERNAL_CODE_OVERFLOW         123
+#define PCRE2_ERROR_MISSING_CONDITION_CLOSING      124
+#define PCRE2_ERROR_LOOKBEHIND_NOT_FIXED_LENGTH    125
+#define PCRE2_ERROR_ZERO_RELATIVE_REFERENCE        126
+#define PCRE2_ERROR_TOO_MANY_CONDITION_BRANCHES    127
+#define PCRE2_ERROR_CONDITION_ASSERTION_EXPECTED   128
+#define PCRE2_ERROR_BAD_RELATIVE_REFERENCE         129
+#define PCRE2_ERROR_UNKNOWN_POSIX_CLASS            130
+#define PCRE2_ERROR_INTERNAL_STUDY_ERROR           131
+#define PCRE2_ERROR_UNICODE_NOT_SUPPORTED          132
+#define PCRE2_ERROR_PARENTHESES_STACK_CHECK        133
+#define PCRE2_ERROR_CODE_POINT_TOO_BIG             134
+#define PCRE2_ERROR_LOOKBEHIND_TOO_COMPLICATED     135
+#define PCRE2_ERROR_LOOKBEHIND_INVALID_BACKSLASH_C 136
+#define PCRE2_ERROR_UNSUPPORTED_ESCAPE_SEQUENCE    137
+#define PCRE2_ERROR_CALLOUT_NUMBER_TOO_BIG         138
+#define PCRE2_ERROR_MISSING_CALLOUT_CLOSING        139
+#define PCRE2_ERROR_ESCAPE_INVALID_IN_VERB         140
+#define PCRE2_ERROR_UNRECOGNIZED_AFTER_QUERY_P     141
+#define PCRE2_ERROR_MISSING_NAME_TERMINATOR        142
+#define PCRE2_ERROR_DUPLICATE_SUBPATTERN_NAME      143
+#define PCRE2_ERROR_INVALID_SUBPATTERN_NAME        144
+#define PCRE2_ERROR_UNICODE_PROPERTIES_UNAVAILABLE 145
+#define PCRE2_ERROR_MALFORMED_UNICODE_PROPERTY     146
+#define PCRE2_ERROR_UNKNOWN_UNICODE_PROPERTY       147
+#define PCRE2_ERROR_SUBPATTERN_NAME_TOO_LONG       148
+#define PCRE2_ERROR_TOO_MANY_NAMED_SUBPATTERNS     149
+#define PCRE2_ERROR_CLASS_INVALID_RANGE            150
+#define PCRE2_ERROR_OCTAL_BYTE_TOO_BIG             151
+#define PCRE2_ERROR_INTERNAL_OVERRAN_WORKSPACE     152
+#define PCRE2_ERROR_INTERNAL_MISSING_SUBPATTERN    153
+#define PCRE2_ERROR_DEFINE_TOO_MANY_BRANCHES       154
+#define PCRE2_ERROR_BACKSLASH_O_MISSING_BRACE      155
+#define PCRE2_ERROR_INTERNAL_UNKNOWN_NEWLINE       156
+#define PCRE2_ERROR_BACKSLASH_G_SYNTAX             157
+#define PCRE2_ERROR_PARENS_QUERY_R_MISSING_CLOSING 158
+/* Error 159 is obsolete and should now never occur */
+#define PCRE2_ERROR_VERB_ARGUMENT_NOT_ALLOWED      159
+#define PCRE2_ERROR_VERB_UNKNOWN                   160
+#define PCRE2_ERROR_SUBPATTERN_NUMBER_TOO_BIG      161
+#define PCRE2_ERROR_SUBPATTERN_NAME_EXPECTED       162
+#define PCRE2_ERROR_INTERNAL_PARSED_OVERFLOW       163
+#define PCRE2_ERROR_INVALID_OCTAL                  164
+#define PCRE2_ERROR_SUBPATTERN_NAMES_MISMATCH      165
+#define PCRE2_ERROR_MARK_MISSING_ARGUMENT          166
+#define PCRE2_ERROR_INVALID_HEXADECIMAL            167
+#define PCRE2_ERROR_BACKSLASH_C_SYNTAX             168
+#define PCRE2_ERROR_BACKSLASH_K_SYNTAX             169
+#define PCRE2_ERROR_INTERNAL_BAD_CODE_LOOKBEHINDS  170
+#define PCRE2_ERROR_BACKSLASH_N_IN_CLASS           171
+#define PCRE2_ERROR_CALLOUT_STRING_TOO_LONG        172
+#define PCRE2_ERROR_UNICODE_DISALLOWED_CODE_POINT  173
+#define PCRE2_ERROR_UTF_IS_DISABLED                174
+#define PCRE2_ERROR_UCP_IS_DISABLED                175
+#define PCRE2_ERROR_VERB_NAME_TOO_LONG             176
+#define PCRE2_ERROR_BACKSLASH_U_CODE_POINT_TOO_BIG 177
+#define PCRE2_ERROR_MISSING_OCTAL_OR_HEX_DIGITS    178
+#define PCRE2_ERROR_VERSION_CONDITION_SYNTAX       179
+#define PCRE2_ERROR_INTERNAL_BAD_CODE_AUTO_POSSESS 180
+#define PCRE2_ERROR_CALLOUT_NO_STRING_DELIMITER    181
+#define PCRE2_ERROR_CALLOUT_BAD_STRING_DELIMITER   182
+#define PCRE2_ERROR_BACKSLASH_C_CALLER_DISABLED    183
+#define PCRE2_ERROR_QUERY_BARJX_NEST_TOO_DEEP      184
+#define PCRE2_ERROR_BACKSLASH_C_LIBRARY_DISABLED   185
+#define PCRE2_ERROR_PATTERN_TOO_COMPLICATED        186
+#define PCRE2_ERROR_LOOKBEHIND_TOO_LONG            187
+#define PCRE2_ERROR_PATTERN_STRING_TOO_LONG        188
+#define PCRE2_ERROR_INTERNAL_BAD_CODE              189
+#define PCRE2_ERROR_INTERNAL_BAD_CODE_IN_SKIP      190
+#define PCRE2_ERROR_NO_SURROGATES_IN_UTF16         191
+#define PCRE2_ERROR_BAD_LITERAL_OPTIONS            192
+#define PCRE2_ERROR_SUPPORTED_ONLY_IN_UNICODE      193
+#define PCRE2_ERROR_INVALID_HYPHEN_IN_OPTIONS      194
+#define PCRE2_ERROR_ALPHA_ASSERTION_UNKNOWN        195
+#define PCRE2_ERROR_SCRIPT_RUN_NOT_AVAILABLE       196
+#define PCRE2_ERROR_TOO_MANY_CAPTURES              197
+#define PCRE2_ERROR_CONDITION_ATOMIC_ASSERTION_EXPECTED  198
+
+
+/* "Expected" matching error codes: no match and partial match. */
+
+#define PCRE2_ERROR_NOMATCH          (-1)
+#define PCRE2_ERROR_PARTIAL          (-2)
+
+/* Error codes for UTF-8 validity checks */
+
+#define PCRE2_ERROR_UTF8_ERR1        (-3)
+#define PCRE2_ERROR_UTF8_ERR2        (-4)
+#define PCRE2_ERROR_UTF8_ERR3        (-5)
+#define PCRE2_ERROR_UTF8_ERR4        (-6)
+#define PCRE2_ERROR_UTF8_ERR5        (-7)
+#define PCRE2_ERROR_UTF8_ERR6        (-8)
+#define PCRE2_ERROR_UTF8_ERR7        (-9)
+#define PCRE2_ERROR_UTF8_ERR8       (-10)
+#define PCRE2_ERROR_UTF8_ERR9       (-11)
+#define PCRE2_ERROR_UTF8_ERR10      (-12)
+#define PCRE2_ERROR_UTF8_ERR11      (-13)
+#define PCRE2_ERROR_UTF8_ERR12      (-14)
+#define PCRE2_ERROR_UTF8_ERR13      (-15)
+#define PCRE2_ERROR_UTF8_ERR14      (-16)
+#define PCRE2_ERROR_UTF8_ERR15      (-17)
+#define PCRE2_ERROR_UTF8_ERR16      (-18)
+#define PCRE2_ERROR_UTF8_ERR17      (-19)
+#define PCRE2_ERROR_UTF8_ERR18      (-20)
+#define PCRE2_ERROR_UTF8_ERR19      (-21)
+#define PCRE2_ERROR_UTF8_ERR20      (-22)
+#define PCRE2_ERROR_UTF8_ERR21      (-23)
+
+/* Error codes for UTF-16 validity checks */
+
+#define PCRE2_ERROR_UTF16_ERR1      (-24)
+#define PCRE2_ERROR_UTF16_ERR2      (-25)
+#define PCRE2_ERROR_UTF16_ERR3      (-26)
+
+/* Error codes for UTF-32 validity checks */
+
+#define PCRE2_ERROR_UTF32_ERR1      (-27)
+#define PCRE2_ERROR_UTF32_ERR2      (-28)
+
+/* Miscellaneous error codes for pcre2[_dfa]_match(), substring extraction
+functions, context functions, and serializing functions. They are in numerical
+order. Originally they were in alphabetical order too, but now that PCRE2 is
+released, the numbers must not be changed. */
+
+#define PCRE2_ERROR_BADDATA           (-29)
+#define PCRE2_ERROR_MIXEDTABLES       (-30)  /* Name was changed */
+#define PCRE2_ERROR_BADMAGIC          (-31)
+#define PCRE2_ERROR_BADMODE           (-32)
+#define PCRE2_ERROR_BADOFFSET         (-33)
+#define PCRE2_ERROR_BADOPTION         (-34)
+#define PCRE2_ERROR_BADREPLACEMENT    (-35)
+#define PCRE2_ERROR_BADUTFOFFSET      (-36)
+#define PCRE2_ERROR_CALLOUT           (-37)  /* Never used by PCRE2 itself */
+#define PCRE2_ERROR_DFA_BADRESTART    (-38)
+#define PCRE2_ERROR_DFA_RECURSE       (-39)
+#define PCRE2_ERROR_DFA_UCOND         (-40)
+#define PCRE2_ERROR_DFA_UFUNC         (-41)
+#define PCRE2_ERROR_DFA_UITEM         (-42)
+#define PCRE2_ERROR_DFA_WSSIZE        (-43)
+#define PCRE2_ERROR_INTERNAL          (-44)
+#define PCRE2_ERROR_JIT_BADOPTION     (-45)
+#define PCRE2_ERROR_JIT_STACKLIMIT    (-46)
+#define PCRE2_ERROR_MATCHLIMIT        (-47)
+#define PCRE2_ERROR_NOMEMORY          (-48)
+#define PCRE2_ERROR_NOSUBSTRING       (-49)
+#define PCRE2_ERROR_NOUNIQUESUBSTRING (-50)
+#define PCRE2_ERROR_NULL              (-51)
+#define PCRE2_ERROR_RECURSELOOP       (-52)
+#define PCRE2_ERROR_DEPTHLIMIT        (-53)
+#define PCRE2_ERROR_RECURSIONLIMIT    (-53)  /* Obsolete synonym */
+#define PCRE2_ERROR_UNAVAILABLE       (-54)
+#define PCRE2_ERROR_UNSET             (-55)
+#define PCRE2_ERROR_BADOFFSETLIMIT    (-56)
+#define PCRE2_ERROR_BADREPESCAPE      (-57)
+#define PCRE2_ERROR_REPMISSINGBRACE   (-58)
+#define PCRE2_ERROR_BADSUBSTITUTION   (-59)
+#define PCRE2_ERROR_BADSUBSPATTERN    (-60)
+#define PCRE2_ERROR_TOOMANYREPLACE    (-61)
+#define PCRE2_ERROR_BADSERIALIZEDDATA (-62)
+#define PCRE2_ERROR_HEAPLIMIT         (-63)
+#define PCRE2_ERROR_CONVERT_SYNTAX    (-64)
+#define PCRE2_ERROR_INTERNAL_DUPMATCH (-65)
+#define PCRE2_ERROR_DFA_UINVALID_UTF  (-66)
+
+
+/* Request types for pcre2_pattern_info() */
+
+#define PCRE2_INFO_ALLOPTIONS            0
+#define PCRE2_INFO_ARGOPTIONS            1
+#define PCRE2_INFO_BACKREFMAX            2
+#define PCRE2_INFO_BSR                   3
+#define PCRE2_INFO_CAPTURECOUNT          4
+#define PCRE2_INFO_FIRSTCODEUNIT         5
+#define PCRE2_INFO_FIRSTCODETYPE         6
+#define PCRE2_INFO_FIRSTBITMAP           7
+#define PCRE2_INFO_HASCRORLF             8
+#define PCRE2_INFO_JCHANGED              9
+#define PCRE2_INFO_JITSIZE              10
+#define PCRE2_INFO_LASTCODEUNIT         11
+#define PCRE2_INFO_LASTCODETYPE         12
+#define PCRE2_INFO_MATCHEMPTY           13
+#define PCRE2_INFO_MATCHLIMIT           14
+#define PCRE2_INFO_MAXLOOKBEHIND        15
+#define PCRE2_INFO_MINLENGTH            16
+#define PCRE2_INFO_NAMECOUNT            17
+#define PCRE2_INFO_NAMEENTRYSIZE        18
+#define PCRE2_INFO_NAMETABLE            19
+#define PCRE2_INFO_NEWLINE              20
+#define PCRE2_INFO_DEPTHLIMIT           21
+#define PCRE2_INFO_RECURSIONLIMIT       21  /* Obsolete synonym */
+#define PCRE2_INFO_SIZE                 22
+#define PCRE2_INFO_HASBACKSLASHC        23
+#define PCRE2_INFO_FRAMESIZE            24
+#define PCRE2_INFO_HEAPLIMIT            25
+#define PCRE2_INFO_EXTRAOPTIONS         26
+
+/* Request types for pcre2_config(). */
+
+#define PCRE2_CONFIG_BSR                     0
+#define PCRE2_CONFIG_JIT                     1
+#define PCRE2_CONFIG_JITTARGET               2
+#define PCRE2_CONFIG_LINKSIZE                3
+#define PCRE2_CONFIG_MATCHLIMIT              4
+#define PCRE2_CONFIG_NEWLINE                 5
+#define PCRE2_CONFIG_PARENSLIMIT             6
+#define PCRE2_CONFIG_DEPTHLIMIT              7
+#define PCRE2_CONFIG_RECURSIONLIMIT          7  /* Obsolete synonym */
+#define PCRE2_CONFIG_STACKRECURSE            8  /* Obsolete */
+#define PCRE2_CONFIG_UNICODE                 9
+#define PCRE2_CONFIG_UNICODE_VERSION        10
+#define PCRE2_CONFIG_VERSION                11
+#define PCRE2_CONFIG_HEAPLIMIT              12
+#define PCRE2_CONFIG_NEVER_BACKSLASH_C      13
+#define PCRE2_CONFIG_COMPILED_WIDTHS        14
+#define PCRE2_CONFIG_TABLES_LENGTH          15
+
+
+/* Types for code units in patterns and subject strings. */
+
+typedef uint8_t  PCRE2_UCHAR8;
+typedef uint16_t PCRE2_UCHAR16;
+typedef uint32_t PCRE2_UCHAR32;
+
+typedef const PCRE2_UCHAR8  *PCRE2_SPTR8;
+typedef const PCRE2_UCHAR16 *PCRE2_SPTR16;
+typedef const PCRE2_UCHAR32 *PCRE2_SPTR32;
+
+/* The PCRE2_SIZE type is used for all string lengths and offsets in PCRE2,
+including pattern offsets for errors and subject offsets after a match. We
+define special values to indicate zero-terminated strings and unset offsets in
+the offset vector (ovector). */
+
+#define PCRE2_SIZE            size_t
+#define PCRE2_SIZE_MAX        SIZE_MAX
+#define PCRE2_ZERO_TERMINATED (~(PCRE2_SIZE)0)
+#define PCRE2_UNSET           (~(PCRE2_SIZE)0)
+
+/* Generic types for opaque structures and JIT callback functions. These
+declarations are defined in a macro that is expanded for each width later. */
+
+#define PCRE2_TYPES_LIST \
+struct pcre2_real_general_context; \
+typedef struct pcre2_real_general_context pcre2_general_context; \
+\
+struct pcre2_real_compile_context; \
+typedef struct pcre2_real_compile_context pcre2_compile_context; \
+\
+struct pcre2_real_match_context; \
+typedef struct pcre2_real_match_context pcre2_match_context; \
+\
+struct pcre2_real_convert_context; \
+typedef struct pcre2_real_convert_context pcre2_convert_context; \
+\
+struct pcre2_real_code; \
+typedef struct pcre2_real_code pcre2_code; \
+\
+struct pcre2_real_match_data; \
+typedef struct pcre2_real_match_data pcre2_match_data; \
+\
+struct pcre2_real_jit_stack; \
+typedef struct pcre2_real_jit_stack pcre2_jit_stack; \
+\
+typedef pcre2_jit_stack *(*pcre2_jit_callback)(void *);
+
+
+/* The structures for passing out data via callout functions. We use structures
+so that new fields can be added on the end in future versions, without changing
+the API of the function, thereby allowing old clients to work without
+modification. Define the generic versions in a macro; the width-specific
+versions are generated from this macro below. */
+
+/* Flags for the callout_flags field. These are cleared after a callout. */
+
+#define PCRE2_CALLOUT_STARTMATCH    0x00000001u  /* Set for each bumpalong */
+#define PCRE2_CALLOUT_BACKTRACK     0x00000002u  /* Set after a backtrack */
+
+#define PCRE2_STRUCTURE_LIST \
+typedef struct pcre2_callout_block { \
+  uint32_t      version;           /* Identifies version of block */ \
+  /* ------------------------ Version 0 ------------------------------- */ \
+  uint32_t      callout_number;    /* Number compiled into pattern */ \
+  uint32_t      capture_top;       /* Max current capture */ \
+  uint32_t      capture_last;      /* Most recently closed capture */ \
+  PCRE2_SIZE   *offset_vector;     /* The offset vector */ \
+  PCRE2_SPTR    mark;              /* Pointer to current mark or NULL */ \
+  PCRE2_SPTR    subject;           /* The subject being matched */ \
+  PCRE2_SIZE    subject_length;    /* The length of the subject */ \
+  PCRE2_SIZE    start_match;       /* Offset to start of this match attempt */ \
+  PCRE2_SIZE    current_position;  /* Where we currently are in the subject */ \
+  PCRE2_SIZE    pattern_position;  /* Offset to next item in the pattern */ \
+  PCRE2_SIZE    next_item_length;  /* Length of next item in the pattern */ \
+  /* ------------------- Added for Version 1 -------------------------- */ \
+  PCRE2_SIZE    callout_string_offset; /* Offset to string within pattern */ \
+  PCRE2_SIZE    callout_string_length; /* Length of string compiled into pattern */ \
+  PCRE2_SPTR    callout_string;    /* String compiled into pattern */ \
+  /* ------------------- Added for Version 2 -------------------------- */ \
+  uint32_t      callout_flags;     /* See above for list */ \
+  /* ------------------------------------------------------------------ */ \
+} pcre2_callout_block; \
+\
+typedef struct pcre2_callout_enumerate_block { \
+  uint32_t      version;           /* Identifies version of block */ \
+  /* ------------------------ Version 0 ------------------------------- */ \
+  PCRE2_SIZE    pattern_position;  /* Offset to next item in the pattern */ \
+  PCRE2_SIZE    next_item_length;  /* Length of next item in the pattern */ \
+  uint32_t      callout_number;    /* Number compiled into pattern */ \
+  PCRE2_SIZE    callout_string_offset; /* Offset to string within pattern */ \
+  PCRE2_SIZE    callout_string_length; /* Length of string compiled into pattern */ \
+  PCRE2_SPTR    callout_string;    /* String compiled into pattern */ \
+  /* ------------------------------------------------------------------ */ \
+} pcre2_callout_enumerate_block; \
+\
+typedef struct pcre2_substitute_callout_block { \
+  uint32_t      version;           /* Identifies version of block */ \
+  /* ------------------------ Version 0 ------------------------------- */ \
+  PCRE2_SPTR    input;             /* Pointer to input subject string */ \
+  PCRE2_SPTR    output;            /* Pointer to output buffer */ \
+  PCRE2_SIZE    output_offsets[2]; /* Changed portion of the output */ \
+  PCRE2_SIZE   *ovector;           /* Pointer to current ovector */ \
+  uint32_t      oveccount;         /* Count of pairs set in ovector */ \
+  uint32_t      subscount;         /* Substitution number */ \
+  /* ------------------------------------------------------------------ */ \
+} pcre2_substitute_callout_block;
+
+
+/* List the generic forms of all other functions in macros, which will be
+expanded for each width below. Start with functions that give general
+information. */
+
+#define PCRE2_GENERAL_INFO_FUNCTIONS \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION pcre2_config(uint32_t, void *);
+
+
+/* Functions for manipulating contexts. */
+
+#define PCRE2_GENERAL_CONTEXT_FUNCTIONS \
+PCRE2_EXP_DECL pcre2_general_context PCRE2_CALL_CONVENTION \
+  *pcre2_general_context_copy(pcre2_general_context *); \
+PCRE2_EXP_DECL pcre2_general_context PCRE2_CALL_CONVENTION \
+  *pcre2_general_context_create(void *(*)(PCRE2_SIZE, void *), \
+    void (*)(void *, void *), void *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+  pcre2_general_context_free(pcre2_general_context *);
+
+#define PCRE2_COMPILE_CONTEXT_FUNCTIONS \
+PCRE2_EXP_DECL pcre2_compile_context PCRE2_CALL_CONVENTION \
+  *pcre2_compile_context_copy(pcre2_compile_context *); \
+PCRE2_EXP_DECL pcre2_compile_context PCRE2_CALL_CONVENTION \
+  *pcre2_compile_context_create(pcre2_general_context *);\
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+  pcre2_compile_context_free(pcre2_compile_context *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_bsr(pcre2_compile_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_character_tables(pcre2_compile_context *, const uint8_t *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_compile_extra_options(pcre2_compile_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_max_pattern_length(pcre2_compile_context *, PCRE2_SIZE); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_newline(pcre2_compile_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_parens_nest_limit(pcre2_compile_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_compile_recursion_guard(pcre2_compile_context *, \
+    int (*)(uint32_t, void *), void *);
+
+#define PCRE2_MATCH_CONTEXT_FUNCTIONS \
+PCRE2_EXP_DECL pcre2_match_context PCRE2_CALL_CONVENTION \
+  *pcre2_match_context_copy(pcre2_match_context *); \
+PCRE2_EXP_DECL pcre2_match_context PCRE2_CALL_CONVENTION \
+  *pcre2_match_context_create(pcre2_general_context *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+  pcre2_match_context_free(pcre2_match_context *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_callout(pcre2_match_context *, \
+    int (*)(pcre2_callout_block *, void *), void *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_substitute_callout(pcre2_match_context *, \
+    int (*)(pcre2_substitute_callout_block *, void *), void *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_depth_limit(pcre2_match_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_heap_limit(pcre2_match_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_match_limit(pcre2_match_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_offset_limit(pcre2_match_context *, PCRE2_SIZE); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_recursion_limit(pcre2_match_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_recursion_memory_management(pcre2_match_context *, \
+    void *(*)(PCRE2_SIZE, void *), void (*)(void *, void *), void *);
+
+#define PCRE2_CONVERT_CONTEXT_FUNCTIONS \
+PCRE2_EXP_DECL pcre2_convert_context PCRE2_CALL_CONVENTION \
+  *pcre2_convert_context_copy(pcre2_convert_context *); \
+PCRE2_EXP_DECL pcre2_convert_context PCRE2_CALL_CONVENTION \
+  *pcre2_convert_context_create(pcre2_general_context *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+  pcre2_convert_context_free(pcre2_convert_context *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_glob_escape(pcre2_convert_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_set_glob_separator(pcre2_convert_context *, uint32_t);
+
+
+/* Functions concerned with compiling a pattern to PCRE internal code. */
+
+#define PCRE2_COMPILE_FUNCTIONS \
+PCRE2_EXP_DECL pcre2_code PCRE2_CALL_CONVENTION \
+  *pcre2_compile(PCRE2_SPTR, PCRE2_SIZE, uint32_t, int *, PCRE2_SIZE *, \
+    pcre2_compile_context *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+  pcre2_code_free(pcre2_code *); \
+PCRE2_EXP_DECL pcre2_code PCRE2_CALL_CONVENTION \
+  *pcre2_code_copy(const pcre2_code *); \
+PCRE2_EXP_DECL pcre2_code PCRE2_CALL_CONVENTION \
+  *pcre2_code_copy_with_tables(const pcre2_code *);
+
+
+/* Functions that give information about a compiled pattern. */
+
+#define PCRE2_PATTERN_INFO_FUNCTIONS \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_pattern_info(const pcre2_code *, uint32_t, void *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_callout_enumerate(const pcre2_code *, \
+    int (*)(pcre2_callout_enumerate_block *, void *), void *);
+
+
+/* Functions for running a match and inspecting the result. */
+
+#define PCRE2_MATCH_FUNCTIONS \
+PCRE2_EXP_DECL pcre2_match_data PCRE2_CALL_CONVENTION \
+  *pcre2_match_data_create(uint32_t, pcre2_general_context *); \
+PCRE2_EXP_DECL pcre2_match_data PCRE2_CALL_CONVENTION \
+  *pcre2_match_data_create_from_pattern(const pcre2_code *, \
+    pcre2_general_context *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_dfa_match(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, \
+    uint32_t, pcre2_match_data *, pcre2_match_context *, int *, PCRE2_SIZE); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_match(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, \
+    uint32_t, pcre2_match_data *, pcre2_match_context *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+  pcre2_match_data_free(pcre2_match_data *); \
+PCRE2_EXP_DECL PCRE2_SPTR PCRE2_CALL_CONVENTION \
+  pcre2_get_mark(pcre2_match_data *); \
+PCRE2_EXP_DECL PCRE2_SIZE PCRE2_CALL_CONVENTION \
+  pcre2_get_match_data_size(pcre2_match_data *); \
+PCRE2_EXP_DECL uint32_t PCRE2_CALL_CONVENTION \
+  pcre2_get_ovector_count(pcre2_match_data *); \
+PCRE2_EXP_DECL PCRE2_SIZE PCRE2_CALL_CONVENTION \
+  *pcre2_get_ovector_pointer(pcre2_match_data *); \
+PCRE2_EXP_DECL PCRE2_SIZE PCRE2_CALL_CONVENTION \
+  pcre2_get_startchar(pcre2_match_data *);
+
+
+/* Convenience functions for handling matched substrings. */
+
+#define PCRE2_SUBSTRING_FUNCTIONS \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_substring_copy_byname(pcre2_match_data *, PCRE2_SPTR, PCRE2_UCHAR *, \
+    PCRE2_SIZE *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_substring_copy_bynumber(pcre2_match_data *, uint32_t, PCRE2_UCHAR *, \
+    PCRE2_SIZE *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+  pcre2_substring_free(PCRE2_UCHAR *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_substring_get_byname(pcre2_match_data *, PCRE2_SPTR, PCRE2_UCHAR **, \
+    PCRE2_SIZE *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_substring_get_bynumber(pcre2_match_data *, uint32_t, PCRE2_UCHAR **, \
+    PCRE2_SIZE *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_substring_length_byname(pcre2_match_data *, PCRE2_SPTR, PCRE2_SIZE *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_substring_length_bynumber(pcre2_match_data *, uint32_t, PCRE2_SIZE *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_substring_nametable_scan(const pcre2_code *, PCRE2_SPTR, PCRE2_SPTR *, \
+    PCRE2_SPTR *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_substring_number_from_name(const pcre2_code *, PCRE2_SPTR); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+  pcre2_substring_list_free(PCRE2_SPTR *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_substring_list_get(pcre2_match_data *, PCRE2_UCHAR ***, PCRE2_SIZE **);
+
+/* Functions for serializing / deserializing compiled patterns. */
+
+#define PCRE2_SERIALIZE_FUNCTIONS \
+PCRE2_EXP_DECL int32_t PCRE2_CALL_CONVENTION \
+  pcre2_serialize_encode(const pcre2_code **, int32_t, uint8_t **, \
+    PCRE2_SIZE *, pcre2_general_context *); \
+PCRE2_EXP_DECL int32_t PCRE2_CALL_CONVENTION \
+  pcre2_serialize_decode(pcre2_code **, int32_t, const uint8_t *, \
+    pcre2_general_context *); \
+PCRE2_EXP_DECL int32_t PCRE2_CALL_CONVENTION \
+  pcre2_serialize_get_number_of_codes(const uint8_t *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+  pcre2_serialize_free(uint8_t *);
+
+
+/* Convenience function for match + substitute. */
+
+#define PCRE2_SUBSTITUTE_FUNCTION \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_substitute(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, \
+    uint32_t, pcre2_match_data *, pcre2_match_context *, PCRE2_SPTR, \
+    PCRE2_SIZE, PCRE2_UCHAR *, PCRE2_SIZE *);
+
+
+/* Functions for converting pattern source strings. */
+
+#define PCRE2_CONVERT_FUNCTIONS \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_pattern_convert(PCRE2_SPTR, PCRE2_SIZE, uint32_t, PCRE2_UCHAR **, \
+    PCRE2_SIZE *, pcre2_convert_context *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+  pcre2_converted_pattern_free(PCRE2_UCHAR *);
+
+
+/* Functions for JIT processing */
+
+#define PCRE2_JIT_FUNCTIONS \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_jit_compile(pcre2_code *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_jit_match(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, \
+    uint32_t, pcre2_match_data *, pcre2_match_context *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+  pcre2_jit_free_unused_memory(pcre2_general_context *); \
+PCRE2_EXP_DECL pcre2_jit_stack PCRE2_CALL_CONVENTION \
+  *pcre2_jit_stack_create(PCRE2_SIZE, PCRE2_SIZE, pcre2_general_context *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+  pcre2_jit_stack_assign(pcre2_match_context *, pcre2_jit_callback, void *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+  pcre2_jit_stack_free(pcre2_jit_stack *);
+
+
+/* Other miscellaneous functions. */
+
+#define PCRE2_OTHER_FUNCTIONS \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+  pcre2_get_error_message(int, PCRE2_UCHAR *, PCRE2_SIZE); \
+PCRE2_EXP_DECL const uint8_t PCRE2_CALL_CONVENTION \
+  *pcre2_maketables(pcre2_general_context *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+  pcre2_maketables_free(pcre2_general_context *, const uint8_t *);
+
+/* Define macros that generate width-specific names from generic versions. The
+three-level macro scheme is necessary to get the macros expanded when we want
+them to be. First we get the width from PCRE2_LOCAL_WIDTH, which is used for
+generating three versions of everything below. After that, PCRE2_SUFFIX will be
+re-defined to use PCRE2_CODE_UNIT_WIDTH, for use when macros such as
+pcre2_compile are called by application code. */
+
+#define PCRE2_JOIN(a,b) a ## b
+#define PCRE2_GLUE(a,b) PCRE2_JOIN(a,b)
+#define PCRE2_SUFFIX(a) PCRE2_GLUE(a,PCRE2_LOCAL_WIDTH)
+
+
+/* Data types */
+
+#define PCRE2_UCHAR                 PCRE2_SUFFIX(PCRE2_UCHAR)
+#define PCRE2_SPTR                  PCRE2_SUFFIX(PCRE2_SPTR)
+
+#define pcre2_code                  PCRE2_SUFFIX(pcre2_code_)
+#define pcre2_jit_callback          PCRE2_SUFFIX(pcre2_jit_callback_)
+#define pcre2_jit_stack             PCRE2_SUFFIX(pcre2_jit_stack_)
+
+#define pcre2_real_code             PCRE2_SUFFIX(pcre2_real_code_)
+#define pcre2_real_general_context  PCRE2_SUFFIX(pcre2_real_general_context_)
+#define pcre2_real_compile_context  PCRE2_SUFFIX(pcre2_real_compile_context_)
+#define pcre2_real_convert_context  PCRE2_SUFFIX(pcre2_real_convert_context_)
+#define pcre2_real_match_context    PCRE2_SUFFIX(pcre2_real_match_context_)
+#define pcre2_real_jit_stack        PCRE2_SUFFIX(pcre2_real_jit_stack_)
+#define pcre2_real_match_data       PCRE2_SUFFIX(pcre2_real_match_data_)
+
+
+/* Data blocks */
+
+#define pcre2_callout_block            PCRE2_SUFFIX(pcre2_callout_block_)
+#define pcre2_callout_enumerate_block  PCRE2_SUFFIX(pcre2_callout_enumerate_block_)
+#define pcre2_substitute_callout_block PCRE2_SUFFIX(pcre2_substitute_callout_block_)
+#define pcre2_general_context          PCRE2_SUFFIX(pcre2_general_context_)
+#define pcre2_compile_context          PCRE2_SUFFIX(pcre2_compile_context_)
+#define pcre2_convert_context          PCRE2_SUFFIX(pcre2_convert_context_)
+#define pcre2_match_context            PCRE2_SUFFIX(pcre2_match_context_)
+#define pcre2_match_data               PCRE2_SUFFIX(pcre2_match_data_)
+
+
+/* Functions: the complete list in alphabetical order */
+
+#define pcre2_callout_enumerate               PCRE2_SUFFIX(pcre2_callout_enumerate_)
+#define pcre2_code_copy                       PCRE2_SUFFIX(pcre2_code_copy_)
+#define pcre2_code_copy_with_tables           PCRE2_SUFFIX(pcre2_code_copy_with_tables_)
+#define pcre2_code_free                       PCRE2_SUFFIX(pcre2_code_free_)
+#define pcre2_compile                         PCRE2_SUFFIX(pcre2_compile_)
+#define pcre2_compile_context_copy            PCRE2_SUFFIX(pcre2_compile_context_copy_)
+#define pcre2_compile_context_create          PCRE2_SUFFIX(pcre2_compile_context_create_)
+#define pcre2_compile_context_free            PCRE2_SUFFIX(pcre2_compile_context_free_)
+#define pcre2_config                          PCRE2_SUFFIX(pcre2_config_)
+#define pcre2_convert_context_copy            PCRE2_SUFFIX(pcre2_convert_context_copy_)
+#define pcre2_convert_context_create          PCRE2_SUFFIX(pcre2_convert_context_create_)
+#define pcre2_convert_context_free            PCRE2_SUFFIX(pcre2_convert_context_free_)
+#define pcre2_converted_pattern_free          PCRE2_SUFFIX(pcre2_converted_pattern_free_)
+#define pcre2_dfa_match                       PCRE2_SUFFIX(pcre2_dfa_match_)
+#define pcre2_general_context_copy            PCRE2_SUFFIX(pcre2_general_context_copy_)
+#define pcre2_general_context_create          PCRE2_SUFFIX(pcre2_general_context_create_)
+#define pcre2_general_context_free            PCRE2_SUFFIX(pcre2_general_context_free_)
+#define pcre2_get_error_message               PCRE2_SUFFIX(pcre2_get_error_message_)
+#define pcre2_get_mark                        PCRE2_SUFFIX(pcre2_get_mark_)
+#define pcre2_get_match_data_size             PCRE2_SUFFIX(pcre2_get_match_data_size_)
+#define pcre2_get_ovector_pointer             PCRE2_SUFFIX(pcre2_get_ovector_pointer_)
+#define pcre2_get_ovector_count               PCRE2_SUFFIX(pcre2_get_ovector_count_)
+#define pcre2_get_startchar                   PCRE2_SUFFIX(pcre2_get_startchar_)
+#define pcre2_jit_compile                     PCRE2_SUFFIX(pcre2_jit_compile_)
+#define pcre2_jit_match                       PCRE2_SUFFIX(pcre2_jit_match_)
+#define pcre2_jit_free_unused_memory          PCRE2_SUFFIX(pcre2_jit_free_unused_memory_)
+#define pcre2_jit_stack_assign                PCRE2_SUFFIX(pcre2_jit_stack_assign_)
+#define pcre2_jit_stack_create                PCRE2_SUFFIX(pcre2_jit_stack_create_)
+#define pcre2_jit_stack_free                  PCRE2_SUFFIX(pcre2_jit_stack_free_)
+#define pcre2_maketables                      PCRE2_SUFFIX(pcre2_maketables_)
+#define pcre2_maketables_free                 PCRE2_SUFFIX(pcre2_maketables_free_)
+#define pcre2_match                           PCRE2_SUFFIX(pcre2_match_)
+#define pcre2_match_context_copy              PCRE2_SUFFIX(pcre2_match_context_copy_)
+#define pcre2_match_context_create            PCRE2_SUFFIX(pcre2_match_context_create_)
+#define pcre2_match_context_free              PCRE2_SUFFIX(pcre2_match_context_free_)
+#define pcre2_match_data_create               PCRE2_SUFFIX(pcre2_match_data_create_)
+#define pcre2_match_data_create_from_pattern  PCRE2_SUFFIX(pcre2_match_data_create_from_pattern_)
+#define pcre2_match_data_free                 PCRE2_SUFFIX(pcre2_match_data_free_)
+#define pcre2_pattern_convert                 PCRE2_SUFFIX(pcre2_pattern_convert_)
+#define pcre2_pattern_info                    PCRE2_SUFFIX(pcre2_pattern_info_)
+#define pcre2_serialize_decode                PCRE2_SUFFIX(pcre2_serialize_decode_)
+#define pcre2_serialize_encode                PCRE2_SUFFIX(pcre2_serialize_encode_)
+#define pcre2_serialize_free                  PCRE2_SUFFIX(pcre2_serialize_free_)
+#define pcre2_serialize_get_number_of_codes   PCRE2_SUFFIX(pcre2_serialize_get_number_of_codes_)
+#define pcre2_set_bsr                         PCRE2_SUFFIX(pcre2_set_bsr_)
+#define pcre2_set_callout                     PCRE2_SUFFIX(pcre2_set_callout_)
+#define pcre2_set_character_tables            PCRE2_SUFFIX(pcre2_set_character_tables_)
+#define pcre2_set_compile_extra_options       PCRE2_SUFFIX(pcre2_set_compile_extra_options_)
+#define pcre2_set_compile_recursion_guard     PCRE2_SUFFIX(pcre2_set_compile_recursion_guard_)
+#define pcre2_set_depth_limit                 PCRE2_SUFFIX(pcre2_set_depth_limit_)
+#define pcre2_set_glob_escape                 PCRE2_SUFFIX(pcre2_set_glob_escape_)
+#define pcre2_set_glob_separator              PCRE2_SUFFIX(pcre2_set_glob_separator_)
+#define pcre2_set_heap_limit                  PCRE2_SUFFIX(pcre2_set_heap_limit_)
+#define pcre2_set_match_limit                 PCRE2_SUFFIX(pcre2_set_match_limit_)
+#define pcre2_set_max_pattern_length          PCRE2_SUFFIX(pcre2_set_max_pattern_length_)
+#define pcre2_set_newline                     PCRE2_SUFFIX(pcre2_set_newline_)
+#define pcre2_set_parens_nest_limit           PCRE2_SUFFIX(pcre2_set_parens_nest_limit_)
+#define pcre2_set_offset_limit                PCRE2_SUFFIX(pcre2_set_offset_limit_)
+#define pcre2_set_substitute_callout          PCRE2_SUFFIX(pcre2_set_substitute_callout_)
+#define pcre2_substitute                      PCRE2_SUFFIX(pcre2_substitute_)
+#define pcre2_substring_copy_byname           PCRE2_SUFFIX(pcre2_substring_copy_byname_)
+#define pcre2_substring_copy_bynumber         PCRE2_SUFFIX(pcre2_substring_copy_bynumber_)
+#define pcre2_substring_free                  PCRE2_SUFFIX(pcre2_substring_free_)
+#define pcre2_substring_get_byname            PCRE2_SUFFIX(pcre2_substring_get_byname_)
+#define pcre2_substring_get_bynumber          PCRE2_SUFFIX(pcre2_substring_get_bynumber_)
+#define pcre2_substring_length_byname         PCRE2_SUFFIX(pcre2_substring_length_byname_)
+#define pcre2_substring_length_bynumber       PCRE2_SUFFIX(pcre2_substring_length_bynumber_)
+#define pcre2_substring_list_get              PCRE2_SUFFIX(pcre2_substring_list_get_)
+#define pcre2_substring_list_free             PCRE2_SUFFIX(pcre2_substring_list_free_)
+#define pcre2_substring_nametable_scan        PCRE2_SUFFIX(pcre2_substring_nametable_scan_)
+#define pcre2_substring_number_from_name      PCRE2_SUFFIX(pcre2_substring_number_from_name_)
+
+/* Keep this old function name for backwards compatibility */
+#define pcre2_set_recursion_limit PCRE2_SUFFIX(pcre2_set_recursion_limit_)
+
+/* Keep this obsolete function for backwards compatibility: it is now a noop. */
+#define pcre2_set_recursion_memory_management PCRE2_SUFFIX(pcre2_set_recursion_memory_management_)
+
+/* Now generate all three sets of width-specific structures and function
+prototypes. */
+
+#define PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS \
+PCRE2_TYPES_LIST \
+PCRE2_STRUCTURE_LIST \
+PCRE2_GENERAL_INFO_FUNCTIONS \
+PCRE2_GENERAL_CONTEXT_FUNCTIONS \
+PCRE2_COMPILE_CONTEXT_FUNCTIONS \
+PCRE2_CONVERT_CONTEXT_FUNCTIONS \
+PCRE2_CONVERT_FUNCTIONS \
+PCRE2_MATCH_CONTEXT_FUNCTIONS \
+PCRE2_COMPILE_FUNCTIONS \
+PCRE2_PATTERN_INFO_FUNCTIONS \
+PCRE2_MATCH_FUNCTIONS \
+PCRE2_SUBSTRING_FUNCTIONS \
+PCRE2_SERIALIZE_FUNCTIONS \
+PCRE2_SUBSTITUTE_FUNCTION \
+PCRE2_JIT_FUNCTIONS \
+PCRE2_OTHER_FUNCTIONS
+
+#define PCRE2_LOCAL_WIDTH 8
+PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS
+#undef PCRE2_LOCAL_WIDTH
+
+#define PCRE2_LOCAL_WIDTH 16
+PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS
+#undef PCRE2_LOCAL_WIDTH
+
+#define PCRE2_LOCAL_WIDTH 32
+PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS
+#undef PCRE2_LOCAL_WIDTH
+
+/* Undefine the list macros; they are no longer needed. */
+
+#undef PCRE2_TYPES_LIST
+#undef PCRE2_STRUCTURE_LIST
+#undef PCRE2_GENERAL_INFO_FUNCTIONS
+#undef PCRE2_GENERAL_CONTEXT_FUNCTIONS
+#undef PCRE2_COMPILE_CONTEXT_FUNCTIONS
+#undef PCRE2_CONVERT_CONTEXT_FUNCTIONS
+#undef PCRE2_MATCH_CONTEXT_FUNCTIONS
+#undef PCRE2_COMPILE_FUNCTIONS
+#undef PCRE2_PATTERN_INFO_FUNCTIONS
+#undef PCRE2_MATCH_FUNCTIONS
+#undef PCRE2_SUBSTRING_FUNCTIONS
+#undef PCRE2_SERIALIZE_FUNCTIONS
+#undef PCRE2_SUBSTITUTE_FUNCTION
+#undef PCRE2_JIT_FUNCTIONS
+#undef PCRE2_OTHER_FUNCTIONS
+#undef PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS
+
+/* PCRE2_CODE_UNIT_WIDTH must be defined. If it is 8, 16, or 32, redefine
+PCRE2_SUFFIX to use it. If it is 0, undefine the other macros and make
+PCRE2_SUFFIX a no-op. Otherwise, generate an error. */
+
+#undef PCRE2_SUFFIX
+#ifndef PCRE2_CODE_UNIT_WIDTH
+#error PCRE2_CODE_UNIT_WIDTH must be defined before including pcre2.h.
+#error Use 8, 16, or 32; or 0 for a multi-width application.
+#else  /* PCRE2_CODE_UNIT_WIDTH is defined */
+#if PCRE2_CODE_UNIT_WIDTH == 8 || \
+    PCRE2_CODE_UNIT_WIDTH == 16 || \
+    PCRE2_CODE_UNIT_WIDTH == 32
+#define PCRE2_SUFFIX(a) PCRE2_GLUE(a, PCRE2_CODE_UNIT_WIDTH)
+#elif PCRE2_CODE_UNIT_WIDTH == 0
+#undef PCRE2_JOIN
+#undef PCRE2_GLUE
+#define PCRE2_SUFFIX(a) a
+#else
+#error PCRE2_CODE_UNIT_WIDTH must be 0, 8, 16, or 32.
+#endif
+#endif  /* PCRE2_CODE_UNIT_WIDTH is defined */
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#endif  /* PCRE2_H_IDEMPOTENT_GUARD */
+
+/* End of pcre2.h */
diff --git a/src/c/pcre2/maint/ucptest.c b/src/c/pcre2/maint/ucptest.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/maint/ucptest.c
@@ -0,0 +1,828 @@
+/***************************************************
+* A program for testing the Unicode property table *
+***************************************************/
+
+/* Copyright (c) University of Cambridge 2008-2020 */
+
+/* Compile thus:
+
+   gcc -DHAVE_CONFIG_H -DPCRE2_CODE_UNIT_WIDTH=8 -o ucptest \
+     ucptest.c ../src/pcre2_ucd.c ../src/pcre2_tables.c
+
+   Add -lreadline or -ledit if PCRE2 was configured with readline or libedit
+   support in pcre2test.
+*/
+
+/* This is a hacked-up program for testing the Unicode properties tables of
+PCRE2. It can also be used for finding characters with certain properties.
+I wrote it to help with debugging PCRE, and have added things that I found
+useful, in a rather haphazard way. The code has never been seriously tidied or
+checked for robustness, but it shouldn't now give compiler warnings.
+
+There is only one option: "-s". If given, it applies only to the "findprop" 
+command. It causes the UTF-8 sequence of bytes that encode the character to be 
+output between angle brackets at the end of the line. On a UTF-8 terminal, this 
+will show the appropriate graphic for the code point.
+
+If the command has arguments, they are concatenated into a buffer, separated by
+spaces. If the first argument starts "U+" or consists entirely of hexadecimal
+digits, "findprop" is inserted at the start. The buffer is then processed as a
+single line file, after which the program exits. If there are no arguments, the
+program reads commands line by line on stdin and writes output to stdout. The 
+return code is always zero.
+
+There are three commands:
+
+"findprop" must be followed by a space-separated list of Unicode code points as
+hex numbers, either without any prefix or starting with "U+". The output is one
+line per character, giving its Unicode properties followed by its other case or 
+cases if one or more exist, followed by its Script Extension list if it is not
+just the same as the base script. This list is in square brackets. The
+properties are:
+
+General type        e.g. Letter
+Specific type       e.g. Upper case letter
+Script              e.g. Medefaidrin
+Grapheme break type e.g. Extend (most common is Other)
+
+"find" must be followed by a list of property names and their values. The 
+values are case-sensitive. This finds characters that have those properties. If
+multiple properties are listed, they must all be matched. Currently supported:
+
+  script <name>    The character must have this script property. Only one
+                     such script may be given.
+  scriptx <name>   This script must be in the character's Script Extension
+                     property list. If this is used many times, all the given
+                     scripts must be present.
+  type <abbrev>    The character's specific type (e.g. Lu or Nd) must match.
+  gbreak <name>    The grapheme break property must match.
+
+If a <name> or <abbrev> is preceded by !, the value must NOT be present. For
+Script Extensions, there may be a mixture of positive and negative
+requirements. All must be satisfied.
+
+Sequences of two or more characters are shown as ranges, for example
+U+0041..U+004A. No more than 100 lines are are output. If there are more
+characters, the list ends with ... 
+
+"list" must be followed by a property name (script, type, or gbreak). The
+defined values for that property are listed. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "../src/config.h"
+#endif
+
+#ifndef SUPPORT_UNICODE
+#define SUPPORT_UNICODE
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../src/pcre2_internal.h"
+#include "../src/pcre2_ucp.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT)
+#if defined(SUPPORT_LIBREADLINE)
+#include <readline/readline.h>
+#include <readline/history.h>
+#else
+#if defined(HAVE_EDITLINE_READLINE_H)
+#include <editline/readline.h>
+#else
+#include <readline/readline.h>
+#endif
+#endif
+#endif
+
+
+/* -------------------------------------------------------------------*/
+
+#define CS   (char *)
+#define CCS  (const char *)
+#define CSS  (char **)
+#define US   (unsigned char *)
+#define CUS  (const unsigned char *)
+#define USS  (unsigned char **)
+
+/* -------------------------------------------------------------------*/
+
+static BOOL show_character = FALSE;
+
+static const unsigned char *type_names[] = {
+  US"Cc", US"Control",
+  US"Cf", US"Format",
+  US"Cn", US"Unassigned",
+  US"Co", US"Private use",
+  US"Cs", US"Surrogate",
+  US"Ll", US"Lower case letter",
+  US"Lm", US"Modifier letter",
+  US"Lo", US"Other letter",
+  US"Lt", US"Title case letter",
+  US"Lu", US"Upper case letter",
+  US"Mc", US"Spacing mark",
+  US"Me", US"Enclosing mark",
+  US"Mn", US"Non-spacing mark",
+  US"Nd", US"Decimal number",
+  US"Nl", US"Letter number",
+  US"No", US"Other number",
+  US"Pc", US"Connector punctuation",
+  US"Pd", US"Dash punctuation",
+  US"Pe", US"Close punctuation",
+  US"Pf", US"Final punctuation",
+  US"Pi", US"Initial punctuation",
+  US"Po", US"Other punctuation",
+  US"Ps", US"Open punctuation",
+  US"Sc", US"Currency symbol",
+  US"Sk", US"Modifier symbol",
+  US"Sm", US"Mathematical symbol",
+  US"So", US"Other symbol",
+  US"Zl", US"Line separator",
+  US"Zp", US"Paragraph separator",
+  US"Zs", US"Space separator" 
+};
+
+static const unsigned char *gb_names[] = {
+  US"CR",                    US"carriage return",
+  US"LF",                    US"linefeed",
+  US"Control",               US"",
+  US"Extend",                US"",
+  US"Prepend",               US"",
+  US"SpacingMark",           US"",
+  US"L",                     US"Hangul syllable type L",
+  US"V",                     US"Hangul syllable type V",
+  US"T",                     US"Hangul syllable type T",
+  US"LV",                    US"Hangul syllable type LV",
+  US"LVT",                   US"Hangul syllable type LVT",
+  US"RegionalIndicator",     US"",
+  US"Other",                 US"",
+  US"ZWJ",                   US"zero width joiner",
+  US"Extended_Pictographic", US""
+};
+
+
+static const unsigned int utf8_table1[] = {
+  0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff};
+
+static const int utf8_table2[] = {
+  0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
+
+
+/*************************************************
+*       Convert character value to UTF-8         *
+*************************************************/
+
+/* This function takes an unsigned long integer value in the range 0 -
+0x7fffffff and encodes it as a UTF-8 character in 1 to 6 bytes.
+
+Arguments:
+  cvalue     the character value
+  buffer     pointer to buffer for result - at least 6 bytes long
+
+Returns:     number of bytes placed in the buffer
+             0 if input code point is too big
+*/
+
+static size_t
+ord2utf8(unsigned int cvalue, unsigned char *buffer)
+{
+size_t i, j;
+for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++)
+  if (cvalue <= utf8_table1[i]) break;
+if (i >= sizeof(utf8_table1)/sizeof(int)) return 0;
+buffer += i;
+for (j = i; j > 0; j--)
+ {
+ *buffer-- = 0x80 | (cvalue & 0x3f);
+ cvalue >>= 6;
+ }
+*buffer = utf8_table2[i] | cvalue;
+return i + 1;
+}
+
+
+
+/*************************************************
+*             Test for interaction               *
+*************************************************/
+
+static BOOL
+is_stdin_tty(void)
+{
+#if defined WIN32
+return _isatty(_fileno(stdin));
+#else
+return isatty(fileno(stdin));
+#endif
+}
+
+
+/*************************************************
+*      Get script name from ucp ident            *
+*************************************************/
+
+static const char *
+get_scriptname(int script)
+{
+size_t i;
+const ucp_type_table *u;
+
+for (i = 0; i < PRIV(utt_size); i++)
+  {
+  u = PRIV(utt) + i; 
+  if (u->type == PT_SC && u->value == script) break;
+  }
+if (i < PRIV(utt_size))
+  return PRIV(utt_names) + u->name_offset;
+  
+return "??";
+}  
+
+
+/*************************************************
+*      Print Unicode property info for a char    *
+*************************************************/
+
+static void
+print_prop(unsigned int c, BOOL is_just_one)
+{
+int type = UCD_CATEGORY(c);
+int fulltype = UCD_CHARTYPE(c);
+int script = UCD_SCRIPT(c);
+int scriptx = UCD_SCRIPTX(c);
+int gbprop = UCD_GRAPHBREAK(c);
+unsigned int othercase = UCD_OTHERCASE(c);
+int caseset = UCD_CASESET(c);
+
+const unsigned char *fulltypename = US"??";
+const unsigned char *typename = US"??";
+const unsigned char *graphbreak = US"??";
+const unsigned char *scriptname = CUS get_scriptname(script);
+
+switch (type)
+  {
+  case ucp_C: typename = US"Control"; break;
+  case ucp_L: typename = US"Letter"; break;
+  case ucp_M: typename = US"Mark"; break;
+  case ucp_N: typename = US"Number"; break;
+  case ucp_P: typename = US"Punctuation"; break;
+  case ucp_S: typename = US"Symbol"; break;
+  case ucp_Z: typename = US"Separator"; break;
+  }
+
+switch (fulltype)
+  {
+  case ucp_Cc: fulltypename = US"Control"; break;
+  case ucp_Cf: fulltypename = US"Format"; break;
+  case ucp_Cn: fulltypename = US"Unassigned"; break;
+  case ucp_Co: fulltypename = US"Private use"; break;
+  case ucp_Cs: fulltypename = US"Surrogate"; break;
+  case ucp_Ll: fulltypename = US"Lower case letter"; break;
+  case ucp_Lm: fulltypename = US"Modifier letter"; break;
+  case ucp_Lo: fulltypename = US"Other letter"; break;
+  case ucp_Lt: fulltypename = US"Title case letter"; break;
+  case ucp_Lu: fulltypename = US"Upper case letter"; break;
+  case ucp_Mc: fulltypename = US"Spacing mark"; break;
+  case ucp_Me: fulltypename = US"Enclosing mark"; break;
+  case ucp_Mn: fulltypename = US"Non-spacing mark"; break;
+  case ucp_Nd: fulltypename = US"Decimal number"; break;
+  case ucp_Nl: fulltypename = US"Letter number"; break;
+  case ucp_No: fulltypename = US"Other number"; break;
+  case ucp_Pc: fulltypename = US"Connector punctuation"; break;
+  case ucp_Pd: fulltypename = US"Dash punctuation"; break;
+  case ucp_Pe: fulltypename = US"Close punctuation"; break;
+  case ucp_Pf: fulltypename = US"Final punctuation"; break;
+  case ucp_Pi: fulltypename = US"Initial punctuation"; break;
+  case ucp_Po: fulltypename = US"Other punctuation"; break;
+  case ucp_Ps: fulltypename = US"Open punctuation"; break;
+  case ucp_Sc: fulltypename = US"Currency symbol"; break;
+  case ucp_Sk: fulltypename = US"Modifier symbol"; break;
+  case ucp_Sm: fulltypename = US"Mathematical symbol"; break;
+  case ucp_So: fulltypename = US"Other symbol"; break;
+  case ucp_Zl: fulltypename = US"Line separator"; break;
+  case ucp_Zp: fulltypename = US"Paragraph separator"; break;
+  case ucp_Zs: fulltypename = US"Space separator"; break;
+  }
+
+switch(gbprop)
+  {
+  case ucp_gbCR:           graphbreak = US"CR"; break;
+  case ucp_gbLF:           graphbreak = US"LF"; break;
+  case ucp_gbControl:      graphbreak = US"Control"; break;
+  case ucp_gbExtend:       graphbreak = US"Extend"; break;
+  case ucp_gbPrepend:      graphbreak = US"Prepend"; break;
+  case ucp_gbSpacingMark:  graphbreak = US"SpacingMark"; break;
+  case ucp_gbL:            graphbreak = US"Hangul syllable type L"; break;
+  case ucp_gbV:            graphbreak = US"Hangul syllable type V"; break;
+  case ucp_gbT:            graphbreak = US"Hangul syllable type T"; break;
+  case ucp_gbLV:           graphbreak = US"Hangul syllable type LV"; break;
+  case ucp_gbLVT:          graphbreak = US"Hangul syllable type LVT"; break;
+  case ucp_gbRegionalIndicator:
+                           graphbreak = US"Regional Indicator"; break;
+  case ucp_gbOther:        graphbreak = US"Other"; break;
+  case ucp_gbZWJ:          graphbreak = US"Zero Width Joiner"; break;
+  case ucp_gbExtended_Pictographic:
+                           graphbreak = US"Extended Pictographic"; break;
+  default:                 graphbreak = US"Unknown"; break;
+  }
+
+printf("U+%04X %s: %s, %s, %s", c, typename, fulltypename, scriptname, graphbreak);
+if (is_just_one && othercase != c)
+  {
+  printf(", U+%04X", othercase);
+  if (caseset != 0)
+    {
+    const uint32_t *p = PRIV(ucd_caseless_sets) + caseset - 1;
+    while (*(++p) < NOTACHAR)
+      {
+      unsigned int d = *p;  
+      if (d != othercase && d != c) printf(", U+%04X", d);
+      } 
+    }
+  }
+
+if (scriptx != script)
+  {
+  printf(", [");
+  if (scriptx >= 0)
+    printf("%s", get_scriptname(scriptx));
+  else
+    {
+    const char *sep = "";
+    const uint8_t *p = PRIV(ucd_script_sets) - scriptx;
+    while (*p != 0)
+      {
+      printf("%s%s", sep, get_scriptname(*p++));
+      sep = ", ";
+      }
+    }
+  printf("]");
+  }
+  
+if (show_character && is_just_one)
+  {
+  unsigned char buffer[8];
+  size_t len = ord2utf8(c, buffer);
+  printf(", >%.*s<", (int)len, buffer);  
+  }  
+
+printf("\n");
+}
+
+
+
+/*************************************************
+*   Find character(s) with given property/ies    *
+*************************************************/
+
+static void
+find_chars(unsigned char *s)
+{
+unsigned char name[24];
+unsigned char value[24];
+unsigned char *t;
+unsigned int count= 0;
+int scriptx_list[24];
+unsigned int scriptx_count = 0;
+uint32_t i, c;
+int script = -1;
+int type = -1;
+int gbreak = -1;
+BOOL script_not = FALSE;
+BOOL type_not = FALSE;
+BOOL gbreak_not = FALSE;
+BOOL hadrange = FALSE;
+const ucd_record *ucd, *next_ucd;
+const char *pad = "        ";
+
+while (*s != 0)
+  {
+  unsigned int offset = 0;
+  BOOL scriptx_not = FALSE;
+
+  for (t = name; *s != 0 && !isspace(*s); s++) *t++ = *s;
+  *t = 0;
+  while (isspace(*s)) s++;
+
+  for (t = value; *s != 0 && !isspace(*s); s++) *t++ = *s;
+  *t = 0;
+  while (isspace(*s)) s++;
+
+  if (strcmp(CS name, "script") == 0 ||
+      strcmp(CS name, "scriptx") == 0)
+    {
+    if (value[0] == '!')
+      {
+      if (name[6] == 'x') scriptx_not = TRUE;
+        else script_not = TRUE;
+      offset = 1;
+      }
+
+    for (i = 0; i < PRIV(utt_size); i++)
+      {
+      const ucp_type_table *u = PRIV(utt) + i; 
+      if (u->type == PT_SC && strcmp(CS(value + offset), 
+            PRIV(utt_names) + u->name_offset) == 0)
+        {
+        c = u->value; 
+        if (name[6] == 'x')
+          {
+          scriptx_list[scriptx_count++] = scriptx_not? (-c):c;
+          }
+        else
+          {
+          if (script < 0) script = c; else
+            {
+            printf("** Only 1 script value allowed\n");
+            return;
+            }
+          }
+        break;
+        }
+      }
+
+    if (i >= PRIV(utt_size))
+      {
+      printf("** Unrecognized script name \"%s\"\n", value);
+      return;
+      }
+    }
+
+  else if (strcmp(CS name, "type") == 0)
+    {
+    if (type >= 0)
+      {
+      printf("** Only 1 type value allowed\n");
+      return;
+      }
+    else
+      {
+      if (value[0] == '!')
+        {
+        type_not = TRUE;
+        offset = 1;
+        }
+
+      for (i = 0; i < sizeof(type_names)/sizeof(char *); i += 2)
+        {
+        if (strcmp(CS (value + offset), CS type_names[i]) == 0)
+          {
+          type = i/2;
+          break;
+          }
+        }
+      if (i >= sizeof(type_names)/sizeof(char *))
+        {
+        printf("** Unrecognized type name \"%s\"\n", value);
+        return;
+        }
+      }
+    }
+
+  else if (strcmp(CS name, "gbreak") == 0)
+    {
+    if (gbreak >= 0)
+      {
+      printf("** Only 1 grapheme break value allowed\n");
+      return;
+      }
+    else
+      {
+      if (value[0] == '!')
+        {
+        gbreak_not = TRUE;
+        offset = 1;
+        }
+
+      for (i = 0; i < sizeof(gb_names)/sizeof(char *); i += 2)
+        {
+        if (strcmp(CS (value + offset), CS gb_names[i]) == 0)
+          {
+          gbreak = i/2;
+          break;
+          }
+        }
+      if (i >= sizeof(gb_names)/sizeof(char *))
+        {
+        printf("** Unrecognized gbreak name \"%s\"\n", value);
+        return;
+        }
+      }
+    }
+
+  else
+    {
+    printf("** Unrecognized property name \"%s\"\n", name);
+    return;
+    }
+  }
+
+if (script < 0 && scriptx_count == 0 && type < 0 && gbreak < 0)
+  {
+  printf("** No properties specified\n");
+  return;
+  }
+
+for (c = 0; c <= 0x10ffff; c++)
+  {
+  if (script >= 0 && (script == UCD_SCRIPT(c)) == script_not) continue;
+
+  if (scriptx_count > 0)
+    {
+    const uint8_t *char_scriptx = NULL;
+    unsigned int found = 0;
+    int scriptx = UCD_SCRIPTX(c);
+
+    if (scriptx < 0) char_scriptx = PRIV(ucd_script_sets) - scriptx;
+
+    for (i = 0; i < scriptx_count; i++)
+      {
+      /* Positive requirment */
+      if (scriptx_list[i] >= 0)
+        {
+        if (scriptx >= 0)
+          {
+          if (scriptx == scriptx_list[i]) found++;
+          }
+
+        else
+          {
+          const uint8_t *p;
+          for (p = char_scriptx; *p != 0; p++)
+            {
+            if (scriptx_list[i] == *p)
+              {
+              found++;
+              break;
+              }
+            }
+          }
+        }
+      /* Negative requirement */
+      else
+        {
+        if (scriptx >= 0)
+          {
+          if (scriptx != -scriptx_list[i]) found++;
+          }
+        else
+          {
+          const uint8_t *p;
+          for (p = char_scriptx; *p != 0; p++)
+            if (-scriptx_list[i] == *p) break;
+          if (*p == 0) found++;
+          }
+        }
+      }
+
+    if (found != scriptx_count) continue;
+    }
+
+  if (type >= 0)
+    {
+    if (type_not)
+      {
+      if (type == UCD_CHARTYPE(c)) continue;
+      }
+    else
+      {
+      if (type != UCD_CHARTYPE(c)) continue;
+      }
+    }
+
+  if (gbreak >= 0)
+    {
+    if (gbreak_not)
+      {
+      if (gbreak == UCD_GRAPHBREAK(c)) continue;
+      }
+    else
+      {
+      if (gbreak != UCD_GRAPHBREAK(c)) continue;
+      }
+    }
+
+  /* All conditions are met. Look for runs. */
+
+  ucd = GET_UCD(c);
+
+  for (i = c + 1; i < 0x10ffff; i++)
+    {
+    next_ucd = GET_UCD(i);
+    if (memcmp(ucd, next_ucd, sizeof(ucd_record)) != 0) break;
+    }
+
+  if (--i > c)
+    {
+    printf("U+%04X..", c);
+    c = i;
+    hadrange = TRUE;
+    }
+  else if (hadrange) printf("%s", pad);
+
+  print_prop(c, FALSE);
+  if (c >= 0x100000) pad = "        ";
+    else if (c >= 0x10000) pad = "       ";
+  count++;
+  if (count >= 100)
+    {
+    printf("...\n");
+    break;
+    }
+  }
+
+if (count == 0) printf("No characters found\n");
+}
+
+
+/*************************************************
+*        Process command line                    *
+*************************************************/
+
+static void
+process_command_line(unsigned char *buffer)
+{
+unsigned char *s, *t;
+unsigned char name[24];
+
+s = buffer;
+while (isspace(*s)) s++;
+if (*s == 0) return;
+
+for (t = name; *s != 0 && !isspace(*s); s++) *t++ = *s;
+*t = 0;
+while (isspace(*s)) s++;
+
+if (strcmp(CS name, "findprop") == 0)
+  {
+  while (*s != 0)
+    {
+    unsigned int c; 
+    unsigned char *endptr;
+    t = s; 
+    if (strncmp(CS t, "U+", 2) == 0) t += 2;
+    c = strtoul(CS t, CSS(&endptr), 16);
+    if (*endptr != 0 && !isspace(*endptr))
+      {
+      while (*endptr != 0 && !isspace(*endptr)) endptr++;
+      printf("** Invalid hex number: ignored \"%.*s\"\n", (int)(endptr-s), s);
+      }
+    else  
+      {
+      if (c > 0x10ffff) 
+        printf("** U+%x is too big for a Unicode code point\n", c);
+      else   
+        print_prop(c, TRUE);
+      } 
+    s = endptr;
+    while (isspace(*s)) s++;
+    }
+  }
+
+else if (strcmp(CS name, "find") == 0)
+  {
+  find_chars(s);
+  }
+  
+else if (strcmp(CS name, "list") == 0)
+  {
+  while (*s != 0)
+    {
+    size_t i;
+    for (t = name; *s != 0 && !isspace(*s); s++) *t++ = *s;
+    *t = 0;
+    while (isspace(*s)) s++;
+    
+    if (strcmp(CS name, "script") == 0 || strcmp(CS name, "scripts") == 0)
+      {
+      for (i = 0; i < PRIV(utt_size); i++) 
+        if (PRIV(utt)[i].type == PT_SC)
+          printf("%s\n", PRIV(utt_names) + PRIV(utt)[i].name_offset);  
+      }
+      
+    else if (strcmp(CS name, "type") == 0 || strcmp(CS name, "types") == 0)
+      {
+      for (i = 0; i < sizeof(type_names)/sizeof(char *); i += 2)
+        printf("%s %s\n", type_names[i], type_names[i+1]); 
+      }  
+      
+    else if (strcmp(CS name, "gbreak") == 0 || strcmp(CS name, "gbreaks") == 0)
+      {
+      for (i = 0; i < sizeof(gb_names)/sizeof(char *); i += 2)
+        {
+        if (gb_names[i+1][0] != 0)  
+          printf("%-3s (%s)\n", gb_names[i], gb_names[i+1]);
+        else   
+          printf("%s\n", gb_names[i]);
+        } 
+      }    
+
+    else 
+      {
+      printf("** Unknown property \"%s\"\n", name);  
+      break;
+      }  
+    }  
+  }  
+
+else printf("** Unknown test command \"%s\"\n", name);
+}
+
+
+
+/*************************************************
+*               Main program                     *
+*************************************************/
+
+int
+main(int argc, char **argv)
+{
+BOOL interactive;
+int first_arg = 1;
+unsigned char buffer[1024];
+
+if (argc > 1 && strcmp(argv[1], "-s") == 0)
+  {
+  show_character = TRUE;
+  first_arg++;
+  }   
+
+if (argc > first_arg)
+  {
+  int i;
+  BOOL hexfirst = TRUE; 
+  char *arg = argv[first_arg]; 
+  unsigned char *s = buffer;
+  
+  if (strncmp(arg, "U+", 2) != 0 && !isdigit(*arg)) 
+    {
+    while (*arg != 0) 
+      {
+      if (!isxdigit(*arg++)) { hexfirst = FALSE; break; }  
+      } 
+    } 
+     
+  if (hexfirst)
+    {
+    strcpy(CS s, "findprop ");
+    s += 9;
+    }
+    
+  for (i = first_arg; i < argc; i++)
+    {
+    s += sprintf(CS s, "%s ", argv[i]);       
+    }
+
+  process_command_line(buffer);
+  return 0;
+  }
+
+interactive = is_stdin_tty();
+
+#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT)
+if (interactive) using_history();
+#endif
+
+for(;;)
+  {
+#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT)
+  if (interactive)
+    {
+    size_t len;
+    unsigned char *s = US readline("> ");
+    if (s == NULL) break;
+    len = strlen(CS s);
+    if (len > 0) add_history(CS s);
+    memcpy(buffer, s, len);
+    buffer[len] = '\n';
+    buffer[len+1] = 0;
+    free(s);
+    }
+  else
+#endif
+
+    {
+    if (interactive) printf("> ");
+    if (fgets(CS buffer, sizeof(buffer), stdin) == NULL) break;
+    if (!interactive) printf("%s", buffer);
+    }
+    
+  process_command_line(buffer);
+  }
+
+if (interactive) printf("\n");
+
+#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT)
+if (interactive) clear_history();
+#endif
+
+return 0;
+}
+
+/* End */
diff --git a/src/c/pcre2/maint/utf8.c b/src/c/pcre2/maint/utf8.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/maint/utf8.c
@@ -0,0 +1,347 @@
+/****************************************************
+* PCRE maintainers' helper program: UTF-8 converter *
+****************************************************/
+
+/* This is a test program for converting character code points to UTF-8 and
+vice versa. Note that this program conforms to the original definition of
+UTF-8, which allows codepoints up to 7fffffff. The more recent definition
+limits the validity of Unicode UTF-8 codepoints to a maximum of 10ffffff, and
+forbids the "surrogate" code points. This program now gives warnings for these
+invalid code points.
+
+The arguments are either single code point values written as U+hh.. or 0xhh..
+for conversion to UTF-8, or sequences of hex values, written without 0x and
+optionally including spaces (but such arguments must be quoted), for conversion
+from UTF-8 to codepoints. For example:
+
+./utf8 0x1234
+U+00001234 => e1 88 b4
+
+./utf8 "e1 88 b4"
+U+00001234 <= e1 88 b4
+
+In the second case, a number of UTF-8 characters can be present in one
+argument. In other words, each such argument is interpreted (after ignoring
+spaces) as a string of UTF-8 bytes representing a string of characters:
+
+./utf8 "65 e188b4 77"
+0x00000065 <= 65
+0x00001234 <= e1 88 b4
+0x00000077 <= 77
+
+If the option -s is given, the sequence of UTF-bytes is written out between
+angle brackets at the end of the line. On a UTF-8 terminal, this will show the
+appropriate graphic for the code point.
+
+Errors provoke error messages, but the program carries on with the next
+argument. The return code is always zero.
+
+Philip Hazel
+Original creation data: unknown
+Code extended and tidied to avoid compiler warnings: 26 March 2020
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+/* The valid ranges for UTF-8 characters are:
+
+0000 0000  to  0000 007f   1 byte (ascii)
+0000 0080  to  0000 07ff   2 bytes
+0000 0800  to  0000 ffff   3 bytes
+0001 0000  to  001f ffff   4 bytes
+0020 0000  to  03ff ffff   5 bytes
+0400 0000  to  7fff ffff   6 bytes
+*/
+
+
+static const unsigned int utf8_table1[] = {
+  0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff};
+
+static const int utf8_table2[] = {
+  0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
+
+static const int utf8_table3[] = {
+  0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
+
+
+/*************************************************
+*       Convert character value to UTF-8         *
+*************************************************/
+
+/* This function takes an unsigned long integer value in the range 0 -
+0x7fffffff and encodes it as a UTF-8 character in 1 to 6 bytes.
+
+Arguments:
+  cvalue     the character value
+  buffer     pointer to buffer for result - at least 6 bytes long
+
+Returns:     number of bytes placed in the buffer
+             0 if input code point is too big
+*/
+
+static size_t
+ord2utf8(unsigned long int cvalue, unsigned char *buffer)
+{
+size_t i, j;
+for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++)
+  if (cvalue <= utf8_table1[i]) break;
+if (i >= sizeof(utf8_table1)/sizeof(int)) return 0;
+buffer += i;
+for (j = i; j > 0; j--)
+ {
+ *buffer-- = 0x80 | (cvalue & 0x3f);
+ cvalue >>= 6;
+ }
+*buffer = utf8_table2[i] | cvalue;
+return i + 1;
+}
+
+
+
+/*************************************************
+*            Convert UTF-8 string to value       *
+*************************************************/
+
+/* This function takes one or more bytes that represent a UTF-8 character from
+the start of a string of bytes. It returns the value of the character, or the
+offset of a malformation. For an overlong encoding that works but is not the
+correct (shortest) one, the error offset is just after the last byte.
+
+Argument:
+  buffer   a pointer to the byte vector
+  buffend  a pointer to the end of the buffer
+  vptr     a pointer to a variable to receive the value
+  lenptr   a pointer to a variable to receive the offset when error detected
+
+Returns:   > 0 => the number of bytes consumed
+             0 => invalid UTF-8: first byte missing 0x40 bit
+            -1 => invalid UTF-8: first byte has too many high-order 1-bits
+            -2 => incomplete sequence at end of string
+            -3 => incomplete sequence within string
+            -4 => overlong code sequence
+*/
+
+static int
+utf82ord(unsigned char *buffer, unsigned char *buffend,
+  long unsigned int *vptr, int *lenptr)
+{
+unsigned int c = *buffer++;
+unsigned int d = c;
+int i, j, s;
+
+/* Check for an ASCII character, or find the number of additional bytes in a
+multibyte character. */
+
+for (i = -1; i < 6; i++)
+  {
+  if ((d & 0x80) == 0) break;
+  d <<= 1;
+  }
+
+switch (i)
+  {
+  case -1:      /* ASCII character; first byte does not have 0x80 bit */
+  *vptr = c;
+  return 1;
+
+  case 0:       /* First byte has 0x80 but is missing 0x40 bit */
+  *lenptr = 0;
+  return 0;
+
+  case 6:
+  *lenptr = 0;  /* Too many high bits */
+  return -1;
+
+  default:
+  break;
+  }
+
+/* i now has a value in the range 1-5 */
+
+s = 6*i;
+d = (c & utf8_table3[i]) << s;
+
+for (j = 0; j < i; j++)
+  {
+  if (buffer >= buffend)
+    {
+    *lenptr = j + 1;
+    return -2;
+    }
+  c = *buffer++;
+  if ((c & 0xc0) != 0x80)
+    {
+    *lenptr = j + 1;
+    return -3;
+    }
+  s -= 6;
+  d |= (c & 0x3f) << s;
+  }
+
+/* Valid UTF-8 syntax */
+
+*vptr = d;
+
+/* Check that encoding was the correct one, not overlong */
+
+for (j = 0; j < (int)(sizeof(utf8_table1)/sizeof(int)); j++)
+  if (d <= utf8_table1[j]) break;
+if (j != i)
+  {
+  *lenptr = i + 1;
+  return -4;
+  }
+
+/* Valid value */
+
+return i + 1;
+}
+
+
+
+/*************************************************
+*                 Main Program                   *
+*************************************************/
+
+int
+main(int argc, char **argv)
+{
+int i = 1;
+int show = 0;
+unsigned char buffer[64];
+
+if (argc > 1 && strcmp(argv[1], "-s") == 0)
+  {
+  show = 1;
+  i = 2;
+  }
+
+for (; i < argc; i++)
+  {
+  char *x = argv[i];
+  char *endptr;
+  if (strncmp(x, "0x", 2) == 0 || strncmp(x, "U+", 2) == 0)
+    {
+    size_t rc, j;
+    unsigned long int d = strtoul(x+2, &endptr, 16);
+    if (*endptr != 0)
+      {
+      printf("** Invalid hex number %s\n", x);
+      continue;   /* With next argument */
+      }
+    rc = ord2utf8(d, buffer);
+    printf("U+%08lx => ", d);
+    if (rc == 0)
+      printf("** Code point greater than 0x7fffffff cannot be encoded");
+    else
+      {
+      for (j = 0; j < rc; j++) printf("%02x ", buffer[j]);
+      if (show)
+        {
+        printf(">");
+        for (j = 0; j < rc; j++) printf("%c", buffer[j]);
+        printf("< ");
+        }
+      if (d >= 0xd800 && d <= 0xdfff)
+        printf("** Invalid Unicode (surrogate)");
+      else if (d > 0x10ffff)
+        printf("** Invalid Unicode (greater than U+10ffff)");
+      }
+    printf("\n");
+    }
+  else
+    {
+    unsigned char *bptr;
+    unsigned char *buffend;
+    int len = 0;
+    int y = 0;
+    int z = 0;
+
+    for (;;)
+      {
+      while (*x == ' ') x++;
+      if (*x == 0 && !z) break;
+      if (!isxdigit(*x))
+        {
+        printf("** Malformed hex string: %s\n", argv[i]);
+        len = -1;
+        break;
+        }
+      y = y * 16 + tolower(*x) - ((isdigit(*x))? '0' : 'W');
+      x++;
+      if (z)
+        {
+        buffer[len++] = y;
+        y = 0;
+        }
+      z ^= 1;
+      }
+
+    if (len < 0) continue;  /* With next argument after malformation */
+
+    bptr = buffer;
+    buffend = buffer + len;
+
+    while (bptr < buffend)
+      {
+      unsigned long int d;
+      int j;
+      int offset;
+      int rc = utf82ord(bptr, buffend, &d, &offset);
+
+      if (rc > 0)
+        {
+        printf("U+%08lx <= ", d);
+        for (j = 0; j < rc; j++) printf("%02x ", bptr[j]);
+        if (show)
+          {
+          printf(">");
+          for (j = 0; j < rc; j++) printf("%c", bptr[j]);
+          printf("<");
+          }
+        printf("\n");
+        bptr += rc;
+        }
+      else if (rc == -4)
+        {
+        printf("U+%08lx <= ", d);
+        for (j = 0; j < offset; j++) printf("%02x ", bptr[j]);
+        printf("** Overlong UTF-8 sequence\n");
+        bptr += offset;
+        }
+      else
+        {
+        switch (rc)
+          {
+          case 0:  printf("** First byte missing 0x40 bit");
+          break;
+
+          case -1: printf("** First byte has too many high-order bits");
+          break;
+
+          case -2: printf("** Incomplete UTF-8 sequence at end of string");
+          break;
+
+          case -3: printf("** Incomplete UTF-8 sequence");
+          break;
+
+          default: printf("** Unexpected return %d from utf82ord()", rc);
+          break;
+          }
+        printf(" at offset %d in string ", offset);
+        while (bptr < buffend) printf("%02x ", *bptr++);
+        printf("\n");
+        break;
+        }
+      }
+    }
+  }
+
+return 0;
+}
+
+/* End */
diff --git a/src/c/pcre2/src/pcre2_auto_possess.c b/src/c/pcre2/src/pcre2_auto_possess.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_auto_possess.c
@@ -0,0 +1,1343 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2020 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains functions that scan a compiled pattern and change
+repeats into possessive repeats where possible. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "pcre2_internal.h"
+
+
+/*************************************************
+*        Tables for auto-possessification        *
+*************************************************/
+
+/* This table is used to check whether auto-possessification is possible
+between adjacent character-type opcodes. The left-hand (repeated) opcode is
+used to select the row, and the right-hand opcode is use to select the column.
+A value of 1 means that auto-possessification is OK. For example, the second
+value in the first row means that \D+\d can be turned into \D++\d.
+
+The Unicode property types (\P and \p) have to be present to fill out the table
+because of what their opcode values are, but the table values should always be
+zero because property types are handled separately in the code. The last four
+columns apply to items that cannot be repeated, so there is no need to have
+rows for them. Note that OP_DIGIT etc. are generated only when PCRE_UCP is
+*not* set. When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */
+
+#define APTROWS (LAST_AUTOTAB_LEFT_OP - FIRST_AUTOTAB_OP + 1)
+#define APTCOLS (LAST_AUTOTAB_RIGHT_OP - FIRST_AUTOTAB_OP + 1)
+
+static const uint8_t autoposstab[APTROWS][APTCOLS] = {
+/* \D \d \S \s \W \w  . .+ \C \P \p \R \H \h \V \v \X \Z \z  $ $M */
+  { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },  /* \D */
+  { 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 },  /* \d */
+  { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 },  /* \S */
+  { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },  /* \s */
+  { 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },  /* \W */
+  { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 },  /* \w */
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0 },  /* .  */
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },  /* .+ */
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },  /* \C */
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },  /* \P */
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },  /* \p */
+  { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 },  /* \R */
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 },  /* \H */
+  { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0 },  /* \h */
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0 },  /* \V */
+  { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0 },  /* \v */
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }   /* \X */
+};
+
+#ifdef SUPPORT_UNICODE
+/* This table is used to check whether auto-possessification is possible
+between adjacent Unicode property opcodes (OP_PROP and OP_NOTPROP). The
+left-hand (repeated) opcode is used to select the row, and the right-hand
+opcode is used to select the column. The values are as follows:
+
+  0   Always return FALSE (never auto-possessify)
+  1   Character groups are distinct (possessify if both are OP_PROP)
+  2   Check character categories in the same group (general or particular)
+  3   TRUE if the two opcodes are not the same (PROP vs NOTPROP)
+
+  4   Check left general category vs right particular category
+  5   Check right general category vs left particular category
+
+  6   Left alphanum vs right general category
+  7   Left space vs right general category
+  8   Left word vs right general category
+
+  9   Right alphanum vs left general category
+ 10   Right space vs left general category
+ 11   Right word vs left general category
+
+ 12   Left alphanum vs right particular category
+ 13   Left space vs right particular category
+ 14   Left word vs right particular category
+
+ 15   Right alphanum vs left particular category
+ 16   Right space vs left particular category
+ 17   Right word vs left particular category
+*/
+
+static const uint8_t propposstab[PT_TABSIZE][PT_TABSIZE] = {
+/* ANY LAMP GC  PC  SC ALNUM SPACE PXSPACE WORD CLIST UCNC */
+  { 0,  0,  0,  0,  0,    0,    0,      0,   0,    0,   0 },  /* PT_ANY */
+  { 0,  3,  0,  0,  0,    3,    1,      1,   0,    0,   0 },  /* PT_LAMP */
+  { 0,  0,  2,  4,  0,    9,   10,     10,  11,    0,   0 },  /* PT_GC */
+  { 0,  0,  5,  2,  0,   15,   16,     16,  17,    0,   0 },  /* PT_PC */
+  { 0,  0,  0,  0,  2,    0,    0,      0,   0,    0,   0 },  /* PT_SC */
+  { 0,  3,  6, 12,  0,    3,    1,      1,   0,    0,   0 },  /* PT_ALNUM */
+  { 0,  1,  7, 13,  0,    1,    3,      3,   1,    0,   0 },  /* PT_SPACE */
+  { 0,  1,  7, 13,  0,    1,    3,      3,   1,    0,   0 },  /* PT_PXSPACE */
+  { 0,  0,  8, 14,  0,    0,    1,      1,   3,    0,   0 },  /* PT_WORD */
+  { 0,  0,  0,  0,  0,    0,    0,      0,   0,    0,   0 },  /* PT_CLIST */
+  { 0,  0,  0,  0,  0,    0,    0,      0,   0,    0,   3 }   /* PT_UCNC */
+};
+
+/* This table is used to check whether auto-possessification is possible
+between adjacent Unicode property opcodes (OP_PROP and OP_NOTPROP) when one
+specifies a general category and the other specifies a particular category. The
+row is selected by the general category and the column by the particular
+category. The value is 1 if the particular category is not part of the general
+category. */
+
+static const uint8_t catposstab[7][30] = {
+/* Cc Cf Cn Co Cs Ll Lm Lo Lt Lu Mc Me Mn Nd Nl No Pc Pd Pe Pf Pi Po Ps Sc Sk Sm So Zl Zp Zs */
+  { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },  /* C */
+  { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },  /* L */
+  { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },  /* M */
+  { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },  /* N */
+  { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 },  /* P */
+  { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1 },  /* S */
+  { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }   /* Z */
+};
+
+/* This table is used when checking ALNUM, (PX)SPACE, SPACE, and WORD against
+a general or particular category. The properties in each row are those
+that apply to the character set in question. Duplication means that a little
+unnecessary work is done when checking, but this keeps things much simpler
+because they can all use the same code. For more details see the comment where
+this table is used.
+
+Note: SPACE and PXSPACE used to be different because Perl excluded VT from
+"space", but from Perl 5.18 it's included, so both categories are treated the
+same here. */
+
+static const uint8_t posspropstab[3][4] = {
+  { ucp_L, ucp_N, ucp_N, ucp_Nl },  /* ALNUM, 3rd and 4th values redundant */
+  { ucp_Z, ucp_Z, ucp_C, ucp_Cc },  /* SPACE and PXSPACE, 2nd value redundant */
+  { ucp_L, ucp_N, ucp_P, ucp_Po }   /* WORD */
+};
+#endif  /* SUPPORT_UNICODE */
+
+
+
+#ifdef SUPPORT_UNICODE
+/*************************************************
+*        Check a character and a property        *
+*************************************************/
+
+/* This function is called by compare_opcodes() when a property item is
+adjacent to a fixed character.
+
+Arguments:
+  c            the character
+  ptype        the property type
+  pdata        the data for the type
+  negated      TRUE if it's a negated property (\P or \p{^)
+
+Returns:       TRUE if auto-possessifying is OK
+*/
+
+static BOOL
+check_char_prop(uint32_t c, unsigned int ptype, unsigned int pdata,
+  BOOL negated)
+{
+const uint32_t *p;
+const ucd_record *prop = GET_UCD(c);
+
+switch(ptype)
+  {
+  case PT_LAMP:
+  return (prop->chartype == ucp_Lu ||
+          prop->chartype == ucp_Ll ||
+          prop->chartype == ucp_Lt) == negated;
+
+  case PT_GC:
+  return (pdata == PRIV(ucp_gentype)[prop->chartype]) == negated;
+
+  case PT_PC:
+  return (pdata == prop->chartype) == negated;
+
+  case PT_SC:
+  return (pdata == prop->script) == negated;
+
+  /* These are specials */
+
+  case PT_ALNUM:
+  return (PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+          PRIV(ucp_gentype)[prop->chartype] == ucp_N) == negated;
+
+  /* Perl space used to exclude VT, but from Perl 5.18 it is included, which
+  means that Perl space and POSIX space are now identical. PCRE was changed
+  at release 8.34. */
+
+  case PT_SPACE:    /* Perl space */
+  case PT_PXSPACE:  /* POSIX space */
+  switch(c)
+    {
+    HSPACE_CASES:
+    VSPACE_CASES:
+    return negated;
+
+    default:
+    return (PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == negated;
+    }
+  break;  /* Control never reaches here */
+
+  case PT_WORD:
+  return (PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+          PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
+          c == CHAR_UNDERSCORE) == negated;
+
+  case PT_CLIST:
+  p = PRIV(ucd_caseless_sets) + prop->caseset;
+  for (;;)
+    {
+    if (c < *p) return !negated;
+    if (c == *p++) return negated;
+    }
+  break;  /* Control never reaches here */
+  }
+
+return FALSE;
+}
+#endif  /* SUPPORT_UNICODE */
+
+
+
+/*************************************************
+*        Base opcode of repeated opcodes         *
+*************************************************/
+
+/* Returns the base opcode for repeated single character type opcodes. If the
+opcode is not a repeated character type, it returns with the original value.
+
+Arguments:  c opcode
+Returns:    base opcode for the type
+*/
+
+static PCRE2_UCHAR
+get_repeat_base(PCRE2_UCHAR c)
+{
+return (c > OP_TYPEPOSUPTO)? c :
+       (c >= OP_TYPESTAR)?   OP_TYPESTAR :
+       (c >= OP_NOTSTARI)?   OP_NOTSTARI :
+       (c >= OP_NOTSTAR)?    OP_NOTSTAR :
+       (c >= OP_STARI)?      OP_STARI :
+                             OP_STAR;
+}
+
+
+/*************************************************
+*        Fill the character property list        *
+*************************************************/
+
+/* Checks whether the code points to an opcode that can take part in auto-
+possessification, and if so, fills a list with its properties.
+
+Arguments:
+  code        points to start of expression
+  utf         TRUE if in UTF mode
+  ucp         TRUE if in UCP mode
+  fcc         points to the case-flipping table
+  list        points to output list
+              list[0] will be filled with the opcode
+              list[1] will be non-zero if this opcode
+                can match an empty character string
+              list[2..7] depends on the opcode
+
+Returns:      points to the start of the next opcode if *code is accepted
+              NULL if *code is not accepted
+*/
+
+static PCRE2_SPTR
+get_chr_property_list(PCRE2_SPTR code, BOOL utf, BOOL ucp, const uint8_t *fcc,
+  uint32_t *list)
+{
+PCRE2_UCHAR c = *code;
+PCRE2_UCHAR base;
+PCRE2_SPTR end;
+uint32_t chr;
+
+#ifdef SUPPORT_UNICODE
+uint32_t *clist_dest;
+const uint32_t *clist_src;
+#else
+(void)utf;    /* Suppress "unused parameter" compiler warnings */
+(void)ucp;
+#endif
+
+list[0] = c;
+list[1] = FALSE;
+code++;
+
+if (c >= OP_STAR && c <= OP_TYPEPOSUPTO)
+  {
+  base = get_repeat_base(c);
+  c -= (base - OP_STAR);
+
+  if (c == OP_UPTO || c == OP_MINUPTO || c == OP_EXACT || c == OP_POSUPTO)
+    code += IMM2_SIZE;
+
+  list[1] = (c != OP_PLUS && c != OP_MINPLUS && c != OP_EXACT &&
+             c != OP_POSPLUS);
+
+  switch(base)
+    {
+    case OP_STAR:
+    list[0] = OP_CHAR;
+    break;
+
+    case OP_STARI:
+    list[0] = OP_CHARI;
+    break;
+
+    case OP_NOTSTAR:
+    list[0] = OP_NOT;
+    break;
+
+    case OP_NOTSTARI:
+    list[0] = OP_NOTI;
+    break;
+
+    case OP_TYPESTAR:
+    list[0] = *code;
+    code++;
+    break;
+    }
+  c = list[0];
+  }
+
+switch(c)
+  {
+  case OP_NOT_DIGIT:
+  case OP_DIGIT:
+  case OP_NOT_WHITESPACE:
+  case OP_WHITESPACE:
+  case OP_NOT_WORDCHAR:
+  case OP_WORDCHAR:
+  case OP_ANY:
+  case OP_ALLANY:
+  case OP_ANYNL:
+  case OP_NOT_HSPACE:
+  case OP_HSPACE:
+  case OP_NOT_VSPACE:
+  case OP_VSPACE:
+  case OP_EXTUNI:
+  case OP_EODN:
+  case OP_EOD:
+  case OP_DOLL:
+  case OP_DOLLM:
+  return code;
+
+  case OP_CHAR:
+  case OP_NOT:
+  GETCHARINCTEST(chr, code);
+  list[2] = chr;
+  list[3] = NOTACHAR;
+  return code;
+
+  case OP_CHARI:
+  case OP_NOTI:
+  list[0] = (c == OP_CHARI) ? OP_CHAR : OP_NOT;
+  GETCHARINCTEST(chr, code);
+  list[2] = chr;
+
+#ifdef SUPPORT_UNICODE
+  if (chr < 128 || (chr < 256 && !utf && !ucp))
+    list[3] = fcc[chr];
+  else
+    list[3] = UCD_OTHERCASE(chr);
+#elif defined SUPPORT_WIDE_CHARS
+  list[3] = (chr < 256) ? fcc[chr] : chr;
+#else
+  list[3] = fcc[chr];
+#endif
+
+  /* The othercase might be the same value. */
+
+  if (chr == list[3])
+    list[3] = NOTACHAR;
+  else
+    list[4] = NOTACHAR;
+  return code;
+
+#ifdef SUPPORT_UNICODE
+  case OP_PROP:
+  case OP_NOTPROP:
+  if (code[0] != PT_CLIST)
+    {
+    list[2] = code[0];
+    list[3] = code[1];
+    return code + 2;
+    }
+
+  /* Convert only if we have enough space. */
+
+  clist_src = PRIV(ucd_caseless_sets) + code[1];
+  clist_dest = list + 2;
+  code += 2;
+
+  do {
+     if (clist_dest >= list + 8)
+       {
+       /* Early return if there is not enough space. This should never
+       happen, since all clists are shorter than 5 character now. */
+       list[2] = code[0];
+       list[3] = code[1];
+       return code;
+       }
+     *clist_dest++ = *clist_src;
+     }
+  while(*clist_src++ != NOTACHAR);
+
+  /* All characters are stored. The terminating NOTACHAR is copied from the
+  clist itself. */
+
+  list[0] = (c == OP_PROP) ? OP_CHAR : OP_NOT;
+  return code;
+#endif
+
+  case OP_NCLASS:
+  case OP_CLASS:
+#ifdef SUPPORT_WIDE_CHARS
+  case OP_XCLASS:
+  if (c == OP_XCLASS)
+    end = code + GET(code, 0) - 1;
+  else
+#endif
+    end = code + 32 / sizeof(PCRE2_UCHAR);
+
+  switch(*end)
+    {
+    case OP_CRSTAR:
+    case OP_CRMINSTAR:
+    case OP_CRQUERY:
+    case OP_CRMINQUERY:
+    case OP_CRPOSSTAR:
+    case OP_CRPOSQUERY:
+    list[1] = TRUE;
+    end++;
+    break;
+
+    case OP_CRPLUS:
+    case OP_CRMINPLUS:
+    case OP_CRPOSPLUS:
+    end++;
+    break;
+
+    case OP_CRRANGE:
+    case OP_CRMINRANGE:
+    case OP_CRPOSRANGE:
+    list[1] = (GET2(end, 1) == 0);
+    end += 1 + 2 * IMM2_SIZE;
+    break;
+    }
+  list[2] = (uint32_t)(end - code);
+  return end;
+  }
+return NULL;    /* Opcode not accepted */
+}
+
+
+
+/*************************************************
+*    Scan further character sets for match       *
+*************************************************/
+
+/* Checks whether the base and the current opcode have a common character, in
+which case the base cannot be possessified.
+
+Arguments:
+  code        points to the byte code
+  utf         TRUE in UTF mode
+  ucp         TRUE in UCP mode
+  cb          compile data block
+  base_list   the data list of the base opcode
+  base_end    the end of the base opcode
+  rec_limit   points to recursion depth counter
+
+Returns:      TRUE if the auto-possessification is possible
+*/
+
+static BOOL
+compare_opcodes(PCRE2_SPTR code, BOOL utf, BOOL ucp, const compile_block *cb,
+  const uint32_t *base_list, PCRE2_SPTR base_end, int *rec_limit)
+{
+PCRE2_UCHAR c;
+uint32_t list[8];
+const uint32_t *chr_ptr;
+const uint32_t *ochr_ptr;
+const uint32_t *list_ptr;
+PCRE2_SPTR next_code;
+#ifdef SUPPORT_WIDE_CHARS
+PCRE2_SPTR xclass_flags;
+#endif
+const uint8_t *class_bitset;
+const uint8_t *set1, *set2, *set_end;
+uint32_t chr;
+BOOL accepted, invert_bits;
+BOOL entered_a_group = FALSE;
+
+if (--(*rec_limit) <= 0) return FALSE;  /* Recursion has gone too deep */
+
+/* Note: the base_list[1] contains whether the current opcode has a greedy
+(represented by a non-zero value) quantifier. This is a different from
+other character type lists, which store here that the character iterator
+matches to an empty string (also represented by a non-zero value). */
+
+for(;;)
+  {
+  /* All operations move the code pointer forward.
+  Therefore infinite recursions are not possible. */
+
+  c = *code;
+
+  /* Skip over callouts */
+
+  if (c == OP_CALLOUT)
+    {
+    code += PRIV(OP_lengths)[c];
+    continue;
+    }
+
+  if (c == OP_CALLOUT_STR)
+    {
+    code += GET(code, 1 + 2*LINK_SIZE);
+    continue;
+    }
+
+  /* At the end of a branch, skip to the end of the group. */
+
+  if (c == OP_ALT)
+    {
+    do code += GET(code, 1); while (*code == OP_ALT);
+    c = *code;
+    }
+
+  /* Inspect the next opcode. */
+
+  switch(c)
+    {
+    /* We can always possessify a greedy iterator at the end of the pattern,
+    which is reached after skipping over the final OP_KET. A non-greedy
+    iterator must never be possessified. */
+
+    case OP_END:
+    return base_list[1] != 0;
+
+    /* When an iterator is at the end of certain kinds of group we can inspect
+    what follows the group by skipping over the closing ket. Note that this
+    does not apply to OP_KETRMAX or OP_KETRMIN because what follows any given
+    iteration is variable (could be another iteration or could be the next
+    item). As these two opcodes are not listed in the next switch, they will
+    end up as the next code to inspect, and return FALSE by virtue of being
+    unsupported. */
+
+    case OP_KET:
+    case OP_KETRPOS:
+    /* The non-greedy case cannot be converted to a possessive form. */
+
+    if (base_list[1] == 0) return FALSE;
+
+    /* If the bracket is capturing it might be referenced by an OP_RECURSE
+    so its last iterator can never be possessified if the pattern contains
+    recursions. (This could be improved by keeping a list of group numbers that
+    are called by recursion.) */
+
+    switch(*(code - GET(code, 1)))
+      {
+      case OP_CBRA:
+      case OP_SCBRA:
+      case OP_CBRAPOS:
+      case OP_SCBRAPOS:
+      if (cb->had_recurse) return FALSE;
+      break;
+
+      /* A script run might have to backtrack if the iterated item can match
+      characters from more than one script. So give up unless repeating an
+      explicit character. */
+
+      case OP_SCRIPT_RUN:
+      if (base_list[0] != OP_CHAR && base_list[0] != OP_CHARI)
+        return FALSE;
+      break;
+
+      /* Atomic sub-patterns and assertions can always auto-possessify their
+      last iterator. However, if the group was entered as a result of checking
+      a previous iterator, this is not possible. */
+
+      case OP_ASSERT:
+      case OP_ASSERT_NOT:
+      case OP_ASSERTBACK:
+      case OP_ASSERTBACK_NOT:
+      case OP_ONCE:
+      return !entered_a_group;
+
+      /* Non-atomic assertions - don't possessify last iterator. This needs
+      more thought. */
+
+      case OP_ASSERT_NA:
+      case OP_ASSERTBACK_NA:
+      return FALSE;
+      }
+
+    /* Skip over the bracket and inspect what comes next. */
+
+    code += PRIV(OP_lengths)[c];
+    continue;
+
+    /* Handle cases where the next item is a group. */
+
+    case OP_ONCE:
+    case OP_BRA:
+    case OP_CBRA:
+    next_code = code + GET(code, 1);
+    code += PRIV(OP_lengths)[c];
+
+    /* Check each branch. We have to recurse a level for all but the last
+    branch. */
+
+    while (*next_code == OP_ALT)
+      {
+      if (!compare_opcodes(code, utf, ucp, cb, base_list, base_end, rec_limit))
+        return FALSE;
+      code = next_code + 1 + LINK_SIZE;
+      next_code += GET(next_code, 1);
+      }
+
+    entered_a_group = TRUE;
+    continue;
+
+    case OP_BRAZERO:
+    case OP_BRAMINZERO:
+
+    next_code = code + 1;
+    if (*next_code != OP_BRA && *next_code != OP_CBRA &&
+        *next_code != OP_ONCE) return FALSE;
+
+    do next_code += GET(next_code, 1); while (*next_code == OP_ALT);
+
+    /* The bracket content will be checked by the OP_BRA/OP_CBRA case above. */
+
+    next_code += 1 + LINK_SIZE;
+    if (!compare_opcodes(next_code, utf, ucp, cb, base_list, base_end,
+         rec_limit))
+      return FALSE;
+
+    code += PRIV(OP_lengths)[c];
+    continue;
+
+    /* The next opcode does not need special handling; fall through and use it
+    to see if the base can be possessified. */
+
+    default:
+    break;
+    }
+
+  /* We now have the next appropriate opcode to compare with the base. Check
+  for a supported opcode, and load its properties. */
+
+  code = get_chr_property_list(code, utf, ucp, cb->fcc, list);
+  if (code == NULL) return FALSE;    /* Unsupported */
+
+  /* If either opcode is a small character list, set pointers for comparing
+  characters from that list with another list, or with a property. */
+
+  if (base_list[0] == OP_CHAR)
+    {
+    chr_ptr = base_list + 2;
+    list_ptr = list;
+    }
+  else if (list[0] == OP_CHAR)
+    {
+    chr_ptr = list + 2;
+    list_ptr = base_list;
+    }
+
+  /* Character bitsets can also be compared to certain opcodes. */
+
+  else if (base_list[0] == OP_CLASS || list[0] == OP_CLASS
+#if PCRE2_CODE_UNIT_WIDTH == 8
+      /* In 8 bit, non-UTF mode, OP_CLASS and OP_NCLASS are the same. */
+      || (!utf && (base_list[0] == OP_NCLASS || list[0] == OP_NCLASS))
+#endif
+      )
+    {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+    if (base_list[0] == OP_CLASS || (!utf && base_list[0] == OP_NCLASS))
+#else
+    if (base_list[0] == OP_CLASS)
+#endif
+      {
+      set1 = (uint8_t *)(base_end - base_list[2]);
+      list_ptr = list;
+      }
+    else
+      {
+      set1 = (uint8_t *)(code - list[2]);
+      list_ptr = base_list;
+      }
+
+    invert_bits = FALSE;
+    switch(list_ptr[0])
+      {
+      case OP_CLASS:
+      case OP_NCLASS:
+      set2 = (uint8_t *)
+        ((list_ptr == list ? code : base_end) - list_ptr[2]);
+      break;
+
+#ifdef SUPPORT_WIDE_CHARS
+      case OP_XCLASS:
+      xclass_flags = (list_ptr == list ? code : base_end) - list_ptr[2] + LINK_SIZE;
+      if ((*xclass_flags & XCL_HASPROP) != 0) return FALSE;
+      if ((*xclass_flags & XCL_MAP) == 0)
+        {
+        /* No bits are set for characters < 256. */
+        if (list[1] == 0) return (*xclass_flags & XCL_NOT) == 0;
+        /* Might be an empty repeat. */
+        continue;
+        }
+      set2 = (uint8_t *)(xclass_flags + 1);
+      break;
+#endif
+
+      case OP_NOT_DIGIT:
+      invert_bits = TRUE;
+      /* Fall through */
+      case OP_DIGIT:
+      set2 = (uint8_t *)(cb->cbits + cbit_digit);
+      break;
+
+      case OP_NOT_WHITESPACE:
+      invert_bits = TRUE;
+      /* Fall through */
+      case OP_WHITESPACE:
+      set2 = (uint8_t *)(cb->cbits + cbit_space);
+      break;
+
+      case OP_NOT_WORDCHAR:
+      invert_bits = TRUE;
+      /* Fall through */
+      case OP_WORDCHAR:
+      set2 = (uint8_t *)(cb->cbits + cbit_word);
+      break;
+
+      default:
+      return FALSE;
+      }
+
+    /* Because the bit sets are unaligned bytes, we need to perform byte
+    comparison here. */
+
+    set_end = set1 + 32;
+    if (invert_bits)
+      {
+      do
+        {
+        if ((*set1++ & ~(*set2++)) != 0) return FALSE;
+        }
+      while (set1 < set_end);
+      }
+    else
+      {
+      do
+        {
+        if ((*set1++ & *set2++) != 0) return FALSE;
+        }
+      while (set1 < set_end);
+      }
+
+    if (list[1] == 0) return TRUE;
+    /* Might be an empty repeat. */
+    continue;
+    }
+
+  /* Some property combinations also acceptable. Unicode property opcodes are
+  processed specially; the rest can be handled with a lookup table. */
+
+  else
+    {
+    uint32_t leftop, rightop;
+
+    leftop = base_list[0];
+    rightop = list[0];
+
+#ifdef SUPPORT_UNICODE
+    accepted = FALSE; /* Always set in non-unicode case. */
+    if (leftop == OP_PROP || leftop == OP_NOTPROP)
+      {
+      if (rightop == OP_EOD)
+        accepted = TRUE;
+      else if (rightop == OP_PROP || rightop == OP_NOTPROP)
+        {
+        int n;
+        const uint8_t *p;
+        BOOL same = leftop == rightop;
+        BOOL lisprop = leftop == OP_PROP;
+        BOOL risprop = rightop == OP_PROP;
+        BOOL bothprop = lisprop && risprop;
+
+        /* There's a table that specifies how each combination is to be
+        processed:
+          0   Always return FALSE (never auto-possessify)
+          1   Character groups are distinct (possessify if both are OP_PROP)
+          2   Check character categories in the same group (general or particular)
+          3   Return TRUE if the two opcodes are not the same
+          ... see comments below
+        */
+
+        n = propposstab[base_list[2]][list[2]];
+        switch(n)
+          {
+          case 0: break;
+          case 1: accepted = bothprop; break;
+          case 2: accepted = (base_list[3] == list[3]) != same; break;
+          case 3: accepted = !same; break;
+
+          case 4:  /* Left general category, right particular category */
+          accepted = risprop && catposstab[base_list[3]][list[3]] == same;
+          break;
+
+          case 5:  /* Right general category, left particular category */
+          accepted = lisprop && catposstab[list[3]][base_list[3]] == same;
+          break;
+
+          /* This code is logically tricky. Think hard before fiddling with it.
+          The posspropstab table has four entries per row. Each row relates to
+          one of PCRE's special properties such as ALNUM or SPACE or WORD.
+          Only WORD actually needs all four entries, but using repeats for the
+          others means they can all use the same code below.
+
+          The first two entries in each row are Unicode general categories, and
+          apply always, because all the characters they include are part of the
+          PCRE character set. The third and fourth entries are a general and a
+          particular category, respectively, that include one or more relevant
+          characters. One or the other is used, depending on whether the check
+          is for a general or a particular category. However, in both cases the
+          category contains more characters than the specials that are defined
+          for the property being tested against. Therefore, it cannot be used
+          in a NOTPROP case.
+
+          Example: the row for WORD contains ucp_L, ucp_N, ucp_P, ucp_Po.
+          Underscore is covered by ucp_P or ucp_Po. */
+
+          case 6:  /* Left alphanum vs right general category */
+          case 7:  /* Left space vs right general category */
+          case 8:  /* Left word vs right general category */
+          p = posspropstab[n-6];
+          accepted = risprop && lisprop ==
+            (list[3] != p[0] &&
+             list[3] != p[1] &&
+            (list[3] != p[2] || !lisprop));
+          break;
+
+          case 9:   /* Right alphanum vs left general category */
+          case 10:  /* Right space vs left general category */
+          case 11:  /* Right word vs left general category */
+          p = posspropstab[n-9];
+          accepted = lisprop && risprop ==
+            (base_list[3] != p[0] &&
+             base_list[3] != p[1] &&
+            (base_list[3] != p[2] || !risprop));
+          break;
+
+          case 12:  /* Left alphanum vs right particular category */
+          case 13:  /* Left space vs right particular category */
+          case 14:  /* Left word vs right particular category */
+          p = posspropstab[n-12];
+          accepted = risprop && lisprop ==
+            (catposstab[p[0]][list[3]] &&
+             catposstab[p[1]][list[3]] &&
+            (list[3] != p[3] || !lisprop));
+          break;
+
+          case 15:  /* Right alphanum vs left particular category */
+          case 16:  /* Right space vs left particular category */
+          case 17:  /* Right word vs left particular category */
+          p = posspropstab[n-15];
+          accepted = lisprop && risprop ==
+            (catposstab[p[0]][base_list[3]] &&
+             catposstab[p[1]][base_list[3]] &&
+            (base_list[3] != p[3] || !risprop));
+          break;
+          }
+        }
+      }
+
+    else
+#endif  /* SUPPORT_UNICODE */
+
+    accepted = leftop >= FIRST_AUTOTAB_OP && leftop <= LAST_AUTOTAB_LEFT_OP &&
+           rightop >= FIRST_AUTOTAB_OP && rightop <= LAST_AUTOTAB_RIGHT_OP &&
+           autoposstab[leftop - FIRST_AUTOTAB_OP][rightop - FIRST_AUTOTAB_OP];
+
+    if (!accepted) return FALSE;
+
+    if (list[1] == 0) return TRUE;
+    /* Might be an empty repeat. */
+    continue;
+    }
+
+  /* Control reaches here only if one of the items is a small character list.
+  All characters are checked against the other side. */
+
+  do
+    {
+    chr = *chr_ptr;
+
+    switch(list_ptr[0])
+      {
+      case OP_CHAR:
+      ochr_ptr = list_ptr + 2;
+      do
+        {
+        if (chr == *ochr_ptr) return FALSE;
+        ochr_ptr++;
+        }
+      while(*ochr_ptr != NOTACHAR);
+      break;
+
+      case OP_NOT:
+      ochr_ptr = list_ptr + 2;
+      do
+        {
+        if (chr == *ochr_ptr)
+          break;
+        ochr_ptr++;
+        }
+      while(*ochr_ptr != NOTACHAR);
+      if (*ochr_ptr == NOTACHAR) return FALSE;   /* Not found */
+      break;
+
+      /* Note that OP_DIGIT etc. are generated only when PCRE2_UCP is *not*
+      set. When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */
+
+      case OP_DIGIT:
+      if (chr < 256 && (cb->ctypes[chr] & ctype_digit) != 0) return FALSE;
+      break;
+
+      case OP_NOT_DIGIT:
+      if (chr > 255 || (cb->ctypes[chr] & ctype_digit) == 0) return FALSE;
+      break;
+
+      case OP_WHITESPACE:
+      if (chr < 256 && (cb->ctypes[chr] & ctype_space) != 0) return FALSE;
+      break;
+
+      case OP_NOT_WHITESPACE:
+      if (chr > 255 || (cb->ctypes[chr] & ctype_space) == 0) return FALSE;
+      break;
+
+      case OP_WORDCHAR:
+      if (chr < 255 && (cb->ctypes[chr] & ctype_word) != 0) return FALSE;
+      break;
+
+      case OP_NOT_WORDCHAR:
+      if (chr > 255 || (cb->ctypes[chr] & ctype_word) == 0) return FALSE;
+      break;
+
+      case OP_HSPACE:
+      switch(chr)
+        {
+        HSPACE_CASES: return FALSE;
+        default: break;
+        }
+      break;
+
+      case OP_NOT_HSPACE:
+      switch(chr)
+        {
+        HSPACE_CASES: break;
+        default: return FALSE;
+        }
+      break;
+
+      case OP_ANYNL:
+      case OP_VSPACE:
+      switch(chr)
+        {
+        VSPACE_CASES: return FALSE;
+        default: break;
+        }
+      break;
+
+      case OP_NOT_VSPACE:
+      switch(chr)
+        {
+        VSPACE_CASES: break;
+        default: return FALSE;
+        }
+      break;
+
+      case OP_DOLL:
+      case OP_EODN:
+      switch (chr)
+        {
+        case CHAR_CR:
+        case CHAR_LF:
+        case CHAR_VT:
+        case CHAR_FF:
+        case CHAR_NEL:
+#ifndef EBCDIC
+        case 0x2028:
+        case 0x2029:
+#endif  /* Not EBCDIC */
+        return FALSE;
+        }
+      break;
+
+      case OP_EOD:    /* Can always possessify before \z */
+      break;
+
+#ifdef SUPPORT_UNICODE
+      case OP_PROP:
+      case OP_NOTPROP:
+      if (!check_char_prop(chr, list_ptr[2], list_ptr[3],
+            list_ptr[0] == OP_NOTPROP))
+        return FALSE;
+      break;
+#endif
+
+      case OP_NCLASS:
+      if (chr > 255) return FALSE;
+      /* Fall through */
+
+      case OP_CLASS:
+      if (chr > 255) break;
+      class_bitset = (uint8_t *)
+        ((list_ptr == list ? code : base_end) - list_ptr[2]);
+      if ((class_bitset[chr >> 3] & (1u << (chr & 7))) != 0) return FALSE;
+      break;
+
+#ifdef SUPPORT_WIDE_CHARS
+      case OP_XCLASS:
+      if (PRIV(xclass)(chr, (list_ptr == list ? code : base_end) -
+          list_ptr[2] + LINK_SIZE, utf)) return FALSE;
+      break;
+#endif
+
+      default:
+      return FALSE;
+      }
+
+    chr_ptr++;
+    }
+  while(*chr_ptr != NOTACHAR);
+
+  /* At least one character must be matched from this opcode. */
+
+  if (list[1] == 0) return TRUE;
+  }
+
+/* Control never reaches here. There used to be a fail-save return FALSE; here,
+but some compilers complain about an unreachable statement. */
+}
+
+
+
+/*************************************************
+*    Scan compiled regex for auto-possession     *
+*************************************************/
+
+/* Replaces single character iterations with their possessive alternatives
+if appropriate. This function modifies the compiled opcode! Hitting a
+non-existent opcode may indicate a bug in PCRE2, but it can also be caused if a
+bad UTF string was compiled with PCRE2_NO_UTF_CHECK. The rec_limit catches
+overly complicated or large patterns. In these cases, the check just stops,
+leaving the remainder of the pattern unpossessified.
+
+Arguments:
+  code        points to start of the byte code
+  cb          compile data block
+
+Returns:      0 for success
+              -1 if a non-existant opcode is encountered
+*/
+
+int
+PRIV(auto_possessify)(PCRE2_UCHAR *code, const compile_block *cb)
+{
+PCRE2_UCHAR c;
+PCRE2_SPTR end;
+PCRE2_UCHAR *repeat_opcode;
+uint32_t list[8];
+int rec_limit = 1000;  /* Was 10,000 but clang+ASAN uses a lot of stack. */
+BOOL utf = (cb->external_options & PCRE2_UTF) != 0;
+BOOL ucp = (cb->external_options & PCRE2_UCP) != 0;
+
+for (;;)
+  {
+  c = *code;
+
+  if (c >= OP_TABLE_LENGTH) return -1;   /* Something gone wrong */
+
+  if (c >= OP_STAR && c <= OP_TYPEPOSUPTO)
+    {
+    c -= get_repeat_base(c) - OP_STAR;
+    end = (c <= OP_MINUPTO) ?
+      get_chr_property_list(code, utf, ucp, cb->fcc, list) : NULL;
+    list[1] = c == OP_STAR || c == OP_PLUS || c == OP_QUERY || c == OP_UPTO;
+
+    if (end != NULL && compare_opcodes(end, utf, ucp, cb, list, end,
+        &rec_limit))
+      {
+      switch(c)
+        {
+        case OP_STAR:
+        *code += OP_POSSTAR - OP_STAR;
+        break;
+
+        case OP_MINSTAR:
+        *code += OP_POSSTAR - OP_MINSTAR;
+        break;
+
+        case OP_PLUS:
+        *code += OP_POSPLUS - OP_PLUS;
+        break;
+
+        case OP_MINPLUS:
+        *code += OP_POSPLUS - OP_MINPLUS;
+        break;
+
+        case OP_QUERY:
+        *code += OP_POSQUERY - OP_QUERY;
+        break;
+
+        case OP_MINQUERY:
+        *code += OP_POSQUERY - OP_MINQUERY;
+        break;
+
+        case OP_UPTO:
+        *code += OP_POSUPTO - OP_UPTO;
+        break;
+
+        case OP_MINUPTO:
+        *code += OP_POSUPTO - OP_MINUPTO;
+        break;
+        }
+      }
+    c = *code;
+    }
+  else if (c == OP_CLASS || c == OP_NCLASS || c == OP_XCLASS)
+    {
+#ifdef SUPPORT_WIDE_CHARS
+    if (c == OP_XCLASS)
+      repeat_opcode = code + GET(code, 1);
+    else
+#endif
+      repeat_opcode = code + 1 + (32 / sizeof(PCRE2_UCHAR));
+
+    c = *repeat_opcode;
+    if (c >= OP_CRSTAR && c <= OP_CRMINRANGE)
+      {
+      /* end must not be NULL. */
+      end = get_chr_property_list(code, utf, ucp, cb->fcc, list);
+
+      list[1] = (c & 1) == 0;
+
+      if (compare_opcodes(end, utf, ucp, cb, list, end, &rec_limit))
+        {
+        switch (c)
+          {
+          case OP_CRSTAR:
+          case OP_CRMINSTAR:
+          *repeat_opcode = OP_CRPOSSTAR;
+          break;
+
+          case OP_CRPLUS:
+          case OP_CRMINPLUS:
+          *repeat_opcode = OP_CRPOSPLUS;
+          break;
+
+          case OP_CRQUERY:
+          case OP_CRMINQUERY:
+          *repeat_opcode = OP_CRPOSQUERY;
+          break;
+
+          case OP_CRRANGE:
+          case OP_CRMINRANGE:
+          *repeat_opcode = OP_CRPOSRANGE;
+          break;
+          }
+        }
+      }
+    c = *code;
+    }
+
+  switch(c)
+    {
+    case OP_END:
+    return 0;
+
+    case OP_TYPESTAR:
+    case OP_TYPEMINSTAR:
+    case OP_TYPEPLUS:
+    case OP_TYPEMINPLUS:
+    case OP_TYPEQUERY:
+    case OP_TYPEMINQUERY:
+    case OP_TYPEPOSSTAR:
+    case OP_TYPEPOSPLUS:
+    case OP_TYPEPOSQUERY:
+    if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2;
+    break;
+
+    case OP_TYPEUPTO:
+    case OP_TYPEMINUPTO:
+    case OP_TYPEEXACT:
+    case OP_TYPEPOSUPTO:
+    if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
+      code += 2;
+    break;
+
+    case OP_CALLOUT_STR:
+    code += GET(code, 1 + 2*LINK_SIZE);
+    break;
+
+#ifdef SUPPORT_WIDE_CHARS
+    case OP_XCLASS:
+    code += GET(code, 1);
+    break;
+#endif
+
+    case OP_MARK:
+    case OP_COMMIT_ARG:
+    case OP_PRUNE_ARG:
+    case OP_SKIP_ARG:
+    case OP_THEN_ARG:
+    code += code[1];
+    break;
+    }
+
+  /* Add in the fixed length from the table */
+
+  code += PRIV(OP_lengths)[c];
+
+  /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may be
+  followed by a multi-byte character. The length in the table is a minimum, so
+  we have to arrange to skip the extra code units. */
+
+#ifdef MAYBE_UTF_MULTI
+  if (utf) switch(c)
+    {
+    case OP_CHAR:
+    case OP_CHARI:
+    case OP_NOT:
+    case OP_NOTI:
+    case OP_STAR:
+    case OP_MINSTAR:
+    case OP_PLUS:
+    case OP_MINPLUS:
+    case OP_QUERY:
+    case OP_MINQUERY:
+    case OP_UPTO:
+    case OP_MINUPTO:
+    case OP_EXACT:
+    case OP_POSSTAR:
+    case OP_POSPLUS:
+    case OP_POSQUERY:
+    case OP_POSUPTO:
+    case OP_STARI:
+    case OP_MINSTARI:
+    case OP_PLUSI:
+    case OP_MINPLUSI:
+    case OP_QUERYI:
+    case OP_MINQUERYI:
+    case OP_UPTOI:
+    case OP_MINUPTOI:
+    case OP_EXACTI:
+    case OP_POSSTARI:
+    case OP_POSPLUSI:
+    case OP_POSQUERYI:
+    case OP_POSUPTOI:
+    case OP_NOTSTAR:
+    case OP_NOTMINSTAR:
+    case OP_NOTPLUS:
+    case OP_NOTMINPLUS:
+    case OP_NOTQUERY:
+    case OP_NOTMINQUERY:
+    case OP_NOTUPTO:
+    case OP_NOTMINUPTO:
+    case OP_NOTEXACT:
+    case OP_NOTPOSSTAR:
+    case OP_NOTPOSPLUS:
+    case OP_NOTPOSQUERY:
+    case OP_NOTPOSUPTO:
+    case OP_NOTSTARI:
+    case OP_NOTMINSTARI:
+    case OP_NOTPLUSI:
+    case OP_NOTMINPLUSI:
+    case OP_NOTQUERYI:
+    case OP_NOTMINQUERYI:
+    case OP_NOTUPTOI:
+    case OP_NOTMINUPTOI:
+    case OP_NOTEXACTI:
+    case OP_NOTPOSSTARI:
+    case OP_NOTPOSPLUSI:
+    case OP_NOTPOSQUERYI:
+    case OP_NOTPOSUPTOI:
+    if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
+    break;
+    }
+#else
+  (void)(utf);  /* Keep compiler happy by referencing function argument */
+#endif  /* SUPPORT_WIDE_CHARS */
+  }
+}
+
+/* End of pcre2_auto_possess.c */
diff --git a/src/c/pcre2/src/pcre2_compile.c b/src/c/pcre2/src/pcre2_compile.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_compile.c
@@ -0,0 +1,10499 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2020 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define NLBLOCK cb             /* Block containing newline information */
+#define PSSTART start_pattern  /* Field containing processed string start */
+#define PSEND   end_pattern    /* Field containing processed string end */
+
+#include "pcre2_internal.h"
+
+/* In rare error cases debugging might require calling pcre2_printint(). */
+
+#if 0
+#ifdef EBCDIC
+#define PRINTABLE(c) ((c) >= 64 && (c) < 255)
+#else
+#define PRINTABLE(c) ((c) >= 32 && (c) < 127)
+#endif
+#include "pcre2_printint.c"
+#define DEBUG_CALL_PRINTINT
+#endif
+
+/* Other debugging code can be enabled by these defines. */
+
+/* #define DEBUG_SHOW_CAPTURES */
+/* #define DEBUG_SHOW_PARSED */
+
+/* There are a few things that vary with different code unit sizes. Handle them
+by defining macros in order to minimize #if usage. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define STRING_UTFn_RIGHTPAR     STRING_UTF8_RIGHTPAR, 5
+#define XDIGIT(c)                xdigitab[c]
+
+#else  /* Either 16-bit or 32-bit */
+#define XDIGIT(c)                (MAX_255(c)? xdigitab[c] : 0xff)
+
+#if PCRE2_CODE_UNIT_WIDTH == 16
+#define STRING_UTFn_RIGHTPAR     STRING_UTF16_RIGHTPAR, 6
+
+#else  /* 32-bit */
+#define STRING_UTFn_RIGHTPAR     STRING_UTF32_RIGHTPAR, 6
+#endif
+#endif
+
+/* Macros to store and retrieve a PCRE2_SIZE value in the parsed pattern, which
+consists of uint32_t elements. Assume that if uint32_t can't hold it, two of
+them will be able to (i.e. assume a 64-bit world). */
+
+#if PCRE2_SIZE_MAX <= UINT32_MAX
+#define PUTOFFSET(s,p) *p++ = s
+#define GETOFFSET(s,p) s = *p++
+#define GETPLUSOFFSET(s,p) s = *(++p)
+#define READPLUSOFFSET(s,p) s = p[1]
+#define SKIPOFFSET(p) p++
+#define SIZEOFFSET 1
+#else
+#define PUTOFFSET(s,p) \
+  { *p++ = (uint32_t)(s >> 32); *p++ = (uint32_t)(s & 0xffffffff); }
+#define GETOFFSET(s,p) \
+  { s = ((PCRE2_SIZE)p[0] << 32) | (PCRE2_SIZE)p[1]; p += 2; }
+#define GETPLUSOFFSET(s,p) \
+  { s = ((PCRE2_SIZE)p[1] << 32) | (PCRE2_SIZE)p[2]; p += 2; }
+#define READPLUSOFFSET(s,p) \
+  { s = ((PCRE2_SIZE)p[1] << 32) | (PCRE2_SIZE)p[2]; }
+#define SKIPOFFSET(p) p += 2
+#define SIZEOFFSET 2
+#endif
+
+/* Macros for manipulating elements of the parsed pattern vector. */
+
+#define META_CODE(x)   (x & 0xffff0000u)
+#define META_DATA(x)   (x & 0x0000ffffu)
+#define META_DIFF(x,y) ((x-y)>>16)
+
+/* Function definitions to allow mutual recursion */
+
+#ifdef SUPPORT_UNICODE
+static unsigned int
+  add_list_to_class_internal(uint8_t *, PCRE2_UCHAR **, uint32_t,
+    compile_block *, const uint32_t *, unsigned int);
+#endif
+
+static int
+  compile_regex(uint32_t, PCRE2_UCHAR **, uint32_t **, int *, uint32_t,
+    uint32_t *, int32_t *, uint32_t *, int32_t *, branch_chain *,
+    compile_block *, PCRE2_SIZE *);
+
+static int
+  get_branchlength(uint32_t **, int *, int *, parsed_recurse_check *,
+    compile_block *);
+
+static BOOL
+  set_lookbehind_lengths(uint32_t **, int *, int *, parsed_recurse_check *,
+    compile_block *);
+
+static int
+  check_lookbehinds(uint32_t *, uint32_t **, parsed_recurse_check *,
+    compile_block *);
+
+
+/*************************************************
+*      Code parameters and static tables         *
+*************************************************/
+
+#define MAX_GROUP_NUMBER   65535u
+#define MAX_REPEAT_COUNT   65535u
+#define REPEAT_UNLIMITED   (MAX_REPEAT_COUNT+1)
+
+/* COMPILE_WORK_SIZE specifies the size of stack workspace, which is used in
+different ways in the different pattern scans. The parsing and group-
+identifying pre-scan uses it to handle nesting, and needs it to be 16-bit
+aligned for this. Having defined the size in code units, we set up
+C16_WORK_SIZE as the number of elements in the 16-bit vector.
+
+During the first compiling phase, when determining how much memory is required,
+the regex is partly compiled into this space, but the compiled parts are
+discarded as soon as they can be, so that hopefully there will never be an
+overrun. The code does, however, check for an overrun, which can occur for
+pathological patterns. The size of the workspace depends on LINK_SIZE because
+the length of compiled items varies with this.
+
+In the real compile phase, this workspace is not currently used. */
+
+#define COMPILE_WORK_SIZE (3000*LINK_SIZE)   /* Size in code units */
+
+#define C16_WORK_SIZE \
+  ((COMPILE_WORK_SIZE * sizeof(PCRE2_UCHAR))/sizeof(uint16_t))
+
+/* A uint32_t vector is used for caching information about the size of
+capturing groups, to improve performance. A default is created on the stack of
+this size. */
+
+#define GROUPINFO_DEFAULT_SIZE 256
+
+/* The overrun tests check for a slightly smaller size so that they detect the
+overrun before it actually does run off the end of the data block. */
+
+#define WORK_SIZE_SAFETY_MARGIN (100)
+
+/* This value determines the size of the initial vector that is used for
+remembering named groups during the pre-compile. It is allocated on the stack,
+but if it is too small, it is expanded, in a similar way to the workspace. The
+value is the number of slots in the list. */
+
+#define NAMED_GROUP_LIST_SIZE  20
+
+/* The pre-compiling pass over the pattern creates a parsed pattern in a vector
+of uint32_t. For short patterns this lives on the stack, with this size. Heap
+memory is used for longer patterns. */
+
+#define PARSED_PATTERN_DEFAULT_SIZE 1024
+
+/* Maximum length value to check against when making sure that the variable
+that holds the compiled pattern length does not overflow. We make it a bit less
+than INT_MAX to allow for adding in group terminating code units, so that we
+don't have to check them every time. */
+
+#define OFLOW_MAX (INT_MAX - 20)
+
+/* Code values for parsed patterns, which are stored in a vector of 32-bit
+unsigned ints. Values less than META_END are literal data values. The coding
+for identifying the item is in the top 16-bits, leaving 16 bits for the
+additional data that some of them need. The META_CODE, META_DATA, and META_DIFF
+macros are used to manipulate parsed pattern elements.
+
+NOTE: When these definitions are changed, the table of extra lengths for each
+code (meta_extra_lengths, just below) must be updated to remain in step. */
+
+#define META_END              0x80000000u  /* End of pattern */
+
+#define META_ALT              0x80010000u  /* alternation */
+#define META_ATOMIC           0x80020000u  /* atomic group */
+#define META_BACKREF          0x80030000u  /* Back ref */
+#define META_BACKREF_BYNAME   0x80040000u  /* \k'name' */
+#define META_BIGVALUE         0x80050000u  /* Next is a literal > META_END */
+#define META_CALLOUT_NUMBER   0x80060000u  /* (?C with numerical argument */
+#define META_CALLOUT_STRING   0x80070000u  /* (?C with string argument */
+#define META_CAPTURE          0x80080000u  /* Capturing parenthesis */
+#define META_CIRCUMFLEX       0x80090000u  /* ^ metacharacter */
+#define META_CLASS            0x800a0000u  /* start non-empty class */
+#define META_CLASS_EMPTY      0x800b0000u  /* empty class */
+#define META_CLASS_EMPTY_NOT  0x800c0000u  /* negative empty class */
+#define META_CLASS_END        0x800d0000u  /* end of non-empty class */
+#define META_CLASS_NOT        0x800e0000u  /* start non-empty negative class */
+#define META_COND_ASSERT      0x800f0000u  /* (?(?assertion)... */
+#define META_COND_DEFINE      0x80100000u  /* (?(DEFINE)... */
+#define META_COND_NAME        0x80110000u  /* (?(<name>)... */
+#define META_COND_NUMBER      0x80120000u  /* (?(digits)... */
+#define META_COND_RNAME       0x80130000u  /* (?(R&name)... */
+#define META_COND_RNUMBER     0x80140000u  /* (?(Rdigits)... */
+#define META_COND_VERSION     0x80150000u  /* (?(VERSION<op>x.y)... */
+#define META_DOLLAR           0x80160000u  /* $ metacharacter */
+#define META_DOT              0x80170000u  /* . metacharacter */
+#define META_ESCAPE           0x80180000u  /* \d and friends */
+#define META_KET              0x80190000u  /* closing parenthesis */
+#define META_NOCAPTURE        0x801a0000u  /* no capture parens */
+#define META_OPTIONS          0x801b0000u  /* (?i) and friends */
+#define META_POSIX            0x801c0000u  /* POSIX class item */
+#define META_POSIX_NEG        0x801d0000u  /* negative POSIX class item */
+#define META_RANGE_ESCAPED    0x801e0000u  /* range with at least one escape */
+#define META_RANGE_LITERAL    0x801f0000u  /* range defined literally */
+#define META_RECURSE          0x80200000u  /* Recursion */
+#define META_RECURSE_BYNAME   0x80210000u  /* (?&name) */
+#define META_SCRIPT_RUN       0x80220000u  /* (*script_run:...) */
+
+/* These must be kept together to make it easy to check that an assertion
+is present where expected in a conditional group. */
+
+#define META_LOOKAHEAD        0x80230000u  /* (?= */
+#define META_LOOKAHEADNOT     0x80240000u  /* (?! */
+#define META_LOOKBEHIND       0x80250000u  /* (?<= */
+#define META_LOOKBEHINDNOT    0x80260000u  /* (?<! */
+
+/* These cannot be conditions */
+
+#define META_LOOKAHEAD_NA     0x80270000u  /* (*napla: */
+#define META_LOOKBEHIND_NA    0x80280000u  /* (*naplb: */
+
+/* These must be kept in this order, with consecutive values, and the _ARG
+versions of COMMIT, PRUNE, SKIP, and THEN immediately after their non-argument
+versions. */
+
+#define META_MARK             0x80290000u  /* (*MARK) */
+#define META_ACCEPT           0x802a0000u  /* (*ACCEPT) */
+#define META_FAIL             0x802b0000u  /* (*FAIL) */
+#define META_COMMIT           0x802c0000u  /* These               */
+#define META_COMMIT_ARG       0x802d0000u  /*   pairs             */
+#define META_PRUNE            0x802e0000u  /*     must            */
+#define META_PRUNE_ARG        0x802f0000u  /*       be            */
+#define META_SKIP             0x80300000u  /*         kept        */
+#define META_SKIP_ARG         0x80310000u  /*           in        */
+#define META_THEN             0x80320000u  /*             this    */
+#define META_THEN_ARG         0x80330000u  /*               order */
+
+/* These must be kept in groups of adjacent 3 values, and all together. */
+
+#define META_ASTERISK         0x80340000u  /* *  */
+#define META_ASTERISK_PLUS    0x80350000u  /* *+ */
+#define META_ASTERISK_QUERY   0x80360000u  /* *? */
+#define META_PLUS             0x80370000u  /* +  */
+#define META_PLUS_PLUS        0x80380000u  /* ++ */
+#define META_PLUS_QUERY       0x80390000u  /* +? */
+#define META_QUERY            0x803a0000u  /* ?  */
+#define META_QUERY_PLUS       0x803b0000u  /* ?+ */
+#define META_QUERY_QUERY      0x803c0000u  /* ?? */
+#define META_MINMAX           0x803d0000u  /* {n,m}  repeat */
+#define META_MINMAX_PLUS      0x803e0000u  /* {n,m}+ repeat */
+#define META_MINMAX_QUERY     0x803f0000u  /* {n,m}? repeat */
+
+#define META_FIRST_QUANTIFIER META_ASTERISK
+#define META_LAST_QUANTIFIER  META_MINMAX_QUERY
+
+/* This is a special "meta code" that is used only to distinguish (*asr: from
+(*sr: in the table of aphabetic assertions. It is never stored in the parsed
+pattern because (*asr: is turned into (*sr:(*atomic: at that stage. There is
+therefore no need for it to have a length entry, so use a high value. */
+
+#define META_ATOMIC_SCRIPT_RUN 0x8fff0000u
+
+/* Table of extra lengths for each of the meta codes. Must be kept in step with
+the definitions above. For some items these values are a basic length to which
+a variable amount has to be added. */
+
+static unsigned char meta_extra_lengths[] = {
+  0,             /* META_END */
+  0,             /* META_ALT */
+  0,             /* META_ATOMIC */
+  0,             /* META_BACKREF - more if group is >= 10 */
+  1+SIZEOFFSET,  /* META_BACKREF_BYNAME */
+  1,             /* META_BIGVALUE */
+  3,             /* META_CALLOUT_NUMBER */
+  3+SIZEOFFSET,  /* META_CALLOUT_STRING */
+  0,             /* META_CAPTURE */
+  0,             /* META_CIRCUMFLEX */
+  0,             /* META_CLASS */
+  0,             /* META_CLASS_EMPTY */
+  0,             /* META_CLASS_EMPTY_NOT */
+  0,             /* META_CLASS_END */
+  0,             /* META_CLASS_NOT */
+  0,             /* META_COND_ASSERT */
+  SIZEOFFSET,    /* META_COND_DEFINE */
+  1+SIZEOFFSET,  /* META_COND_NAME */
+  1+SIZEOFFSET,  /* META_COND_NUMBER */
+  1+SIZEOFFSET,  /* META_COND_RNAME */
+  1+SIZEOFFSET,  /* META_COND_RNUMBER */
+  3,             /* META_COND_VERSION */
+  0,             /* META_DOLLAR */
+  0,             /* META_DOT */
+  0,             /* META_ESCAPE - more for ESC_P, ESC_p, ESC_g, ESC_k */
+  0,             /* META_KET */
+  0,             /* META_NOCAPTURE */
+  1,             /* META_OPTIONS */
+  1,             /* META_POSIX */
+  1,             /* META_POSIX_NEG */
+  0,             /* META_RANGE_ESCAPED */
+  0,             /* META_RANGE_LITERAL */
+  SIZEOFFSET,    /* META_RECURSE */
+  1+SIZEOFFSET,  /* META_RECURSE_BYNAME */
+  0,             /* META_SCRIPT_RUN */
+  0,             /* META_LOOKAHEAD */
+  0,             /* META_LOOKAHEADNOT */
+  SIZEOFFSET,    /* META_LOOKBEHIND */
+  SIZEOFFSET,    /* META_LOOKBEHINDNOT */
+  0,             /* META_LOOKAHEAD_NA */
+  SIZEOFFSET,    /* META_LOOKBEHIND_NA */
+  1,             /* META_MARK - plus the string length */
+  0,             /* META_ACCEPT */
+  0,             /* META_FAIL */
+  0,             /* META_COMMIT */
+  1,             /* META_COMMIT_ARG - plus the string length */
+  0,             /* META_PRUNE */
+  1,             /* META_PRUNE_ARG - plus the string length */
+  0,             /* META_SKIP */
+  1,             /* META_SKIP_ARG - plus the string length */
+  0,             /* META_THEN */
+  1,             /* META_THEN_ARG - plus the string length */
+  0,             /* META_ASTERISK */
+  0,             /* META_ASTERISK_PLUS */
+  0,             /* META_ASTERISK_QUERY */
+  0,             /* META_PLUS */
+  0,             /* META_PLUS_PLUS */
+  0,             /* META_PLUS_QUERY */
+  0,             /* META_QUERY */
+  0,             /* META_QUERY_PLUS */
+  0,             /* META_QUERY_QUERY */
+  2,             /* META_MINMAX */
+  2,             /* META_MINMAX_PLUS */
+  2              /* META_MINMAX_QUERY */
+};
+
+/* Types for skipping parts of a parsed pattern. */
+
+enum { PSKIP_ALT, PSKIP_CLASS, PSKIP_KET };
+
+/* Macro for setting individual bits in class bitmaps. It took some
+experimenting to figure out how to stop gcc 5.3.0 from warning with
+-Wconversion. This version gets a warning:
+
+  #define SETBIT(a,b) a[(b)/8] |= (uint8_t)(1u << ((b)&7))
+
+Let's hope the apparently less efficient version isn't actually so bad if the
+compiler is clever with identical subexpressions. */
+
+#define SETBIT(a,b) a[(b)/8] = (uint8_t)(a[(b)/8] | (1u << ((b)&7)))
+
+/* Private flags added to firstcu and reqcu. */
+
+#define REQ_CASELESS    (1u << 0)       /* Indicates caselessness */
+#define REQ_VARY        (1u << 1)       /* reqcu followed non-literal item */
+/* Negative values for the firstcu and reqcu flags */
+#define REQ_UNSET       (-2)            /* Not yet found anything */
+#define REQ_NONE        (-1)            /* Found not fixed char */
+
+/* These flags are used in the groupinfo vector. */
+
+#define GI_SET_FIXED_LENGTH    0x80000000u
+#define GI_NOT_FIXED_LENGTH    0x40000000u
+#define GI_FIXED_LENGTH_MASK   0x0000ffffu
+
+/* This simple test for a decimal digit works for both ASCII/Unicode and EBCDIC
+and is fast (a good compiler can turn it into a subtraction and unsigned
+comparison). */
+
+#define IS_DIGIT(x) ((x) >= CHAR_0 && (x) <= CHAR_9)
+
+/* Table to identify hex digits. The tables in chartables are dependent on the
+locale, and may mark arbitrary characters as digits. We want to recognize only
+0-9, a-z, and A-Z as hex digits, which is why we have a private table here. It
+costs 256 bytes, but it is a lot faster than doing character value tests (at
+least in some simple cases I timed), and in some applications one wants PCRE2
+to compile efficiently as well as match efficiently. The value in the table is
+the binary hex digit value, or 0xff for non-hex digits. */
+
+/* This is the "normal" case, for ASCII systems, and EBCDIC systems running in
+UTF-8 mode. */
+
+#ifndef EBCDIC
+static const uint8_t xdigitab[] =
+  {
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*   0-  7 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*   8- 15 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  16- 23 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  24- 31 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*    - '  */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  ( - /  */
+  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, /*  0 - 7  */
+  0x08,0x09,0xff,0xff,0xff,0xff,0xff,0xff, /*  8 - ?  */
+  0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /*  @ - G  */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  H - O  */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  P - W  */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  X - _  */
+  0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /*  ` - g  */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  h - o  */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  p - w  */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  x -127 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 128-135 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 136-143 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 144-151 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 152-159 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 160-167 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 168-175 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 176-183 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 184-191 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 192-199 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 2ff-207 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 208-215 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 216-223 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 224-231 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 232-239 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 240-247 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};/* 248-255 */
+
+#else
+
+/* This is the "abnormal" case, for EBCDIC systems not running in UTF-8 mode. */
+
+static const uint8_t xdigitab[] =
+  {
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*   0-  7  0 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*   8- 15    */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  16- 23 10 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  24- 31    */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  32- 39 20 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  40- 47    */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  48- 55 30 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  56- 63    */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*    - 71 40 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  72- |     */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  & - 87 50 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  88- 95    */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  - -103 60 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 104- ?     */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 112-119 70 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 120- "     */
+  0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* 128- g  80 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  h -143    */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 144- p  90 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  q -159    */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 160- x  A0 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  y -175    */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  ^ -183 B0 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 184-191    */
+  0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /*  { - G  C0 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  H -207    */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  } - P  D0 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  Q -223    */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  \ - X  E0 */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /*  Y -239    */
+  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, /*  0 - 7  F0 */
+  0x08,0x09,0xff,0xff,0xff,0xff,0xff,0xff};/*  8 -255    */
+#endif  /* EBCDIC */
+
+
+/* Table for handling alphanumeric escaped characters. Positive returns are
+simple data values; negative values are for special things like \d and so on.
+Zero means further processing is needed (for things like \x), or the escape is
+invalid. */
+
+/* This is the "normal" table for ASCII systems or for EBCDIC systems running
+in UTF-8 mode. It runs from '0' to 'z'. */
+
+#ifndef EBCDIC
+#define ESCAPES_FIRST       CHAR_0
+#define ESCAPES_LAST        CHAR_z
+#define UPPER_CASE(c)       (c-32)
+
+static const short int escapes[] = {
+     0,                       0,
+     0,                       0,
+     0,                       0,
+     0,                       0,
+     0,                       0,
+     CHAR_COLON,              CHAR_SEMICOLON,
+     CHAR_LESS_THAN_SIGN,     CHAR_EQUALS_SIGN,
+     CHAR_GREATER_THAN_SIGN,  CHAR_QUESTION_MARK,
+     CHAR_COMMERCIAL_AT,      -ESC_A,
+     -ESC_B,                  -ESC_C,
+     -ESC_D,                  -ESC_E,
+     0,                       -ESC_G,
+     -ESC_H,                  0,
+     0,                       -ESC_K,
+     0,                       0,
+     -ESC_N,                  0,
+     -ESC_P,                  -ESC_Q,
+     -ESC_R,                  -ESC_S,
+     0,                       0,
+     -ESC_V,                  -ESC_W,
+     -ESC_X,                  0,
+     -ESC_Z,                  CHAR_LEFT_SQUARE_BRACKET,
+     CHAR_BACKSLASH,          CHAR_RIGHT_SQUARE_BRACKET,
+     CHAR_CIRCUMFLEX_ACCENT,  CHAR_UNDERSCORE,
+     CHAR_GRAVE_ACCENT,       CHAR_BEL,
+     -ESC_b,                  0,
+     -ESC_d,                  CHAR_ESC,
+     CHAR_FF,                 0,
+     -ESC_h,                  0,
+     0,                       -ESC_k,
+     0,                       0,
+     CHAR_LF,                 0,
+     -ESC_p,                  0,
+     CHAR_CR,                 -ESC_s,
+     CHAR_HT,                 0,
+     -ESC_v,                  -ESC_w,
+     0,                       0,
+     -ESC_z
+};
+
+#else
+
+/* This is the "abnormal" table for EBCDIC systems without UTF-8 support.
+It runs from 'a' to '9'. For some minimal testing of EBCDIC features, the code
+is sometimes compiled on an ASCII system. In this case, we must not use CHAR_a
+because it is defined as 'a', which of course picks up the ASCII value. */
+
+#if 'a' == 0x81                    /* Check for a real EBCDIC environment */
+#define ESCAPES_FIRST       CHAR_a
+#define ESCAPES_LAST        CHAR_9
+#define UPPER_CASE(c)       (c+64)
+#else                              /* Testing in an ASCII environment */
+#define ESCAPES_FIRST  ((unsigned char)'\x81')   /* EBCDIC 'a' */
+#define ESCAPES_LAST   ((unsigned char)'\xf9')   /* EBCDIC '9' */
+#define UPPER_CASE(c)  (c-32)
+#endif
+
+static const short int escapes[] = {
+/*  80 */         CHAR_BEL, -ESC_b,       0, -ESC_d, CHAR_ESC, CHAR_FF,      0,
+/*  88 */ -ESC_h,        0,      0,     '{',      0,        0,       0,      0,
+/*  90 */      0,        0, -ESC_k,       0,      0,  CHAR_LF,       0, -ESC_p,
+/*  98 */      0,  CHAR_CR,      0,     '}',      0,        0,       0,      0,
+/*  A0 */      0,      '~', -ESC_s, CHAR_HT,      0,   -ESC_v,  -ESC_w,      0,
+/*  A8 */      0,   -ESC_z,      0,       0,      0,      '[',       0,      0,
+/*  B0 */      0,        0,      0,       0,      0,        0,       0,      0,
+/*  B8 */      0,        0,      0,       0,      0,      ']',     '=',    '-',
+/*  C0 */    '{',   -ESC_A, -ESC_B,  -ESC_C, -ESC_D,   -ESC_E,       0, -ESC_G,
+/*  C8 */ -ESC_H,        0,      0,       0,      0,        0,       0,      0,
+/*  D0 */    '}',        0, -ESC_K,       0,      0,   -ESC_N,       0, -ESC_P,
+/*  D8 */ -ESC_Q,   -ESC_R,      0,       0,      0,        0,       0,      0,
+/*  E0 */   '\\',        0, -ESC_S,       0,      0,   -ESC_V,  -ESC_W, -ESC_X,
+/*  E8 */      0,   -ESC_Z,      0,       0,      0,        0,       0,      0,
+/*  F0 */      0,        0,      0,       0,      0,        0,       0,      0,
+/*  F8 */      0,        0
+};
+
+/* We also need a table of characters that may follow \c in an EBCDIC
+environment for characters 0-31. */
+
+static unsigned char ebcdic_escape_c[] = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
+
+#endif   /* EBCDIC */
+
+
+/* Table of special "verbs" like (*PRUNE). This is a short table, so it is
+searched linearly. Put all the names into a single string, in order to reduce
+the number of relocations when a shared library is dynamically linked. The
+string is built from string macros so that it works in UTF-8 mode on EBCDIC
+platforms. */
+
+typedef struct verbitem {
+  unsigned int len;          /* Length of verb name */
+  uint32_t meta;             /* Base META_ code */
+  int has_arg;               /* Argument requirement */
+} verbitem;
+
+static const char verbnames[] =
+  "\0"                       /* Empty name is a shorthand for MARK */
+  STRING_MARK0
+  STRING_ACCEPT0
+  STRING_F0
+  STRING_FAIL0
+  STRING_COMMIT0
+  STRING_PRUNE0
+  STRING_SKIP0
+  STRING_THEN;
+
+static const verbitem verbs[] = {
+  { 0, META_MARK,   +1 },  /* > 0 => must have an argument */
+  { 4, META_MARK,   +1 },
+  { 6, META_ACCEPT, -1 },  /* < 0 => Optional argument, convert to pre-MARK */
+  { 1, META_FAIL,   -1 },
+  { 4, META_FAIL,   -1 },
+  { 6, META_COMMIT,  0 },
+  { 5, META_PRUNE,   0 },  /* Optional argument; bump META code if found */
+  { 4, META_SKIP,    0 },
+  { 4, META_THEN,    0 }
+};
+
+static const int verbcount = sizeof(verbs)/sizeof(verbitem);
+
+/* Verb opcodes, indexed by their META code offset from META_MARK. */
+
+static const uint32_t verbops[] = {
+  OP_MARK, OP_ACCEPT, OP_FAIL, OP_COMMIT, OP_COMMIT_ARG, OP_PRUNE,
+  OP_PRUNE_ARG, OP_SKIP, OP_SKIP_ARG, OP_THEN, OP_THEN_ARG };
+
+/* Table of "alpha assertions" like (*pla:...), similar to the (*VERB) table. */
+
+typedef struct alasitem {
+  unsigned int len;          /* Length of name */
+  uint32_t meta;             /* Base META_ code */
+} alasitem;
+
+static const char alasnames[] =
+  STRING_pla0
+  STRING_plb0
+  STRING_napla0
+  STRING_naplb0
+  STRING_nla0
+  STRING_nlb0
+  STRING_positive_lookahead0
+  STRING_positive_lookbehind0
+  STRING_non_atomic_positive_lookahead0
+  STRING_non_atomic_positive_lookbehind0
+  STRING_negative_lookahead0
+  STRING_negative_lookbehind0
+  STRING_atomic0
+  STRING_sr0
+  STRING_asr0
+  STRING_script_run0
+  STRING_atomic_script_run;
+
+static const alasitem alasmeta[] = {
+  {  3, META_LOOKAHEAD         },
+  {  3, META_LOOKBEHIND        },
+  {  5, META_LOOKAHEAD_NA      },
+  {  5, META_LOOKBEHIND_NA     },
+  {  3, META_LOOKAHEADNOT      },
+  {  3, META_LOOKBEHINDNOT     },
+  { 18, META_LOOKAHEAD         },
+  { 19, META_LOOKBEHIND        },
+  { 29, META_LOOKAHEAD_NA      },
+  { 30, META_LOOKBEHIND_NA     },
+  { 18, META_LOOKAHEADNOT      },
+  { 19, META_LOOKBEHINDNOT     },
+  {  6, META_ATOMIC            },
+  {  2, META_SCRIPT_RUN        }, /* sr = script run */
+  {  3, META_ATOMIC_SCRIPT_RUN }, /* asr = atomic script run */
+  { 10, META_SCRIPT_RUN        }, /* script run */
+  { 17, META_ATOMIC_SCRIPT_RUN }  /* atomic script run */
+};
+
+static const int alascount = sizeof(alasmeta)/sizeof(alasitem);
+
+/* Offsets from OP_STAR for case-independent and negative repeat opcodes. */
+
+static uint32_t chartypeoffset[] = {
+  OP_STAR - OP_STAR,    OP_STARI - OP_STAR,
+  OP_NOTSTAR - OP_STAR, OP_NOTSTARI - OP_STAR };
+
+/* Tables of names of POSIX character classes and their lengths. The names are
+now all in a single string, to reduce the number of relocations when a shared
+library is dynamically loaded. The list of lengths is terminated by a zero
+length entry. The first three must be alpha, lower, upper, as this is assumed
+for handling case independence. The indices for graph, print, and punct are
+needed, so identify them. */
+
+static const char posix_names[] =
+  STRING_alpha0 STRING_lower0 STRING_upper0 STRING_alnum0
+  STRING_ascii0 STRING_blank0 STRING_cntrl0 STRING_digit0
+  STRING_graph0 STRING_print0 STRING_punct0 STRING_space0
+  STRING_word0  STRING_xdigit;
+
+static const uint8_t posix_name_lengths[] = {
+  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 };
+
+#define PC_GRAPH  8
+#define PC_PRINT  9
+#define PC_PUNCT 10
+
+/* Table of class bit maps for each POSIX class. Each class is formed from a
+base map, with an optional addition or removal of another map. Then, for some
+classes, there is some additional tweaking: for [:blank:] the vertical space
+characters are removed, and for [:alpha:] and [:alnum:] the underscore
+character is removed. The triples in the table consist of the base map offset,
+second map offset or -1 if no second map, and a non-negative value for map
+addition or a negative value for map subtraction (if there are two maps). The
+absolute value of the third field has these meanings: 0 => no tweaking, 1 =>
+remove vertical space characters, 2 => remove underscore. */
+
+static const int posix_class_maps[] = {
+  cbit_word,  cbit_digit, -2,             /* alpha */
+  cbit_lower, -1,          0,             /* lower */
+  cbit_upper, -1,          0,             /* upper */
+  cbit_word,  -1,          2,             /* alnum - word without underscore */
+  cbit_print, cbit_cntrl,  0,             /* ascii */
+  cbit_space, -1,          1,             /* blank - a GNU extension */
+  cbit_cntrl, -1,          0,             /* cntrl */
+  cbit_digit, -1,          0,             /* digit */
+  cbit_graph, -1,          0,             /* graph */
+  cbit_print, -1,          0,             /* print */
+  cbit_punct, -1,          0,             /* punct */
+  cbit_space, -1,          0,             /* space */
+  cbit_word,  -1,          0,             /* word - a Perl extension */
+  cbit_xdigit,-1,          0              /* xdigit */
+};
+
+#ifdef SUPPORT_UNICODE
+
+/* The POSIX class Unicode property substitutes that are used in UCP mode must
+be in the order of the POSIX class names, defined above. */
+
+static int posix_substitutes[] = {
+  PT_GC, ucp_L,     /* alpha */
+  PT_PC, ucp_Ll,    /* lower */
+  PT_PC, ucp_Lu,    /* upper */
+  PT_ALNUM, 0,      /* alnum */
+  -1, 0,            /* ascii, treat as non-UCP */
+  -1, 1,            /* blank, treat as \h */
+  PT_PC, ucp_Cc,    /* cntrl */
+  PT_PC, ucp_Nd,    /* digit */
+  PT_PXGRAPH, 0,    /* graph */
+  PT_PXPRINT, 0,    /* print */
+  PT_PXPUNCT, 0,    /* punct */
+  PT_PXSPACE, 0,    /* space */   /* Xps is POSIX space, but from 8.34 */
+  PT_WORD, 0,       /* word  */   /* Perl and POSIX space are the same */
+  -1, 0             /* xdigit, treat as non-UCP */
+};
+#define POSIX_SUBSIZE (sizeof(posix_substitutes) / (2*sizeof(uint32_t)))
+#endif  /* SUPPORT_UNICODE */
+
+/* Masks for checking option settings. When PCRE2_LITERAL is set, only a subset
+are allowed. */
+
+#define PUBLIC_LITERAL_COMPILE_OPTIONS \
+  (PCRE2_ANCHORED|PCRE2_AUTO_CALLOUT|PCRE2_CASELESS|PCRE2_ENDANCHORED| \
+   PCRE2_FIRSTLINE|PCRE2_LITERAL|PCRE2_MATCH_INVALID_UTF| \
+   PCRE2_NO_START_OPTIMIZE|PCRE2_NO_UTF_CHECK|PCRE2_USE_OFFSET_LIMIT|PCRE2_UTF)
+
+#define PUBLIC_COMPILE_OPTIONS \
+  (PUBLIC_LITERAL_COMPILE_OPTIONS| \
+   PCRE2_ALLOW_EMPTY_CLASS|PCRE2_ALT_BSUX|PCRE2_ALT_CIRCUMFLEX| \
+   PCRE2_ALT_VERBNAMES|PCRE2_DOLLAR_ENDONLY|PCRE2_DOTALL|PCRE2_DUPNAMES| \
+   PCRE2_EXTENDED|PCRE2_EXTENDED_MORE|PCRE2_MATCH_UNSET_BACKREF| \
+   PCRE2_MULTILINE|PCRE2_NEVER_BACKSLASH_C|PCRE2_NEVER_UCP| \
+   PCRE2_NEVER_UTF|PCRE2_NO_AUTO_CAPTURE|PCRE2_NO_AUTO_POSSESS| \
+   PCRE2_NO_DOTSTAR_ANCHOR|PCRE2_UCP|PCRE2_UNGREEDY)
+
+#define PUBLIC_LITERAL_COMPILE_EXTRA_OPTIONS \
+   (PCRE2_EXTRA_MATCH_LINE|PCRE2_EXTRA_MATCH_WORD)
+
+#define PUBLIC_COMPILE_EXTRA_OPTIONS \
+   (PUBLIC_LITERAL_COMPILE_EXTRA_OPTIONS| \
+    PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES|PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL| \
+    PCRE2_EXTRA_ESCAPED_CR_IS_LF|PCRE2_EXTRA_ALT_BSUX)
+
+/* Compile time error code numbers. They are given names so that they can more
+easily be tracked. When a new number is added, the tables called eint1 and
+eint2 in pcre2posix.c may need to be updated, and a new error text must be
+added to compile_error_texts in pcre2_error.c. */
+
+enum { ERR0 = COMPILE_ERROR_BASE,
+       ERR1,  ERR2,  ERR3,  ERR4,  ERR5,  ERR6,  ERR7,  ERR8,  ERR9,  ERR10,
+       ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19, ERR20,
+       ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR28, ERR29, ERR30,
+       ERR31, ERR32, ERR33, ERR34, ERR35, ERR36, ERR37, ERR38, ERR39, ERR40,
+       ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47, ERR48, ERR49, ERR50,
+       ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59, ERR60,
+       ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69, ERR70,
+       ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79, ERR80,
+       ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88, ERR89, ERR90,
+       ERR91, ERR92, ERR93, ERR94, ERR95, ERR96, ERR97, ERR98 };
+
+/* This is a table of start-of-pattern options such as (*UTF) and settings such
+as (*LIMIT_MATCH=nnnn) and (*CRLF). For completeness and backward
+compatibility, (*UTFn) is supported in the relevant libraries, but (*UTF) is
+generic and always supported. */
+
+enum { PSO_OPT,     /* Value is an option bit */
+       PSO_FLG,     /* Value is a flag bit */
+       PSO_NL,      /* Value is a newline type */
+       PSO_BSR,     /* Value is a \R type */
+       PSO_LIMH,    /* Read integer value for heap limit */
+       PSO_LIMM,    /* Read integer value for match limit */
+       PSO_LIMD };  /* Read integer value for depth limit */
+
+typedef struct pso {
+  const uint8_t *name;
+  uint16_t length;
+  uint16_t type;
+  uint32_t value;
+} pso;
+
+/* NB: STRING_UTFn_RIGHTPAR contains the length as well */
+
+static pso pso_list[] = {
+  { (uint8_t *)STRING_UTFn_RIGHTPAR,                  PSO_OPT, PCRE2_UTF },
+  { (uint8_t *)STRING_UTF_RIGHTPAR,                4, PSO_OPT, PCRE2_UTF },
+  { (uint8_t *)STRING_UCP_RIGHTPAR,                4, PSO_OPT, PCRE2_UCP },
+  { (uint8_t *)STRING_NOTEMPTY_RIGHTPAR,           9, PSO_FLG, PCRE2_NOTEMPTY_SET },
+  { (uint8_t *)STRING_NOTEMPTY_ATSTART_RIGHTPAR,  17, PSO_FLG, PCRE2_NE_ATST_SET },
+  { (uint8_t *)STRING_NO_AUTO_POSSESS_RIGHTPAR,   16, PSO_OPT, PCRE2_NO_AUTO_POSSESS },
+  { (uint8_t *)STRING_NO_DOTSTAR_ANCHOR_RIGHTPAR, 18, PSO_OPT, PCRE2_NO_DOTSTAR_ANCHOR },
+  { (uint8_t *)STRING_NO_JIT_RIGHTPAR,             7, PSO_FLG, PCRE2_NOJIT },
+  { (uint8_t *)STRING_NO_START_OPT_RIGHTPAR,      13, PSO_OPT, PCRE2_NO_START_OPTIMIZE },
+  { (uint8_t *)STRING_LIMIT_HEAP_EQ,              11, PSO_LIMH, 0 },
+  { (uint8_t *)STRING_LIMIT_MATCH_EQ,             12, PSO_LIMM, 0 },
+  { (uint8_t *)STRING_LIMIT_DEPTH_EQ,             12, PSO_LIMD, 0 },
+  { (uint8_t *)STRING_LIMIT_RECURSION_EQ,         16, PSO_LIMD, 0 },
+  { (uint8_t *)STRING_CR_RIGHTPAR,                 3, PSO_NL,  PCRE2_NEWLINE_CR },
+  { (uint8_t *)STRING_LF_RIGHTPAR,                 3, PSO_NL,  PCRE2_NEWLINE_LF },
+  { (uint8_t *)STRING_CRLF_RIGHTPAR,               5, PSO_NL,  PCRE2_NEWLINE_CRLF },
+  { (uint8_t *)STRING_ANY_RIGHTPAR,                4, PSO_NL,  PCRE2_NEWLINE_ANY },
+  { (uint8_t *)STRING_NUL_RIGHTPAR,                4, PSO_NL,  PCRE2_NEWLINE_NUL },
+  { (uint8_t *)STRING_ANYCRLF_RIGHTPAR,            8, PSO_NL,  PCRE2_NEWLINE_ANYCRLF },
+  { (uint8_t *)STRING_BSR_ANYCRLF_RIGHTPAR,       12, PSO_BSR, PCRE2_BSR_ANYCRLF },
+  { (uint8_t *)STRING_BSR_UNICODE_RIGHTPAR,       12, PSO_BSR, PCRE2_BSR_UNICODE }
+};
+
+/* This table is used when converting repeating opcodes into possessified
+versions as a result of an explicit possessive quantifier such as ++. A zero
+value means there is no possessified version - in those cases the item in
+question must be wrapped in ONCE brackets. The table is truncated at OP_CALLOUT
+because all relevant opcodes are less than that. */
+
+static const uint8_t opcode_possessify[] = {
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /* 0 - 15  */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /* 16 - 31 */
+
+  0,                       /* NOTI */
+  OP_POSSTAR, 0,           /* STAR, MINSTAR */
+  OP_POSPLUS, 0,           /* PLUS, MINPLUS */
+  OP_POSQUERY, 0,          /* QUERY, MINQUERY */
+  OP_POSUPTO, 0,           /* UPTO, MINUPTO */
+  0,                       /* EXACT */
+  0, 0, 0, 0,              /* POS{STAR,PLUS,QUERY,UPTO} */
+
+  OP_POSSTARI, 0,          /* STARI, MINSTARI */
+  OP_POSPLUSI, 0,          /* PLUSI, MINPLUSI */
+  OP_POSQUERYI, 0,         /* QUERYI, MINQUERYI */
+  OP_POSUPTOI, 0,          /* UPTOI, MINUPTOI */
+  0,                       /* EXACTI */
+  0, 0, 0, 0,              /* POS{STARI,PLUSI,QUERYI,UPTOI} */
+
+  OP_NOTPOSSTAR, 0,        /* NOTSTAR, NOTMINSTAR */
+  OP_NOTPOSPLUS, 0,        /* NOTPLUS, NOTMINPLUS */
+  OP_NOTPOSQUERY, 0,       /* NOTQUERY, NOTMINQUERY */
+  OP_NOTPOSUPTO, 0,        /* NOTUPTO, NOTMINUPTO */
+  0,                       /* NOTEXACT */
+  0, 0, 0, 0,              /* NOTPOS{STAR,PLUS,QUERY,UPTO} */
+
+  OP_NOTPOSSTARI, 0,       /* NOTSTARI, NOTMINSTARI */
+  OP_NOTPOSPLUSI, 0,       /* NOTPLUSI, NOTMINPLUSI */
+  OP_NOTPOSQUERYI, 0,      /* NOTQUERYI, NOTMINQUERYI */
+  OP_NOTPOSUPTOI, 0,       /* NOTUPTOI, NOTMINUPTOI */
+  0,                       /* NOTEXACTI */
+  0, 0, 0, 0,              /* NOTPOS{STARI,PLUSI,QUERYI,UPTOI} */
+
+  OP_TYPEPOSSTAR, 0,       /* TYPESTAR, TYPEMINSTAR */
+  OP_TYPEPOSPLUS, 0,       /* TYPEPLUS, TYPEMINPLUS */
+  OP_TYPEPOSQUERY, 0,      /* TYPEQUERY, TYPEMINQUERY */
+  OP_TYPEPOSUPTO, 0,       /* TYPEUPTO, TYPEMINUPTO */
+  0,                       /* TYPEEXACT */
+  0, 0, 0, 0,              /* TYPEPOS{STAR,PLUS,QUERY,UPTO} */
+
+  OP_CRPOSSTAR, 0,         /* CRSTAR, CRMINSTAR */
+  OP_CRPOSPLUS, 0,         /* CRPLUS, CRMINPLUS */
+  OP_CRPOSQUERY, 0,        /* CRQUERY, CRMINQUERY */
+  OP_CRPOSRANGE, 0,        /* CRRANGE, CRMINRANGE */
+  0, 0, 0, 0,              /* CRPOS{STAR,PLUS,QUERY,RANGE} */
+
+  0, 0, 0,                 /* CLASS, NCLASS, XCLASS */
+  0, 0,                    /* REF, REFI */
+  0, 0,                    /* DNREF, DNREFI */
+  0, 0                     /* RECURSE, CALLOUT */
+};
+
+
+#ifdef DEBUG_SHOW_PARSED
+/*************************************************
+*     Show the parsed pattern for debugging      *
+*************************************************/
+
+/* For debugging the pre-scan, this code, which outputs the parsed data vector,
+can be enabled. */
+
+static void show_parsed(compile_block *cb)
+{
+uint32_t *pptr = cb->parsed_pattern;
+
+for (;;)
+  {
+  int max, min;
+  PCRE2_SIZE offset;
+  uint32_t i;
+  uint32_t length;
+  uint32_t meta_arg = META_DATA(*pptr);
+
+  fprintf(stderr, "+++ %02d %.8x ", (int)(pptr - cb->parsed_pattern), *pptr);
+
+  if (*pptr < META_END)
+    {
+    if (*pptr > 32 && *pptr < 128) fprintf(stderr, "%c", *pptr);
+    pptr++;
+    }
+
+  else switch (META_CODE(*pptr++))
+    {
+    default:
+    fprintf(stderr, "**** OOPS - unknown META value - giving up ****\n");
+    return;
+
+    case META_END:
+    fprintf(stderr, "META_END\n");
+    return;
+
+    case META_CAPTURE:
+    fprintf(stderr, "META_CAPTURE %d", meta_arg);
+    break;
+
+    case META_RECURSE:
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "META_RECURSE %d %zd", meta_arg, offset);
+    break;
+
+    case META_BACKREF:
+    if (meta_arg < 10)
+      offset = cb->small_ref_offset[meta_arg];
+    else
+      GETOFFSET(offset, pptr);
+    fprintf(stderr, "META_BACKREF %d %zd", meta_arg, offset);
+    break;
+
+    case META_ESCAPE:
+    if (meta_arg == ESC_P || meta_arg == ESC_p)
+      {
+      uint32_t ptype = *pptr >> 16;
+      uint32_t pvalue = *pptr++ & 0xffff;
+      fprintf(stderr, "META \\%c %d %d", (meta_arg == ESC_P)? 'P':'p',
+        ptype, pvalue);
+      }
+    else
+      {
+      uint32_t cc;
+      /* There's just one escape we might have here that isn't negated in the
+      escapes table. */
+      if (meta_arg == ESC_g) cc = CHAR_g;
+      else for (cc = ESCAPES_FIRST; cc <= ESCAPES_LAST; cc++)
+        {
+        if (meta_arg == (uint32_t)(-escapes[cc - ESCAPES_FIRST])) break;
+        }
+      if (cc > ESCAPES_LAST) cc = CHAR_QUESTION_MARK;
+      fprintf(stderr, "META \\%c", cc);
+      }
+    break;
+
+    case META_MINMAX:
+    min = *pptr++;
+    max = *pptr++;
+    if (max != REPEAT_UNLIMITED)
+      fprintf(stderr, "META {%d,%d}", min, max);
+    else
+      fprintf(stderr, "META {%d,}", min);
+    break;
+
+    case META_MINMAX_QUERY:
+    min = *pptr++;
+    max = *pptr++;
+    if (max != REPEAT_UNLIMITED)
+      fprintf(stderr, "META {%d,%d}?", min, max);
+    else
+      fprintf(stderr, "META {%d,}?", min);
+    break;
+
+    case META_MINMAX_PLUS:
+    min = *pptr++;
+    max = *pptr++;
+    if (max != REPEAT_UNLIMITED)
+      fprintf(stderr, "META {%d,%d}+", min, max);
+    else
+      fprintf(stderr, "META {%d,}+", min);
+    break;
+
+    case META_BIGVALUE: fprintf(stderr, "META_BIGVALUE %.8x", *pptr++); break;
+    case META_CIRCUMFLEX: fprintf(stderr, "META_CIRCUMFLEX"); break;
+    case META_COND_ASSERT: fprintf(stderr, "META_COND_ASSERT"); break;
+    case META_DOLLAR: fprintf(stderr, "META_DOLLAR"); break;
+    case META_DOT: fprintf(stderr, "META_DOT"); break;
+    case META_ASTERISK: fprintf(stderr, "META *"); break;
+    case META_ASTERISK_QUERY: fprintf(stderr, "META *?"); break;
+    case META_ASTERISK_PLUS: fprintf(stderr, "META *+"); break;
+    case META_PLUS: fprintf(stderr, "META +"); break;
+    case META_PLUS_QUERY: fprintf(stderr, "META +?"); break;
+    case META_PLUS_PLUS: fprintf(stderr, "META ++"); break;
+    case META_QUERY: fprintf(stderr, "META ?"); break;
+    case META_QUERY_QUERY: fprintf(stderr, "META ??"); break;
+    case META_QUERY_PLUS: fprintf(stderr, "META ?+"); break;
+
+    case META_ATOMIC: fprintf(stderr, "META (?>"); break;
+    case META_NOCAPTURE: fprintf(stderr, "META (?:"); break;
+    case META_LOOKAHEAD: fprintf(stderr, "META (?="); break;
+    case META_LOOKAHEADNOT: fprintf(stderr, "META (?!"); break;
+    case META_LOOKAHEAD_NA: fprintf(stderr, "META (*napla:"); break;
+    case META_SCRIPT_RUN: fprintf(stderr, "META (*sr:"); break;
+    case META_KET: fprintf(stderr, "META )"); break;
+    case META_ALT: fprintf(stderr, "META | %d", meta_arg); break;
+
+    case META_CLASS: fprintf(stderr, "META ["); break;
+    case META_CLASS_NOT: fprintf(stderr, "META [^"); break;
+    case META_CLASS_END: fprintf(stderr, "META ]"); break;
+    case META_CLASS_EMPTY: fprintf(stderr, "META []"); break;
+    case META_CLASS_EMPTY_NOT: fprintf(stderr, "META [^]"); break;
+
+    case META_RANGE_LITERAL: fprintf(stderr, "META - (literal)"); break;
+    case META_RANGE_ESCAPED: fprintf(stderr, "META - (escaped)"); break;
+
+    case META_POSIX: fprintf(stderr, "META_POSIX %d", *pptr++); break;
+    case META_POSIX_NEG: fprintf(stderr, "META_POSIX_NEG %d", *pptr++); break;
+
+    case META_ACCEPT: fprintf(stderr, "META (*ACCEPT)"); break;
+    case META_FAIL: fprintf(stderr, "META (*FAIL)"); break;
+    case META_COMMIT: fprintf(stderr, "META (*COMMIT)"); break;
+    case META_PRUNE: fprintf(stderr, "META (*PRUNE)"); break;
+    case META_SKIP: fprintf(stderr, "META (*SKIP)"); break;
+    case META_THEN: fprintf(stderr, "META (*THEN)"); break;
+
+    case META_OPTIONS: fprintf(stderr, "META_OPTIONS 0x%02x", *pptr++); break;
+
+    case META_LOOKBEHIND:
+    fprintf(stderr, "META (?<= %d offset=", meta_arg);
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
+    break;
+
+    case META_LOOKBEHIND_NA:
+    fprintf(stderr, "META (*naplb: %d offset=", meta_arg);
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
+    break;
+
+    case META_LOOKBEHINDNOT:
+    fprintf(stderr, "META (?<! %d offset=", meta_arg);
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
+    break;
+
+    case META_CALLOUT_NUMBER:
+    fprintf(stderr, "META (?C%d) next=%d/%d", pptr[2], pptr[0],
+       pptr[1]);
+    pptr += 3;
+    break;
+
+    case META_CALLOUT_STRING:
+      {
+      uint32_t patoffset = *pptr++;    /* Offset of next pattern item */
+      uint32_t patlength = *pptr++;    /* Length of next pattern item */
+      fprintf(stderr, "META (?Cstring) length=%d offset=", *pptr++);
+      GETOFFSET(offset, pptr);
+      fprintf(stderr, "%zd next=%d/%d", offset, patoffset, patlength);
+      }
+    break;
+
+    case META_RECURSE_BYNAME:
+    fprintf(stderr, "META (?(&name) length=%d offset=", *pptr++);
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
+    break;
+
+    case META_BACKREF_BYNAME:
+    fprintf(stderr, "META_BACKREF_BYNAME length=%d offset=", *pptr++);
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
+    break;
+
+    case META_COND_NUMBER:
+    fprintf(stderr, "META_COND_NUMBER %d offset=", pptr[SIZEOFFSET]);
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
+    pptr++;
+    break;
+
+    case META_COND_DEFINE:
+    fprintf(stderr, "META (?(DEFINE) offset=");
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
+    break;
+
+    case META_COND_VERSION:
+    fprintf(stderr, "META (?(VERSION%s", (*pptr++ == 0)? "=" : ">=");
+    fprintf(stderr, "%d.", *pptr++);
+    fprintf(stderr, "%d)", *pptr++);
+    break;
+
+    case META_COND_NAME:
+    fprintf(stderr, "META (?(<name>) length=%d offset=", *pptr++);
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
+    break;
+
+    case META_COND_RNAME:
+    fprintf(stderr, "META (?(R&name) length=%d offset=", *pptr++);
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
+    break;
+
+    /* This is kept as a name, because it might be. */
+
+    case META_COND_RNUMBER:
+    fprintf(stderr, "META (?(Rnumber) length=%d offset=", *pptr++);
+    GETOFFSET(offset, pptr);
+    fprintf(stderr, "%zd", offset);
+    break;
+
+    case META_MARK:
+    fprintf(stderr, "META (*MARK:");
+    goto SHOWARG;
+
+    case META_COMMIT_ARG:
+    fprintf(stderr, "META (*COMMIT:");
+    goto SHOWARG;
+
+    case META_PRUNE_ARG:
+    fprintf(stderr, "META (*PRUNE:");
+    goto SHOWARG;
+
+    case META_SKIP_ARG:
+    fprintf(stderr, "META (*SKIP:");
+    goto SHOWARG;
+
+    case META_THEN_ARG:
+    fprintf(stderr, "META (*THEN:");
+    SHOWARG:
+    length = *pptr++;
+    for (i = 0; i < length; i++)
+      {
+      uint32_t cc = *pptr++;
+      if (cc > 32 && cc < 128) fprintf(stderr, "%c", cc);
+        else fprintf(stderr, "\\x{%x}", cc);
+      }
+    fprintf(stderr, ") length=%u", length);
+    break;
+    }
+  fprintf(stderr, "\n");
+  }
+return;
+}
+#endif  /* DEBUG_SHOW_PARSED */
+
+
+
+/*************************************************
+*               Copy compiled code               *
+*************************************************/
+
+/* Compiled JIT code cannot be copied, so the new compiled block has no
+associated JIT data. */
+
+PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION
+pcre2_code_copy(const pcre2_code *code)
+{
+PCRE2_SIZE* ref_count;
+pcre2_code *newcode;
+
+if (code == NULL) return NULL;
+newcode = code->memctl.malloc(code->blocksize, code->memctl.memory_data);
+if (newcode == NULL) return NULL;
+memcpy(newcode, code, code->blocksize);
+newcode->executable_jit = NULL;
+
+/* If the code is one that has been deserialized, increment the reference count
+in the decoded tables. */
+
+if ((code->flags & PCRE2_DEREF_TABLES) != 0)
+  {
+  ref_count = (PCRE2_SIZE *)(code->tables + TABLES_LENGTH);
+  (*ref_count)++;
+  }
+
+return newcode;
+}
+
+
+
+/*************************************************
+*     Copy compiled code and character tables    *
+*************************************************/
+
+/* Compiled JIT code cannot be copied, so the new compiled block has no
+associated JIT data. This version of code_copy also makes a separate copy of
+the character tables. */
+
+PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION
+pcre2_code_copy_with_tables(const pcre2_code *code)
+{
+PCRE2_SIZE* ref_count;
+pcre2_code *newcode;
+uint8_t *newtables;
+
+if (code == NULL) return NULL;
+newcode = code->memctl.malloc(code->blocksize, code->memctl.memory_data);
+if (newcode == NULL) return NULL;
+memcpy(newcode, code, code->blocksize);
+newcode->executable_jit = NULL;
+
+newtables = code->memctl.malloc(TABLES_LENGTH + sizeof(PCRE2_SIZE),
+  code->memctl.memory_data);
+if (newtables == NULL)
+  {
+  code->memctl.free((void *)newcode, code->memctl.memory_data);
+  return NULL;
+  }
+memcpy(newtables, code->tables, TABLES_LENGTH);
+ref_count = (PCRE2_SIZE *)(newtables + TABLES_LENGTH);
+*ref_count = 1;
+
+newcode->tables = newtables;
+newcode->flags |= PCRE2_DEREF_TABLES;
+return newcode;
+}
+
+
+
+/*************************************************
+*               Free compiled code               *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_code_free(pcre2_code *code)
+{
+PCRE2_SIZE* ref_count;
+
+if (code != NULL)
+  {
+  if (code->executable_jit != NULL)
+    PRIV(jit_free)(code->executable_jit, &code->memctl);
+
+  if ((code->flags & PCRE2_DEREF_TABLES) != 0)
+    {
+    /* Decoded tables belong to the codes after deserialization, and they must
+    be freed when there are no more references to them. The *ref_count should
+    always be > 0. */
+
+    ref_count = (PCRE2_SIZE *)(code->tables + TABLES_LENGTH);
+    if (*ref_count > 0)
+      {
+      (*ref_count)--;
+      if (*ref_count == 0)
+        code->memctl.free((void *)code->tables, code->memctl.memory_data);
+      }
+    }
+
+  code->memctl.free(code, code->memctl.memory_data);
+  }
+}
+
+
+
+/*************************************************
+*         Read a number, possibly signed         *
+*************************************************/
+
+/* This function is used to read numbers in the pattern. The initial pointer
+must be the sign or first digit of the number. When relative values (introduced
+by + or -) are allowed, they are relative group numbers, and the result must be
+greater than zero.
+
+Arguments:
+  ptrptr      points to the character pointer variable
+  ptrend      points to the end of the input string
+  allow_sign  if < 0, sign not allowed; if >= 0, sign is relative to this
+  max_value   the largest number allowed
+  max_error   the error to give for an over-large number
+  intptr      where to put the result
+  errcodeptr  where to put an error code
+
+Returns:      TRUE  - a number was read
+              FALSE - errorcode == 0 => no number was found
+                      errorcode != 0 => an error occurred
+*/
+
+static BOOL
+read_number(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, int32_t allow_sign,
+  uint32_t max_value, uint32_t max_error, int *intptr, int *errorcodeptr)
+{
+int sign = 0;
+uint32_t n = 0;
+PCRE2_SPTR ptr = *ptrptr;
+BOOL yield = FALSE;
+
+*errorcodeptr = 0;
+
+if (allow_sign >= 0 && ptr < ptrend)
+  {
+  if (*ptr == CHAR_PLUS)
+    {
+    sign = +1;
+    max_value -= allow_sign;
+    ptr++;
+    }
+  else if (*ptr == CHAR_MINUS)
+    {
+    sign = -1;
+    ptr++;
+    }
+  }
+
+if (ptr >= ptrend || !IS_DIGIT(*ptr)) return FALSE;
+while (ptr < ptrend && IS_DIGIT(*ptr))
+  {
+  n = n * 10 + *ptr++ - CHAR_0;
+  if (n > max_value)
+    {
+    *errorcodeptr = max_error;
+    goto EXIT;
+    }
+  }
+
+if (allow_sign >= 0 && sign != 0)
+  {
+  if (n == 0)
+    {
+    *errorcodeptr = ERR26;  /* +0 and -0 are not allowed */
+    goto EXIT;
+    }
+
+  if (sign > 0) n += allow_sign;
+  else if ((int)n > allow_sign)
+    {
+    *errorcodeptr = ERR15;  /* Non-existent subpattern */
+    goto EXIT;
+    }
+  else n = allow_sign + 1 - n;
+  }
+
+yield = TRUE;
+
+EXIT:
+*intptr = n;
+*ptrptr = ptr;
+return yield;
+}
+
+
+
+/*************************************************
+*         Read repeat counts                     *
+*************************************************/
+
+/* Read an item of the form {n,m} and return the values if non-NULL pointers
+are supplied. Repeat counts must be less than 65536 (MAX_REPEAT_COUNT); a
+larger value is used for "unlimited". We have to use signed arguments for
+read_number() because it is capable of returning a signed value.
+
+Arguments:
+  ptrptr         points to pointer to character after'{'
+  ptrend         pointer to end of input
+  minp           if not NULL, pointer to int for min
+  maxp           if not NULL, pointer to int for max (-1 if no max)
+                 returned as -1 if no max
+  errorcodeptr   points to error code variable
+
+Returns:         FALSE if not a repeat quantifier, errorcode set zero
+                 FALSE on error, with errorcode set non-zero
+                 TRUE on success, with pointer updated to point after '}'
+*/
+
+static BOOL
+read_repeat_counts(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t *minp,
+  uint32_t *maxp, int *errorcodeptr)
+{
+PCRE2_SPTR p = *ptrptr;
+BOOL yield = FALSE;
+int32_t min = 0;
+int32_t max = REPEAT_UNLIMITED; /* This value is larger than MAX_REPEAT_COUNT */
+
+/* NB read_number() initializes the error code to zero. The only error is for a
+number that is too big. */
+
+if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &min, errorcodeptr))
+  goto EXIT;
+
+if (p >= ptrend) goto EXIT;
+
+if (*p == CHAR_RIGHT_CURLY_BRACKET)
+  {
+  p++;
+  max = min;
+  }
+
+else
+  {
+  if (*p++ != CHAR_COMMA || p >= ptrend) goto EXIT;
+  if (*p != CHAR_RIGHT_CURLY_BRACKET)
+    {
+    if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &max,
+        errorcodeptr) || p >= ptrend ||  *p != CHAR_RIGHT_CURLY_BRACKET)
+      goto EXIT;
+    if (max < min)
+      {
+      *errorcodeptr = ERR4;
+      goto EXIT;
+      }
+    }
+  p++;
+  }
+
+yield = TRUE;
+if (minp != NULL) *minp = (uint32_t)min;
+if (maxp != NULL) *maxp = (uint32_t)max;
+
+/* Update the pattern pointer on success, or after an error, but not when
+the result is "not a repeat quantifier". */
+
+EXIT:
+if (yield || *errorcodeptr != 0) *ptrptr = p;
+return yield;
+}
+
+
+
+/*************************************************
+*            Handle escapes                      *
+*************************************************/
+
+/* This function is called when a \ has been encountered. It either returns a
+positive value for a simple escape such as \d, or 0 for a data character, which
+is placed in chptr. A backreference to group n is returned as negative n. On
+entry, ptr is pointing at the character after \. On exit, it points after the
+final code unit of the escape sequence.
+
+This function is also called from pcre2_substitute() to handle escape sequences
+in replacement strings. In this case, the cb argument is NULL, and in the case
+of escapes that have further processing, only sequences that define a data
+character are recognised. The isclass argument is not relevant; the options
+argument is the final value of the compiled pattern's options.
+
+Arguments:
+  ptrptr         points to the input position pointer
+  ptrend         points to the end of the input
+  chptr          points to a returned data character
+  errorcodeptr   points to the errorcode variable (containing zero)
+  options        the current options bits
+  isclass        TRUE if inside a character class
+  cb             compile data block or NULL when called from pcre2_substitute()
+
+Returns:         zero => a data character
+                 positive => a special escape sequence
+                 negative => a numerical back reference
+                 on error, errorcodeptr is set non-zero
+*/
+
+int
+PRIV(check_escape)(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t *chptr,
+  int *errorcodeptr, uint32_t options, uint32_t extra_options, BOOL isclass,
+  compile_block *cb)
+{
+BOOL utf = (options & PCRE2_UTF) != 0;
+PCRE2_SPTR ptr = *ptrptr;
+uint32_t c, cc;
+int escape = 0;
+int i;
+
+/* If backslash is at the end of the string, it's an error. */
+
+if (ptr >= ptrend)
+  {
+  *errorcodeptr = ERR1;
+  return 0;
+  }
+
+GETCHARINCTEST(c, ptr);         /* Get character value, increment pointer */
+*errorcodeptr = 0;              /* Be optimistic */
+
+/* Non-alphanumerics are literals, so we just leave the value in c. An initial
+value test saves a memory lookup for code points outside the alphanumeric
+range. */
+
+if (c < ESCAPES_FIRST || c > ESCAPES_LAST) {}  /* Definitely literal */
+
+/* Otherwise, do a table lookup. Non-zero values need little processing here. A
+positive value is a literal value for something like \n. A negative value is
+the negation of one of the ESC_ macros that is passed back for handling by the
+calling function. Some extra checking is needed for \N because only \N{U+dddd}
+is supported. If the value is zero, further processing is handled below. */
+
+else if ((i = escapes[c - ESCAPES_FIRST]) != 0)
+  {
+  if (i > 0)
+    {
+    c = (uint32_t)i;
+    if (c == CHAR_CR && (extra_options & PCRE2_EXTRA_ESCAPED_CR_IS_LF) != 0)
+      c = CHAR_LF;
+    }
+  else  /* Negative table entry */
+    {
+    escape = -i;                    /* Else return a special escape */
+    if (cb != NULL && (escape == ESC_P || escape == ESC_p || escape == ESC_X))
+      cb->external_flags |= PCRE2_HASBKPORX;   /* Note \P, \p, or \X */
+
+    /* Perl supports \N{name} for character names and \N{U+dddd} for numerical
+    Unicode code points, as well as plain \N for "not newline". PCRE does not
+    support \N{name}. However, it does support quantification such as \N{2,3},
+    so if \N{ is not followed by U+dddd we check for a quantifier. */
+
+    if (escape == ESC_N && ptr < ptrend && *ptr == CHAR_LEFT_CURLY_BRACKET)
+      {
+      PCRE2_SPTR p = ptr + 1;
+
+      /* \N{U+ can be handled by the \x{ code. However, this construction is
+      not valid in EBCDIC environments because it specifies a Unicode
+      character, not a codepoint in the local code. For example \N{U+0041}
+      must be "A" in all environments. Also, in Perl, \N{U+ forces Unicode
+      casing semantics for the entire pattern, so allow it only in UTF (i.e.
+      Unicode) mode. */
+
+      if (ptrend - p > 1 && *p == CHAR_U && p[1] == CHAR_PLUS)
+        {
+#ifdef EBCDIC
+        *errorcodeptr = ERR93;
+#else
+        if (utf)
+          {
+          ptr = p + 1;
+          escape = 0;   /* Not a fancy escape after all */
+          goto COME_FROM_NU;
+          }
+        else *errorcodeptr = ERR93;
+#endif
+        }
+
+      /* Give an error if what follows is not a quantifier, but don't override
+      an error set by the quantifier reader (e.g. number overflow). */
+
+      else
+        {
+        if (!read_repeat_counts(&p, ptrend, NULL, NULL, errorcodeptr) &&
+             *errorcodeptr == 0)
+          *errorcodeptr = ERR37;
+        }
+      }
+    }
+  }
+
+/* Escapes that need further processing, including those that are unknown, have
+a zero entry in the lookup table. When called from pcre2_substitute(), only \c,
+\o, and \x are recognized (\u and \U can never appear as they are used for case
+forcing). */
+
+else
+  {
+  int s;
+  PCRE2_SPTR oldptr;
+  BOOL overflow;
+  BOOL alt_bsux =
+    ((options & PCRE2_ALT_BSUX) | (extra_options & PCRE2_EXTRA_ALT_BSUX)) != 0;
+
+  /* Filter calls from pcre2_substitute(). */
+
+  if (cb == NULL)
+    {
+    if (c != CHAR_c && c != CHAR_o && c != CHAR_x)
+      {
+      *errorcodeptr = ERR3;
+      return 0;
+      }
+    alt_bsux = FALSE;   /* Do not modify \x handling */
+    }
+
+  switch (c)
+    {
+    /* A number of Perl escapes are not handled by PCRE. We give an explicit
+    error. */
+
+    case CHAR_F:
+    case CHAR_l:
+    case CHAR_L:
+    *errorcodeptr = ERR37;
+    break;
+
+    /* \u is unrecognized when neither PCRE2_ALT_BSUX nor PCRE2_EXTRA_ALT_BSUX
+    is set. Otherwise, \u must be followed by exactly four hex digits or, if
+    PCRE2_EXTRA_ALT_BSUX is set, by any number of hex digits in braces.
+    Otherwise it is a lowercase u letter. This gives some compatibility with
+    ECMAScript (aka JavaScript). */
+
+    case CHAR_u:
+    if (!alt_bsux) *errorcodeptr = ERR37; else
+      {
+      uint32_t xc;
+
+      if (ptr >= ptrend) break;
+      if (*ptr == CHAR_LEFT_CURLY_BRACKET &&
+          (extra_options & PCRE2_EXTRA_ALT_BSUX) != 0)
+        {
+        PCRE2_SPTR hptr = ptr + 1;
+        cc = 0;
+
+        while (hptr < ptrend && (xc = XDIGIT(*hptr)) != 0xff)
+          {
+          if ((cc & 0xf0000000) != 0)  /* Test for 32-bit overflow */
+            {
+            *errorcodeptr = ERR77;
+            ptr = hptr;   /* Show where */
+            break;        /* *hptr != } will cause another break below */
+            }
+          cc = (cc << 4) | xc;
+          hptr++;
+          }
+
+        if (hptr == ptr + 1 ||   /* No hex digits */
+            hptr >= ptrend ||    /* Hit end of input */
+            *hptr != CHAR_RIGHT_CURLY_BRACKET)  /* No } terminator */
+          break;         /* Hex escape not recognized */
+
+        c = cc;          /* Accept the code point */
+        ptr = hptr + 1;
+        }
+
+      else  /* Must be exactly 4 hex digits */
+        {
+        if (ptrend - ptr < 4) break;               /* Less than 4 chars */
+        if ((cc = XDIGIT(ptr[0])) == 0xff) break;  /* Not a hex digit */
+        if ((xc = XDIGIT(ptr[1])) == 0xff) break;  /* Not a hex digit */
+        cc = (cc << 4) | xc;
+        if ((xc = XDIGIT(ptr[2])) == 0xff) break;  /* Not a hex digit */
+        cc = (cc << 4) | xc;
+        if ((xc = XDIGIT(ptr[3])) == 0xff) break;  /* Not a hex digit */
+        c = (cc << 4) | xc;
+        ptr += 4;
+        }
+
+      if (utf)
+        {
+        if (c > 0x10ffffU) *errorcodeptr = ERR77;
+        else
+          if (c >= 0xd800 && c <= 0xdfff &&
+              (extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0)
+                *errorcodeptr = ERR73;
+        }
+      else if (c > MAX_NON_UTF_CHAR) *errorcodeptr = ERR77;
+      }
+    break;
+
+    /* \U is unrecognized unless PCRE2_ALT_BSUX or PCRE2_EXTRA_ALT_BSUX is set,
+    in which case it is an upper case letter. */
+
+    case CHAR_U:
+    if (!alt_bsux) *errorcodeptr = ERR37;
+    break;
+
+    /* In a character class, \g is just a literal "g". Outside a character
+    class, \g must be followed by one of a number of specific things:
+
+    (1) A number, either plain or braced. If positive, it is an absolute
+    backreference. If negative, it is a relative backreference. This is a Perl
+    5.10 feature.
+
+    (2) Perl 5.10 also supports \g{name} as a reference to a named group. This
+    is part of Perl's movement towards a unified syntax for back references. As
+    this is synonymous with \k{name}, we fudge it up by pretending it really
+    was \k{name}.
+
+    (3) For Oniguruma compatibility we also support \g followed by a name or a
+    number either in angle brackets or in single quotes. However, these are
+    (possibly recursive) subroutine calls, _not_ backreferences. We return
+    the ESC_g code.
+
+    Summary: Return a negative number for a numerical back reference, ESC_k for
+    a named back reference, and ESC_g for a named or numbered subroutine call.
+    */
+
+    case CHAR_g:
+    if (isclass) break;
+
+    if (ptr >= ptrend)
+      {
+      *errorcodeptr = ERR57;
+      break;
+      }
+
+    if (*ptr == CHAR_LESS_THAN_SIGN || *ptr == CHAR_APOSTROPHE)
+      {
+      escape = ESC_g;
+      break;
+      }
+
+    /* If there is a brace delimiter, try to read a numerical reference. If
+    there isn't one, assume we have a name and treat it as \k. */
+
+    if (*ptr == CHAR_LEFT_CURLY_BRACKET)
+      {
+      PCRE2_SPTR p = ptr + 1;
+      if (!read_number(&p, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &s,
+          errorcodeptr))
+        {
+        if (*errorcodeptr == 0) escape = ESC_k;  /* No number found */
+        break;
+        }
+      if (p >= ptrend || *p != CHAR_RIGHT_CURLY_BRACKET)
+        {
+        *errorcodeptr = ERR57;
+        break;
+        }
+      ptr = p + 1;
+      }
+
+    /* Read an undelimited number */
+
+    else
+      {
+      if (!read_number(&ptr, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &s,
+          errorcodeptr))
+        {
+        if (*errorcodeptr == 0) *errorcodeptr = ERR57;  /* No number found */
+        break;
+        }
+      }
+
+    if (s <= 0)
+      {
+      *errorcodeptr = ERR15;
+      break;
+      }
+
+    escape = -s;
+    break;
+
+    /* The handling of escape sequences consisting of a string of digits
+    starting with one that is not zero is not straightforward. Perl has changed
+    over the years. Nowadays \g{} for backreferences and \o{} for octal are
+    recommended to avoid the ambiguities in the old syntax.
+
+    Outside a character class, the digits are read as a decimal number. If the
+    number is less than 10, or if there are that many previous extracting left
+    brackets, it is a back reference. Otherwise, up to three octal digits are
+    read to form an escaped character code. Thus \123 is likely to be octal 123
+    (cf \0123, which is octal 012 followed by the literal 3).
+
+    Inside a character class, \ followed by a digit is always either a literal
+    8 or 9 or an octal number. */
+
+    case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4: case CHAR_5:
+    case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9:
+
+    if (!isclass)
+      {
+      oldptr = ptr;
+      ptr--;   /* Back to the digit */
+      if (!read_number(&ptr, ptrend, -1, INT_MAX/10 - 1, ERR61, &s,
+          errorcodeptr))
+        break;
+
+      /* \1 to \9 are always back references. \8x and \9x are too; \1x to \7x
+      are octal escapes if there are not that many previous captures. */
+
+      if (s < 10 || oldptr[-1] >= CHAR_8 || s <= (int)cb->bracount)
+        {
+        if (s > (int)MAX_GROUP_NUMBER) *errorcodeptr = ERR61;
+          else escape = -s;     /* Indicates a back reference */
+        break;
+        }
+      ptr = oldptr;      /* Put the pointer back and fall through */
+      }
+
+    /* Handle a digit following \ when the number is not a back reference, or
+    we are within a character class. If the first digit is 8 or 9, Perl used to
+    generate a binary zero and then treat the digit as a following literal. At
+    least by Perl 5.18 this changed so as not to insert the binary zero. */
+
+    if (c >= CHAR_8) break;
+
+    /* Fall through */
+
+    /* \0 always starts an octal number, but we may drop through to here with a
+    larger first octal digit. The original code used just to take the least
+    significant 8 bits of octal numbers (I think this is what early Perls used
+    to do). Nowadays we allow for larger numbers in UTF-8 mode and 16-bit mode,
+    but no more than 3 octal digits. */
+
+    case CHAR_0:
+    c -= CHAR_0;
+    while(i++ < 2 && ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7)
+        c = c * 8 + *ptr++ - CHAR_0;
+#if PCRE2_CODE_UNIT_WIDTH == 8
+    if (!utf && c > 0xff) *errorcodeptr = ERR51;
+#endif
+    break;
+
+    /* \o is a relatively new Perl feature, supporting a more general way of
+    specifying character codes in octal. The only supported form is \o{ddd}. */
+
+    case CHAR_o:
+    if (ptr >= ptrend || *ptr++ != CHAR_LEFT_CURLY_BRACKET)
+      {
+      ptr--;
+      *errorcodeptr = ERR55;
+      }
+    else if (ptr >= ptrend || *ptr == CHAR_RIGHT_CURLY_BRACKET)
+      *errorcodeptr = ERR78;
+    else
+      {
+      c = 0;
+      overflow = FALSE;
+      while (ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7)
+        {
+        cc = *ptr++;
+        if (c == 0 && cc == CHAR_0) continue;     /* Leading zeroes */
+#if PCRE2_CODE_UNIT_WIDTH == 32
+        if (c >= 0x20000000l) { overflow = TRUE; break; }
+#endif
+        c = (c << 3) + (cc - CHAR_0);
+#if PCRE2_CODE_UNIT_WIDTH == 8
+        if (c > (utf ? 0x10ffffU : 0xffU)) { overflow = TRUE; break; }
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+        if (c > (utf ? 0x10ffffU : 0xffffU)) { overflow = TRUE; break; }
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+        if (utf && c > 0x10ffffU) { overflow = TRUE; break; }
+#endif
+        }
+      if (overflow)
+        {
+        while (ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7) ptr++;
+        *errorcodeptr = ERR34;
+        }
+      else if (ptr < ptrend && *ptr++ == CHAR_RIGHT_CURLY_BRACKET)
+        {
+        if (utf && c >= 0xd800 && c <= 0xdfff &&
+            (extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0)
+          {
+          ptr--;
+          *errorcodeptr = ERR73;
+          }
+        }
+      else
+        {
+        ptr--;
+        *errorcodeptr = ERR64;
+        }
+      }
+    break;
+
+    /* When PCRE2_ALT_BSUX or PCRE2_EXTRA_ALT_BSUX is set, \x must be followed
+    by two hexadecimal digits. Otherwise it is a lowercase x letter. */
+
+    case CHAR_x:
+    if (alt_bsux)
+      {
+      uint32_t xc;
+      if (ptrend - ptr < 2) break;               /* Less than 2 characters */
+      if ((cc = XDIGIT(ptr[0])) == 0xff) break;  /* Not a hex digit */
+      if ((xc = XDIGIT(ptr[1])) == 0xff) break;  /* Not a hex digit */
+      c = (cc << 4) | xc;
+      ptr += 2;
+      }
+
+    /* Handle \x in Perl's style. \x{ddd} is a character code which can be
+    greater than 0xff in UTF-8 or non-8bit mode, but only if the ddd are hex
+    digits. If not, { used to be treated as a data character. However, Perl
+    seems to read hex digits up to the first non-such, and ignore the rest, so
+    that, for example \x{zz} matches a binary zero. This seems crazy, so PCRE
+    now gives an error. */
+
+    else
+      {
+      if (ptr < ptrend && *ptr == CHAR_LEFT_CURLY_BRACKET)
+        {
+#ifndef EBCDIC
+        COME_FROM_NU:
+#endif
+        if (++ptr >= ptrend || *ptr == CHAR_RIGHT_CURLY_BRACKET)
+          {
+          *errorcodeptr = ERR78;
+          break;
+          }
+        c = 0;
+        overflow = FALSE;
+
+        while (ptr < ptrend && (cc = XDIGIT(*ptr)) != 0xff)
+          {
+          ptr++;
+          if (c == 0 && cc == 0) continue;   /* Leading zeroes */
+#if PCRE2_CODE_UNIT_WIDTH == 32
+          if (c >= 0x10000000l) { overflow = TRUE; break; }
+#endif
+          c = (c << 4) | cc;
+          if ((utf && c > 0x10ffffU) || (!utf && c > MAX_NON_UTF_CHAR))
+            {
+            overflow = TRUE;
+            break;
+            }
+          }
+
+        if (overflow)
+          {
+          while (ptr < ptrend && XDIGIT(*ptr) != 0xff) ptr++;
+          *errorcodeptr = ERR34;
+          }
+        else if (ptr < ptrend && *ptr++ == CHAR_RIGHT_CURLY_BRACKET)
+          {
+          if (utf && c >= 0xd800 && c <= 0xdfff &&
+              (extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0)
+            {
+            ptr--;
+            *errorcodeptr = ERR73;
+            }
+          }
+
+        /* If the sequence of hex digits does not end with '}', give an error.
+        We used just to recognize this construct and fall through to the normal
+        \x handling, but nowadays Perl gives an error, which seems much more
+        sensible, so we do too. */
+
+        else
+          {
+          ptr--;
+          *errorcodeptr = ERR67;
+          }
+        }   /* End of \x{} processing */
+
+      /* Read a up to two hex digits after \x */
+
+      else
+        {
+        c = 0;
+        if (ptr >= ptrend || (cc = XDIGIT(*ptr)) == 0xff) break;  /* Not a hex digit */
+        ptr++;
+        c = cc;
+        if (ptr >= ptrend || (cc = XDIGIT(*ptr)) == 0xff) break;  /* Not a hex digit */
+        ptr++;
+        c = (c << 4) | cc;
+        }     /* End of \xdd handling */
+      }       /* End of Perl-style \x handling */
+    break;
+
+    /* The handling of \c is different in ASCII and EBCDIC environments. In an
+    ASCII (or Unicode) environment, an error is given if the character
+    following \c is not a printable ASCII character. Otherwise, the following
+    character is upper-cased if it is a letter, and after that the 0x40 bit is
+    flipped. The result is the value of the escape.
+
+    In an EBCDIC environment the handling of \c is compatible with the
+    specification in the perlebcdic document. The following character must be
+    a letter or one of small number of special characters. These provide a
+    means of defining the character values 0-31.
+
+    For testing the EBCDIC handling of \c in an ASCII environment, recognize
+    the EBCDIC value of 'c' explicitly. */
+
+#if defined EBCDIC && 'a' != 0x81
+    case 0x83:
+#else
+    case CHAR_c:
+#endif
+    if (ptr >= ptrend)
+      {
+      *errorcodeptr = ERR2;
+      break;
+      }
+    c = *ptr;
+    if (c >= CHAR_a && c <= CHAR_z) c = UPPER_CASE(c);
+
+    /* Handle \c in an ASCII/Unicode environment. */
+
+#ifndef EBCDIC    /* ASCII/UTF-8 coding */
+    if (c < 32 || c > 126)  /* Excludes all non-printable ASCII */
+      {
+      *errorcodeptr = ERR68;
+      break;
+      }
+    c ^= 0x40;
+
+    /* Handle \c in an EBCDIC environment. The special case \c? is converted to
+    255 (0xff) or 95 (0x5f) if other characters suggest we are using the
+    POSIX-BC encoding. (This is the way Perl indicates that it handles \c?.)
+    The other valid sequences correspond to a list of specific characters. */
+
+#else
+    if (c == CHAR_QUESTION_MARK)
+      c = ('\\' == 188 && '`' == 74)? 0x5f : 0xff;
+    else
+      {
+      for (i = 0; i < 32; i++)
+        {
+        if (c == ebcdic_escape_c[i]) break;
+        }
+      if (i < 32) c = i; else *errorcodeptr = ERR68;
+      }
+#endif  /* EBCDIC */
+
+    ptr++;
+    break;
+
+    /* Any other alphanumeric following \ is an error. Perl gives an error only
+    if in warning mode, but PCRE doesn't have a warning mode. */
+
+    default:
+    *errorcodeptr = ERR3;
+    *ptrptr = ptr - 1;     /* Point to the character at fault */
+    return 0;
+    }
+  }
+
+/* Set the pointer to the next character before returning. */
+
+*ptrptr = ptr;
+*chptr = c;
+return escape;
+}
+
+
+
+#ifdef SUPPORT_UNICODE
+/*************************************************
+*               Handle \P and \p                 *
+*************************************************/
+
+/* This function is called after \P or \p has been encountered, provided that
+PCRE2 is compiled with support for UTF and Unicode properties. On entry, the
+contents of ptrptr are pointing after the P or p. On exit, it is left pointing
+after the final code unit of the escape sequence.
+
+Arguments:
+  ptrptr         the pattern position pointer
+  negptr         a boolean that is set TRUE for negation else FALSE
+  ptypeptr       an unsigned int that is set to the type value
+  pdataptr       an unsigned int that is set to the detailed property value
+  errorcodeptr   the error code variable
+  cb             the compile data
+
+Returns:         TRUE if the type value was found, or FALSE for an invalid type
+*/
+
+static BOOL
+get_ucp(PCRE2_SPTR *ptrptr, BOOL *negptr, uint16_t *ptypeptr,
+  uint16_t *pdataptr, int *errorcodeptr, compile_block *cb)
+{
+PCRE2_UCHAR c;
+PCRE2_SIZE i, bot, top;
+PCRE2_SPTR ptr = *ptrptr;
+PCRE2_UCHAR name[32];
+
+if (ptr >= cb->end_pattern) goto ERROR_RETURN;
+c = *ptr++;
+*negptr = FALSE;
+
+/* \P or \p can be followed by a name in {}, optionally preceded by ^ for
+negation. */
+
+if (c == CHAR_LEFT_CURLY_BRACKET)
+  {
+  if (ptr >= cb->end_pattern) goto ERROR_RETURN;
+  if (*ptr == CHAR_CIRCUMFLEX_ACCENT)
+    {
+    *negptr = TRUE;
+    ptr++;
+    }
+  for (i = 0; i < (int)(sizeof(name) / sizeof(PCRE2_UCHAR)) - 1; i++)
+    {
+    if (ptr >= cb->end_pattern) goto ERROR_RETURN;
+    c = *ptr++;
+    if (c == CHAR_NUL) goto ERROR_RETURN;
+    if (c == CHAR_RIGHT_CURLY_BRACKET) break;
+    name[i] = c;
+    }
+  if (c != CHAR_RIGHT_CURLY_BRACKET) goto ERROR_RETURN;
+  name[i] = 0;
+  }
+
+/* Otherwise there is just one following character, which must be an ASCII
+letter. */
+
+else if (MAX_255(c) && (cb->ctypes[c] & ctype_letter) != 0)
+  {
+  name[0] = c;
+  name[1] = 0;
+  }
+else goto ERROR_RETURN;
+
+*ptrptr = ptr;
+
+/* Search for a recognized property name using binary chop. */
+
+bot = 0;
+top = PRIV(utt_size);
+
+while (bot < top)
+  {
+  int r;
+  i = (bot + top) >> 1;
+  r = PRIV(strcmp_c8)(name, PRIV(utt_names) + PRIV(utt)[i].name_offset);
+  if (r == 0)
+    {
+    *ptypeptr = PRIV(utt)[i].type;
+    *pdataptr = PRIV(utt)[i].value;
+    return TRUE;
+    }
+  if (r > 0) bot = i + 1; else top = i;
+  }
+*errorcodeptr = ERR47;   /* Unrecognized name */
+return FALSE;
+
+ERROR_RETURN:            /* Malformed \P or \p */
+*errorcodeptr = ERR46;
+*ptrptr = ptr;
+return FALSE;
+}
+#endif
+
+
+
+/*************************************************
+*           Check for POSIX class syntax         *
+*************************************************/
+
+/* This function is called when the sequence "[:" or "[." or "[=" is
+encountered in a character class. It checks whether this is followed by a
+sequence of characters terminated by a matching ":]" or ".]" or "=]". If we
+reach an unescaped ']' without the special preceding character, return FALSE.
+
+Originally, this function only recognized a sequence of letters between the
+terminators, but it seems that Perl recognizes any sequence of characters,
+though of course unknown POSIX names are subsequently rejected. Perl gives an
+"Unknown POSIX class" error for [:f\oo:] for example, where previously PCRE
+didn't consider this to be a POSIX class. Likewise for [:1234:].
+
+The problem in trying to be exactly like Perl is in the handling of escapes. We
+have to be sure that [abc[:x\]pqr] is *not* treated as containing a POSIX
+class, but [abc[:x\]pqr:]] is (so that an error can be generated). The code
+below handles the special cases \\ and \], but does not try to do any other
+escape processing. This makes it different from Perl for cases such as
+[:l\ower:] where Perl recognizes it as the POSIX class "lower" but PCRE does
+not recognize "l\ower". This is a lesser evil than not diagnosing bad classes
+when Perl does, I think.
+
+A user pointed out that PCRE was rejecting [:a[:digit:]] whereas Perl was not.
+It seems that the appearance of a nested POSIX class supersedes an apparent
+external class. For example, [:a[:digit:]b:] matches "a", "b", ":", or
+a digit. This is handled by returning FALSE if the start of a new group with
+the same terminator is encountered, since the next closing sequence must close
+the nested group, not the outer one.
+
+In Perl, unescaped square brackets may also appear as part of class names. For
+example, [:a[:abc]b:] gives unknown POSIX class "[:abc]b:]". However, for
+[:a[:abc]b][b:] it gives unknown POSIX class "[:abc]b][b:]", which does not
+seem right at all. PCRE does not allow closing square brackets in POSIX class
+names.
+
+Arguments:
+  ptr      pointer to the character after the initial [ (colon, dot, equals)
+  ptrend   pointer to the end of the pattern
+  endptr   where to return a pointer to the terminating ':', '.', or '='
+
+Returns:   TRUE or FALSE
+*/
+
+static BOOL
+check_posix_syntax(PCRE2_SPTR ptr, PCRE2_SPTR ptrend, PCRE2_SPTR *endptr)
+{
+PCRE2_UCHAR terminator;  /* Don't combine these lines; the Solaris cc */
+terminator = *ptr++;     /* compiler warns about "non-constant" initializer. */
+
+for (; ptrend - ptr >= 2; ptr++)
+  {
+  if (*ptr == CHAR_BACKSLASH &&
+      (ptr[1] == CHAR_RIGHT_SQUARE_BRACKET || ptr[1] == CHAR_BACKSLASH))
+    ptr++;
+
+  else if ((*ptr == CHAR_LEFT_SQUARE_BRACKET && ptr[1] == terminator) ||
+            *ptr == CHAR_RIGHT_SQUARE_BRACKET) return FALSE;
+
+  else if (*ptr == terminator && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET)
+    {
+    *endptr = ptr;
+    return TRUE;
+    }
+  }
+
+return FALSE;
+}
+
+
+
+/*************************************************
+*          Check POSIX class name                *
+*************************************************/
+
+/* This function is called to check the name given in a POSIX-style class entry
+such as [:alnum:].
+
+Arguments:
+  ptr        points to the first letter
+  len        the length of the name
+
+Returns:     a value representing the name, or -1 if unknown
+*/
+
+static int
+check_posix_name(PCRE2_SPTR ptr, int len)
+{
+const char *pn = posix_names;
+int yield = 0;
+while (posix_name_lengths[yield] != 0)
+  {
+  if (len == posix_name_lengths[yield] &&
+    PRIV(strncmp_c8)(ptr, pn, (unsigned int)len) == 0) return yield;
+  pn += posix_name_lengths[yield] + 1;
+  yield++;
+  }
+return -1;
+}
+
+
+
+/*************************************************
+*       Read a subpattern or VERB name           *
+*************************************************/
+
+/* This function is called from parse_regex() below whenever it needs to read
+the name of a subpattern or a (*VERB) or an (*alpha_assertion). The initial
+pointer must be to the character before the name. If that character is '*' we
+are reading a verb or alpha assertion name. The pointer is updated to point
+after the name, for a VERB or alpha assertion name, or after tha name's
+terminator for a subpattern name. Returning both the offset and the name
+pointer is redundant information, but some callers use one and some the other,
+so it is simplest just to return both.
+
+Arguments:
+  ptrptr      points to the character pointer variable
+  ptrend      points to the end of the input string
+  utf         true if the input is UTF-encoded
+  terminator  the terminator of a subpattern name must be this
+  offsetptr   where to put the offset from the start of the pattern
+  nameptr     where to put a pointer to the name in the input
+  namelenptr  where to put the length of the name
+  errcodeptr  where to put an error code
+  cb          pointer to the compile data block
+
+Returns:    TRUE if a name was read
+            FALSE otherwise, with error code set
+*/
+
+static BOOL
+read_name(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, BOOL utf, uint32_t terminator,
+  PCRE2_SIZE *offsetptr, PCRE2_SPTR *nameptr, uint32_t *namelenptr,
+  int *errorcodeptr, compile_block *cb)
+{
+PCRE2_SPTR ptr = *ptrptr;
+BOOL is_group = (*ptr != CHAR_ASTERISK);
+
+if (++ptr >= ptrend)               /* No characters in name */
+  {
+  *errorcodeptr = is_group? ERR62: /* Subpattern name expected */
+                            ERR60; /* Verb not recognized or malformed */
+  goto FAILED;
+  }
+
+*nameptr = ptr;
+*offsetptr = (PCRE2_SIZE)(ptr - cb->start_pattern);
+
+/* In UTF mode, a group name may contain letters and decimal digits as defined
+by Unicode properties, and underscores, but must not start with a digit. */
+
+#ifdef SUPPORT_UNICODE
+if (utf && is_group)
+  {
+  uint32_t c, type;
+
+  GETCHAR(c, ptr);
+  type = UCD_CHARTYPE(c);
+
+  if (type == ucp_Nd)
+    {
+    *errorcodeptr = ERR44;
+    goto FAILED;
+    }
+
+  for(;;)
+    {
+    if (type != ucp_Nd && PRIV(ucp_gentype)[type] != ucp_L &&
+        c != CHAR_UNDERSCORE) break;
+    ptr++;
+    FORWARDCHARTEST(ptr, ptrend);
+    if (ptr >= ptrend) break;
+    GETCHAR(c, ptr);
+    type = UCD_CHARTYPE(c);
+    }
+  }
+else
+#else
+(void)utf;  /* Avoid compiler warning */
+#endif      /* SUPPORT_UNICODE */
+
+/* Handle non-group names and group names in non-UTF modes. A group name must
+not start with a digit. If either of the others start with a digit it just
+won't be recognized. */
+
+  {
+  if (is_group && IS_DIGIT(*ptr))
+    {
+    *errorcodeptr = ERR44;
+    goto FAILED;
+    }
+
+  while (ptr < ptrend && MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype_word) != 0)
+    {
+    ptr++;
+    }
+  }
+
+/* Check name length */
+
+if (ptr > *nameptr + MAX_NAME_SIZE)
+  {
+  *errorcodeptr = ERR48;
+  goto FAILED;
+  }
+*namelenptr = (uint32_t)(ptr - *nameptr);
+
+/* Subpattern names must not be empty, and their terminator is checked here.
+(What follows a verb or alpha assertion name is checked separately.) */
+
+if (is_group)
+  {
+  if (ptr == *nameptr)
+    {
+    *errorcodeptr = ERR62;   /* Subpattern name expected */
+    goto FAILED;
+    }
+  if (ptr >= ptrend || *ptr != (PCRE2_UCHAR)terminator)
+    {
+    *errorcodeptr = ERR42;
+    goto FAILED;
+    }
+  ptr++;
+  }
+
+*ptrptr = ptr;
+return TRUE;
+
+FAILED:
+*ptrptr = ptr;
+return FALSE;
+}
+
+
+
+/*************************************************
+*          Manage callouts at start of cycle     *
+*************************************************/
+
+/* At the start of a new item in parse_regex() we are able to record the
+details of the previous item in a prior callout, and also to set up an
+automatic callout if enabled. Avoid having two adjacent automatic callouts,
+which would otherwise happen for items such as \Q that contribute nothing to
+the parsed pattern.
+
+Arguments:
+  ptr              current pattern pointer
+  pcalloutptr      points to a pointer to previous callout, or NULL
+  auto_callout     TRUE if auto_callouts are enabled
+  parsed_pattern   the parsed pattern pointer
+  cb               compile block
+
+Returns: possibly updated parsed_pattern pointer.
+*/
+
+static uint32_t *
+manage_callouts(PCRE2_SPTR ptr, uint32_t **pcalloutptr, BOOL auto_callout,
+  uint32_t *parsed_pattern, compile_block *cb)
+{
+uint32_t *previous_callout = *pcalloutptr;
+
+if (previous_callout != NULL) previous_callout[2] = (uint32_t)(ptr -
+  cb->start_pattern - (PCRE2_SIZE)previous_callout[1]);
+
+if (!auto_callout) previous_callout = NULL; else
+  {
+  if (previous_callout == NULL ||
+      previous_callout != parsed_pattern - 4 ||
+      previous_callout[3] != 255)
+    {
+    previous_callout = parsed_pattern;  /* Set up new automatic callout */
+    parsed_pattern += 4;
+    previous_callout[0] = META_CALLOUT_NUMBER;
+    previous_callout[2] = 0;
+    previous_callout[3] = 255;
+    }
+  previous_callout[1] = (uint32_t)(ptr - cb->start_pattern);
+  }
+
+*pcalloutptr = previous_callout;
+return parsed_pattern;
+}
+
+
+
+/*************************************************
+*      Parse regex and identify named groups     *
+*************************************************/
+
+/* This function is called first of all. It scans the pattern and does two
+things: (1) It identifies capturing groups and makes a table of named capturing
+groups so that information about them is fully available to both the compiling
+scans. (2) It writes a parsed version of the pattern with comments omitted and
+escapes processed into the parsed_pattern vector.
+
+Arguments:
+  ptr             points to the start of the pattern
+  options         compiling dynamic options (may change during the scan)
+  has_lookbehind  points to a boolean, set TRUE if a lookbehind is found
+  cb              pointer to the compile data block
+
+Returns:   zero on success or a non-zero error code, with the
+             error offset placed in the cb field
+*/
+
+/* A structure and some flags for dealing with nested groups. */
+
+typedef struct nest_save {
+  uint16_t  nest_depth;
+  uint16_t  reset_group;
+  uint16_t  max_group;
+  uint16_t  flags;
+  uint32_t  options;
+} nest_save;
+
+#define NSF_RESET          0x0001u
+#define NSF_CONDASSERT     0x0002u
+#define NSF_ATOMICSR       0x0004u
+
+/* Options that are changeable within the pattern must be tracked during
+parsing. Some (e.g. PCRE2_EXTENDED) are implemented entirely during parsing,
+but all must be tracked so that META_OPTIONS items set the correct values for
+the main compiling phase. */
+
+#define PARSE_TRACKED_OPTIONS (PCRE2_CASELESS|PCRE2_DOTALL|PCRE2_DUPNAMES| \
+  PCRE2_EXTENDED|PCRE2_EXTENDED_MORE|PCRE2_MULTILINE|PCRE2_NO_AUTO_CAPTURE| \
+  PCRE2_UNGREEDY)
+
+/* States used for analyzing ranges in character classes. The two OK values
+must be last. */
+
+enum { RANGE_NO, RANGE_STARTED, RANGE_OK_ESCAPED, RANGE_OK_LITERAL };
+
+/* Only in 32-bit mode can there be literals > META_END. A macro encapsulates
+the storing of literal values in the main parsed pattern, where they can always
+be quantified. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+#define PARSED_LITERAL(c, p) \
+  { \
+  if (c >= META_END) *p++ = META_BIGVALUE; \
+  *p++ = c; \
+  okquantifier = TRUE; \
+  }
+#else
+#define PARSED_LITERAL(c, p) *p++ = c; okquantifier = TRUE;
+#endif
+
+/* Here's the actual function. */
+
+static int parse_regex(PCRE2_SPTR ptr, uint32_t options, BOOL *has_lookbehind,
+  compile_block *cb)
+{
+uint32_t c;
+uint32_t delimiter;
+uint32_t namelen;
+uint32_t class_range_state;
+uint32_t *verblengthptr = NULL;     /* Value avoids compiler warning */
+uint32_t *verbstartptr = NULL;
+uint32_t *previous_callout = NULL;
+uint32_t *parsed_pattern = cb->parsed_pattern;
+uint32_t *parsed_pattern_end = cb->parsed_pattern_end;
+uint32_t meta_quantifier = 0;
+uint32_t add_after_mark = 0;
+uint32_t extra_options = cb->cx->extra_options;
+uint16_t nest_depth = 0;
+int after_manual_callout = 0;
+int expect_cond_assert = 0;
+int errorcode = 0;
+int escape;
+int i;
+BOOL inescq = FALSE;
+BOOL inverbname = FALSE;
+BOOL utf = (options & PCRE2_UTF) != 0;
+BOOL auto_callout = (options & PCRE2_AUTO_CALLOUT) != 0;
+BOOL isdupname;
+BOOL negate_class;
+BOOL okquantifier = FALSE;
+PCRE2_SPTR thisptr;
+PCRE2_SPTR name;
+PCRE2_SPTR ptrend = cb->end_pattern;
+PCRE2_SPTR verbnamestart = NULL;    /* Value avoids compiler warning */
+named_group *ng;
+nest_save *top_nest, *end_nests;
+
+/* Insert leading items for word and line matching (features provided for the
+benefit of pcre2grep). */
+
+if ((extra_options & PCRE2_EXTRA_MATCH_LINE) != 0)
+  {
+  *parsed_pattern++ = META_CIRCUMFLEX;
+  *parsed_pattern++ = META_NOCAPTURE;
+  }
+else if ((extra_options & PCRE2_EXTRA_MATCH_WORD) != 0)
+  {
+  *parsed_pattern++ = META_ESCAPE + ESC_b;
+  *parsed_pattern++ = META_NOCAPTURE;
+  }
+
+/* If the pattern is actually a literal string, process it separately to avoid
+cluttering up the main loop. */
+
+if ((options & PCRE2_LITERAL) != 0)
+  {
+  while (ptr < ptrend)
+    {
+    if (parsed_pattern >= parsed_pattern_end)
+      {
+      errorcode = ERR63;  /* Internal error (parsed pattern overflow) */
+      goto FAILED;
+      }
+    thisptr = ptr;
+    GETCHARINCTEST(c, ptr);
+    if (auto_callout)
+      parsed_pattern = manage_callouts(thisptr, &previous_callout,
+        auto_callout, parsed_pattern, cb);
+    PARSED_LITERAL(c, parsed_pattern);
+    }
+  goto PARSED_END;
+  }
+
+/* Process a real regex which may contain meta-characters. */
+
+top_nest = NULL;
+end_nests = (nest_save *)(cb->start_workspace + cb->workspace_size);
+
+/* The size of the nest_save structure might not be a factor of the size of the
+workspace. Therefore we must round down end_nests so as to correctly avoid
+creating a nest_save that spans the end of the workspace. */
+
+end_nests = (nest_save *)((char *)end_nests -
+  ((cb->workspace_size * sizeof(PCRE2_UCHAR)) % sizeof(nest_save)));
+
+/* PCRE2_EXTENDED_MORE implies PCRE2_EXTENDED */
+
+if ((options & PCRE2_EXTENDED_MORE) != 0) options |= PCRE2_EXTENDED;
+
+/* Now scan the pattern */
+
+while (ptr < ptrend)
+  {
+  int prev_expect_cond_assert;
+  uint32_t min_repeat, max_repeat;
+  uint32_t set, unset, *optset;
+  uint32_t terminator;
+  uint32_t prev_meta_quantifier;
+  BOOL prev_okquantifier;
+  PCRE2_SPTR tempptr;
+  PCRE2_SIZE offset;
+
+  if (parsed_pattern >= parsed_pattern_end)
+    {
+    errorcode = ERR63;  /* Internal error (parsed pattern overflow) */
+    goto FAILED;
+    }
+
+  if (nest_depth > cb->cx->parens_nest_limit)
+    {
+    errorcode = ERR19;
+    goto FAILED;        /* Parentheses too deeply nested */
+    }
+
+  /* Get next input character, save its position for callout handling. */
+
+  thisptr = ptr;
+  GETCHARINCTEST(c, ptr);
+
+  /* Copy quoted literals until \E, allowing for the possibility of automatic
+  callouts, except when processing a (*VERB) "name".  */
+
+  if (inescq)
+    {
+    if (c == CHAR_BACKSLASH && ptr < ptrend && *ptr == CHAR_E)
+      {
+      inescq = FALSE;
+      ptr++;   /* Skip E */
+      }
+    else
+      {
+      if (expect_cond_assert > 0)   /* A literal is not allowed if we are */
+        {                           /* expecting a conditional assertion, */
+        ptr--;                      /* but an empty \Q\E sequence is OK.  */
+        errorcode = ERR28;
+        goto FAILED;
+        }
+      if (inverbname)
+        {                          /* Don't use PARSED_LITERAL() because it */
+#if PCRE2_CODE_UNIT_WIDTH == 32    /* sets okquantifier. */
+        if (c >= META_END) *parsed_pattern++ = META_BIGVALUE;
+#endif
+        *parsed_pattern++ = c;
+        }
+      else
+        {
+        if (after_manual_callout-- <= 0)
+          parsed_pattern = manage_callouts(thisptr, &previous_callout,
+            auto_callout, parsed_pattern, cb);
+        PARSED_LITERAL(c, parsed_pattern);
+        }
+      meta_quantifier = 0;
+      }
+    continue;  /* Next character */
+    }
+
+  /* If we are processing the "name" part of a (*VERB:NAME) item, all
+  characters up to the closing parenthesis are literals except when
+  PCRE2_ALT_VERBNAMES is set. That causes backslash interpretation, but only \Q
+  and \E and escaped characters are allowed (no character types such as \d). If
+  PCRE2_EXTENDED is also set, we must ignore white space and # comments. Do
+  this by not entering the special (*VERB:NAME) processing - they are then
+  picked up below. Note that c is a character, not a code unit, so we must not
+  use MAX_255 to test its size because MAX_255 tests code units and is assumed
+  TRUE in 8-bit mode. */
+
+  if (inverbname &&
+       (
+        /* EITHER: not both options set */
+        ((options & (PCRE2_EXTENDED | PCRE2_ALT_VERBNAMES)) !=
+                    (PCRE2_EXTENDED | PCRE2_ALT_VERBNAMES)) ||
+#ifdef SUPPORT_UNICODE
+        /* OR: character > 255 AND not Unicode Pattern White Space */
+        (c > 255 && (c|1) != 0x200f && (c|1) != 0x2029) ||
+#endif
+        /* OR: not a # comment or isspace() white space */
+        (c < 256 && c != CHAR_NUMBER_SIGN && (cb->ctypes[c] & ctype_space) == 0
+#ifdef SUPPORT_UNICODE
+        /* and not CHAR_NEL when Unicode is supported */
+          && c != CHAR_NEL
+#endif
+       )))
+    {
+    PCRE2_SIZE verbnamelength;
+
+    switch(c)
+      {
+      default:                     /* Don't use PARSED_LITERAL() because it */
+#if PCRE2_CODE_UNIT_WIDTH == 32    /* sets okquantifier. */
+      if (c >= META_END) *parsed_pattern++ = META_BIGVALUE;
+#endif
+      *parsed_pattern++ = c;
+      break;
+
+      case CHAR_RIGHT_PARENTHESIS:
+      inverbname = FALSE;
+      /* This is the length in characters */
+      verbnamelength = (PCRE2_SIZE)(parsed_pattern - verblengthptr - 1);
+      /* But the limit on the length is in code units */
+      if (ptr - verbnamestart - 1 > (int)MAX_MARK)
+        {
+        ptr--;
+        errorcode = ERR76;
+        goto FAILED;
+        }
+      *verblengthptr = (uint32_t)verbnamelength;
+
+      /* If this name was on a verb such as (*ACCEPT) which does not continue,
+      a (*MARK) was generated for the name. We now add the original verb as the
+      next item. */
+
+      if (add_after_mark != 0)
+        {
+        *parsed_pattern++ = add_after_mark;
+        add_after_mark = 0;
+        }
+      break;
+
+      case CHAR_BACKSLASH:
+      if ((options & PCRE2_ALT_VERBNAMES) != 0)
+        {
+        escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options,
+          cb->cx->extra_options, FALSE, cb);
+        if (errorcode != 0) goto FAILED;
+        }
+      else escape = 0;   /* Treat all as literal */
+
+      switch(escape)
+        {
+        case 0:                    /* Don't use PARSED_LITERAL() because it */
+#if PCRE2_CODE_UNIT_WIDTH == 32    /* sets okquantifier. */
+        if (c >= META_END) *parsed_pattern++ = META_BIGVALUE;
+#endif
+        *parsed_pattern++ = c;
+        break;
+
+        case ESC_Q:
+        inescq = TRUE;
+        break;
+
+        case ESC_E:           /* Ignore */
+        break;
+
+        default:
+        errorcode = ERR40;    /* Invalid in verb name */
+        goto FAILED;
+        }
+      }
+    continue;   /* Next character in pattern */
+    }
+
+  /* Not a verb name character. At this point we must process everything that
+  must not change the quantification state. This is mainly comments, but we
+  handle \Q and \E here as well, so that an item such as A\Q\E+ is treated as
+  A+, as in Perl. An isolated \E is ignored. */
+
+  if (c == CHAR_BACKSLASH && ptr < ptrend)
+    {
+    if (*ptr == CHAR_Q || *ptr == CHAR_E)
+      {
+      inescq = *ptr == CHAR_Q;
+      ptr++;
+      continue;
+      }
+    }
+
+  /* Skip over whitespace and # comments in extended mode. Note that c is a
+  character, not a code unit, so we must not use MAX_255 to test its size
+  because MAX_255 tests code units and is assumed TRUE in 8-bit mode. The
+  whitespace characters are those designated as "Pattern White Space" by
+  Unicode, which are the isspace() characters plus CHAR_NEL (newline), which is
+  U+0085 in Unicode, plus U+200E, U+200F, U+2028, and U+2029. These are a
+  subset of space characters that match \h and \v. */
+
+  if ((options & PCRE2_EXTENDED) != 0)
+    {
+    if (c < 256 && (cb->ctypes[c] & ctype_space) != 0) continue;
+#ifdef SUPPORT_UNICODE
+    if (c == CHAR_NEL || (c|1) == 0x200f || (c|1) == 0x2029) continue;
+#endif
+    if (c == CHAR_NUMBER_SIGN)
+      {
+      while (ptr < ptrend)
+        {
+        if (IS_NEWLINE(ptr))      /* For non-fixed-length newline cases, */
+          {                       /* IS_NEWLINE sets cb->nllen. */
+          ptr += cb->nllen;
+          break;
+          }
+        ptr++;
+#ifdef SUPPORT_UNICODE
+        if (utf) FORWARDCHARTEST(ptr, ptrend);
+#endif
+        }
+      continue;  /* Next character in pattern */
+      }
+    }
+
+  /* Skip over bracketed comments */
+
+  if (c == CHAR_LEFT_PARENTHESIS && ptrend - ptr >= 2 &&
+      ptr[0] == CHAR_QUESTION_MARK && ptr[1] == CHAR_NUMBER_SIGN)
+    {
+    while (++ptr < ptrend && *ptr != CHAR_RIGHT_PARENTHESIS);
+    if (ptr >= ptrend)
+      {
+      errorcode = ERR18;  /* A special error for missing ) in a comment */
+      goto FAILED;        /* to make it easier to debug. */
+      }
+    ptr++;
+    continue;  /* Next character in pattern */
+    }
+
+  /* If the next item is not a quantifier, fill in length of any previous
+  callout and create an auto callout if required. */
+
+  if (c != CHAR_ASTERISK && c != CHAR_PLUS && c != CHAR_QUESTION_MARK &&
+       (c != CHAR_LEFT_CURLY_BRACKET ||
+         (tempptr = ptr,
+         !read_repeat_counts(&tempptr, ptrend, NULL, NULL, &errorcode))))
+    {
+    if (after_manual_callout-- <= 0)
+      parsed_pattern = manage_callouts(thisptr, &previous_callout, auto_callout,
+        parsed_pattern, cb);
+    }
+
+  /* If expect_cond_assert is 2, we have just passed (?( and are expecting an
+  assertion, possibly preceded by a callout. If the value is 1, we have just
+  had the callout and expect an assertion. There must be at least 3 more
+  characters in all cases. When expect_cond_assert is 2, we know that the
+  current character is an opening parenthesis, as otherwise we wouldn't be
+  here. However, when it is 1, we need to check, and it's easiest just to check
+  always. Note that expect_cond_assert may be negative, since all callouts just
+  decrement it. */
+
+  if (expect_cond_assert > 0)
+    {
+    BOOL ok = c == CHAR_LEFT_PARENTHESIS && ptrend - ptr >= 3 &&
+              (ptr[0] == CHAR_QUESTION_MARK || ptr[0] == CHAR_ASTERISK);
+    if (ok)
+      {
+      if (ptr[0] == CHAR_ASTERISK)  /* New alpha assertion format, possibly */
+        {
+        ok = MAX_255(ptr[1]) && (cb->ctypes[ptr[1]] & ctype_lcletter) != 0;
+        }
+      else switch(ptr[1])  /* Traditional symbolic format */
+        {
+        case CHAR_C:
+        ok = expect_cond_assert == 2;
+        break;
+
+        case CHAR_EQUALS_SIGN:
+        case CHAR_EXCLAMATION_MARK:
+        break;
+
+        case CHAR_LESS_THAN_SIGN:
+        ok = ptr[2] == CHAR_EQUALS_SIGN || ptr[2] == CHAR_EXCLAMATION_MARK;
+        break;
+
+        default:
+        ok = FALSE;
+        }
+      }
+
+    if (!ok)
+      {
+      ptr--;   /* Adjust error offset */
+      errorcode = ERR28;
+      goto FAILED;
+      }
+    }
+
+  /* Remember whether we are expecting a conditional assertion, and set the
+  default for this item. */
+
+  prev_expect_cond_assert = expect_cond_assert;
+  expect_cond_assert = 0;
+
+  /* Remember quantification status for the previous significant item, then set
+  default for this item. */
+
+  prev_okquantifier = okquantifier;
+  prev_meta_quantifier = meta_quantifier;
+  okquantifier = FALSE;
+  meta_quantifier = 0;
+
+  /* If the previous significant item was a quantifier, adjust the parsed code
+  if there is a following modifier. The base meta value is always followed by
+  the PLUS and QUERY values, in that order. We do this here rather than after
+  reading a quantifier so that intervening comments and /x whitespace can be
+  ignored without having to replicate code. */
+
+  if (prev_meta_quantifier != 0 && (c == CHAR_QUESTION_MARK || c == CHAR_PLUS))
+    {
+    parsed_pattern[(prev_meta_quantifier == META_MINMAX)? -3 : -1] =
+      prev_meta_quantifier + ((c == CHAR_QUESTION_MARK)?
+        0x00020000u : 0x00010000u);
+    continue;  /* Next character in pattern */
+    }
+
+
+  /* Process the next item in the main part of a pattern. */
+
+  switch(c)
+    {
+    default:              /* Non-special character */
+    PARSED_LITERAL(c, parsed_pattern);
+    break;
+
+
+    /* ---- Escape sequence ---- */
+
+    case CHAR_BACKSLASH:
+    tempptr = ptr;
+    escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options,
+      cb->cx->extra_options, FALSE, cb);
+    if (errorcode != 0)
+      {
+      ESCAPE_FAILED:
+      if ((extra_options & PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL) == 0)
+        goto FAILED;
+      ptr = tempptr;
+      if (ptr >= ptrend) c = CHAR_BACKSLASH; else
+        {
+        GETCHARINCTEST(c, ptr);   /* Get character value, increment pointer */
+        }
+      escape = 0;                 /* Treat as literal character */
+      }
+
+    /* The escape was a data escape or literal character. */
+
+    if (escape == 0)
+      {
+      PARSED_LITERAL(c, parsed_pattern);
+      }
+
+    /* The escape was a back (or forward) reference. We keep the offset in
+    order to give a more useful diagnostic for a bad forward reference. For
+    references to groups numbered less than 10 we can't use more than two items
+    in parsed_pattern because they may be just two characters in the input (and
+    in a 64-bit world an offset may need two elements). So for them, the offset
+    of the first occurrent is held in a special vector. */
+
+    else if (escape < 0)
+      {
+      offset = (PCRE2_SIZE)(ptr - cb->start_pattern - 1);
+      escape = -escape;
+      *parsed_pattern++ = META_BACKREF | (uint32_t)escape;
+      if (escape < 10)
+        {
+        if (cb->small_ref_offset[escape] == PCRE2_UNSET)
+          cb->small_ref_offset[escape] = offset;
+        }
+      else
+        {
+        PUTOFFSET(offset, parsed_pattern);
+        }
+      okquantifier = TRUE;
+      }
+
+    /* The escape was a character class such as \d etc. or other special
+    escape indicator such as \A or \X. Most of them generate just a single
+    parsed item, but \P and \p are followed by a 16-bit type and a 16-bit
+    value. They are supported only when Unicode is available. The type and
+    value are packed into a single 32-bit value so that the whole sequences
+    uses only two elements in the parsed_vector. This is because the same
+    coding is used if \d (for example) is turned into \p{Nd} when PCRE2_UCP is
+    set.
+
+    There are also some cases where the escape sequence is followed by a name:
+    \k{name}, \k<name>, and \k'name' are backreferences by name, and \g<name>
+    and \g'name' are subroutine calls by name; \g{name} is a synonym for
+    \k{name}. Note that \g<number> and \g'number' are handled by check_escape()
+    and returned as a negative value (handled above). A name is coded as an
+    offset into the pattern and a length. */
+
+    else switch (escape)
+      {
+      case ESC_C:
+#ifdef NEVER_BACKSLASH_C
+      errorcode = ERR85;
+      goto ESCAPE_FAILED;
+#else
+      if ((options & PCRE2_NEVER_BACKSLASH_C) != 0)
+        {
+        errorcode = ERR83;
+        goto ESCAPE_FAILED;
+        }
+#endif
+      okquantifier = TRUE;
+      *parsed_pattern++ = META_ESCAPE + escape;
+      break;
+
+      case ESC_X:
+#ifndef SUPPORT_UNICODE
+      errorcode = ERR45;   /* Supported only with Unicode support */
+      goto ESCAPE_FAILED;
+#endif
+      case ESC_H:
+      case ESC_h:
+      case ESC_N:
+      case ESC_R:
+      case ESC_V:
+      case ESC_v:
+      okquantifier = TRUE;
+      *parsed_pattern++ = META_ESCAPE + escape;
+      break;
+
+      default:  /* \A, \B, \b, \G, \K, \Z, \z cannot be quantified. */
+      *parsed_pattern++ = META_ESCAPE + escape;
+      break;
+
+      /* Escapes that change in UCP mode. Note that PCRE2_UCP will never be set
+      without Unicode support because it is checked when pcre2_compile() is
+      called. */
+
+      case ESC_d:
+      case ESC_D:
+      case ESC_s:
+      case ESC_S:
+      case ESC_w:
+      case ESC_W:
+      okquantifier = TRUE;
+      if ((options & PCRE2_UCP) == 0)
+        {
+        *parsed_pattern++ = META_ESCAPE + escape;
+        }
+      else
+        {
+        *parsed_pattern++ = META_ESCAPE +
+          ((escape == ESC_d || escape == ESC_s || escape == ESC_w)?
+            ESC_p : ESC_P);
+        switch(escape)
+          {
+          case ESC_d:
+          case ESC_D:
+          *parsed_pattern++ = (PT_PC << 16) | ucp_Nd;
+          break;
+
+          case ESC_s:
+          case ESC_S:
+          *parsed_pattern++ = PT_SPACE << 16;
+          break;
+
+          case ESC_w:
+          case ESC_W:
+          *parsed_pattern++ = PT_WORD << 16;
+          break;
+          }
+        }
+      break;
+
+      /* Unicode property matching */
+
+      case ESC_P:
+      case ESC_p:
+#ifdef SUPPORT_UNICODE
+        {
+        BOOL negated;
+        uint16_t ptype = 0, pdata = 0;
+        if (!get_ucp(&ptr, &negated, &ptype, &pdata, &errorcode, cb))
+          goto ESCAPE_FAILED;
+        if (negated) escape = (escape == ESC_P)? ESC_p : ESC_P;
+        *parsed_pattern++ = META_ESCAPE + escape;
+        *parsed_pattern++ = (ptype << 16) | pdata;
+        okquantifier = TRUE;
+        }
+#else
+      errorcode = ERR45;
+      goto ESCAPE_FAILED;
+#endif
+      break;  /* End \P and \p */
+
+      /* When \g is used with quotes or angle brackets as delimiters, it is a
+      numerical or named subroutine call, and control comes here. When used
+      with brace delimiters it is a numberical back reference and does not come
+      here because check_escape() returns it directly as a reference. \k is
+      always a named back reference. */
+
+      case ESC_g:
+      case ESC_k:
+      if (ptr >= ptrend || (*ptr != CHAR_LEFT_CURLY_BRACKET &&
+          *ptr != CHAR_LESS_THAN_SIGN && *ptr != CHAR_APOSTROPHE))
+        {
+        errorcode = (escape == ESC_g)? ERR57 : ERR69;
+        goto ESCAPE_FAILED;
+        }
+      terminator = (*ptr == CHAR_LESS_THAN_SIGN)?
+        CHAR_GREATER_THAN_SIGN : (*ptr == CHAR_APOSTROPHE)?
+        CHAR_APOSTROPHE : CHAR_RIGHT_CURLY_BRACKET;
+
+      /* For a non-braced \g, check for a numerical recursion. */
+
+      if (escape == ESC_g && terminator != CHAR_RIGHT_CURLY_BRACKET)
+        {
+        PCRE2_SPTR p = ptr + 1;
+
+        if (read_number(&p, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &i,
+            &errorcode))
+          {
+          if (p >= ptrend || *p != terminator)
+            {
+            errorcode = ERR57;
+            goto ESCAPE_FAILED;
+            }
+          ptr = p;
+          goto SET_RECURSION;
+          }
+        if (errorcode != 0) goto ESCAPE_FAILED;
+        }
+
+      /* Not a numerical recursion */
+
+      if (!read_name(&ptr, ptrend, utf, terminator, &offset, &name, &namelen,
+          &errorcode, cb)) goto ESCAPE_FAILED;
+
+      /* \k and \g when used with braces are back references, whereas \g used
+      with quotes or angle brackets is a recursion */
+
+      *parsed_pattern++ =
+        (escape == ESC_k || terminator == CHAR_RIGHT_CURLY_BRACKET)?
+          META_BACKREF_BYNAME : META_RECURSE_BYNAME;
+      *parsed_pattern++ = namelen;
+
+      PUTOFFSET(offset, parsed_pattern);
+      okquantifier = TRUE;
+      break;  /* End special escape processing */
+      }
+    break;    /* End escape sequence processing */
+
+
+    /* ---- Single-character special items ---- */
+
+    case CHAR_CIRCUMFLEX_ACCENT:
+    *parsed_pattern++ = META_CIRCUMFLEX;
+    break;
+
+    case CHAR_DOLLAR_SIGN:
+    *parsed_pattern++ = META_DOLLAR;
+    break;
+
+    case CHAR_DOT:
+    *parsed_pattern++ = META_DOT;
+    okquantifier = TRUE;
+    break;
+
+
+    /* ---- Single-character quantifiers ---- */
+
+    case CHAR_ASTERISK:
+    meta_quantifier = META_ASTERISK;
+    goto CHECK_QUANTIFIER;
+
+    case CHAR_PLUS:
+    meta_quantifier = META_PLUS;
+    goto CHECK_QUANTIFIER;
+
+    case CHAR_QUESTION_MARK:
+    meta_quantifier = META_QUERY;
+    goto CHECK_QUANTIFIER;
+
+
+    /* ---- Potential {n,m} quantifier ---- */
+
+    case CHAR_LEFT_CURLY_BRACKET:
+    if (!read_repeat_counts(&ptr, ptrend, &min_repeat, &max_repeat,
+        &errorcode))
+      {
+      if (errorcode != 0) goto FAILED;     /* Error in quantifier. */
+      PARSED_LITERAL(c, parsed_pattern);   /* Not a quantifier */
+      break;                               /* No more quantifier processing */
+      }
+    meta_quantifier = META_MINMAX;
+    /* Fall through */
+
+
+    /* ---- Quantifier post-processing ---- */
+
+    /* Check that a quantifier is allowed after the previous item. */
+
+    CHECK_QUANTIFIER:
+    if (!prev_okquantifier)
+      {
+      errorcode = ERR9;
+      goto FAILED_BACK;
+      }
+
+    /* Most (*VERB)s are not allowed to be quantified, but an ungreedy
+    quantifier can be useful for (*ACCEPT) - meaning "succeed on backtrack", a
+    sort of negated (*COMMIT). We therefore allow (*ACCEPT) to be quantified by
+    wrapping it in non-capturing brackets, but we have to allow for a preceding
+    (*MARK) for when (*ACCEPT) has an argument. */
+
+    if (parsed_pattern[-1] == META_ACCEPT)
+      {
+      uint32_t *p;
+      for (p = parsed_pattern - 1; p >= verbstartptr; p--) p[1] = p[0];
+      *verbstartptr = META_NOCAPTURE;
+      parsed_pattern[1] = META_KET;
+      parsed_pattern += 2;
+      }
+
+    /* Now we can put the quantifier into the parsed pattern vector. At this
+    stage, we have only the basic quantifier. The check for a following + or ?
+    modifier happens at the top of the loop, after any intervening comments
+    have been removed. */
+
+    *parsed_pattern++ = meta_quantifier;
+    if (c == CHAR_LEFT_CURLY_BRACKET)
+      {
+      *parsed_pattern++ = min_repeat;
+      *parsed_pattern++ = max_repeat;
+      }
+    break;
+
+
+    /* ---- Character class ---- */
+
+    case CHAR_LEFT_SQUARE_BRACKET:
+    okquantifier = TRUE;
+
+    /* In another (POSIX) regex library, the ugly syntax [[:<:]] and [[:>:]] is
+    used for "start of word" and "end of word". As these are otherwise illegal
+    sequences, we don't break anything by recognizing them. They are replaced
+    by \b(?=\w) and \b(?<=\w) respectively. Sequences like [a[:<:]] are
+    erroneous and are handled by the normal code below. */
+
+    if (ptrend - ptr >= 6 &&
+         (PRIV(strncmp_c8)(ptr, STRING_WEIRD_STARTWORD, 6) == 0 ||
+          PRIV(strncmp_c8)(ptr, STRING_WEIRD_ENDWORD, 6) == 0))
+      {
+      *parsed_pattern++ = META_ESCAPE + ESC_b;
+
+      if (ptr[2] == CHAR_LESS_THAN_SIGN)
+        {
+        *parsed_pattern++ = META_LOOKAHEAD;
+        }
+      else
+        {
+        *parsed_pattern++ = META_LOOKBEHIND;
+        *has_lookbehind = TRUE;
+
+        /* The offset is used only for the "non-fixed length" error; this won't
+        occur here, so just store zero. */
+
+        PUTOFFSET((PCRE2_SIZE)0, parsed_pattern);
+        }
+
+      if ((options & PCRE2_UCP) == 0)
+        *parsed_pattern++ = META_ESCAPE + ESC_w;
+      else
+        {
+        *parsed_pattern++ = META_ESCAPE + ESC_p;
+        *parsed_pattern++ = PT_WORD << 16;
+        }
+      *parsed_pattern++ = META_KET;
+      ptr += 6;
+      break;
+      }
+
+    /* PCRE supports POSIX class stuff inside a class. Perl gives an error if
+    they are encountered at the top level, so we'll do that too. */
+
+    if (ptr < ptrend && (*ptr == CHAR_COLON || *ptr == CHAR_DOT ||
+         *ptr == CHAR_EQUALS_SIGN) &&
+        check_posix_syntax(ptr, ptrend, &tempptr))
+      {
+      errorcode = (*ptr-- == CHAR_COLON)? ERR12 : ERR13;
+      goto FAILED;
+      }
+
+    /* Process a regular character class. If the first character is '^', set
+    the negation flag. If the first few characters (either before or after ^)
+    are \Q\E or \E or space or tab in extended-more mode, we skip them too.
+    This makes for compatibility with Perl. */
+
+    negate_class = FALSE;
+    while (ptr < ptrend)
+      {
+      GETCHARINCTEST(c, ptr);
+      if (c == CHAR_BACKSLASH)
+        {
+        if (ptr < ptrend && *ptr == CHAR_E) ptr++;
+        else if (ptrend - ptr >= 3 &&
+             PRIV(strncmp_c8)(ptr, STR_Q STR_BACKSLASH STR_E, 3) == 0)
+          ptr += 3;
+        else
+          break;
+        }
+      else if ((options & PCRE2_EXTENDED_MORE) != 0 &&
+               (c == CHAR_SPACE || c == CHAR_HT))  /* Note: just these two */
+        continue;
+      else if (!negate_class && c == CHAR_CIRCUMFLEX_ACCENT)
+        negate_class = TRUE;
+      else break;
+      }
+
+    /* Now the real contents of the class; c has the first "real" character.
+    Empty classes are permitted only if the option is set. */
+
+    if (c == CHAR_RIGHT_SQUARE_BRACKET &&
+        (cb->external_options & PCRE2_ALLOW_EMPTY_CLASS) != 0)
+      {
+      *parsed_pattern++ = negate_class? META_CLASS_EMPTY_NOT : META_CLASS_EMPTY;
+      break;  /* End of class processing */
+      }
+
+    /* Process a non-empty class. */
+
+    *parsed_pattern++ = negate_class? META_CLASS_NOT : META_CLASS;
+    class_range_state = RANGE_NO;
+
+    /* In an EBCDIC environment, Perl treats alphabetic ranges specially
+    because there are holes in the encoding, and simply using the range A-Z
+    (for example) would include the characters in the holes. This applies only
+    to ranges where both values are literal; [\xC1-\xE9] is different to [A-Z]
+    in this respect. In order to accommodate this, we keep track of whether
+    character values are literal or not, and a state variable for handling
+    ranges. */
+
+    /* Loop for the contents of the class */
+
+    for (;;)
+      {
+      BOOL char_is_literal = TRUE;
+
+      /* Inside \Q...\E everything is literal except \E */
+
+      if (inescq)
+        {
+        if (c == CHAR_BACKSLASH && ptr < ptrend && *ptr == CHAR_E)
+          {
+          inescq = FALSE;                   /* Reset literal state */
+          ptr++;                            /* Skip the 'E' */
+          goto CLASS_CONTINUE;
+          }
+        goto CLASS_LITERAL;
+        }
+
+      /* Skip over space and tab (only) in extended-more mode. */
+
+      if ((options & PCRE2_EXTENDED_MORE) != 0 &&
+          (c == CHAR_SPACE || c == CHAR_HT))
+        goto CLASS_CONTINUE;
+
+      /* Handle POSIX class names. Perl allows a negation extension of the
+      form [:^name:]. A square bracket that doesn't match the syntax is
+      treated as a literal. We also recognize the POSIX constructions
+      [.ch.] and [=ch=] ("collating elements") and fault them, as Perl
+      5.6 and 5.8 do. */
+
+      if (c == CHAR_LEFT_SQUARE_BRACKET &&
+          ptrend - ptr >= 3 &&
+          (*ptr == CHAR_COLON || *ptr == CHAR_DOT ||
+           *ptr == CHAR_EQUALS_SIGN) &&
+          check_posix_syntax(ptr, ptrend, &tempptr))
+        {
+        BOOL posix_negate = FALSE;
+        int posix_class;
+
+        /* Perl treats a hyphen before a POSIX class as a literal, not the
+        start of a range. However, it gives a warning in its warning mode. PCRE
+        does not have a warning mode, so we give an error, because this is
+        likely an error on the user's part. */
+
+        if (class_range_state == RANGE_STARTED)
+          {
+          errorcode = ERR50;
+          goto FAILED;
+          }
+
+        if (*ptr != CHAR_COLON)
+          {
+          errorcode = ERR13;
+          goto FAILED_BACK;
+          }
+
+        if (*(++ptr) == CHAR_CIRCUMFLEX_ACCENT)
+          {
+          posix_negate = TRUE;
+          ptr++;
+          }
+
+        posix_class = check_posix_name(ptr, (int)(tempptr - ptr));
+        if (posix_class < 0)
+          {
+          errorcode = ERR30;
+          goto FAILED;
+          }
+        ptr = tempptr + 2;
+
+        /* Perl treats a hyphen after a POSIX class as a literal, not the
+        start of a range. However, it gives a warning in its warning mode
+        unless the hyphen is the last character in the class. PCRE does not
+        have a warning mode, so we give an error, because this is likely an
+        error on the user's part. */
+
+        if (ptr < ptrend - 1 && *ptr == CHAR_MINUS &&
+            ptr[1] != CHAR_RIGHT_SQUARE_BRACKET)
+          {
+          errorcode = ERR50;
+          goto FAILED;
+          }
+
+        /* Set "a hyphen is not the start of a range" for the -] case, and also
+        in case the POSIX class is followed by \E or \Q\E (possibly repeated -
+        fuzzers do that kind of thing) and *then* a hyphen. This causes that
+        hyphen to be treated as a literal. I don't think it's worth setting up
+        special apparatus to do otherwise. */
+
+        class_range_state = RANGE_NO;
+
+        /* When PCRE2_UCP is set, some of the POSIX classes are converted to
+        use Unicode properties \p or \P or, in one case, \h or \H. The
+        substitutes table has two values per class, containing the type and
+        value of a \p or \P item. The special cases are specified with a
+        negative type: a non-zero value causes \h or \H to be used, and a zero
+        value falls through to behave like a non-UCP POSIX class. */
+
+#ifdef SUPPORT_UNICODE
+        if ((options & PCRE2_UCP) != 0)
+          {
+          int ptype = posix_substitutes[2*posix_class];
+          int pvalue = posix_substitutes[2*posix_class + 1];
+          if (ptype >= 0)
+            {
+            *parsed_pattern++ = META_ESCAPE + (posix_negate? ESC_P : ESC_p);
+            *parsed_pattern++ = (ptype << 16) | pvalue;
+            goto CLASS_CONTINUE;
+            }
+
+          if (pvalue != 0)
+            {
+            *parsed_pattern++ = META_ESCAPE + (posix_negate? ESC_H : ESC_h);
+            goto CLASS_CONTINUE;
+            }
+
+          /* Fall through */
+          }
+#endif  /* SUPPORT_UNICODE */
+
+        /* Non-UCP POSIX class */
+
+        *parsed_pattern++ = posix_negate? META_POSIX_NEG : META_POSIX;
+        *parsed_pattern++ = posix_class;
+        }
+
+      /* Handle potential start of range */
+
+      else if (c == CHAR_MINUS && class_range_state >= RANGE_OK_ESCAPED)
+        {
+        *parsed_pattern++ = (class_range_state == RANGE_OK_LITERAL)?
+          META_RANGE_LITERAL : META_RANGE_ESCAPED;
+        class_range_state = RANGE_STARTED;
+        }
+
+      /* Handle a literal character */
+
+      else if (c != CHAR_BACKSLASH)
+        {
+        CLASS_LITERAL:
+        if (class_range_state == RANGE_STARTED)
+          {
+          if (c == parsed_pattern[-2])       /* Optimize one-char range */
+            parsed_pattern--;
+          else if (parsed_pattern[-2] > c)   /* Check range is in order */
+            {
+            errorcode = ERR8;
+            goto FAILED_BACK;
+            }
+          else
+            {
+            if (!char_is_literal && parsed_pattern[-1] == META_RANGE_LITERAL)
+              parsed_pattern[-1] = META_RANGE_ESCAPED;
+            PARSED_LITERAL(c, parsed_pattern);
+            }
+          class_range_state = RANGE_NO;
+          }
+        else  /* Potential start of range */
+          {
+          class_range_state = char_is_literal?
+            RANGE_OK_LITERAL : RANGE_OK_ESCAPED;
+          PARSED_LITERAL(c, parsed_pattern);
+          }
+        }
+
+      /* Handle escapes in a class */
+
+      else
+        {
+        tempptr = ptr;
+        escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options,
+          cb->cx->extra_options, TRUE, cb);
+
+        if (errorcode != 0)
+          {
+          if ((extra_options & PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL) == 0)
+            goto FAILED;
+          ptr = tempptr;
+          if (ptr >= ptrend) c = CHAR_BACKSLASH; else
+            {
+            GETCHARINCTEST(c, ptr);   /* Get character value, increment pointer */
+            }
+          escape = 0;                 /* Treat as literal character */
+          }
+
+        switch(escape)
+          {
+          case 0:  /* Escaped character code point is in c */
+          char_is_literal = FALSE;
+          goto CLASS_LITERAL;
+
+          case ESC_b:
+          c = CHAR_BS;    /* \b is backspace in a class */
+          char_is_literal = FALSE;
+          goto CLASS_LITERAL;
+
+          case ESC_Q:
+          inescq = TRUE;  /* Enter literal mode */
+          goto CLASS_CONTINUE;
+
+          case ESC_E:     /* Ignore orphan \E */
+          goto CLASS_CONTINUE;
+
+          case ESC_B:     /* Always an error in a class */
+          case ESC_R:
+          case ESC_X:
+          errorcode = ERR7;
+          ptr--;
+          goto FAILED;
+          }
+
+        /* The second part of a range can be a single-character escape
+        sequence (detected above), but not any of the other escapes. Perl
+        treats a hyphen as a literal in such circumstances. However, in Perl's
+        warning mode, a warning is given, so PCRE now faults it, as it is
+        almost certainly a mistake on the user's part. */
+
+        if (class_range_state == RANGE_STARTED)
+          {
+          errorcode = ERR50;
+          goto FAILED;  /* Not CLASS_ESCAPE_FAILED; always an error */
+          }
+
+        /* Of the remaining escapes, only those that define characters are
+        allowed in a class. None may start a range. */
+
+        class_range_state = RANGE_NO;
+        switch(escape)
+          {
+          case ESC_N:
+          errorcode = ERR71;
+          goto FAILED;
+
+          case ESC_H:
+          case ESC_h:
+          case ESC_V:
+          case ESC_v:
+          *parsed_pattern++ = META_ESCAPE + escape;
+          break;
+
+          /* These escapes are converted to Unicode property tests when
+          PCRE2_UCP is set. */
+
+          case ESC_d:
+          case ESC_D:
+          case ESC_s:
+          case ESC_S:
+          case ESC_w:
+          case ESC_W:
+          if ((options & PCRE2_UCP) == 0)
+            {
+            *parsed_pattern++ = META_ESCAPE + escape;
+            }
+          else
+            {
+            *parsed_pattern++ = META_ESCAPE +
+              ((escape == ESC_d || escape == ESC_s || escape == ESC_w)?
+                ESC_p : ESC_P);
+            switch(escape)
+              {
+              case ESC_d:
+              case ESC_D:
+              *parsed_pattern++ = (PT_PC << 16) | ucp_Nd;
+              break;
+
+              case ESC_s:
+              case ESC_S:
+              *parsed_pattern++ = PT_SPACE << 16;
+              break;
+
+              case ESC_w:
+              case ESC_W:
+              *parsed_pattern++ = PT_WORD << 16;
+              break;
+              }
+            }
+          break;
+
+          /* Explicit Unicode property matching */
+
+          case ESC_P:
+          case ESC_p:
+#ifdef SUPPORT_UNICODE
+            {
+            BOOL negated;
+            uint16_t ptype = 0, pdata = 0;
+            if (!get_ucp(&ptr, &negated, &ptype, &pdata, &errorcode, cb))
+              goto FAILED;
+            if (negated) escape = (escape == ESC_P)? ESC_p : ESC_P;
+            *parsed_pattern++ = META_ESCAPE + escape;
+            *parsed_pattern++ = (ptype << 16) | pdata;
+            }
+#else
+          errorcode = ERR45;
+          goto FAILED;
+#endif
+          break;  /* End \P and \p */
+
+          default:    /* All others are not allowed in a class */
+          errorcode = ERR7;
+          ptr--;
+          goto FAILED;
+          }
+
+        /* Perl gives a warning unless a following hyphen is the last character
+        in the class. PCRE throws an error. */
+
+        if (ptr < ptrend - 1 && *ptr == CHAR_MINUS &&
+            ptr[1] != CHAR_RIGHT_SQUARE_BRACKET)
+          {
+          errorcode = ERR50;
+          goto FAILED;
+          }
+        }
+
+      /* Proceed to next thing in the class. */
+
+      CLASS_CONTINUE:
+      if (ptr >= ptrend)
+        {
+        errorcode = ERR6;  /* Missing terminating ']' */
+        goto FAILED;
+        }
+      GETCHARINCTEST(c, ptr);
+      if (c == CHAR_RIGHT_SQUARE_BRACKET && !inescq) break;
+      }     /* End of class-processing loop */
+
+    /* -] at the end of a class is a literal '-' */
+
+    if (class_range_state == RANGE_STARTED)
+      {
+      parsed_pattern[-1] = CHAR_MINUS;
+      class_range_state = RANGE_NO;
+      }
+
+    *parsed_pattern++ = META_CLASS_END;
+    break;  /* End of character class */
+
+
+    /* ---- Opening parenthesis ---- */
+
+    case CHAR_LEFT_PARENTHESIS:
+    if (ptr >= ptrend) goto UNCLOSED_PARENTHESIS;
+
+    /* If ( is not followed by ? it is either a capture or a special verb or an
+    alpha assertion or a positive non-atomic lookahead. */
+
+    if (*ptr != CHAR_QUESTION_MARK)
+      {
+      const char *vn;
+
+      /* Handle capturing brackets (or non-capturing if auto-capture is turned
+      off). */
+
+      if (*ptr != CHAR_ASTERISK)
+        {
+        nest_depth++;
+        if ((options & PCRE2_NO_AUTO_CAPTURE) == 0)
+          {
+          if (cb->bracount >= MAX_GROUP_NUMBER)
+            {
+            errorcode = ERR97;
+            goto FAILED;
+            }
+          cb->bracount++;
+          *parsed_pattern++ = META_CAPTURE | cb->bracount;
+          }
+        else *parsed_pattern++ = META_NOCAPTURE;
+        }
+
+      /* Do nothing for (* followed by end of pattern or ) so it gives a "bad
+      quantifier" error rather than "(*MARK) must have an argument". */
+
+      else if (ptrend - ptr <= 1 || (c = ptr[1]) == CHAR_RIGHT_PARENTHESIS)
+        break;
+
+      /* Handle "alpha assertions" such as (*pla:...). Most of these are
+      synonyms for the historical symbolic assertions, but the script run and
+      non-atomic lookaround ones are new. They are distinguished by starting
+      with a lower case letter. Checking both ends of the alphabet makes this
+      work in all character codes. */
+
+      else if (CHMAX_255(c) && (cb->ctypes[c] & ctype_lcletter) != 0)
+        {
+        uint32_t meta;
+
+        vn = alasnames;
+        if (!read_name(&ptr, ptrend, utf, 0, &offset, &name, &namelen,
+          &errorcode, cb)) goto FAILED;
+        if (ptr >= ptrend || *ptr != CHAR_COLON)
+          {
+          errorcode = ERR95;  /* Malformed */
+          goto FAILED;
+          }
+
+        /* Scan the table of alpha assertion names */
+
+        for (i = 0; i < alascount; i++)
+          {
+          if (namelen == alasmeta[i].len &&
+              PRIV(strncmp_c8)(name, vn, namelen) == 0)
+            break;
+          vn += alasmeta[i].len + 1;
+          }
+
+        if (i >= alascount)
+          {
+          errorcode = ERR95;  /* Alpha assertion not recognized */
+          goto FAILED;
+          }
+
+        /* Check for expecting an assertion condition. If so, only atomic
+        lookaround assertions are valid. */
+
+        meta = alasmeta[i].meta;
+        if (prev_expect_cond_assert > 0 &&
+            (meta < META_LOOKAHEAD || meta > META_LOOKBEHINDNOT))
+          {
+          errorcode = (meta == META_LOOKAHEAD_NA || meta == META_LOOKBEHIND_NA)?
+            ERR98 : ERR28;  /* (Atomic) assertion expected */
+          goto FAILED;
+          }
+
+        /* The lookaround alphabetic synonyms can mostly be handled by jumping
+        to the code that handles the traditional symbolic forms. */
+
+        switch(meta)
+          {
+          default:
+          errorcode = ERR89;  /* Unknown code; should never occur because */
+          goto FAILED;        /* the meta values come from a table above. */
+
+          case META_ATOMIC:
+          goto ATOMIC_GROUP;
+
+          case META_LOOKAHEAD:
+          goto POSITIVE_LOOK_AHEAD;
+
+          case META_LOOKAHEAD_NA:
+          goto POSITIVE_NONATOMIC_LOOK_AHEAD;
+
+          case META_LOOKAHEADNOT:
+          goto NEGATIVE_LOOK_AHEAD;
+
+          case META_LOOKBEHIND:
+          case META_LOOKBEHINDNOT:
+          case META_LOOKBEHIND_NA:
+          *parsed_pattern++ = meta;
+          ptr--;
+          goto POST_LOOKBEHIND;
+
+          /* The script run facilities are handled here. Unicode support is
+          required (give an error if not, as this is a security issue). Always
+          record a META_SCRIPT_RUN item. Then, for the atomic version, insert
+          META_ATOMIC and remember that we need two META_KETs at the end. */
+
+          case META_SCRIPT_RUN:
+          case META_ATOMIC_SCRIPT_RUN:
+#ifdef SUPPORT_UNICODE
+          *parsed_pattern++ = META_SCRIPT_RUN;
+          nest_depth++;
+          ptr++;
+          if (meta == META_ATOMIC_SCRIPT_RUN)
+            {
+            *parsed_pattern++ = META_ATOMIC;
+            if (top_nest == NULL) top_nest = (nest_save *)(cb->start_workspace);
+            else if (++top_nest >= end_nests)
+              {
+              errorcode = ERR84;
+              goto FAILED;
+              }
+            top_nest->nest_depth = nest_depth;
+            top_nest->flags = NSF_ATOMICSR;
+            top_nest->options = options & PARSE_TRACKED_OPTIONS;
+            }
+          break;
+#else  /* SUPPORT_UNICODE */
+          errorcode = ERR96;
+          goto FAILED;
+#endif
+          }
+        }
+
+
+      /* ---- Handle (*VERB) and (*VERB:NAME) ---- */
+
+      else
+        {
+        vn = verbnames;
+        if (!read_name(&ptr, ptrend, utf, 0, &offset, &name, &namelen,
+          &errorcode, cb)) goto FAILED;
+        if (ptr >= ptrend || (*ptr != CHAR_COLON &&
+                              *ptr != CHAR_RIGHT_PARENTHESIS))
+          {
+          errorcode = ERR60;  /* Malformed */
+          goto FAILED;
+          }
+
+        /* Scan the table of verb names */
+
+        for (i = 0; i < verbcount; i++)
+          {
+          if (namelen == verbs[i].len &&
+              PRIV(strncmp_c8)(name, vn, namelen) == 0)
+            break;
+          vn += verbs[i].len + 1;
+          }
+
+        if (i >= verbcount)
+          {
+          errorcode = ERR60;  /* Verb not recognized */
+          goto FAILED;
+          }
+
+        /* An empty argument is treated as no argument. */
+
+        if (*ptr == CHAR_COLON && ptr + 1 < ptrend &&
+             ptr[1] == CHAR_RIGHT_PARENTHESIS)
+          ptr++;    /* Advance to the closing parens */
+
+        /* Check for mandatory non-empty argument; this is (*MARK) */
+
+        if (verbs[i].has_arg > 0 && *ptr != CHAR_COLON)
+          {
+          errorcode = ERR66;
+          goto FAILED;
+          }
+
+        /* Remember where this verb, possibly with a preceding (*MARK), starts,
+        for handling quantified (*ACCEPT). */
+
+        verbstartptr = parsed_pattern;
+        okquantifier = (verbs[i].meta == META_ACCEPT);
+
+        /* It appears that Perl allows any characters whatsoever, other than a
+        closing parenthesis, to appear in arguments ("names"), so we no longer
+        insist on letters, digits, and underscores. Perl does not, however, do
+        any interpretation within arguments, and has no means of including a
+        closing parenthesis. PCRE supports escape processing but only when it
+        is requested by an option. We set inverbname TRUE here, and let the
+        main loop take care of this so that escape and \x processing is done by
+        the main code above. */
+
+        if (*ptr++ == CHAR_COLON)   /* Skip past : or ) */
+          {
+          /* Some optional arguments can be treated as a preceding (*MARK) */
+
+          if (verbs[i].has_arg < 0)
+            {
+            add_after_mark = verbs[i].meta;
+            *parsed_pattern++ = META_MARK;
+            }
+
+          /* The remaining verbs with arguments (except *MARK) need a different
+          opcode. */
+
+          else
+            {
+            *parsed_pattern++ = verbs[i].meta +
+              ((verbs[i].meta != META_MARK)? 0x00010000u:0);
+            }
+
+          /* Set up for reading the name in the main loop. */
+
+          verblengthptr = parsed_pattern++;
+          verbnamestart = ptr;
+          inverbname = TRUE;
+          }
+        else  /* No verb "name" argument */
+          {
+          *parsed_pattern++ = verbs[i].meta;
+          }
+        }     /* End of (*VERB) handling */
+      break;  /* Done with this parenthesis */
+      }       /* End of groups that don't start with (? */
+
+
+    /* ---- Items starting (? ---- */
+
+    /* The type of item is determined by what follows (?. Handle (?| and option
+    changes under "default" because both need a new block on the nest stack.
+    Comments starting with (?# are handled above. Note that there is some
+    ambiguity about the sequence (?- because if a digit follows it's a relative
+    recursion or subroutine call whereas otherwise it's an option unsetting. */
+
+    if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS;
+
+    switch(*ptr)
+      {
+      default:
+      if (*ptr == CHAR_MINUS && ptrend - ptr > 1 && IS_DIGIT(ptr[1]))
+        goto RECURSION_BYNUMBER;  /* The + case is handled by CHAR_PLUS */
+
+      /* We now have either (?| or a (possibly empty) option setting,
+      optionally followed by a non-capturing group. */
+
+      nest_depth++;
+      if (top_nest == NULL) top_nest = (nest_save *)(cb->start_workspace);
+      else if (++top_nest >= end_nests)
+        {
+        errorcode = ERR84;
+        goto FAILED;
+        }
+      top_nest->nest_depth = nest_depth;
+      top_nest->flags = 0;
+      top_nest->options = options & PARSE_TRACKED_OPTIONS;
+
+      /* Start of non-capturing group that resets the capture count for each
+      branch. */
+
+      if (*ptr == CHAR_VERTICAL_LINE)
+        {
+        top_nest->reset_group = (uint16_t)cb->bracount;
+        top_nest->max_group = (uint16_t)cb->bracount;
+        top_nest->flags |= NSF_RESET;
+        cb->external_flags |= PCRE2_DUPCAPUSED;
+        *parsed_pattern++ = META_NOCAPTURE;
+        ptr++;
+        }
+
+      /* Scan for options imnsxJU to be set or unset. */
+
+      else
+        {
+        BOOL hyphenok = TRUE;
+        uint32_t oldoptions = options;
+
+        top_nest->reset_group = 0;
+        top_nest->max_group = 0;
+        set = unset = 0;
+        optset = &set;
+
+        /* ^ at the start unsets imnsx and disables the subsequent use of - */
+
+        if (ptr < ptrend && *ptr == CHAR_CIRCUMFLEX_ACCENT)
+          {
+          options &= ~(PCRE2_CASELESS|PCRE2_MULTILINE|PCRE2_NO_AUTO_CAPTURE|
+                       PCRE2_DOTALL|PCRE2_EXTENDED|PCRE2_EXTENDED_MORE);
+          hyphenok = FALSE;
+          ptr++;
+          }
+
+        while (ptr < ptrend && *ptr != CHAR_RIGHT_PARENTHESIS &&
+                               *ptr != CHAR_COLON)
+          {
+          switch (*ptr++)
+            {
+            case CHAR_MINUS:
+            if (!hyphenok)
+              {
+              errorcode = ERR94;
+              ptr--;  /* Correct the offset */
+              goto FAILED;
+              }
+            optset = &unset;
+            hyphenok = FALSE;
+            break;
+
+            case CHAR_J:  /* Record that it changed in the external options */
+            *optset |= PCRE2_DUPNAMES;
+            cb->external_flags |= PCRE2_JCHANGED;
+            break;
+
+            case CHAR_i: *optset |= PCRE2_CASELESS; break;
+            case CHAR_m: *optset |= PCRE2_MULTILINE; break;
+            case CHAR_n: *optset |= PCRE2_NO_AUTO_CAPTURE; break;
+            case CHAR_s: *optset |= PCRE2_DOTALL; break;
+            case CHAR_U: *optset |= PCRE2_UNGREEDY; break;
+
+            /* If x appears twice it sets the extended extended option. */
+
+            case CHAR_x:
+            *optset |= PCRE2_EXTENDED;
+            if (ptr < ptrend && *ptr == CHAR_x)
+              {
+              *optset |= PCRE2_EXTENDED_MORE;
+              ptr++;
+              }
+            break;
+
+            default:
+            errorcode = ERR11;
+            ptr--;    /* Correct the offset */
+            goto FAILED;
+            }
+          }
+
+        /* If we are setting extended without extended-more, ensure that any
+        existing extended-more gets unset. Also, unsetting extended must also
+        unset extended-more. */
+
+        if ((set & (PCRE2_EXTENDED|PCRE2_EXTENDED_MORE)) == PCRE2_EXTENDED ||
+            (unset & PCRE2_EXTENDED) != 0)
+          unset |= PCRE2_EXTENDED_MORE;
+
+        options = (options | set) & (~unset);
+
+        /* If the options ended with ')' this is not the start of a nested
+        group with option changes, so the options change at this level.
+        In this case, if the previous level set up a nest block, discard the
+        one we have just created. Otherwise adjust it for the previous level.
+        If the options ended with ':' we are starting a non-capturing group,
+        possibly with an options setting. */
+
+        if (ptr >= ptrend) goto UNCLOSED_PARENTHESIS;
+        if (*ptr++ == CHAR_RIGHT_PARENTHESIS)
+          {
+          nest_depth--;  /* This is not a nested group after all. */
+          if (top_nest > (nest_save *)(cb->start_workspace) &&
+              (top_nest-1)->nest_depth == nest_depth) top_nest--;
+          else top_nest->nest_depth = nest_depth;
+          }
+        else *parsed_pattern++ = META_NOCAPTURE;
+
+        /* If nothing changed, no need to record. */
+
+        if (options != oldoptions)
+          {
+          *parsed_pattern++ = META_OPTIONS;
+          *parsed_pattern++ = options;
+          }
+        }     /* End options processing */
+      break;  /* End default case after (? */
+
+
+      /* ---- Python syntax support ---- */
+
+      case CHAR_P:
+      if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS;
+
+      /* (?P<name> is the same as (?<name>, which defines a named group. */
+
+      if (*ptr == CHAR_LESS_THAN_SIGN)
+        {
+        terminator = CHAR_GREATER_THAN_SIGN;
+        goto DEFINE_NAME;
+        }
+
+      /* (?P>name) is the same as (?&name), which is a recursion or subroutine
+      call. */
+
+      if (*ptr == CHAR_GREATER_THAN_SIGN) goto RECURSE_BY_NAME;
+
+      /* (?P=name) is the same as \k<name>, a back reference by name. Anything
+      else after (?P is an error. */
+
+      if (*ptr != CHAR_EQUALS_SIGN)
+        {
+        errorcode = ERR41;
+        goto FAILED;
+        }
+      if (!read_name(&ptr, ptrend, utf, CHAR_RIGHT_PARENTHESIS, &offset, &name,
+          &namelen, &errorcode, cb)) goto FAILED;
+      *parsed_pattern++ = META_BACKREF_BYNAME;
+      *parsed_pattern++ = namelen;
+      PUTOFFSET(offset, parsed_pattern);
+      okquantifier = TRUE;
+      break;   /* End of (?P processing */
+
+
+      /* ---- Recursion/subroutine calls by number ---- */
+
+      case CHAR_R:
+      i = 0;         /* (?R) == (?R0) */
+      ptr++;
+      if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS)
+        {
+        errorcode = ERR58;
+        goto FAILED;
+        }
+      goto SET_RECURSION;
+
+      /* An item starting (?- followed by a digit comes here via the "default"
+      case because (?- followed by a non-digit is an options setting. */
+
+      case CHAR_PLUS:
+      if (ptrend - ptr < 2 || !IS_DIGIT(ptr[1]))
+        {
+        errorcode = ERR29;   /* Missing number */
+        goto FAILED;
+        }
+      /* Fall through */
+
+      case CHAR_0: case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4:
+      case CHAR_5: case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9:
+      RECURSION_BYNUMBER:
+      if (!read_number(&ptr, ptrend,
+          (IS_DIGIT(*ptr))? -1:(int)(cb->bracount), /* + and - are relative */
+          MAX_GROUP_NUMBER, ERR61,
+          &i, &errorcode)) goto FAILED;
+      if (i < 0)  /* NB (?0) is permitted */
+        {
+        errorcode = ERR15;   /* Unknown group */
+        goto FAILED_BACK;
+        }
+      if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS)
+        goto UNCLOSED_PARENTHESIS;
+
+      SET_RECURSION:
+      *parsed_pattern++ = META_RECURSE | (uint32_t)i;
+      offset = (PCRE2_SIZE)(ptr - cb->start_pattern);
+      ptr++;
+      PUTOFFSET(offset, parsed_pattern);
+      okquantifier = TRUE;
+      break;  /* End of recursive call by number handling */
+
+
+      /* ---- Recursion/subroutine calls by name ---- */
+
+      case CHAR_AMPERSAND:
+      RECURSE_BY_NAME:
+      if (!read_name(&ptr, ptrend, utf, CHAR_RIGHT_PARENTHESIS, &offset, &name,
+          &namelen, &errorcode, cb)) goto FAILED;
+      *parsed_pattern++ = META_RECURSE_BYNAME;
+      *parsed_pattern++ = namelen;
+      PUTOFFSET(offset, parsed_pattern);
+      okquantifier = TRUE;
+      break;
+
+      /* ---- Callout with numerical or string argument ---- */
+
+      case CHAR_C:
+      if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS;
+
+      /* If the previous item was a condition starting (?(? an assertion,
+      optionally preceded by a callout, is expected. This is checked later on,
+      during actual compilation. However we need to identify this kind of
+      assertion in this pass because it must not be qualified. The value of
+      expect_cond_assert is set to 2 after (?(? is processed. We decrement it
+      for a callout - still leaving a positive value that identifies the
+      assertion. Multiple callouts or any other items will make it zero or
+      less, which doesn't matter because they will cause an error later. */
+
+      expect_cond_assert = prev_expect_cond_assert - 1;
+
+      /* If previous_callout is not NULL, it means this follows a previous
+      callout. If it was a manual callout, do nothing; this means its "length
+      of next pattern item" field will remain zero. If it was an automatic
+      callout, abolish it. */
+
+      if (previous_callout != NULL && (options & PCRE2_AUTO_CALLOUT) != 0 &&
+          previous_callout == parsed_pattern - 4 &&
+          parsed_pattern[-1] == 255)
+        parsed_pattern = previous_callout;
+
+      /* Save for updating next pattern item length, and skip one item before
+      completing. */
+
+      previous_callout = parsed_pattern;
+      after_manual_callout = 1;
+
+      /* Handle a string argument; specific delimiter is required. */
+
+      if (*ptr != CHAR_RIGHT_PARENTHESIS && !IS_DIGIT(*ptr))
+        {
+        PCRE2_SIZE calloutlength;
+        PCRE2_SPTR startptr = ptr;
+
+        delimiter = 0;
+        for (i = 0; PRIV(callout_start_delims)[i] != 0; i++)
+          {
+          if (*ptr == PRIV(callout_start_delims)[i])
+            {
+            delimiter = PRIV(callout_end_delims)[i];
+            break;
+            }
+          }
+        if (delimiter == 0)
+          {
+          errorcode = ERR82;
+          goto FAILED;
+          }
+
+        *parsed_pattern = META_CALLOUT_STRING;
+        parsed_pattern += 3;   /* Skip pattern info */
+
+        for (;;)
+          {
+          if (++ptr >= ptrend)
+            {
+            errorcode = ERR81;
+            ptr = startptr;   /* To give a more useful message */
+            goto FAILED;
+            }
+          if (*ptr == delimiter && (++ptr >= ptrend || *ptr != delimiter))
+            break;
+          }
+
+        calloutlength = (PCRE2_SIZE)(ptr - startptr);
+        if (calloutlength > UINT32_MAX)
+          {
+          errorcode = ERR72;
+          goto FAILED;
+          }
+        *parsed_pattern++ = (uint32_t)calloutlength;
+        offset = (PCRE2_SIZE)(startptr - cb->start_pattern);
+        PUTOFFSET(offset, parsed_pattern);
+        }
+
+      /* Handle a callout with an optional numerical argument, which must be
+      less than or equal to 255. A missing argument gives 0. */
+
+      else
+        {
+        int n = 0;
+        *parsed_pattern = META_CALLOUT_NUMBER;     /* Numerical callout */
+        parsed_pattern += 3;                       /* Skip pattern info */
+        while (ptr < ptrend && IS_DIGIT(*ptr))
+          {
+          n = n * 10 + *ptr++ - CHAR_0;
+          if (n > 255)
+            {
+            errorcode = ERR38;
+            goto FAILED;
+            }
+          }
+        *parsed_pattern++ = n;
+        }
+
+      /* Both formats must have a closing parenthesis */
+
+      if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS)
+        {
+        errorcode = ERR39;
+        goto FAILED;
+        }
+      ptr++;
+
+      /* Remember the offset to the next item in the pattern, and set a default
+      length. This should get updated after the next item is read. */
+
+      previous_callout[1] = (uint32_t)(ptr - cb->start_pattern);
+      previous_callout[2] = 0;
+      break;                  /* End callout */
+
+
+      /* ---- Conditional group ---- */
+
+      /* A condition can be an assertion, a number (referring to a numbered
+      group's having been set), a name (referring to a named group), or 'R',
+      referring to overall recursion. R<digits> and R&name are also permitted
+      for recursion state tests. Numbers may be preceded by + or - to specify a
+      relative group number.
+
+      There are several syntaxes for testing a named group: (?(name)) is used
+      by Python; Perl 5.10 onwards uses (?(<name>) or (?('name')).
+
+      There are two unfortunate ambiguities. 'R' can be the recursive thing or
+      the name 'R' (and similarly for 'R' followed by digits). 'DEFINE' can be
+      the Perl DEFINE feature or the Python named test. We look for a name
+      first; if not found, we try the other case.
+
+      For compatibility with auto-callouts, we allow a callout to be specified
+      before a condition that is an assertion. */
+
+      case CHAR_LEFT_PARENTHESIS:
+      if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS;
+      nest_depth++;
+
+      /* If the next character is ? or * there must be an assertion next
+      (optionally preceded by a callout). We do not check this here, but
+      instead we set expect_cond_assert to 2. If this is still greater than
+      zero (callouts decrement it) when the next assertion is read, it will be
+      marked as a condition that must not be repeated. A value greater than
+      zero also causes checking that an assertion (possibly with callout)
+      follows. */
+
+      if (*ptr == CHAR_QUESTION_MARK || *ptr == CHAR_ASTERISK)
+        {
+        *parsed_pattern++ = META_COND_ASSERT;
+        ptr--;   /* Pull pointer back to the opening parenthesis. */
+        expect_cond_assert = 2;
+        break;  /* End of conditional */
+        }
+
+      /* Handle (?([+-]number)... */
+
+      if (read_number(&ptr, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &i,
+          &errorcode))
+        {
+        if (i <= 0)
+          {
+          errorcode = ERR15;
+          goto FAILED;
+          }
+        *parsed_pattern++ = META_COND_NUMBER;
+        offset = (PCRE2_SIZE)(ptr - cb->start_pattern - 2);
+        PUTOFFSET(offset, parsed_pattern);
+        *parsed_pattern++ = i;
+        }
+      else if (errorcode != 0) goto FAILED;   /* Number too big */
+
+      /* No number found. Handle the special case (?(VERSION[>]=n.m)... */
+
+      else if (ptrend - ptr >= 10 &&
+               PRIV(strncmp_c8)(ptr, STRING_VERSION, 7) == 0 &&
+               ptr[7] != CHAR_RIGHT_PARENTHESIS)
+        {
+        uint32_t ge = 0;
+        int major = 0;
+        int minor = 0;
+
+        ptr += 7;
+        if (*ptr == CHAR_GREATER_THAN_SIGN)
+          {
+          ge = 1;
+          ptr++;
+          }
+
+        /* NOTE: cannot write IS_DIGIT(*(++ptr)) here because IS_DIGIT
+        references its argument twice. */
+
+        if (*ptr != CHAR_EQUALS_SIGN || (ptr++, !IS_DIGIT(*ptr)))
+          goto BAD_VERSION_CONDITION;
+
+        if (!read_number(&ptr, ptrend, -1, 1000, ERR79, &major, &errorcode))
+          goto FAILED;
+
+        if (ptr >= ptrend) goto BAD_VERSION_CONDITION;
+        if (*ptr == CHAR_DOT)
+          {
+          if (++ptr >= ptrend || !IS_DIGIT(*ptr)) goto BAD_VERSION_CONDITION;
+          minor = (*ptr++ - CHAR_0) * 10;
+          if (ptr >= ptrend) goto BAD_VERSION_CONDITION;
+          if (IS_DIGIT(*ptr)) minor += *ptr++ - CHAR_0;
+          if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS)
+            goto BAD_VERSION_CONDITION;
+          }
+
+        *parsed_pattern++ = META_COND_VERSION;
+        *parsed_pattern++ = ge;
+        *parsed_pattern++ = major;
+        *parsed_pattern++ = minor;
+        }
+
+      /* All the remaining cases now require us to read a name. We cannot at
+      this stage distinguish ambiguous cases such as (?(R12) which might be a
+      recursion test by number or a name, because the named groups have not yet
+      all been identified. Those cases are treated as names, but given a
+      different META code. */
+
+      else
+        {
+        BOOL was_r_ampersand = FALSE;
+
+        if (*ptr == CHAR_R && ptrend - ptr > 1 && ptr[1] == CHAR_AMPERSAND)
+          {
+          terminator = CHAR_RIGHT_PARENTHESIS;
+          was_r_ampersand = TRUE;
+          ptr++;
+          }
+        else if (*ptr == CHAR_LESS_THAN_SIGN)
+          terminator = CHAR_GREATER_THAN_SIGN;
+        else if (*ptr == CHAR_APOSTROPHE)
+          terminator = CHAR_APOSTROPHE;
+        else
+          {
+          terminator = CHAR_RIGHT_PARENTHESIS;
+          ptr--;   /* Point to char before name */
+          }
+        if (!read_name(&ptr, ptrend, utf, terminator, &offset, &name, &namelen,
+            &errorcode, cb)) goto FAILED;
+
+        /* Handle (?(R&name) */
+
+        if (was_r_ampersand)
+          {
+          *parsed_pattern = META_COND_RNAME;
+          ptr--;   /* Back to closing parens */
+          }
+
+        /* Handle (?(name). If the name is "DEFINE" we identify it with a
+        special code. Likewise if the name consists of R followed only by
+        digits. Otherwise, handle it like a quoted name. */
+
+        else if (terminator == CHAR_RIGHT_PARENTHESIS)
+          {
+          if (namelen == 6 && PRIV(strncmp_c8)(name, STRING_DEFINE, 6) == 0)
+            *parsed_pattern = META_COND_DEFINE;
+          else
+            {
+            for (i = 1; i < (int)namelen; i++)
+              if (!IS_DIGIT(name[i])) break;
+            *parsed_pattern = (*name == CHAR_R && i >= (int)namelen)?
+              META_COND_RNUMBER : META_COND_NAME;
+            }
+          ptr--;   /* Back to closing parens */
+          }
+
+        /* Handle (?('name') or (?(<name>) */
+
+        else *parsed_pattern = META_COND_NAME;
+
+        /* All these cases except DEFINE end with the name length and offset;
+        DEFINE just has an offset (for the "too many branches" error). */
+
+        if (*parsed_pattern++ != META_COND_DEFINE) *parsed_pattern++ = namelen;
+        PUTOFFSET(offset, parsed_pattern);
+        }  /* End cases that read a name */
+
+      /* Check the closing parenthesis of the condition */
+
+      if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS)
+        {
+        errorcode = ERR24;
+        goto FAILED;
+        }
+      ptr++;
+      break;  /* End of condition processing */
+
+
+      /* ---- Atomic group ---- */
+
+      case CHAR_GREATER_THAN_SIGN:
+      ATOMIC_GROUP:                          /* Come from (*atomic: */
+      *parsed_pattern++ = META_ATOMIC;
+      nest_depth++;
+      ptr++;
+      break;
+
+
+      /* ---- Lookahead assertions ---- */
+
+      case CHAR_EQUALS_SIGN:
+      POSITIVE_LOOK_AHEAD:                   /* Come from (*pla: */
+      *parsed_pattern++ = META_LOOKAHEAD;
+      ptr++;
+      goto POST_ASSERTION;
+
+      case CHAR_ASTERISK:
+      POSITIVE_NONATOMIC_LOOK_AHEAD:         /* Come from (?* */
+      *parsed_pattern++ = META_LOOKAHEAD_NA;
+      ptr++;
+      goto POST_ASSERTION;
+
+      case CHAR_EXCLAMATION_MARK:
+      NEGATIVE_LOOK_AHEAD:                   /* Come from (*nla: */
+      *parsed_pattern++ = META_LOOKAHEADNOT;
+      ptr++;
+      goto POST_ASSERTION;
+
+
+      /* ---- Lookbehind assertions ---- */
+
+      /* (?< followed by = or ! or * is a lookbehind assertion. Otherwise (?<
+      is the start of the name of a capturing group. */
+
+      case CHAR_LESS_THAN_SIGN:
+      if (ptrend - ptr <= 1 ||
+         (ptr[1] != CHAR_EQUALS_SIGN &&
+          ptr[1] != CHAR_EXCLAMATION_MARK &&
+          ptr[1] != CHAR_ASTERISK))
+        {
+        terminator = CHAR_GREATER_THAN_SIGN;
+        goto DEFINE_NAME;
+        }
+      *parsed_pattern++ = (ptr[1] == CHAR_EQUALS_SIGN)?
+        META_LOOKBEHIND : (ptr[1] == CHAR_EXCLAMATION_MARK)?
+        META_LOOKBEHINDNOT : META_LOOKBEHIND_NA;
+
+      POST_LOOKBEHIND:           /* Come from (*plb: (*naplb: and (*nlb: */
+      *has_lookbehind = TRUE;
+      offset = (PCRE2_SIZE)(ptr - cb->start_pattern - 2);
+      PUTOFFSET(offset, parsed_pattern);
+      ptr += 2;
+      /* Fall through */
+
+      /* If the previous item was a condition starting (?(? an assertion,
+      optionally preceded by a callout, is expected. This is checked later on,
+      during actual compilation. However we need to identify this kind of
+      assertion in this pass because it must not be qualified. The value of
+      expect_cond_assert is set to 2 after (?(? is processed. We decrement it
+      for a callout - still leaving a positive value that identifies the
+      assertion. Multiple callouts or any other items will make it zero or
+      less, which doesn't matter because they will cause an error later. */
+
+      POST_ASSERTION:
+      nest_depth++;
+      if (prev_expect_cond_assert > 0)
+        {
+        if (top_nest == NULL) top_nest = (nest_save *)(cb->start_workspace);
+        else if (++top_nest >= end_nests)
+          {
+          errorcode = ERR84;
+          goto FAILED;
+          }
+        top_nest->nest_depth = nest_depth;
+        top_nest->flags = NSF_CONDASSERT;
+        top_nest->options = options & PARSE_TRACKED_OPTIONS;
+        }
+      break;
+
+
+      /* ---- Define a named group ---- */
+
+      /* A named group may be defined as (?'name') or (?<name>). In the latter
+      case we jump to DEFINE_NAME from the disambiguation of (?< above with the
+      terminator set to '>'. */
+
+      case CHAR_APOSTROPHE:
+      terminator = CHAR_APOSTROPHE;    /* Terminator */
+
+      DEFINE_NAME:
+      if (!read_name(&ptr, ptrend, utf, terminator, &offset, &name, &namelen,
+          &errorcode, cb)) goto FAILED;
+
+      /* We have a name for this capturing group. It is also assigned a number,
+      which is its primary means of identification. */
+
+      if (cb->bracount >= MAX_GROUP_NUMBER)
+        {
+        errorcode = ERR97;
+        goto FAILED;
+        }
+      cb->bracount++;
+      *parsed_pattern++ = META_CAPTURE | cb->bracount;
+      nest_depth++;
+
+      /* Check not too many names */
+
+      if (cb->names_found >= MAX_NAME_COUNT)
+        {
+        errorcode = ERR49;
+        goto FAILED;
+        }
+
+      /* Adjust the entry size to accommodate the longest name found. */
+
+      if (namelen + IMM2_SIZE + 1 > cb->name_entry_size)
+        cb->name_entry_size = (uint16_t)(namelen + IMM2_SIZE + 1);
+
+      /* Scan the list to check for duplicates. For duplicate names, if the
+      number is the same, break the loop, which causes the name to be
+      discarded; otherwise, if DUPNAMES is not set, give an error.
+      If it is set, allow the name with a different number, but continue
+      scanning in case this is a duplicate with the same number. For
+      non-duplicate names, give an error if the number is duplicated. */
+
+      isdupname = FALSE;
+      ng = cb->named_groups;
+      for (i = 0; i < cb->names_found; i++, ng++)
+        {
+        if (namelen == ng->length &&
+            PRIV(strncmp)(name, ng->name, (PCRE2_SIZE)namelen) == 0)
+          {
+          if (ng->number == cb->bracount) break;
+          if ((options & PCRE2_DUPNAMES) == 0)
+            {
+            errorcode = ERR43;
+            goto FAILED;
+            }
+          isdupname = ng->isdup = TRUE;     /* Mark as a duplicate */
+          cb->dupnames = TRUE;              /* Duplicate names exist */
+          }
+        else if (ng->number == cb->bracount)
+          {
+          errorcode = ERR65;
+          goto FAILED;
+          }
+        }
+
+      if (i < cb->names_found) break;   /* Ignore duplicate with same number */
+
+      /* Increase the list size if necessary */
+
+      if (cb->names_found >= cb->named_group_list_size)
+        {
+        uint32_t newsize = cb->named_group_list_size * 2;
+        named_group *newspace =
+          cb->cx->memctl.malloc(newsize * sizeof(named_group),
+          cb->cx->memctl.memory_data);
+        if (newspace == NULL)
+          {
+          errorcode = ERR21;
+          goto FAILED;
+          }
+
+        memcpy(newspace, cb->named_groups,
+          cb->named_group_list_size * sizeof(named_group));
+        if (cb->named_group_list_size > NAMED_GROUP_LIST_SIZE)
+          cb->cx->memctl.free((void *)cb->named_groups,
+          cb->cx->memctl.memory_data);
+        cb->named_groups = newspace;
+        cb->named_group_list_size = newsize;
+        }
+
+      /* Add this name to the list */
+
+      cb->named_groups[cb->names_found].name = name;
+      cb->named_groups[cb->names_found].length = (uint16_t)namelen;
+      cb->named_groups[cb->names_found].number = cb->bracount;
+      cb->named_groups[cb->names_found].isdup = (uint16_t)isdupname;
+      cb->names_found++;
+      break;
+      }        /* End of (? switch */
+    break;     /* End of ( handling */
+
+
+    /* ---- Branch terminators ---- */
+
+    /* Alternation: reset the capture count if we are in a (?| group. */
+
+    case CHAR_VERTICAL_LINE:
+    if (top_nest != NULL && top_nest->nest_depth == nest_depth &&
+        (top_nest->flags & NSF_RESET) != 0)
+      {
+      if (cb->bracount > top_nest->max_group)
+        top_nest->max_group = (uint16_t)cb->bracount;
+      cb->bracount = top_nest->reset_group;
+      }
+    *parsed_pattern++ = META_ALT;
+    break;
+
+    /* End of group; reset the capture count to the maximum if we are in a (?|
+    group and/or reset the options that are tracked during parsing. Disallow
+    quantifier for a condition that is an assertion. */
+
+    case CHAR_RIGHT_PARENTHESIS:
+    okquantifier = TRUE;
+    if (top_nest != NULL && top_nest->nest_depth == nest_depth)
+      {
+      options = (options & ~PARSE_TRACKED_OPTIONS) | top_nest->options;
+      if ((top_nest->flags & NSF_RESET) != 0 &&
+          top_nest->max_group > cb->bracount)
+        cb->bracount = top_nest->max_group;
+      if ((top_nest->flags & NSF_CONDASSERT) != 0)
+        okquantifier = FALSE;
+
+      if ((top_nest->flags & NSF_ATOMICSR) != 0)
+        {
+        *parsed_pattern++ = META_KET;
+        }
+
+      if (top_nest == (nest_save *)(cb->start_workspace)) top_nest = NULL;
+        else top_nest--;
+      }
+    if (nest_depth == 0)    /* Unmatched closing parenthesis */
+      {
+      errorcode = ERR22;
+      goto FAILED_BACK;
+      }
+    nest_depth--;
+    *parsed_pattern++ = META_KET;
+    break;
+    }  /* End of switch on pattern character */
+  }    /* End of main character scan loop */
+
+/* End of pattern reached. Check for missing ) at the end of a verb name. */
+
+if (inverbname && ptr >= ptrend)
+  {
+  errorcode = ERR60;
+  goto FAILED;
+  }
+
+/* Manage callout for the final item */
+
+PARSED_END:
+parsed_pattern = manage_callouts(ptr, &previous_callout, auto_callout,
+  parsed_pattern, cb);
+
+/* Insert trailing items for word and line matching (features provided for the
+benefit of pcre2grep). */
+
+if ((extra_options & PCRE2_EXTRA_MATCH_LINE) != 0)
+  {
+  *parsed_pattern++ = META_KET;
+  *parsed_pattern++ = META_DOLLAR;
+  }
+else if ((extra_options & PCRE2_EXTRA_MATCH_WORD) != 0)
+  {
+  *parsed_pattern++ = META_KET;
+  *parsed_pattern++ = META_ESCAPE + ESC_b;
+  }
+
+/* Terminate the parsed pattern, then return success if all groups are closed.
+Otherwise we have unclosed parentheses. */
+
+if (parsed_pattern >= parsed_pattern_end)
+  {
+  errorcode = ERR63;  /* Internal error (parsed pattern overflow) */
+  goto FAILED;
+  }
+
+*parsed_pattern = META_END;
+if (nest_depth == 0) return 0;
+
+UNCLOSED_PARENTHESIS:
+errorcode = ERR14;
+
+/* Come here for all failures. */
+
+FAILED:
+cb->erroroffset = (PCRE2_SIZE)(ptr - cb->start_pattern);
+return errorcode;
+
+/* Some errors need to indicate the previous character. */
+
+FAILED_BACK:
+ptr--;
+goto FAILED;
+
+/* This failure happens several times. */
+
+BAD_VERSION_CONDITION:
+errorcode = ERR79;
+goto FAILED;
+}
+
+
+
+/*************************************************
+*       Find first significant opcode            *
+*************************************************/
+
+/* This is called by several functions that scan a compiled expression looking
+for a fixed first character, or an anchoring opcode etc. It skips over things
+that do not influence this. For some calls, it makes sense to skip negative
+forward and all backward assertions, and also the \b assertion; for others it
+does not.
+
+Arguments:
+  code         pointer to the start of the group
+  skipassert   TRUE if certain assertions are to be skipped
+
+Returns:       pointer to the first significant opcode
+*/
+
+static const PCRE2_UCHAR*
+first_significant_code(PCRE2_SPTR code, BOOL skipassert)
+{
+for (;;)
+  {
+  switch ((int)*code)
+    {
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK:
+    case OP_ASSERTBACK_NOT:
+    case OP_ASSERTBACK_NA:
+    if (!skipassert) return code;
+    do code += GET(code, 1); while (*code == OP_ALT);
+    code += PRIV(OP_lengths)[*code];
+    break;
+
+    case OP_WORD_BOUNDARY:
+    case OP_NOT_WORD_BOUNDARY:
+    if (!skipassert) return code;
+    /* Fall through */
+
+    case OP_CALLOUT:
+    case OP_CREF:
+    case OP_DNCREF:
+    case OP_RREF:
+    case OP_DNRREF:
+    case OP_FALSE:
+    case OP_TRUE:
+    code += PRIV(OP_lengths)[*code];
+    break;
+
+    case OP_CALLOUT_STR:
+    code += GET(code, 1 + 2*LINK_SIZE);
+    break;
+
+    case OP_SKIPZERO:
+    code += 2 + GET(code, 2) + LINK_SIZE;
+    break;
+
+    case OP_COND:
+    case OP_SCOND:
+    if (code[1+LINK_SIZE] != OP_FALSE ||   /* Not DEFINE */
+        code[GET(code, 1)] != OP_KET)      /* More than one branch */
+      return code;
+    code += GET(code, 1) + 1 + LINK_SIZE;
+    break;
+
+    case OP_MARK:
+    case OP_COMMIT_ARG:
+    case OP_PRUNE_ARG:
+    case OP_SKIP_ARG:
+    case OP_THEN_ARG:
+    code += code[1] + PRIV(OP_lengths)[*code];
+    break;
+
+    default:
+    return code;
+    }
+  }
+/* Control never reaches here */
+}
+
+
+
+#ifdef SUPPORT_UNICODE
+/*************************************************
+*           Get othercase range                  *
+*************************************************/
+
+/* This function is passed the start and end of a class range in UCP mode. It
+searches up the characters, looking for ranges of characters in the "other"
+case. Each call returns the next one, updating the start address. A character
+with multiple other cases is returned on its own with a special return value.
+
+Arguments:
+  cptr        points to starting character value; updated
+  d           end value
+  ocptr       where to put start of othercase range
+  odptr       where to put end of othercase range
+
+Yield:        -1 when no more
+               0 when a range is returned
+              >0 the CASESET offset for char with multiple other cases
+                in this case, ocptr contains the original
+*/
+
+static int
+get_othercase_range(uint32_t *cptr, uint32_t d, uint32_t *ocptr,
+  uint32_t *odptr)
+{
+uint32_t c, othercase, next;
+unsigned int co;
+
+/* Find the first character that has an other case. If it has multiple other
+cases, return its case offset value. */
+
+for (c = *cptr; c <= d; c++)
+  {
+  if ((co = UCD_CASESET(c)) != 0)
+    {
+    *ocptr = c++;   /* Character that has the set */
+    *cptr = c;      /* Rest of input range */
+    return (int)co;
+    }
+  if ((othercase = UCD_OTHERCASE(c)) != c) break;
+  }
+
+if (c > d) return -1;  /* Reached end of range */
+
+/* Found a character that has a single other case. Search for the end of the
+range, which is either the end of the input range, or a character that has zero
+or more than one other cases. */
+
+*ocptr = othercase;
+next = othercase + 1;
+
+for (++c; c <= d; c++)
+  {
+  if ((co = UCD_CASESET(c)) != 0 || UCD_OTHERCASE(c) != next) break;
+  next++;
+  }
+
+*odptr = next - 1;     /* End of othercase range */
+*cptr = c;             /* Rest of input range */
+return 0;
+}
+#endif  /* SUPPORT_UNICODE */
+
+
+
+/*************************************************
+* Add a character or range to a class (internal) *
+*************************************************/
+
+/* This function packages up the logic of adding a character or range of
+characters to a class. The character values in the arguments will be within the
+valid values for the current mode (8-bit, 16-bit, UTF, etc). This function is
+called only from within the "add to class" group of functions, some of which
+are recursive and mutually recursive. The external entry point is
+add_to_class().
+
+Arguments:
+  classbits     the bit map for characters < 256
+  uchardptr     points to the pointer for extra data
+  options       the options word
+  cb            compile data
+  start         start of range character
+  end           end of range character
+
+Returns:        the number of < 256 characters added
+                the pointer to extra data is updated
+*/
+
+static unsigned int
+add_to_class_internal(uint8_t *classbits, PCRE2_UCHAR **uchardptr,
+  uint32_t options, compile_block *cb, uint32_t start, uint32_t end)
+{
+uint32_t c;
+uint32_t classbits_end = (end <= 0xff ? end : 0xff);
+unsigned int n8 = 0;
+
+/* If caseless matching is required, scan the range and process alternate
+cases. In Unicode, there are 8-bit characters that have alternate cases that
+are greater than 255 and vice-versa. Sometimes we can just extend the original
+range. */
+
+if ((options & PCRE2_CASELESS) != 0)
+  {
+#ifdef SUPPORT_UNICODE
+  if ((options & (PCRE2_UTF|PCRE2_UCP)) != 0)
+    {
+    int rc;
+    uint32_t oc, od;
+
+    options &= ~PCRE2_CASELESS;   /* Remove for recursive calls */
+    c = start;
+
+    while ((rc = get_othercase_range(&c, end, &oc, &od)) >= 0)
+      {
+      /* Handle a single character that has more than one other case. */
+
+      if (rc > 0) n8 += add_list_to_class_internal(classbits, uchardptr, options, cb,
+        PRIV(ucd_caseless_sets) + rc, oc);
+
+      /* Do nothing if the other case range is within the original range. */
+
+      else if (oc >= cb->class_range_start && od <= cb->class_range_end) continue;
+
+      /* Extend the original range if there is overlap, noting that if oc < c, we
+      can't have od > end because a subrange is always shorter than the basic
+      range. Otherwise, use a recursive call to add the additional range. */
+
+      else if (oc < start && od >= start - 1) start = oc; /* Extend downwards */
+      else if (od > end && oc <= end + 1)
+        {
+        end = od;       /* Extend upwards */
+        if (end > classbits_end) classbits_end = (end <= 0xff ? end : 0xff);
+        }
+      else n8 += add_to_class_internal(classbits, uchardptr, options, cb, oc, od);
+      }
+    }
+  else
+#endif  /* SUPPORT_UNICODE */
+
+  /* Not UTF mode */
+
+  for (c = start; c <= classbits_end; c++)
+    {
+    SETBIT(classbits, cb->fcc[c]);
+    n8++;
+    }
+  }
+
+/* Now handle the originally supplied range. Adjust the final value according
+to the bit length - this means that the same lists of (e.g.) horizontal spaces
+can be used in all cases. */
+
+if ((options & PCRE2_UTF) == 0 && end > MAX_NON_UTF_CHAR)
+  end = MAX_NON_UTF_CHAR;
+
+if (start > cb->class_range_start && end < cb->class_range_end) return n8;
+
+/* Use the bitmap for characters < 256. Otherwise use extra data.*/
+
+for (c = start; c <= classbits_end; c++)
+  {
+  /* Regardless of start, c will always be <= 255. */
+  SETBIT(classbits, c);
+  n8++;
+  }
+
+#ifdef SUPPORT_WIDE_CHARS
+if (start <= 0xff) start = 0xff + 1;
+
+if (end >= start)
+  {
+  PCRE2_UCHAR *uchardata = *uchardptr;
+
+#ifdef SUPPORT_UNICODE
+  if ((options & PCRE2_UTF) != 0)
+    {
+    if (start < end)
+      {
+      *uchardata++ = XCL_RANGE;
+      uchardata += PRIV(ord2utf)(start, uchardata);
+      uchardata += PRIV(ord2utf)(end, uchardata);
+      }
+    else if (start == end)
+      {
+      *uchardata++ = XCL_SINGLE;
+      uchardata += PRIV(ord2utf)(start, uchardata);
+      }
+    }
+  else
+#endif  /* SUPPORT_UNICODE */
+
+  /* Without UTF support, character values are constrained by the bit length,
+  and can only be > 256 for 16-bit and 32-bit libraries. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+    {}
+#else
+  if (start < end)
+    {
+    *uchardata++ = XCL_RANGE;
+    *uchardata++ = start;
+    *uchardata++ = end;
+    }
+  else if (start == end)
+    {
+    *uchardata++ = XCL_SINGLE;
+    *uchardata++ = start;
+    }
+#endif  /* PCRE2_CODE_UNIT_WIDTH == 8 */
+  *uchardptr = uchardata;   /* Updata extra data pointer */
+  }
+#else  /* SUPPORT_WIDE_CHARS */
+  (void)uchardptr;          /* Avoid compiler warning */
+#endif /* SUPPORT_WIDE_CHARS */
+
+return n8;    /* Number of 8-bit characters */
+}
+
+
+
+#ifdef SUPPORT_UNICODE
+/*************************************************
+* Add a list of characters to a class (internal) *
+*************************************************/
+
+/* This function is used for adding a list of case-equivalent characters to a
+class when in UTF mode. This function is called only from within
+add_to_class_internal(), with which it is mutually recursive.
+
+Arguments:
+  classbits     the bit map for characters < 256
+  uchardptr     points to the pointer for extra data
+  options       the options word
+  cb            contains pointers to tables etc.
+  p             points to row of 32-bit values, terminated by NOTACHAR
+  except        character to omit; this is used when adding lists of
+                  case-equivalent characters to avoid including the one we
+                  already know about
+
+Returns:        the number of < 256 characters added
+                the pointer to extra data is updated
+*/
+
+static unsigned int
+add_list_to_class_internal(uint8_t *classbits, PCRE2_UCHAR **uchardptr,
+  uint32_t options, compile_block *cb, const uint32_t *p, unsigned int except)
+{
+unsigned int n8 = 0;
+while (p[0] < NOTACHAR)
+  {
+  unsigned int n = 0;
+  if (p[0] != except)
+    {
+    while(p[n+1] == p[0] + n + 1) n++;
+    n8 += add_to_class_internal(classbits, uchardptr, options, cb, p[0], p[n]);
+    }
+  p += n + 1;
+  }
+return n8;
+}
+#endif
+
+
+
+/*************************************************
+*   External entry point for add range to class  *
+*************************************************/
+
+/* This function sets the overall range so that the internal functions can try
+to avoid duplication when handling case-independence.
+
+Arguments:
+  classbits     the bit map for characters < 256
+  uchardptr     points to the pointer for extra data
+  options       the options word
+  cb            compile data
+  start         start of range character
+  end           end of range character
+
+Returns:        the number of < 256 characters added
+                the pointer to extra data is updated
+*/
+
+static unsigned int
+add_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options,
+  compile_block *cb, uint32_t start, uint32_t end)
+{
+cb->class_range_start = start;
+cb->class_range_end = end;
+return add_to_class_internal(classbits, uchardptr, options, cb, start, end);
+}
+
+
+/*************************************************
+*   External entry point for add list to class   *
+*************************************************/
+
+/* This function is used for adding a list of horizontal or vertical whitespace
+characters to a class. The list must be in order so that ranges of characters
+can be detected and handled appropriately. This function sets the overall range
+so that the internal functions can try to avoid duplication when handling
+case-independence.
+
+Arguments:
+  classbits     the bit map for characters < 256
+  uchardptr     points to the pointer for extra data
+  options       the options word
+  cb            contains pointers to tables etc.
+  p             points to row of 32-bit values, terminated by NOTACHAR
+  except        character to omit; this is used when adding lists of
+                  case-equivalent characters to avoid including the one we
+                  already know about
+
+Returns:        the number of < 256 characters added
+                the pointer to extra data is updated
+*/
+
+static unsigned int
+add_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options,
+  compile_block *cb, const uint32_t *p, unsigned int except)
+{
+unsigned int n8 = 0;
+while (p[0] < NOTACHAR)
+  {
+  unsigned int n = 0;
+  if (p[0] != except)
+    {
+    while(p[n+1] == p[0] + n + 1) n++;
+    cb->class_range_start = p[0];
+    cb->class_range_end = p[n];
+    n8 += add_to_class_internal(classbits, uchardptr, options, cb, p[0], p[n]);
+    }
+  p += n + 1;
+  }
+return n8;
+}
+
+
+
+/*************************************************
+*    Add characters not in a list to a class     *
+*************************************************/
+
+/* This function is used for adding the complement of a list of horizontal or
+vertical whitespace to a class. The list must be in order.
+
+Arguments:
+  classbits     the bit map for characters < 256
+  uchardptr     points to the pointer for extra data
+  options       the options word
+  cb            contains pointers to tables etc.
+  p             points to row of 32-bit values, terminated by NOTACHAR
+
+Returns:        the number of < 256 characters added
+                the pointer to extra data is updated
+*/
+
+static unsigned int
+add_not_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr,
+  uint32_t options, compile_block *cb, const uint32_t *p)
+{
+BOOL utf = (options & PCRE2_UTF) != 0;
+unsigned int n8 = 0;
+if (p[0] > 0)
+  n8 += add_to_class(classbits, uchardptr, options, cb, 0, p[0] - 1);
+while (p[0] < NOTACHAR)
+  {
+  while (p[1] == p[0] + 1) p++;
+  n8 += add_to_class(classbits, uchardptr, options, cb, p[0] + 1,
+    (p[1] == NOTACHAR) ? (utf ? 0x10ffffu : 0xffffffffu) : p[1] - 1);
+  p++;
+  }
+return n8;
+}
+
+
+
+/*************************************************
+*    Find details of duplicate group names       *
+*************************************************/
+
+/* This is called from compile_branch() when it needs to know the index and
+count of duplicates in the names table when processing named backreferences,
+either directly, or as conditions.
+
+Arguments:
+  name          points to the name
+  length        the length of the name
+  indexptr      where to put the index
+  countptr      where to put the count of duplicates
+  errorcodeptr  where to put an error code
+  cb            the compile block
+
+Returns:        TRUE if OK, FALSE if not, error code set
+*/
+
+static BOOL
+find_dupname_details(PCRE2_SPTR name, uint32_t length, int *indexptr,
+  int *countptr, int *errorcodeptr, compile_block *cb)
+{
+uint32_t i, groupnumber;
+int count;
+PCRE2_UCHAR *slot = cb->name_table;
+
+/* Find the first entry in the table */
+
+for (i = 0; i < cb->names_found; i++)
+  {
+  if (PRIV(strncmp)(name, slot+IMM2_SIZE, length) == 0 &&
+      slot[IMM2_SIZE+length] == 0) break;
+  slot += cb->name_entry_size;
+  }
+
+/* This should not occur, because this function is called only when we know we
+have duplicate names. Give an internal error. */
+
+if (i >= cb->names_found)
+  {
+  *errorcodeptr = ERR53;
+  cb->erroroffset = name - cb->start_pattern;
+  return FALSE;
+  }
+
+/* Record the index and then see how many duplicates there are, updating the
+backref map and maximum back reference as we do. */
+
+*indexptr = i;
+count = 0;
+
+for (;;)
+  {
+  count++;
+  groupnumber = GET2(slot,0);
+  cb->backref_map |= (groupnumber < 32)? (1u << groupnumber) : 1;
+  if (groupnumber > cb->top_backref) cb->top_backref = groupnumber;
+  if (++i >= cb->names_found) break;
+  slot += cb->name_entry_size;
+  if (PRIV(strncmp)(name, slot+IMM2_SIZE, length) != 0 ||
+    (slot+IMM2_SIZE)[length] != 0) break;
+  }
+
+*countptr = count;
+return TRUE;
+}
+
+
+
+/*************************************************
+*           Compile one branch                   *
+*************************************************/
+
+/* Scan the parsed pattern, compiling it into the a vector of PCRE2_UCHAR. If
+the options are changed during the branch, the pointer is used to change the
+external options bits. This function is used during the pre-compile phase when
+we are trying to find out the amount of memory needed, as well as during the
+real compile phase. The value of lengthptr distinguishes the two phases.
+
+Arguments:
+  optionsptr        pointer to the option bits
+  codeptr           points to the pointer to the current code point
+  pptrptr           points to the current parsed pattern pointer
+  errorcodeptr      points to error code variable
+  firstcuptr        place to put the first required code unit
+  firstcuflagsptr   place to put the first code unit flags, or a negative number
+  reqcuptr          place to put the last required code unit
+  reqcuflagsptr     place to put the last required code unit flags, or a negative number
+  bcptr             points to current branch chain
+  cb                contains pointers to tables etc.
+  lengthptr         NULL during the real compile phase
+                    points to length accumulator during pre-compile phase
+
+Returns:            0 There's been an error, *errorcodeptr is non-zero
+                   +1 Success, this branch must match at least one character
+                   -1 Success, this branch may match an empty string
+*/
+
+static int
+compile_branch(uint32_t *optionsptr, PCRE2_UCHAR **codeptr, uint32_t **pptrptr,
+  int *errorcodeptr, uint32_t *firstcuptr, int32_t *firstcuflagsptr,
+  uint32_t *reqcuptr, int32_t *reqcuflagsptr, branch_chain *bcptr,
+  compile_block *cb, PCRE2_SIZE *lengthptr)
+{
+int bravalue = 0;
+int okreturn = -1;
+int group_return = 0;
+uint32_t repeat_min = 0, repeat_max = 0;      /* To please picky compilers */
+uint32_t greedy_default, greedy_non_default;
+uint32_t repeat_type, op_type;
+uint32_t options = *optionsptr;               /* May change dynamically */
+uint32_t firstcu, reqcu;
+uint32_t zeroreqcu, zerofirstcu;
+uint32_t escape;
+uint32_t *pptr = *pptrptr;
+uint32_t meta, meta_arg;
+int32_t firstcuflags, reqcuflags;
+int32_t zeroreqcuflags, zerofirstcuflags;
+int32_t req_caseopt, reqvary, tempreqvary;
+PCRE2_SIZE offset = 0;
+PCRE2_SIZE length_prevgroup = 0;
+PCRE2_UCHAR *code = *codeptr;
+PCRE2_UCHAR *last_code = code;
+PCRE2_UCHAR *orig_code = code;
+PCRE2_UCHAR *tempcode;
+PCRE2_UCHAR *previous = NULL;
+PCRE2_UCHAR op_previous;
+BOOL groupsetfirstcu = FALSE;
+BOOL had_accept = FALSE;
+BOOL matched_char = FALSE;
+BOOL previous_matched_char = FALSE;
+BOOL reset_caseful = FALSE;
+const uint8_t *cbits = cb->cbits;
+uint8_t classbits[32];
+
+/* We can fish out the UTF setting once and for all into a BOOL, but we must
+not do this for other options (e.g. PCRE2_EXTENDED) because they may change
+dynamically as we process the pattern. */
+
+#ifdef SUPPORT_UNICODE
+BOOL utf = (options & PCRE2_UTF) != 0;
+BOOL ucp = (options & PCRE2_UCP) != 0;
+#else  /* No Unicode support */
+BOOL utf = FALSE;
+#endif
+
+/* Helper variables for OP_XCLASS opcode (for characters > 255). We define
+class_uchardata always so that it can be passed to add_to_class() always,
+though it will not be used in non-UTF 8-bit cases. This avoids having to supply
+alternative calls for the different cases. */
+
+PCRE2_UCHAR *class_uchardata;
+#ifdef SUPPORT_WIDE_CHARS
+BOOL xclass;
+PCRE2_UCHAR *class_uchardata_base;
+#endif
+
+/* Set up the default and non-default settings for greediness */
+
+greedy_default = ((options & PCRE2_UNGREEDY) != 0);
+greedy_non_default = greedy_default ^ 1;
+
+/* Initialize no first unit, no required unit. REQ_UNSET means "no char
+matching encountered yet". It gets changed to REQ_NONE if we hit something that
+matches a non-fixed first unit; reqcu just remains unset if we never find one.
+
+When we hit a repeat whose minimum is zero, we may have to adjust these values
+to take the zero repeat into account. This is implemented by setting them to
+zerofirstcu and zeroreqcu when such a repeat is encountered. The individual
+item types that can be repeated set these backoff variables appropriately. */
+
+firstcu = reqcu = zerofirstcu = zeroreqcu = 0;
+firstcuflags = reqcuflags = zerofirstcuflags = zeroreqcuflags = REQ_UNSET;
+
+/* The variable req_caseopt contains either the REQ_CASELESS value or zero,
+according to the current setting of the caseless flag. The REQ_CASELESS value
+leaves the lower 28 bit empty. It is added into the firstcu or reqcu variables
+to record the case status of the value. This is used only for ASCII characters.
+*/
+
+req_caseopt = ((options & PCRE2_CASELESS) != 0)? REQ_CASELESS:0;
+
+/* Switch on next META item until the end of the branch */
+
+for (;; pptr++)
+  {
+#ifdef SUPPORT_WIDE_CHARS
+  BOOL xclass_has_prop;
+#endif
+  BOOL negate_class;
+  BOOL should_flip_negation;
+  BOOL match_all_or_no_wide_chars;
+  BOOL possessive_quantifier;
+  BOOL note_group_empty;
+  int class_has_8bitchar;
+  int i;
+  uint32_t mclength;
+  uint32_t skipunits;
+  uint32_t subreqcu, subfirstcu;
+  uint32_t groupnumber;
+  uint32_t verbarglen, verbculen;
+  int32_t subreqcuflags, subfirstcuflags;  /* Must be signed */
+  open_capitem *oc;
+  PCRE2_UCHAR mcbuffer[8];
+
+  /* Get next META item in the pattern and its potential argument. */
+
+  meta = META_CODE(*pptr);
+  meta_arg = META_DATA(*pptr);
+
+  /* If we are in the pre-compile phase, accumulate the length used for the
+  previous cycle of this loop, unless the next item is a quantifier. */
+
+  if (lengthptr != NULL)
+    {
+    if (code > cb->start_workspace + cb->workspace_size -
+        WORK_SIZE_SAFETY_MARGIN)                       /* Check for overrun */
+      {
+      *errorcodeptr = (code >= cb->start_workspace + cb->workspace_size)?
+        ERR52 : ERR86;
+      return 0;
+      }
+
+    /* There is at least one situation where code goes backwards: this is the
+    case of a zero quantifier after a class (e.g. [ab]{0}). When the quantifier
+    is processed, the whole class is eliminated. However, it is created first,
+    so we have to allow memory for it. Therefore, don't ever reduce the length
+    at this point. */
+
+    if (code < last_code) code = last_code;
+
+    /* If the next thing is not a quantifier, we add the length of the previous
+    item into the total, and reset the code pointer to the start of the
+    workspace. Otherwise leave the previous item available to be quantified. */
+
+    if (meta < META_ASTERISK || meta > META_MINMAX_QUERY)
+      {
+      if (OFLOW_MAX - *lengthptr < (PCRE2_SIZE)(code - orig_code))
+        {
+        *errorcodeptr = ERR20;   /* Integer overflow */
+        return 0;
+        }
+      *lengthptr += (PCRE2_SIZE)(code - orig_code);
+      if (*lengthptr > MAX_PATTERN_SIZE)
+        {
+        *errorcodeptr = ERR20;   /* Pattern is too large */
+        return 0;
+        }
+      code = orig_code;
+      }
+
+    /* Remember where this code item starts so we can catch the "backwards"
+    case above next time round. */
+
+    last_code = code;
+    }
+
+  /* Process the next parsed pattern item. If it is not a quantifier, remember
+  where it starts so that it can be quantified when a quantifier follows.
+  Checking for the legality of quantifiers happens in parse_regex(), except for
+  a quantifier after an assertion that is a condition. */
+
+  if (meta < META_ASTERISK || meta > META_MINMAX_QUERY)
+    {
+    previous = code;
+    if (matched_char && !had_accept) okreturn = 1;
+    }
+
+  previous_matched_char = matched_char;
+  matched_char = FALSE;
+  note_group_empty = FALSE;
+  skipunits = 0;         /* Default value for most subgroups */
+
+  switch(meta)
+    {
+    /* ===================================================================*/
+    /* The branch terminates at pattern end or | or ) */
+
+    case META_END:
+    case META_ALT:
+    case META_KET:
+    *firstcuptr = firstcu;
+    *firstcuflagsptr = firstcuflags;
+    *reqcuptr = reqcu;
+    *reqcuflagsptr = reqcuflags;
+    *codeptr = code;
+    *pptrptr = pptr;
+    return okreturn;
+
+
+    /* ===================================================================*/
+    /* Handle single-character metacharacters. In multiline mode, ^ disables
+    the setting of any following char as a first character. */
+
+    case META_CIRCUMFLEX:
+    if ((options & PCRE2_MULTILINE) != 0)
+      {
+      if (firstcuflags == REQ_UNSET)
+        zerofirstcuflags = firstcuflags = REQ_NONE;
+      *code++ = OP_CIRCM;
+      }
+    else *code++ = OP_CIRC;
+    break;
+
+    case META_DOLLAR:
+    *code++ = ((options & PCRE2_MULTILINE) != 0)? OP_DOLLM : OP_DOLL;
+    break;
+
+    /* There can never be a first char if '.' is first, whatever happens about
+    repeats. The value of reqcu doesn't change either. */
+
+    case META_DOT:
+    matched_char = TRUE;
+    if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+    zerofirstcu = firstcu;
+    zerofirstcuflags = firstcuflags;
+    zeroreqcu = reqcu;
+    zeroreqcuflags = reqcuflags;
+    *code++ = ((options & PCRE2_DOTALL) != 0)? OP_ALLANY: OP_ANY;
+    break;
+
+
+    /* ===================================================================*/
+    /* Empty character classes are allowed if PCRE2_ALLOW_EMPTY_CLASS is set.
+    Otherwise, an initial ']' is taken as a data character. When empty classes
+    are allowed, [] must always fail, so generate OP_FAIL, whereas [^] must
+    match any character, so generate OP_ALLANY. */
+
+    case META_CLASS_EMPTY:
+    case META_CLASS_EMPTY_NOT:
+    matched_char = TRUE;
+    *code++ = (meta == META_CLASS_EMPTY_NOT)? OP_ALLANY : OP_FAIL;
+    if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+    zerofirstcu = firstcu;
+    zerofirstcuflags = firstcuflags;
+    break;
+
+
+    /* ===================================================================*/
+    /* Non-empty character class. If the included characters are all < 256, we
+    build a 32-byte bitmap of the permitted characters, except in the special
+    case where there is only one such character. For negated classes, we build
+    the map as usual, then invert it at the end. However, we use a different
+    opcode so that data characters > 255 can be handled correctly.
+
+    If the class contains characters outside the 0-255 range, a different
+    opcode is compiled. It may optionally have a bit map for characters < 256,
+    but those above are are explicitly listed afterwards. A flag code unit
+    tells whether the bitmap is present, and whether this is a negated class or
+    not. */
+
+    case META_CLASS_NOT:
+    case META_CLASS:
+    matched_char = TRUE;
+    negate_class = meta == META_CLASS_NOT;
+
+    /* We can optimize the case of a single character in a class by generating
+    OP_CHAR or OP_CHARI if it's positive, or OP_NOT or OP_NOTI if it's
+    negative. In the negative case there can be no first char if this item is
+    first, whatever repeat count may follow. In the case of reqcu, save the
+    previous value for reinstating. */
+
+    /* NOTE: at present this optimization is not effective if the only
+    character in a class in 32-bit, non-UCP mode has its top bit set. */
+
+    if (pptr[1] < META_END && pptr[2] == META_CLASS_END)
+      {
+#ifdef SUPPORT_UNICODE
+      uint32_t d;
+#endif
+      uint32_t c = pptr[1];
+
+      pptr += 2;                 /* Move on to class end */
+      if (meta == META_CLASS)    /* A positive one-char class can be */
+        {                        /* handled as a normal literal character. */
+        meta = c;                /* Set up the character */
+        goto NORMAL_CHAR_SET;
+        }
+
+      /* Handle a negative one-character class */
+
+      zeroreqcu = reqcu;
+      zeroreqcuflags = reqcuflags;
+      if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+      zerofirstcu = firstcu;
+      zerofirstcuflags = firstcuflags;
+
+      /* For caseless UTF or UCP mode, check whether this character has more
+      than one other case. If so, generate a special OP_NOTPROP item instead of
+      OP_NOTI. */
+
+#ifdef SUPPORT_UNICODE
+      if ((utf||ucp) && (options & PCRE2_CASELESS) != 0 &&
+          (d = UCD_CASESET(c)) != 0)
+        {
+        *code++ = OP_NOTPROP;
+        *code++ = PT_CLIST;
+        *code++ = d;
+        break;   /* We are finished with this class */
+        }
+#endif
+      /* Char has only one other case, or UCP not available */
+
+      *code++ = ((options & PCRE2_CASELESS) != 0)? OP_NOTI: OP_NOT;
+      code += PUTCHAR(c, code);
+      break;   /* We are finished with this class */
+      }        /* End of 1-char optimization */
+
+    /* Handle character classes that contain more than just one literal
+    character. If there are exactly two characters in a positive class, see if
+    they are case partners. This can be optimized to generate a caseless single
+    character match (which also sets first/required code units if relevant). */
+
+    if (meta == META_CLASS && pptr[1] < META_END && pptr[2] < META_END &&
+        pptr[3] == META_CLASS_END)
+      {
+      uint32_t c = pptr[1];
+
+#ifdef SUPPORT_UNICODE
+      if (UCD_CASESET(c) == 0)
+#endif
+        {
+        uint32_t d;
+
+#ifdef SUPPORT_UNICODE
+        if ((utf || ucp) && c > 127) d = UCD_OTHERCASE(c); else
+#endif
+          {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+          if (c > 255) d = c; else
+#endif
+          d = TABLE_GET(c, cb->fcc, c);
+          }
+
+        if (c != d && pptr[2] == d)
+          {
+          pptr += 3;                 /* Move on to class end */
+          meta = c;
+          if ((options & PCRE2_CASELESS) == 0)
+            {
+            reset_caseful = TRUE;
+            options |= PCRE2_CASELESS;
+            req_caseopt = REQ_CASELESS;
+            }
+          goto CLASS_CASELESS_CHAR;
+          }
+        }
+      }
+
+    /* If a non-extended class contains a negative special such as \S, we need
+    to flip the negation flag at the end, so that support for characters > 255
+    works correctly (they are all included in the class). An extended class may
+    need to insert specific matching or non-matching code for wide characters.
+    */
+
+    should_flip_negation = match_all_or_no_wide_chars = FALSE;
+
+    /* Extended class (xclass) will be used when characters > 255
+    might match. */
+
+#ifdef SUPPORT_WIDE_CHARS
+    xclass = FALSE;
+    class_uchardata = code + LINK_SIZE + 2;   /* For XCLASS items */
+    class_uchardata_base = class_uchardata;   /* Save the start */
+#endif
+
+    /* For optimization purposes, we track some properties of the class:
+    class_has_8bitchar will be non-zero if the class contains at least one
+    character with a code point less than 256; xclass_has_prop will be TRUE if
+    Unicode property checks are present in the class. */
+
+    class_has_8bitchar = 0;
+#ifdef SUPPORT_WIDE_CHARS
+    xclass_has_prop = FALSE;
+#endif
+
+    /* Initialize the 256-bit (32-byte) bit map to all zeros. We build the map
+    in a temporary bit of memory, in case the class contains fewer than two
+    8-bit characters because in that case the compiled code doesn't use the bit
+    map. */
+
+    memset(classbits, 0, 32 * sizeof(uint8_t));
+
+    /* Process items until META_CLASS_END is reached. */
+
+    while ((meta = *(++pptr)) != META_CLASS_END)
+      {
+      /* Handle POSIX classes such as [:alpha:] etc. */
+
+      if (meta == META_POSIX || meta == META_POSIX_NEG)
+        {
+        BOOL local_negate = (meta == META_POSIX_NEG);
+        int posix_class = *(++pptr);
+        int taboffset, tabopt;
+        uint8_t pbits[32];
+
+        should_flip_negation = local_negate;  /* Note negative special */
+
+        /* If matching is caseless, upper and lower are converted to alpha.
+        This relies on the fact that the class table starts with alpha,
+        lower, upper as the first 3 entries. */
+
+        if ((options & PCRE2_CASELESS) != 0 && posix_class <= 2)
+          posix_class = 0;
+
+        /* When PCRE2_UCP is set, some of the POSIX classes are converted to
+        different escape sequences that use Unicode properties \p or \P.
+        Others that are not available via \p or \P have to generate
+        XCL_PROP/XCL_NOTPROP directly, which is done here. */
+
+#ifdef SUPPORT_UNICODE
+        if ((options & PCRE2_UCP) != 0) switch(posix_class)
+          {
+          case PC_GRAPH:
+          case PC_PRINT:
+          case PC_PUNCT:
+          *class_uchardata++ = local_negate? XCL_NOTPROP : XCL_PROP;
+          *class_uchardata++ = (PCRE2_UCHAR)
+            ((posix_class == PC_GRAPH)? PT_PXGRAPH :
+             (posix_class == PC_PRINT)? PT_PXPRINT : PT_PXPUNCT);
+          *class_uchardata++ = 0;
+          xclass_has_prop = TRUE;
+          goto CONTINUE_CLASS;
+
+          /* For the other POSIX classes (ascii, xdigit) we are going to
+          fall through to the non-UCP case and build a bit map for
+          characters with code points less than 256. However, if we are in
+          a negated POSIX class, characters with code points greater than
+          255 must either all match or all not match, depending on whether
+          the whole class is not or is negated. For example, for
+          [[:^ascii:]... they must all match, whereas for [^[:^xdigit:]...
+          they must not.
+
+          In the special case where there are no xclass items, this is
+          automatically handled by the use of OP_CLASS or OP_NCLASS, but an
+          explicit range is needed for OP_XCLASS. Setting a flag here
+          causes the range to be generated later when it is known that
+          OP_XCLASS is required. In the 8-bit library this is relevant only in
+          utf mode, since no wide characters can exist otherwise. */
+
+          default:
+#if PCRE2_CODE_UNIT_WIDTH == 8
+          if (utf)
+#endif
+          match_all_or_no_wide_chars |= local_negate;
+          break;
+          }
+#endif  /* SUPPORT_UNICODE */
+
+        /* In the non-UCP case, or when UCP makes no difference, we build the
+        bit map for the POSIX class in a chunk of local store because we may
+        be adding and subtracting from it, and we don't want to subtract bits
+        that may be in the main map already. At the end we or the result into
+        the bit map that is being built. */
+
+        posix_class *= 3;
+
+        /* Copy in the first table (always present) */
+
+        memcpy(pbits, cbits + posix_class_maps[posix_class],
+          32 * sizeof(uint8_t));
+
+        /* If there is a second table, add or remove it as required. */
+
+        taboffset = posix_class_maps[posix_class + 1];
+        tabopt = posix_class_maps[posix_class + 2];
+
+        if (taboffset >= 0)
+          {
+          if (tabopt >= 0)
+            for (i = 0; i < 32; i++) pbits[i] |= cbits[(int)i + taboffset];
+          else
+            for (i = 0; i < 32; i++) pbits[i] &= ~cbits[(int)i + taboffset];
+          }
+
+        /* Now see if we need to remove any special characters. An option
+        value of 1 removes vertical space and 2 removes underscore. */
+
+        if (tabopt < 0) tabopt = -tabopt;
+        if (tabopt == 1) pbits[1] &= ~0x3c;
+          else if (tabopt == 2) pbits[11] &= 0x7f;
+
+        /* Add the POSIX table or its complement into the main table that is
+        being built and we are done. */
+
+        if (local_negate)
+          for (i = 0; i < 32; i++) classbits[i] |= ~pbits[i];
+        else
+          for (i = 0; i < 32; i++) classbits[i] |= pbits[i];
+
+        /* Every class contains at least one < 256 character. */
+
+        class_has_8bitchar = 1;
+        goto CONTINUE_CLASS;    /* End of POSIX handling */
+        }
+
+      /* Other than POSIX classes, the only items we should encounter are
+      \d-type escapes and literal characters (possibly as ranges). */
+
+      if (meta == META_BIGVALUE)
+        {
+        meta = *(++pptr);
+        goto CLASS_LITERAL;
+        }
+
+      /* Any other non-literal must be an escape */
+
+      if (meta >= META_END)
+        {
+        if (META_CODE(meta) != META_ESCAPE)
+          {
+#ifdef DEBUG_SHOW_PARSED
+          fprintf(stderr, "** Unrecognized parsed pattern item 0x%.8x "
+                          "in character class\n", meta);
+#endif
+          *errorcodeptr = ERR89;  /* Internal error - unrecognized. */
+          return 0;
+          }
+        escape = META_DATA(meta);
+
+        /* Every class contains at least one < 256 character. */
+
+        class_has_8bitchar++;
+
+        switch(escape)
+          {
+          case ESC_d:
+          for (i = 0; i < 32; i++) classbits[i] |= cbits[i+cbit_digit];
+          break;
+
+          case ESC_D:
+          should_flip_negation = TRUE;
+          for (i = 0; i < 32; i++) classbits[i] |= ~cbits[i+cbit_digit];
+          break;
+
+          case ESC_w:
+          for (i = 0; i < 32; i++) classbits[i] |= cbits[i+cbit_word];
+          break;
+
+          case ESC_W:
+          should_flip_negation = TRUE;
+          for (i = 0; i < 32; i++) classbits[i] |= ~cbits[i+cbit_word];
+          break;
+
+          /* Perl 5.004 onwards omitted VT from \s, but restored it at Perl
+          5.18. Before PCRE 8.34, we had to preserve the VT bit if it was
+          previously set by something earlier in the character class.
+          Luckily, the value of CHAR_VT is 0x0b in both ASCII and EBCDIC, so
+          we could just adjust the appropriate bit. From PCRE 8.34 we no
+          longer treat \s and \S specially. */
+
+          case ESC_s:
+          for (i = 0; i < 32; i++) classbits[i] |= cbits[i+cbit_space];
+          break;
+
+          case ESC_S:
+          should_flip_negation = TRUE;
+          for (i = 0; i < 32; i++) classbits[i] |= ~cbits[i+cbit_space];
+          break;
+
+          /* When adding the horizontal or vertical space lists to a class, or
+          their complements, disable PCRE2_CASELESS, because it justs wastes
+          time, and in the "not-x" UTF cases can create unwanted duplicates in
+          the XCLASS list (provoked by characters that have more than one other
+          case and by both cases being in the same "not-x" sublist). */
+
+          case ESC_h:
+          (void)add_list_to_class(classbits, &class_uchardata,
+            options & ~PCRE2_CASELESS, cb, PRIV(hspace_list), NOTACHAR);
+          break;
+
+          case ESC_H:
+          (void)add_not_list_to_class(classbits, &class_uchardata,
+            options & ~PCRE2_CASELESS, cb, PRIV(hspace_list));
+          break;
+
+          case ESC_v:
+          (void)add_list_to_class(classbits, &class_uchardata,
+            options & ~PCRE2_CASELESS, cb, PRIV(vspace_list), NOTACHAR);
+          break;
+
+          case ESC_V:
+          (void)add_not_list_to_class(classbits, &class_uchardata,
+            options & ~PCRE2_CASELESS, cb, PRIV(vspace_list));
+          break;
+
+          /* If Unicode is not supported, \P and \p are not allowed and are
+          faulted at parse time, so will never appear here. */
+
+#ifdef SUPPORT_UNICODE
+          case ESC_p:
+          case ESC_P:
+            {
+            uint32_t ptype = *(++pptr) >> 16;
+            uint32_t pdata = *pptr & 0xffff;
+            *class_uchardata++ = (escape == ESC_p)? XCL_PROP : XCL_NOTPROP;
+            *class_uchardata++ = ptype;
+            *class_uchardata++ = pdata;
+            xclass_has_prop = TRUE;
+            class_has_8bitchar--;                /* Undo! */
+            }
+          break;
+#endif
+          }
+
+        goto CONTINUE_CLASS;
+        }  /* End handling \d-type escapes */
+
+      /* A literal character may be followed by a range meta. At parse time
+      there are checks for out-of-order characters, for ranges where the two
+      characters are equal, and for hyphens that cannot indicate a range. At
+      this point, therefore, no checking is needed. */
+
+      else
+        {
+        uint32_t c, d;
+
+        CLASS_LITERAL:
+        c = d = meta;
+
+        /* Remember if \r or \n were explicitly used */
+
+        if (c == CHAR_CR || c == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF;
+
+        /* Process a character range */
+
+        if (pptr[1] == META_RANGE_LITERAL || pptr[1] == META_RANGE_ESCAPED)
+          {
+#ifdef EBCDIC
+          BOOL range_is_literal = (pptr[1] == META_RANGE_LITERAL);
+#endif
+          pptr += 2;
+          d = *pptr;
+          if (d == META_BIGVALUE) d = *(++pptr);
+
+          /* Remember an explicit \r or \n, and add the range to the class. */
+
+          if (d == CHAR_CR || d == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF;
+
+          /* In an EBCDIC environment, Perl treats alphabetic ranges specially
+          because there are holes in the encoding, and simply using the range
+          A-Z (for example) would include the characters in the holes. This
+          applies only to literal ranges; [\xC1-\xE9] is different to [A-Z]. */
+
+#ifdef EBCDIC
+          if (range_is_literal &&
+               (cb->ctypes[c] & ctype_letter) != 0 &&
+               (cb->ctypes[d] & ctype_letter) != 0 &&
+               (c <= CHAR_z) == (d <= CHAR_z))
+            {
+            uint32_t uc = (d <= CHAR_z)? 0 : 64;
+            uint32_t C = c - uc;
+            uint32_t D = d - uc;
+
+            if (C <= CHAR_i)
+              {
+              class_has_8bitchar +=
+                add_to_class(classbits, &class_uchardata, options, cb, C + uc,
+                  ((D < CHAR_i)? D : CHAR_i) + uc);
+              C = CHAR_j;
+              }
+
+            if (C <= D && C <= CHAR_r)
+              {
+              class_has_8bitchar +=
+                add_to_class(classbits, &class_uchardata, options, cb, C + uc,
+                  ((D < CHAR_r)? D : CHAR_r) + uc);
+              C = CHAR_s;
+              }
+
+            if (C <= D)
+              {
+              class_has_8bitchar +=
+                add_to_class(classbits, &class_uchardata, options, cb, C + uc,
+                  D + uc);
+              }
+            }
+          else
+#endif
+          /* Not an EBCDIC special range */
+
+          class_has_8bitchar +=
+            add_to_class(classbits, &class_uchardata, options, cb, c, d);
+          goto CONTINUE_CLASS;   /* Go get the next char in the class */
+          }  /* End of range handling */
+
+
+        /* Handle a single character. */
+
+        class_has_8bitchar +=
+          add_to_class(classbits, &class_uchardata, options, cb, meta, meta);
+        }
+
+      /* Continue to the next item in the class. */
+
+      CONTINUE_CLASS:
+
+#ifdef SUPPORT_WIDE_CHARS
+      /* If any wide characters or Unicode properties have been encountered,
+      set xclass = TRUE. Then, in the pre-compile phase, accumulate the length
+      of the extra data and reset the pointer. This is so that very large
+      classes that contain a zillion wide characters or Unicode property tests
+      do not overwrite the workspace (which is on the stack). */
+
+      if (class_uchardata > class_uchardata_base)
+        {
+        xclass = TRUE;
+        if (lengthptr != NULL)
+          {
+          *lengthptr += class_uchardata - class_uchardata_base;
+          class_uchardata = class_uchardata_base;
+          }
+        }
+#endif
+
+      continue;  /* Needed to avoid error when not supporting wide chars */
+      }   /* End of main class-processing loop */
+
+    /* If this class is the first thing in the branch, there can be no first
+    char setting, whatever the repeat count. Any reqcu setting must remain
+    unchanged after any kind of repeat. */
+
+    if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+    zerofirstcu = firstcu;
+    zerofirstcuflags = firstcuflags;
+    zeroreqcu = reqcu;
+    zeroreqcuflags = reqcuflags;
+
+    /* If there are characters with values > 255, or Unicode property settings
+    (\p or \P), we have to compile an extended class, with its own opcode,
+    unless there were no property settings and there was a negated special such
+    as \S in the class, and PCRE2_UCP is not set, because in that case all
+    characters > 255 are in or not in the class, so any that were explicitly
+    given as well can be ignored.
+
+    In the UCP case, if certain negated POSIX classes ([:^ascii:] or
+    [^:xdigit:]) were present in a class, we either have to match or not match
+    all wide characters (depending on whether the whole class is or is not
+    negated). This requirement is indicated by match_all_or_no_wide_chars being
+    true. We do this by including an explicit range, which works in both cases.
+    This applies only in UTF and 16-bit and 32-bit non-UTF modes, since there
+    cannot be any wide characters in 8-bit non-UTF mode.
+
+    When there *are* properties in a positive UTF-8 or any 16-bit or 32_bit
+    class where \S etc is present without PCRE2_UCP, causing an extended class
+    to be compiled, we make sure that all characters > 255 are included by
+    forcing match_all_or_no_wide_chars to be true.
+
+    If, when generating an xclass, there are no characters < 256, we can omit
+    the bitmap in the actual compiled code. */
+
+#ifdef SUPPORT_WIDE_CHARS  /* Defined for 16/32 bits, or 8-bit with Unicode */
+    if (xclass && (
+#ifdef SUPPORT_UNICODE
+        (options & PCRE2_UCP) != 0 ||
+#endif
+        xclass_has_prop || !should_flip_negation))
+      {
+      if (match_all_or_no_wide_chars || (
+#if PCRE2_CODE_UNIT_WIDTH == 8
+           utf &&
+#endif
+           should_flip_negation && !negate_class && (options & PCRE2_UCP) == 0))
+        {
+        *class_uchardata++ = XCL_RANGE;
+        if (utf)   /* Will always be utf in the 8-bit library */
+          {
+          class_uchardata += PRIV(ord2utf)(0x100, class_uchardata);
+          class_uchardata += PRIV(ord2utf)(MAX_UTF_CODE_POINT, class_uchardata);
+          }
+        else       /* Can only happen for the 16-bit & 32-bit libraries */
+          {
+#if PCRE2_CODE_UNIT_WIDTH == 16
+          *class_uchardata++ = 0x100;
+          *class_uchardata++ = 0xffffu;
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+          *class_uchardata++ = 0x100;
+          *class_uchardata++ = 0xffffffffu;
+#endif
+          }
+        }
+      *class_uchardata++ = XCL_END;    /* Marks the end of extra data */
+      *code++ = OP_XCLASS;
+      code += LINK_SIZE;
+      *code = negate_class? XCL_NOT:0;
+      if (xclass_has_prop) *code |= XCL_HASPROP;
+
+      /* If the map is required, move up the extra data to make room for it;
+      otherwise just move the code pointer to the end of the extra data. */
+
+      if (class_has_8bitchar > 0)
+        {
+        *code++ |= XCL_MAP;
+        (void)memmove(code + (32 / sizeof(PCRE2_UCHAR)), code,
+          CU2BYTES(class_uchardata - code));
+        if (negate_class && !xclass_has_prop)
+          {
+          /* Using 255 ^ instead of ~ avoids clang sanitize warning. */
+          for (i = 0; i < 32; i++) classbits[i] = 255 ^ classbits[i];
+          }
+        memcpy(code, classbits, 32);
+        code = class_uchardata + (32 / sizeof(PCRE2_UCHAR));
+        }
+      else code = class_uchardata;
+
+      /* Now fill in the complete length of the item */
+
+      PUT(previous, 1, (int)(code - previous));
+      break;   /* End of class handling */
+      }
+#endif  /* SUPPORT_WIDE_CHARS */
+
+    /* If there are no characters > 255, or they are all to be included or
+    excluded, set the opcode to OP_CLASS or OP_NCLASS, depending on whether the
+    whole class was negated and whether there were negative specials such as \S
+    (non-UCP) in the class. Then copy the 32-byte map into the code vector,
+    negating it if necessary. */
+
+    *code++ = (negate_class == should_flip_negation) ? OP_CLASS : OP_NCLASS;
+    if (lengthptr == NULL)    /* Save time in the pre-compile phase */
+      {
+      if (negate_class)
+        {
+       /* Using 255 ^ instead of ~ avoids clang sanitize warning. */
+       for (i = 0; i < 32; i++) classbits[i] = 255 ^ classbits[i];
+       }
+      memcpy(code, classbits, 32);
+      }
+    code += 32 / sizeof(PCRE2_UCHAR);
+    break;  /* End of class processing */
+
+
+    /* ===================================================================*/
+    /* Deal with (*VERB)s. */
+
+    /* Check for open captures before ACCEPT and close those that are within
+    the same assertion level, also converting ACCEPT to ASSERT_ACCEPT in an
+    assertion. In the first pass, just accumulate the length required;
+    otherwise hitting (*ACCEPT) inside many nested parentheses can cause
+    workspace overflow. Do not set firstcu after *ACCEPT. */
+
+    case META_ACCEPT:
+    cb->had_accept = had_accept = TRUE;
+    for (oc = cb->open_caps;
+         oc != NULL && oc->assert_depth >= cb->assert_depth;
+         oc = oc->next)
+      {
+      if (lengthptr != NULL)
+        {
+        *lengthptr += CU2BYTES(1) + IMM2_SIZE;
+        }
+      else
+        {
+        *code++ = OP_CLOSE;
+        PUT2INC(code, 0, oc->number);
+        }
+      }
+    *code++ = (cb->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT;
+    if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+    break;
+
+    case META_PRUNE:
+    case META_SKIP:
+    cb->had_pruneorskip = TRUE;
+    /* Fall through */
+    case META_COMMIT:
+    case META_FAIL:
+    *code++ = verbops[(meta - META_MARK) >> 16];
+    break;
+
+    case META_THEN:
+    cb->external_flags |= PCRE2_HASTHEN;
+    *code++ = OP_THEN;
+    break;
+
+    /* Handle verbs with arguments. Arguments can be very long, especially in
+    16- and 32-bit modes, and can overflow the workspace in the first pass.
+    However, the argument length is constrained to be small enough to fit in
+    one code unit. This check happens in parse_regex(). In the first pass,
+    instead of putting the argument into memory, we just update the length
+    counter and set up an empty argument. */
+
+    case META_THEN_ARG:
+    cb->external_flags |= PCRE2_HASTHEN;
+    goto VERB_ARG;
+
+    case META_PRUNE_ARG:
+    case META_SKIP_ARG:
+    cb->had_pruneorskip = TRUE;
+    /* Fall through */
+    case META_MARK:
+    case META_COMMIT_ARG:
+    VERB_ARG:
+    *code++ = verbops[(meta - META_MARK) >> 16];
+    /* The length is in characters. */
+    verbarglen = *(++pptr);
+    verbculen = 0;
+    tempcode = code++;
+    for (i = 0; i < (int)verbarglen; i++)
+      {
+      meta = *(++pptr);
+#ifdef SUPPORT_UNICODE
+      if (utf) mclength = PRIV(ord2utf)(meta, mcbuffer); else
+#endif
+        {
+        mclength = 1;
+        mcbuffer[0] = meta;
+        }
+      if (lengthptr != NULL) *lengthptr += mclength; else
+        {
+        memcpy(code, mcbuffer, CU2BYTES(mclength));
+        code += mclength;
+        verbculen += mclength;
+        }
+      }
+
+    *tempcode = verbculen;   /* Fill in the code unit length */
+    *code++ = 0;             /* Terminating zero */
+    break;
+
+
+    /* ===================================================================*/
+    /* Handle options change. The new setting must be passed back for use in
+    subsequent branches. Reset the greedy defaults and the case value for
+    firstcu and reqcu. */
+
+    case META_OPTIONS:
+    *optionsptr = options = *(++pptr);
+    greedy_default = ((options & PCRE2_UNGREEDY) != 0);
+    greedy_non_default = greedy_default ^ 1;
+    req_caseopt = ((options & PCRE2_CASELESS) != 0)? REQ_CASELESS : 0;
+    break;
+
+
+    /* ===================================================================*/
+    /* Handle conditional subpatterns. The case of (?(Rdigits) is ambiguous
+    because it could be a numerical check on recursion, or a name check on a
+    group's being set. The pre-pass sets up META_COND_RNUMBER as a name so that
+    we can handle it either way. We first try for a name; if not found, process
+    the number. */
+
+    case META_COND_RNUMBER:   /* (?(Rdigits) */
+    case META_COND_NAME:      /* (?(name) or (?'name') or ?(<name>) */
+    case META_COND_RNAME:     /* (?(R&name) - test for recursion */
+    bravalue = OP_COND;
+      {
+      int count, index;
+      PCRE2_SPTR name;
+      named_group *ng = cb->named_groups;
+      uint32_t length = *(++pptr);
+
+      GETPLUSOFFSET(offset, pptr);
+      name = cb->start_pattern + offset;
+
+      /* In the first pass, the names generated in the pre-pass are available,
+      but the main name table has not yet been created. Scan the list of names
+      generated in the pre-pass in order to get a number and whether or not
+      this name is duplicated. If it is not duplicated, we can handle it as a
+      numerical group. */
+
+      for (i = 0; i < cb->names_found; i++, ng++)
+        {
+        if (length == ng->length &&
+            PRIV(strncmp)(name, ng->name, length) == 0)
+          {
+          if (!ng->isdup)
+            {
+            code[1+LINK_SIZE] = (meta == META_COND_RNAME)? OP_RREF : OP_CREF;
+            PUT2(code, 2+LINK_SIZE, ng->number);
+            if (ng->number > cb->top_backref) cb->top_backref = ng->number;
+            skipunits = 1+IMM2_SIZE;
+            goto GROUP_PROCESS_NOTE_EMPTY;
+            }
+          break;  /* Found a duplicated name */
+          }
+        }
+
+      /* If the name was not found we have a bad reference, unless we are
+      dealing with R<digits>, which is treated as a recursion test by number.
+      */
+
+      if (i >= cb->names_found)
+        {
+        groupnumber = 0;
+        if (meta == META_COND_RNUMBER)
+          {
+          for (i = 1; i < (int)length; i++)
+            {
+            groupnumber = groupnumber * 10 + name[i] - CHAR_0;
+            if (groupnumber > MAX_GROUP_NUMBER)
+              {
+              *errorcodeptr = ERR61;
+              cb->erroroffset = offset + i;
+              return 0;
+              }
+            }
+          }
+
+        if (meta != META_COND_RNUMBER || groupnumber > cb->bracount)
+          {
+          *errorcodeptr = ERR15;
+          cb->erroroffset = offset;
+          return 0;
+          }
+
+        /* (?Rdigits) treated as a recursion reference by number. A value of
+        zero (which is the result of both (?R) and (?R0)) means "any", and is
+        translated into RREF_ANY (which is 0xffff). */
+
+        if (groupnumber == 0) groupnumber = RREF_ANY;
+        code[1+LINK_SIZE] = OP_RREF;
+        PUT2(code, 2+LINK_SIZE, groupnumber);
+        skipunits = 1+IMM2_SIZE;
+        goto GROUP_PROCESS_NOTE_EMPTY;
+        }
+
+      /* A duplicated name was found. Note that if an R<digits> name is found
+      (META_COND_RNUMBER), it is a reference test, not a recursion test. */
+
+      code[1+LINK_SIZE] = (meta == META_COND_RNAME)? OP_RREF : OP_CREF;
+
+      /* We have a duplicated name. In the compile pass we have to search the
+      main table in order to get the index and count values. */
+
+      count = 0;  /* Values for first pass (avoids compiler warning) */
+      index = 0;
+      if (lengthptr == NULL && !find_dupname_details(name, length, &index,
+            &count, errorcodeptr, cb)) return 0;
+
+      /* Add one to the opcode to change CREF/RREF into DNCREF/DNRREF and
+      insert appropriate data values. */
+
+      code[1+LINK_SIZE]++;
+      skipunits = 1+2*IMM2_SIZE;
+      PUT2(code, 2+LINK_SIZE, index);
+      PUT2(code, 2+LINK_SIZE+IMM2_SIZE, count);
+      }
+    goto GROUP_PROCESS_NOTE_EMPTY;
+
+    /* The DEFINE condition is always false. Its internal groups may never
+    be called, so matched_char must remain false, hence the jump to
+    GROUP_PROCESS rather than GROUP_PROCESS_NOTE_EMPTY. */
+
+    case META_COND_DEFINE:
+    bravalue = OP_COND;
+    GETPLUSOFFSET(offset, pptr);
+    code[1+LINK_SIZE] = OP_DEFINE;
+    skipunits = 1;
+    goto GROUP_PROCESS;
+
+    /* Conditional test of a group's being set. */
+
+    case META_COND_NUMBER:
+    bravalue = OP_COND;
+    GETPLUSOFFSET(offset, pptr);
+    groupnumber = *(++pptr);
+    if (groupnumber > cb->bracount)
+      {
+      *errorcodeptr = ERR15;
+      cb->erroroffset = offset;
+      return 0;
+      }
+    if (groupnumber > cb->top_backref) cb->top_backref = groupnumber;
+    offset -= 2;   /* Point at initial ( for too many branches error */
+    code[1+LINK_SIZE] = OP_CREF;
+    skipunits = 1+IMM2_SIZE;
+    PUT2(code, 2+LINK_SIZE, groupnumber);
+    goto GROUP_PROCESS_NOTE_EMPTY;
+
+    /* Test for the PCRE2 version. */
+
+    case META_COND_VERSION:
+    bravalue = OP_COND;
+    if (pptr[1] > 0)
+      code[1+LINK_SIZE] = ((PCRE2_MAJOR > pptr[2]) ||
+        (PCRE2_MAJOR == pptr[2] && PCRE2_MINOR >= pptr[3]))?
+          OP_TRUE : OP_FALSE;
+    else
+      code[1+LINK_SIZE] = (PCRE2_MAJOR == pptr[2] && PCRE2_MINOR == pptr[3])?
+        OP_TRUE : OP_FALSE;
+    skipunits = 1;
+    pptr += 3;
+    goto GROUP_PROCESS_NOTE_EMPTY;
+
+    /* The condition is an assertion, possibly preceded by a callout. */
+
+    case META_COND_ASSERT:
+    bravalue = OP_COND;
+    goto GROUP_PROCESS_NOTE_EMPTY;
+
+
+    /* ===================================================================*/
+    /* Handle all kinds of nested bracketed groups. The non-capturing,
+    non-conditional cases are here; others come to GROUP_PROCESS via goto. */
+
+    case META_LOOKAHEAD:
+    bravalue = OP_ASSERT;
+    cb->assert_depth += 1;
+    goto GROUP_PROCESS;
+
+    case META_LOOKAHEAD_NA:
+    bravalue = OP_ASSERT_NA;
+    cb->assert_depth += 1;
+    goto GROUP_PROCESS;
+
+    /* Optimize (?!) to (*FAIL) unless it is quantified - which is a weird
+    thing to do, but Perl allows all assertions to be quantified, and when
+    they contain capturing parentheses there may be a potential use for
+    this feature. Not that that applies to a quantified (?!) but we allow
+    it for uniformity. */
+
+    case META_LOOKAHEADNOT:
+    if (pptr[1] == META_KET &&
+         (pptr[2] < META_ASTERISK || pptr[2] > META_MINMAX_QUERY))
+      {
+      *code++ = OP_FAIL;
+      pptr++;
+      }
+    else
+      {
+      bravalue = OP_ASSERT_NOT;
+      cb->assert_depth += 1;
+      goto GROUP_PROCESS;
+      }
+    break;
+
+    case META_LOOKBEHIND:
+    bravalue = OP_ASSERTBACK;
+    cb->assert_depth += 1;
+    goto GROUP_PROCESS;
+
+    case META_LOOKBEHINDNOT:
+    bravalue = OP_ASSERTBACK_NOT;
+    cb->assert_depth += 1;
+    goto GROUP_PROCESS;
+
+    case META_LOOKBEHIND_NA:
+    bravalue = OP_ASSERTBACK_NA;
+    cb->assert_depth += 1;
+    goto GROUP_PROCESS;
+
+    case META_ATOMIC:
+    bravalue = OP_ONCE;
+    goto GROUP_PROCESS_NOTE_EMPTY;
+
+    case META_SCRIPT_RUN:
+    bravalue = OP_SCRIPT_RUN;
+    goto GROUP_PROCESS_NOTE_EMPTY;
+
+    case META_NOCAPTURE:
+    bravalue = OP_BRA;
+    /* Fall through */
+
+    /* Process nested bracketed regex. The nesting depth is maintained for the
+    benefit of the stackguard function. The test for too deep nesting is now
+    done in parse_regex(). Assertion and DEFINE groups come to GROUP_PROCESS;
+    others come to GROUP_PROCESS_NOTE_EMPTY, to indicate that we need to take
+    note of whether or not they may match an empty string. */
+
+    GROUP_PROCESS_NOTE_EMPTY:
+    note_group_empty = TRUE;
+
+    GROUP_PROCESS:
+    cb->parens_depth += 1;
+    *code = bravalue;
+    pptr++;
+    tempcode = code;
+    tempreqvary = cb->req_varyopt;        /* Save value before group */
+    length_prevgroup = 0;                 /* Initialize for pre-compile phase */
+
+    if ((group_return =
+         compile_regex(
+         options,                         /* The option state */
+         &tempcode,                       /* Where to put code (updated) */
+         &pptr,                           /* Input pointer (updated) */
+         errorcodeptr,                    /* Where to put an error message */
+         skipunits,                       /* Skip over bracket number */
+         &subfirstcu,                     /* For possible first char */
+         &subfirstcuflags,
+         &subreqcu,                       /* For possible last char */
+         &subreqcuflags,
+         bcptr,                           /* Current branch chain */
+         cb,                              /* Compile data block */
+         (lengthptr == NULL)? NULL :      /* Actual compile phase */
+           &length_prevgroup              /* Pre-compile phase */
+         )) == 0)
+      return 0;  /* Error */
+
+    cb->parens_depth -= 1;
+
+    /* If that was a non-conditional significant group (not an assertion, not a
+    DEFINE) that matches at least one character, then the current item matches
+    a character. Conditionals are handled below. */
+
+    if (note_group_empty && bravalue != OP_COND && group_return > 0)
+      matched_char = TRUE;
+
+    /* If we've just compiled an assertion, pop the assert depth. */
+
+    if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NA)
+      cb->assert_depth -= 1;
+
+    /* At the end of compiling, code is still pointing to the start of the
+    group, while tempcode has been updated to point past the end of the group.
+    The parsed pattern pointer (pptr) is on the closing META_KET.
+
+    If this is a conditional bracket, check that there are no more than
+    two branches in the group, or just one if it's a DEFINE group. We do this
+    in the real compile phase, not in the pre-pass, where the whole group may
+    not be available. */
+
+    if (bravalue == OP_COND && lengthptr == NULL)
+      {
+      PCRE2_UCHAR *tc = code;
+      int condcount = 0;
+
+      do {
+         condcount++;
+         tc += GET(tc,1);
+         }
+      while (*tc != OP_KET);
+
+      /* A DEFINE group is never obeyed inline (the "condition" is always
+      false). It must have only one branch. Having checked this, change the
+      opcode to OP_FALSE. */
+
+      if (code[LINK_SIZE+1] == OP_DEFINE)
+        {
+        if (condcount > 1)
+          {
+          cb->erroroffset = offset;
+          *errorcodeptr = ERR54;
+          return 0;
+          }
+        code[LINK_SIZE+1] = OP_FALSE;
+        bravalue = OP_DEFINE;   /* A flag to suppress char handling below */
+        }
+
+      /* A "normal" conditional group. If there is just one branch, we must not
+      make use of its firstcu or reqcu, because this is equivalent to an
+      empty second branch. Also, it may match an empty string. If there are two
+      branches, this item must match a character if the group must. */
+
+      else
+        {
+        if (condcount > 2)
+          {
+          cb->erroroffset = offset;
+          *errorcodeptr = ERR27;
+          return 0;
+          }
+        if (condcount == 1) subfirstcuflags = subreqcuflags = REQ_NONE;
+          else if (group_return > 0) matched_char = TRUE;
+        }
+      }
+
+    /* In the pre-compile phase, update the length by the length of the group,
+    less the brackets at either end. Then reduce the compiled code to just a
+    set of non-capturing brackets so that it doesn't use much memory if it is
+    duplicated by a quantifier.*/
+
+    if (lengthptr != NULL)
+      {
+      if (OFLOW_MAX - *lengthptr < length_prevgroup - 2 - 2*LINK_SIZE)
+        {
+        *errorcodeptr = ERR20;
+        return 0;
+        }
+      *lengthptr += length_prevgroup - 2 - 2*LINK_SIZE;
+      code++;   /* This already contains bravalue */
+      PUTINC(code, 0, 1 + LINK_SIZE);
+      *code++ = OP_KET;
+      PUTINC(code, 0, 1 + LINK_SIZE);
+      break;    /* No need to waste time with special character handling */
+      }
+
+    /* Otherwise update the main code pointer to the end of the group. */
+
+    code = tempcode;
+
+    /* For a DEFINE group, required and first character settings are not
+    relevant. */
+
+    if (bravalue == OP_DEFINE) break;
+
+    /* Handle updating of the required and first code units for other types of
+    group. Update for normal brackets of all kinds, and conditions with two
+    branches (see code above). If the bracket is followed by a quantifier with
+    zero repeat, we have to back off. Hence the definition of zeroreqcu and
+    zerofirstcu outside the main loop so that they can be accessed for the back
+    off. */
+
+    zeroreqcu = reqcu;
+    zeroreqcuflags = reqcuflags;
+    zerofirstcu = firstcu;
+    zerofirstcuflags = firstcuflags;
+    groupsetfirstcu = FALSE;
+
+    if (bravalue >= OP_ONCE)  /* Not an assertion */
+      {
+      /* If we have not yet set a firstcu in this branch, take it from the
+      subpattern, remembering that it was set here so that a repeat of more
+      than one can replicate it as reqcu if necessary. If the subpattern has
+      no firstcu, set "none" for the whole branch. In both cases, a zero
+      repeat forces firstcu to "none". */
+
+      if (firstcuflags == REQ_UNSET && subfirstcuflags != REQ_UNSET)
+        {
+        if (subfirstcuflags >= 0)
+          {
+          firstcu = subfirstcu;
+          firstcuflags = subfirstcuflags;
+          groupsetfirstcu = TRUE;
+          }
+        else firstcuflags = REQ_NONE;
+        zerofirstcuflags = REQ_NONE;
+        }
+
+      /* If firstcu was previously set, convert the subpattern's firstcu
+      into reqcu if there wasn't one, using the vary flag that was in
+      existence beforehand. */
+
+      else if (subfirstcuflags >= 0 && subreqcuflags < 0)
+        {
+        subreqcu = subfirstcu;
+        subreqcuflags = subfirstcuflags | tempreqvary;
+        }
+
+      /* If the subpattern set a required code unit (or set a first code unit
+      that isn't really the first code unit - see above), set it. */
+
+      if (subreqcuflags >= 0)
+        {
+        reqcu = subreqcu;
+        reqcuflags = subreqcuflags;
+        }
+      }
+
+    /* For a forward assertion, we take the reqcu, if set, provided that the
+    group has also set a firstcu. This can be helpful if the pattern that
+    follows the assertion doesn't set a different char. For example, it's
+    useful for /(?=abcde).+/. We can't set firstcu for an assertion, however
+    because it leads to incorrect effect for patterns such as /(?=a)a.+/ when
+    the "real" "a" would then become a reqcu instead of a firstcu. This is
+    overcome by a scan at the end if there's no firstcu, looking for an
+    asserted first char. A similar effect for patterns like /(?=.*X)X$/ means
+    we must only take the reqcu when the group also set a firstcu. Otherwise,
+    in that example, 'X' ends up set for both. */
+
+    else if ((bravalue == OP_ASSERT || bravalue == OP_ASSERT_NA) &&
+             subreqcuflags >= 0 && subfirstcuflags >= 0)
+      {
+      reqcu = subreqcu;
+      reqcuflags = subreqcuflags;
+      }
+
+    break;  /* End of nested group handling */
+
+
+    /* ===================================================================*/
+    /* Handle named backreferences and recursions. */
+
+    case META_BACKREF_BYNAME:
+    case META_RECURSE_BYNAME:
+      {
+      int count, index;
+      PCRE2_SPTR name;
+      BOOL is_dupname = FALSE;
+      named_group *ng = cb->named_groups;
+      uint32_t length = *(++pptr);
+
+      GETPLUSOFFSET(offset, pptr);
+      name = cb->start_pattern + offset;
+
+      /* In the first pass, the names generated in the pre-pass are available,
+      but the main name table has not yet been created. Scan the list of names
+      generated in the pre-pass in order to get a number and whether or not
+      this name is duplicated. */
+
+      groupnumber = 0;
+      for (i = 0; i < cb->names_found; i++, ng++)
+        {
+        if (length == ng->length &&
+            PRIV(strncmp)(name, ng->name, length) == 0)
+          {
+          is_dupname = ng->isdup;
+          groupnumber = ng->number;
+
+          /* For a recursion, that's all that is needed. We can now go to
+          the code that handles numerical recursion, applying it to the first
+          group with the given name. */
+
+          if (meta == META_RECURSE_BYNAME)
+            {
+            meta_arg = groupnumber;
+            goto HANDLE_NUMERICAL_RECURSION;
+            }
+
+          /* For a back reference, update the back reference map and the
+          maximum back reference. */
+
+          cb->backref_map |= (groupnumber < 32)? (1u << groupnumber) : 1;
+          if (groupnumber > cb->top_backref)
+            cb->top_backref = groupnumber;
+          }
+        }
+
+      /* If the name was not found we have a bad reference. */
+
+      if (groupnumber == 0)
+        {
+        *errorcodeptr = ERR15;
+        cb->erroroffset = offset;
+        return 0;
+        }
+
+      /* If a back reference name is not duplicated, we can handle it as
+      a numerical reference. */
+
+      if (!is_dupname)
+        {
+        meta_arg = groupnumber;
+        goto HANDLE_SINGLE_REFERENCE;
+        }
+
+      /* If a back reference name is duplicated, we generate a different
+      opcode to a numerical back reference. In the second pass we must
+      search for the index and count in the final name table. */
+
+      count = 0;  /* Values for first pass (avoids compiler warning) */
+      index = 0;
+      if (lengthptr == NULL && !find_dupname_details(name, length, &index,
+            &count, errorcodeptr, cb)) return 0;
+
+      if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+      *code++ = ((options & PCRE2_CASELESS) != 0)? OP_DNREFI : OP_DNREF;
+      PUT2INC(code, 0, index);
+      PUT2INC(code, 0, count);
+      }
+    break;
+
+
+    /* ===================================================================*/
+    /* Handle a numerical callout. */
+
+    case META_CALLOUT_NUMBER:
+    code[0] = OP_CALLOUT;
+    PUT(code, 1, pptr[1]);               /* Offset to next pattern item */
+    PUT(code, 1 + LINK_SIZE, pptr[2]);   /* Length of next pattern item */
+    code[1 + 2*LINK_SIZE] = pptr[3];
+    pptr += 3;
+    code += PRIV(OP_lengths)[OP_CALLOUT];
+    break;
+
+
+    /* ===================================================================*/
+    /* Handle a callout with a string argument. In the pre-pass we just compute
+    the length without generating anything. The length in pptr[3] includes both
+    delimiters; in the actual compile only the first one is copied, but a
+    terminating zero is added. Any doubled delimiters within the string make
+    this an overestimate, but it is not worth bothering about. */
+
+    case META_CALLOUT_STRING:
+    if (lengthptr != NULL)
+      {
+      *lengthptr += pptr[3] + (1 + 4*LINK_SIZE);
+      pptr += 3;
+      SKIPOFFSET(pptr);
+      }
+
+    /* In the real compile we can copy the string. The starting delimiter is
+     included so that the client can discover it if they want. We also pass the
+     start offset to help a script language give better error messages. */
+
+    else
+      {
+      PCRE2_SPTR pp;
+      uint32_t delimiter;
+      uint32_t length = pptr[3];
+      PCRE2_UCHAR *callout_string = code + (1 + 4*LINK_SIZE);
+
+      code[0] = OP_CALLOUT_STR;
+      PUT(code, 1, pptr[1]);               /* Offset to next pattern item */
+      PUT(code, 1 + LINK_SIZE, pptr[2]);   /* Length of next pattern item */
+
+      pptr += 3;
+      GETPLUSOFFSET(offset, pptr);         /* Offset to string in pattern */
+      pp = cb->start_pattern + offset;
+      delimiter = *callout_string++ = *pp++;
+      if (delimiter == CHAR_LEFT_CURLY_BRACKET)
+        delimiter = CHAR_RIGHT_CURLY_BRACKET;
+      PUT(code, 1 + 3*LINK_SIZE, (int)(offset + 1));  /* One after delimiter */
+
+      /* The syntax of the pattern was checked in the parsing scan. The length
+      includes both delimiters, but we have passed the opening one just above,
+      so we reduce length before testing it. The test is for > 1 because we do
+      not want to copy the final delimiter. This also ensures that pp[1] is
+      accessible. */
+
+      while (--length > 1)
+        {
+        if (*pp == delimiter && pp[1] == delimiter)
+          {
+          *callout_string++ = delimiter;
+          pp += 2;
+          length--;
+          }
+        else *callout_string++ = *pp++;
+        }
+      *callout_string++ = CHAR_NUL;
+
+      /* Set the length of the entire item, the advance to its end. */
+
+      PUT(code, 1 + 2*LINK_SIZE, (int)(callout_string - code));
+      code = callout_string;
+      }
+    break;
+
+
+    /* ===================================================================*/
+    /* Handle repetition. The different types are all sorted out in the parsing
+    pass. */
+
+    case META_MINMAX_PLUS:
+    case META_MINMAX_QUERY:
+    case META_MINMAX:
+    repeat_min = *(++pptr);
+    repeat_max = *(++pptr);
+    goto REPEAT;
+
+    case META_ASTERISK:
+    case META_ASTERISK_PLUS:
+    case META_ASTERISK_QUERY:
+    repeat_min = 0;
+    repeat_max = REPEAT_UNLIMITED;
+    goto REPEAT;
+
+    case META_PLUS:
+    case META_PLUS_PLUS:
+    case META_PLUS_QUERY:
+    repeat_min = 1;
+    repeat_max = REPEAT_UNLIMITED;
+    goto REPEAT;
+
+    case META_QUERY:
+    case META_QUERY_PLUS:
+    case META_QUERY_QUERY:
+    repeat_min = 0;
+    repeat_max = 1;
+
+    REPEAT:
+    if (previous_matched_char && repeat_min > 0) matched_char = TRUE;
+
+    /* Remember whether this is a variable length repeat, and default to
+    single-char opcodes. */
+
+    reqvary = (repeat_min == repeat_max)? 0 : REQ_VARY;
+    op_type = 0;
+
+    /* Adjust first and required code units for a zero repeat. */
+
+    if (repeat_min == 0)
+      {
+      firstcu = zerofirstcu;
+      firstcuflags = zerofirstcuflags;
+      reqcu = zeroreqcu;
+      reqcuflags = zeroreqcuflags;
+      }
+
+    /* Note the greediness and possessiveness. */
+
+    switch (meta)
+      {
+      case META_MINMAX_PLUS:
+      case META_ASTERISK_PLUS:
+      case META_PLUS_PLUS:
+      case META_QUERY_PLUS:
+      repeat_type = 0;                  /* Force greedy */
+      possessive_quantifier = TRUE;
+      break;
+
+      case META_MINMAX_QUERY:
+      case META_ASTERISK_QUERY:
+      case META_PLUS_QUERY:
+      case META_QUERY_QUERY:
+      repeat_type = greedy_non_default;
+      possessive_quantifier = FALSE;
+      break;
+
+      default:
+      repeat_type = greedy_default;
+      possessive_quantifier = FALSE;
+      break;
+      }
+
+    /* Save start of previous item, in case we have to move it up in order to
+    insert something before it, and remember what it was. */
+
+    tempcode = previous;
+    op_previous = *previous;
+
+    /* Now handle repetition for the different types of item. If the repeat
+    minimum and the repeat maximum are both 1, we can ignore the quantifier for
+    non-parenthesized items, as they have only one alternative. For anything in
+    parentheses, we must not ignore if {1} is possessive. */
+
+    switch (op_previous)
+      {
+      /* If previous was a character or negated character match, abolish the
+      item and generate a repeat item instead. If a char item has a minimum of
+      more than one, ensure that it is set in reqcu - it might not be if a
+      sequence such as x{3} is the first thing in a branch because the x will
+      have gone into firstcu instead.  */
+
+      case OP_CHAR:
+      case OP_CHARI:
+      case OP_NOT:
+      case OP_NOTI:
+      if (repeat_max == 1 && repeat_min == 1) goto END_REPEAT;
+      op_type = chartypeoffset[op_previous - OP_CHAR];
+
+      /* Deal with UTF characters that take up more than one code unit. */
+
+#ifdef MAYBE_UTF_MULTI
+      if (utf && NOT_FIRSTCU(code[-1]))
+        {
+        PCRE2_UCHAR *lastchar = code - 1;
+        BACKCHAR(lastchar);
+        mclength = (uint32_t)(code - lastchar);   /* Length of UTF character */
+        memcpy(mcbuffer, lastchar, CU2BYTES(mclength));  /* Save the char */
+        }
+      else
+#endif  /* MAYBE_UTF_MULTI */
+
+      /* Handle the case of a single code unit - either with no UTF support, or
+      with UTF disabled, or for a single-code-unit UTF character. */
+        {
+        mcbuffer[0] = code[-1];
+        mclength = 1;
+        if (op_previous <= OP_CHARI && repeat_min > 1)
+          {
+          reqcu = mcbuffer[0];
+          reqcuflags = req_caseopt | cb->req_varyopt;
+          }
+        }
+      goto OUTPUT_SINGLE_REPEAT;  /* Code shared with single character types */
+
+      /* If previous was a character class or a back reference, we put the
+      repeat stuff after it, but just skip the item if the repeat was {0,0}. */
+
+#ifdef SUPPORT_WIDE_CHARS
+      case OP_XCLASS:
+#endif
+      case OP_CLASS:
+      case OP_NCLASS:
+      case OP_REF:
+      case OP_REFI:
+      case OP_DNREF:
+      case OP_DNREFI:
+
+      if (repeat_max == 0)
+        {
+        code = previous;
+        goto END_REPEAT;
+        }
+      if (repeat_max == 1 && repeat_min == 1) goto END_REPEAT;
+
+      if (repeat_min == 0 && repeat_max == REPEAT_UNLIMITED)
+        *code++ = OP_CRSTAR + repeat_type;
+      else if (repeat_min == 1 && repeat_max == REPEAT_UNLIMITED)
+        *code++ = OP_CRPLUS + repeat_type;
+      else if (repeat_min == 0 && repeat_max == 1)
+        *code++ = OP_CRQUERY + repeat_type;
+      else
+        {
+        *code++ = OP_CRRANGE + repeat_type;
+        PUT2INC(code, 0, repeat_min);
+        if (repeat_max == REPEAT_UNLIMITED) repeat_max = 0;  /* 2-byte encoding for max */
+        PUT2INC(code, 0, repeat_max);
+        }
+      break;
+
+      /* If previous is OP_FAIL, it was generated by an empty class []
+      (PCRE2_ALLOW_EMPTY_CLASS is set). The other ways in which OP_FAIL can be
+      generated, that is by (*FAIL) or (?!), disallow a quantifier at parse
+      time. We can just ignore this repeat. */
+
+      case OP_FAIL:
+      goto END_REPEAT;
+
+      /* Prior to 10.30, repeated recursions were wrapped in OP_ONCE brackets
+      because pcre2_match() could not handle backtracking into recursively
+      called groups. Now that this backtracking is available, we no longer need
+      to do this. However, we still need to replicate recursions as we do for
+      groups so as to have independent backtracking points. We can replicate
+      for the minimum number of repeats directly. For optional repeats we now
+      wrap the recursion in OP_BRA brackets and make use of the bracket
+      repetition. */
+
+      case OP_RECURSE:
+      if (repeat_max == 1 && repeat_min == 1 && !possessive_quantifier)
+        goto END_REPEAT;
+
+      /* Generate unwrapped repeats for a non-zero minimum, except when the
+      minimum is 1 and the maximum unlimited, because that can be handled with
+      OP_BRA terminated by OP_KETRMAX/MIN. When the maximum is equal to the
+      minimum, we just need to generate the appropriate additional copies.
+      Otherwise we need to generate one more, to simulate the situation when
+      the minimum is zero. */
+
+      if (repeat_min > 0 && (repeat_min != 1 || repeat_max != REPEAT_UNLIMITED))
+        {
+        int replicate = repeat_min;
+        if (repeat_min == repeat_max) replicate--;
+
+        /* In the pre-compile phase, we don't actually do the replication. We
+        just adjust the length as if we had. Do some paranoid checks for
+        potential integer overflow. The INT64_OR_DOUBLE type is a 64-bit
+        integer type when available, otherwise double. */
+
+        if (lengthptr != NULL)
+          {
+          PCRE2_SIZE delta = replicate*(1 + LINK_SIZE);
+          if ((INT64_OR_DOUBLE)replicate*
+                (INT64_OR_DOUBLE)(1 + LINK_SIZE) >
+                  (INT64_OR_DOUBLE)INT_MAX ||
+              OFLOW_MAX - *lengthptr < delta)
+            {
+            *errorcodeptr = ERR20;
+            return 0;
+            }
+          *lengthptr += delta;
+          }
+
+        else for (i = 0; i < replicate; i++)
+          {
+          memcpy(code, previous, CU2BYTES(1 + LINK_SIZE));
+          previous = code;
+          code += 1 + LINK_SIZE;
+          }
+
+        /* If the number of repeats is fixed, we are done. Otherwise, adjust
+        the counts and fall through. */
+
+        if (repeat_min == repeat_max) break;
+        if (repeat_max != REPEAT_UNLIMITED) repeat_max -= repeat_min;
+        repeat_min = 0;
+        }
+
+      /* Wrap the recursion call in OP_BRA brackets. */
+
+      (void)memmove(previous + 1 + LINK_SIZE, previous, CU2BYTES(1 + LINK_SIZE));
+      op_previous = *previous = OP_BRA;
+      PUT(previous, 1, 2 + 2*LINK_SIZE);
+      previous[2 + 2*LINK_SIZE] = OP_KET;
+      PUT(previous, 3 + 2*LINK_SIZE, 2 + 2*LINK_SIZE);
+      code += 2 + 2 * LINK_SIZE;
+      length_prevgroup = 3 + 3*LINK_SIZE;
+      group_return = -1;  /* Set "may match empty string" */
+
+      /* Now treat as a repeated OP_BRA. */
+      /* Fall through */
+
+      /* If previous was a bracket group, we may have to replicate it in
+      certain cases. Note that at this point we can encounter only the "basic"
+      bracket opcodes such as BRA and CBRA, as this is the place where they get
+      converted into the more special varieties such as BRAPOS and SBRA.
+      Originally, PCRE did not allow repetition of assertions, but now it does,
+      for Perl compatibility. */
+
+      case OP_ASSERT:
+      case OP_ASSERT_NOT:
+      case OP_ASSERT_NA:
+      case OP_ASSERTBACK:
+      case OP_ASSERTBACK_NOT:
+      case OP_ASSERTBACK_NA:
+      case OP_ONCE:
+      case OP_SCRIPT_RUN:
+      case OP_BRA:
+      case OP_CBRA:
+      case OP_COND:
+        {
+        int len = (int)(code - previous);
+        PCRE2_UCHAR *bralink = NULL;
+        PCRE2_UCHAR *brazeroptr = NULL;
+
+        if (repeat_max == 1 && repeat_min == 1 && !possessive_quantifier)
+          goto END_REPEAT;
+
+        /* Repeating a DEFINE group (or any group where the condition is always
+        FALSE and there is only one branch) is pointless, but Perl allows the
+        syntax, so we just ignore the repeat. */
+
+        if (op_previous == OP_COND && previous[LINK_SIZE+1] == OP_FALSE &&
+            previous[GET(previous, 1)] != OP_ALT)
+          goto END_REPEAT;
+
+        /* Perl allows all assertions to be quantified, and when they contain
+        capturing parentheses and/or are optional there are potential uses for
+        this feature. PCRE2 used to force the maximum quantifier to 1 on the
+        invalid grounds that further repetition was never useful. This was
+        always a bit pointless, since an assertion could be wrapped with a
+        repeated group to achieve the effect. General repetition is now
+        permitted, but if the maximum is unlimited it is set to one more than
+        the minimum. */
+
+        if (op_previous < OP_ONCE)    /* Assertion */
+          {
+          if (repeat_max == REPEAT_UNLIMITED) repeat_max = repeat_min + 1;
+          }
+
+        /* The case of a zero minimum is special because of the need to stick
+        OP_BRAZERO in front of it, and because the group appears once in the
+        data, whereas in other cases it appears the minimum number of times. For
+        this reason, it is simplest to treat this case separately, as otherwise
+        the code gets far too messy. There are several special subcases when the
+        minimum is zero. */
+
+        if (repeat_min == 0)
+          {
+          /* If the maximum is also zero, we used to just omit the group from
+          the output altogether, like this:
+
+          ** if (repeat_max == 0)
+          **   {
+          **   code = previous;
+          **   goto END_REPEAT;
+          **   }
+
+          However, that fails when a group or a subgroup within it is
+          referenced as a subroutine from elsewhere in the pattern, so now we
+          stick in OP_SKIPZERO in front of it so that it is skipped on
+          execution. As we don't have a list of which groups are referenced, we
+          cannot do this selectively.
+
+          If the maximum is 1 or unlimited, we just have to stick in the
+          BRAZERO and do no more at this point. */
+
+          if (repeat_max <= 1 || repeat_max == REPEAT_UNLIMITED)
+            {
+            (void)memmove(previous + 1, previous, CU2BYTES(len));
+            code++;
+            if (repeat_max == 0)
+              {
+              *previous++ = OP_SKIPZERO;
+              goto END_REPEAT;
+              }
+            brazeroptr = previous;    /* Save for possessive optimizing */
+            *previous++ = OP_BRAZERO + repeat_type;
+            }
+
+          /* If the maximum is greater than 1 and limited, we have to replicate
+          in a nested fashion, sticking OP_BRAZERO before each set of brackets.
+          The first one has to be handled carefully because it's the original
+          copy, which has to be moved up. The remainder can be handled by code
+          that is common with the non-zero minimum case below. We have to
+          adjust the value or repeat_max, since one less copy is required. */
+
+          else
+            {
+            int linkoffset;
+            (void)memmove(previous + 2 + LINK_SIZE, previous, CU2BYTES(len));
+            code += 2 + LINK_SIZE;
+            *previous++ = OP_BRAZERO + repeat_type;
+            *previous++ = OP_BRA;
+
+            /* We chain together the bracket link offset fields that have to be
+            filled in later when the ends of the brackets are reached. */
+
+            linkoffset = (bralink == NULL)? 0 : (int)(previous - bralink);
+            bralink = previous;
+            PUTINC(previous, 0, linkoffset);
+            }
+
+          if (repeat_max != REPEAT_UNLIMITED) repeat_max--;
+          }
+
+        /* If the minimum is greater than zero, replicate the group as many
+        times as necessary, and adjust the maximum to the number of subsequent
+        copies that we need. */
+
+        else
+          {
+          if (repeat_min > 1)
+            {
+            /* In the pre-compile phase, we don't actually do the replication.
+            We just adjust the length as if we had. Do some paranoid checks for
+            potential integer overflow. The INT64_OR_DOUBLE type is a 64-bit
+            integer type when available, otherwise double. */
+
+            if (lengthptr != NULL)
+              {
+              PCRE2_SIZE delta = (repeat_min - 1)*length_prevgroup;
+              if ((INT64_OR_DOUBLE)(repeat_min - 1)*
+                    (INT64_OR_DOUBLE)length_prevgroup >
+                      (INT64_OR_DOUBLE)INT_MAX ||
+                  OFLOW_MAX - *lengthptr < delta)
+                {
+                *errorcodeptr = ERR20;
+                return 0;
+                }
+              *lengthptr += delta;
+              }
+
+            /* This is compiling for real. If there is a set first code unit
+            for the group, and we have not yet set a "required code unit", set
+            it. */
+
+            else
+              {
+              if (groupsetfirstcu && reqcuflags < 0)
+                {
+                reqcu = firstcu;
+                reqcuflags = firstcuflags;
+                }
+              for (i = 1; (uint32_t)i < repeat_min; i++)
+                {
+                memcpy(code, previous, CU2BYTES(len));
+                code += len;
+                }
+              }
+            }
+
+          if (repeat_max != REPEAT_UNLIMITED) repeat_max -= repeat_min;
+          }
+
+        /* This code is common to both the zero and non-zero minimum cases. If
+        the maximum is limited, it replicates the group in a nested fashion,
+        remembering the bracket starts on a stack. In the case of a zero
+        minimum, the first one was set up above. In all cases the repeat_max
+        now specifies the number of additional copies needed. Again, we must
+        remember to replicate entries on the forward reference list. */
+
+        if (repeat_max != REPEAT_UNLIMITED)
+          {
+          /* In the pre-compile phase, we don't actually do the replication. We
+          just adjust the length as if we had. For each repetition we must add
+          1 to the length for BRAZERO and for all but the last repetition we
+          must add 2 + 2*LINKSIZE to allow for the nesting that occurs. Do some
+          paranoid checks to avoid integer overflow. The INT64_OR_DOUBLE type
+          is a 64-bit integer type when available, otherwise double. */
+
+          if (lengthptr != NULL && repeat_max > 0)
+            {
+            PCRE2_SIZE delta = repeat_max*(length_prevgroup + 1 + 2 + 2*LINK_SIZE) -
+                        2 - 2*LINK_SIZE;   /* Last one doesn't nest */
+            if ((INT64_OR_DOUBLE)repeat_max *
+                  (INT64_OR_DOUBLE)(length_prevgroup + 1 + 2 + 2*LINK_SIZE)
+                    > (INT64_OR_DOUBLE)INT_MAX ||
+                OFLOW_MAX - *lengthptr < delta)
+              {
+              *errorcodeptr = ERR20;
+              return 0;
+              }
+            *lengthptr += delta;
+            }
+
+          /* This is compiling for real */
+
+          else for (i = repeat_max - 1; i >= 0; i--)
+            {
+            *code++ = OP_BRAZERO + repeat_type;
+
+            /* All but the final copy start a new nesting, maintaining the
+            chain of brackets outstanding. */
+
+            if (i != 0)
+              {
+              int linkoffset;
+              *code++ = OP_BRA;
+              linkoffset = (bralink == NULL)? 0 : (int)(code - bralink);
+              bralink = code;
+              PUTINC(code, 0, linkoffset);
+              }
+
+            memcpy(code, previous, CU2BYTES(len));
+            code += len;
+            }
+
+          /* Now chain through the pending brackets, and fill in their length
+          fields (which are holding the chain links pro tem). */
+
+          while (bralink != NULL)
+            {
+            int oldlinkoffset;
+            int linkoffset = (int)(code - bralink + 1);
+            PCRE2_UCHAR *bra = code - linkoffset;
+            oldlinkoffset = GET(bra, 1);
+            bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset;
+            *code++ = OP_KET;
+            PUTINC(code, 0, linkoffset);
+            PUT(bra, 1, linkoffset);
+            }
+          }
+
+        /* If the maximum is unlimited, set a repeater in the final copy. For
+        SCRIPT_RUN and ONCE brackets, that's all we need to do. However,
+        possessively repeated ONCE brackets can be converted into non-capturing
+        brackets, as the behaviour of (?:xx)++ is the same as (?>xx)++ and this
+        saves having to deal with possessive ONCEs specially.
+
+        Otherwise, when we are doing the actual compile phase, check to see
+        whether this group is one that could match an empty string. If so,
+        convert the initial operator to the S form (e.g. OP_BRA -> OP_SBRA) so
+        that runtime checking can be done. [This check is also applied to ONCE
+        and SCRIPT_RUN groups at runtime, but in a different way.]
+
+        Then, if the quantifier was possessive and the bracket is not a
+        conditional, we convert the BRA code to the POS form, and the KET code
+        to KETRPOS. (It turns out to be convenient at runtime to detect this
+        kind of subpattern at both the start and at the end.) The use of
+        special opcodes makes it possible to reduce greatly the stack usage in
+        pcre2_match(). If the group is preceded by OP_BRAZERO, convert this to
+        OP_BRAPOSZERO.
+
+        Then, if the minimum number of matches is 1 or 0, cancel the possessive
+        flag so that the default action below, of wrapping everything inside
+        atomic brackets, does not happen. When the minimum is greater than 1,
+        there will be earlier copies of the group, and so we still have to wrap
+        the whole thing. */
+
+        else
+          {
+          PCRE2_UCHAR *ketcode = code - 1 - LINK_SIZE;
+          PCRE2_UCHAR *bracode = ketcode - GET(ketcode, 1);
+
+          /* Convert possessive ONCE brackets to non-capturing */
+
+          if (*bracode == OP_ONCE && possessive_quantifier) *bracode = OP_BRA;
+
+          /* For non-possessive ONCE and for SCRIPT_RUN brackets, all we need
+          to do is to set the KET. */
+
+          if (*bracode == OP_ONCE || *bracode == OP_SCRIPT_RUN)
+            *ketcode = OP_KETRMAX + repeat_type;
+
+          /* Handle non-SCRIPT_RUN and non-ONCE brackets and possessive ONCEs
+          (which have been converted to non-capturing above). */
+
+          else
+            {
+            /* In the compile phase, adjust the opcode if the group can match
+            an empty string. For a conditional group with only one branch, the
+            value of group_return will not show "could be empty", so we must
+            check that separately. */
+
+            if (lengthptr == NULL)
+              {
+              if (group_return < 0) *bracode += OP_SBRA - OP_BRA;
+              if (*bracode == OP_COND && bracode[GET(bracode,1)] != OP_ALT)
+                *bracode = OP_SCOND;
+              }
+
+            /* Handle possessive quantifiers. */
+
+            if (possessive_quantifier)
+              {
+              /* For COND brackets, we wrap the whole thing in a possessively
+              repeated non-capturing bracket, because we have not invented POS
+              versions of the COND opcodes. */
+
+              if (*bracode == OP_COND || *bracode == OP_SCOND)
+                {
+                int nlen = (int)(code - bracode);
+                (void)memmove(bracode + 1 + LINK_SIZE, bracode, CU2BYTES(nlen));
+                code += 1 + LINK_SIZE;
+                nlen += 1 + LINK_SIZE;
+                *bracode = (*bracode == OP_COND)? OP_BRAPOS : OP_SBRAPOS;
+                *code++ = OP_KETRPOS;
+                PUTINC(code, 0, nlen);
+                PUT(bracode, 1, nlen);
+                }
+
+              /* For non-COND brackets, we modify the BRA code and use KETRPOS. */
+
+              else
+                {
+                *bracode += 1;              /* Switch to xxxPOS opcodes */
+                *ketcode = OP_KETRPOS;
+                }
+
+              /* If the minimum is zero, mark it as possessive, then unset the
+              possessive flag when the minimum is 0 or 1. */
+
+              if (brazeroptr != NULL) *brazeroptr = OP_BRAPOSZERO;
+              if (repeat_min < 2) possessive_quantifier = FALSE;
+              }
+
+            /* Non-possessive quantifier */
+
+            else *ketcode = OP_KETRMAX + repeat_type;
+            }
+          }
+        }
+      break;
+
+      /* If previous was a character type match (\d or similar), abolish it and
+      create a suitable repeat item. The code is shared with single-character
+      repeats by setting op_type to add a suitable offset into repeat_type.
+      Note the the Unicode property types will be present only when
+      SUPPORT_UNICODE is defined, but we don't wrap the little bits of code
+      here because it just makes it horribly messy. */
+
+      default:
+      if (op_previous >= OP_EODN)   /* Not a character type - internal error */
+        {
+        *errorcodeptr = ERR10;
+        return 0;
+        }
+      else
+        {
+        int prop_type, prop_value;
+        PCRE2_UCHAR *oldcode;
+
+        if (repeat_max == 1 && repeat_min == 1) goto END_REPEAT;
+
+        op_type = OP_TYPESTAR - OP_STAR;      /* Use type opcodes */
+        mclength = 0;                         /* Not a character */
+
+        if (op_previous == OP_PROP || op_previous == OP_NOTPROP)
+          {
+          prop_type = previous[1];
+          prop_value = previous[2];
+          }
+        else
+          {
+          /* Come here from just above with a character in mcbuffer/mclength. */
+          OUTPUT_SINGLE_REPEAT:
+          prop_type = prop_value = -1;
+          }
+
+        /* At this point, if prop_type == prop_value == -1 we either have a
+        character in mcbuffer when mclength is greater than zero, or we have
+        mclength zero, in which case there is a non-property character type in
+        op_previous. If prop_type/value are not negative, we have a property
+        character type in op_previous. */
+
+        oldcode = code;                   /* Save where we were */
+        code = previous;                  /* Usually overwrite previous item */
+
+        /* If the maximum is zero then the minimum must also be zero; Perl allows
+        this case, so we do too - by simply omitting the item altogether. */
+
+        if (repeat_max == 0) goto END_REPEAT;
+
+        /* Combine the op_type with the repeat_type */
+
+        repeat_type += op_type;
+
+        /* A minimum of zero is handled either as the special case * or ?, or as
+        an UPTO, with the maximum given. */
+
+        if (repeat_min == 0)
+          {
+          if (repeat_max == REPEAT_UNLIMITED) *code++ = OP_STAR + repeat_type;
+            else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type;
+          else
+            {
+            *code++ = OP_UPTO + repeat_type;
+            PUT2INC(code, 0, repeat_max);
+            }
+          }
+
+        /* A repeat minimum of 1 is optimized into some special cases. If the
+        maximum is unlimited, we use OP_PLUS. Otherwise, the original item is
+        left in place and, if the maximum is greater than 1, we use OP_UPTO with
+        one less than the maximum. */
+
+        else if (repeat_min == 1)
+          {
+          if (repeat_max == REPEAT_UNLIMITED)
+            *code++ = OP_PLUS + repeat_type;
+          else
+            {
+            code = oldcode;  /* Leave previous item in place */
+            if (repeat_max == 1) goto END_REPEAT;
+            *code++ = OP_UPTO + repeat_type;
+            PUT2INC(code, 0, repeat_max - 1);
+            }
+          }
+
+        /* The case {n,n} is just an EXACT, while the general case {n,m} is
+        handled as an EXACT followed by an UPTO or STAR or QUERY. */
+
+        else
+          {
+          *code++ = OP_EXACT + op_type;  /* NB EXACT doesn't have repeat_type */
+          PUT2INC(code, 0, repeat_min);
+
+          /* Unless repeat_max equals repeat_min, fill in the data for EXACT,
+          and then generate the second opcode. For a repeated Unicode property
+          match, there are two extra values that define the required property,
+          and mclength is set zero to indicate this. */
+
+          if (repeat_max != repeat_min)
+            {
+            if (mclength > 0)
+              {
+              memcpy(code, mcbuffer, CU2BYTES(mclength));
+              code += mclength;
+              }
+            else
+              {
+              *code++ = op_previous;
+              if (prop_type >= 0)
+                {
+                *code++ = prop_type;
+                *code++ = prop_value;
+                }
+              }
+
+            /* Now set up the following opcode */
+
+            if (repeat_max == REPEAT_UNLIMITED)
+              *code++ = OP_STAR + repeat_type;
+            else
+              {
+              repeat_max -= repeat_min;
+              if (repeat_max == 1)
+                {
+                *code++ = OP_QUERY + repeat_type;
+                }
+              else
+                {
+                *code++ = OP_UPTO + repeat_type;
+                PUT2INC(code, 0, repeat_max);
+                }
+              }
+            }
+          }
+
+        /* Fill in the character or character type for the final opcode. */
+
+        if (mclength > 0)
+          {
+          memcpy(code, mcbuffer, CU2BYTES(mclength));
+          code += mclength;
+          }
+        else
+          {
+          *code++ = op_previous;
+          if (prop_type >= 0)
+            {
+            *code++ = prop_type;
+            *code++ = prop_value;
+            }
+          }
+        }
+      break;
+      }  /* End of switch on different op_previous values */
+
+
+    /* If the character following a repeat is '+', possessive_quantifier is
+    TRUE. For some opcodes, there are special alternative opcodes for this
+    case. For anything else, we wrap the entire repeated item inside OP_ONCE
+    brackets. Logically, the '+' notation is just syntactic sugar, taken from
+    Sun's Java package, but the special opcodes can optimize it.
+
+    Some (but not all) possessively repeated subpatterns have already been
+    completely handled in the code just above. For them, possessive_quantifier
+    is always FALSE at this stage. Note that the repeated item starts at
+    tempcode, not at previous, which might be the first part of a string whose
+    (former) last char we repeated. */
+
+    if (possessive_quantifier)
+      {
+      int len;
+
+      /* Possessifying an EXACT quantifier has no effect, so we can ignore it.
+      However, QUERY, STAR, or UPTO may follow (for quantifiers such as {5,6},
+      {5,}, or {5,10}). We skip over an EXACT item; if the length of what
+      remains is greater than zero, there's a further opcode that can be
+      handled. If not, do nothing, leaving the EXACT alone. */
+
+      switch(*tempcode)
+        {
+        case OP_TYPEEXACT:
+        tempcode += PRIV(OP_lengths)[*tempcode] +
+          ((tempcode[1 + IMM2_SIZE] == OP_PROP
+          || tempcode[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0);
+        break;
+
+        /* CHAR opcodes are used for exacts whose count is 1. */
+
+        case OP_CHAR:
+        case OP_CHARI:
+        case OP_NOT:
+        case OP_NOTI:
+        case OP_EXACT:
+        case OP_EXACTI:
+        case OP_NOTEXACT:
+        case OP_NOTEXACTI:
+        tempcode += PRIV(OP_lengths)[*tempcode];
+#ifdef SUPPORT_UNICODE
+        if (utf && HAS_EXTRALEN(tempcode[-1]))
+          tempcode += GET_EXTRALEN(tempcode[-1]);
+#endif
+        break;
+
+        /* For the class opcodes, the repeat operator appears at the end;
+        adjust tempcode to point to it. */
+
+        case OP_CLASS:
+        case OP_NCLASS:
+        tempcode += 1 + 32/sizeof(PCRE2_UCHAR);
+        break;
+
+#ifdef SUPPORT_WIDE_CHARS
+        case OP_XCLASS:
+        tempcode += GET(tempcode, 1);
+        break;
+#endif
+        }
+
+      /* If tempcode is equal to code (which points to the end of the repeated
+      item), it means we have skipped an EXACT item but there is no following
+      QUERY, STAR, or UPTO; the value of len will be 0, and we do nothing. In
+      all other cases, tempcode will be pointing to the repeat opcode, and will
+      be less than code, so the value of len will be greater than 0. */
+
+      len = (int)(code - tempcode);
+      if (len > 0)
+        {
+        unsigned int repcode = *tempcode;
+
+        /* There is a table for possessifying opcodes, all of which are less
+        than OP_CALLOUT. A zero entry means there is no possessified version.
+        */
+
+        if (repcode < OP_CALLOUT && opcode_possessify[repcode] > 0)
+          *tempcode = opcode_possessify[repcode];
+
+        /* For opcode without a special possessified version, wrap the item in
+        ONCE brackets. */
+
+        else
+          {
+          (void)memmove(tempcode + 1 + LINK_SIZE, tempcode, CU2BYTES(len));
+          code += 1 + LINK_SIZE;
+          len += 1 + LINK_SIZE;
+          tempcode[0] = OP_ONCE;
+          *code++ = OP_KET;
+          PUTINC(code, 0, len);
+          PUT(tempcode, 1, len);
+          }
+        }
+      }
+
+    /* We set the "follows varying string" flag for subsequently encountered
+    reqcus if it isn't already set and we have just passed a varying length
+    item. */
+
+    END_REPEAT:
+    cb->req_varyopt |= reqvary;
+    break;
+
+
+    /* ===================================================================*/
+    /* Handle a 32-bit data character with a value greater than META_END. */
+
+    case META_BIGVALUE:
+    pptr++;
+    goto NORMAL_CHAR;
+
+
+    /* ===============================================================*/
+    /* Handle a back reference by number, which is the meta argument. The
+    pattern offsets for back references to group numbers less than 10 are held
+    in a special vector, to avoid using more than two parsed pattern elements
+    in 64-bit environments. We only need the offset to the first occurrence,
+    because if that doesn't fail, subsequent ones will also be OK. */
+
+    case META_BACKREF:
+    if (meta_arg < 10) offset = cb->small_ref_offset[meta_arg];
+      else GETPLUSOFFSET(offset, pptr);
+
+    if (meta_arg > cb->bracount)
+      {
+      cb->erroroffset = offset;
+      *errorcodeptr = ERR15;  /* Non-existent subpattern */
+      return 0;
+      }
+
+    /* Come here from named backref handling when the reference is to a
+    single group (that is, not to a duplicated name). The back reference
+    data will have already been updated. We must disable firstcu if not
+    set, to cope with cases like (?=(\w+))\1: which would otherwise set ':'
+    later. */
+
+    HANDLE_SINGLE_REFERENCE:
+    if (firstcuflags == REQ_UNSET) zerofirstcuflags = firstcuflags = REQ_NONE;
+    *code++ = ((options & PCRE2_CASELESS) != 0)? OP_REFI : OP_REF;
+    PUT2INC(code, 0, meta_arg);
+
+    /* Update the map of back references, and keep the highest one. We
+    could do this in parse_regex() for numerical back references, but not
+    for named back references, because we don't know the numbers to which
+    named back references refer. So we do it all in this function. */
+
+    cb->backref_map |= (meta_arg < 32)? (1u << meta_arg) : 1;
+    if (meta_arg > cb->top_backref) cb->top_backref = meta_arg;
+    break;
+
+
+    /* ===============================================================*/
+    /* Handle recursion by inserting the number of the called group (which is
+    the meta argument) after OP_RECURSE. At the end of compiling the pattern is
+    scanned and these numbers are replaced by offsets within the pattern. It is
+    done like this to avoid problems with forward references and adjusting
+    offsets when groups are duplicated and moved (as discovered in previous
+    implementations). Note that a recursion does not have a set first
+    character. */
+
+    case META_RECURSE:
+    GETPLUSOFFSET(offset, pptr);
+    if (meta_arg > cb->bracount)
+      {
+      cb->erroroffset = offset;
+      *errorcodeptr = ERR15;  /* Non-existent subpattern */
+      return 0;
+      }
+    HANDLE_NUMERICAL_RECURSION:
+    *code = OP_RECURSE;
+    PUT(code, 1, meta_arg);
+    code += 1 + LINK_SIZE;
+    groupsetfirstcu = FALSE;
+    cb->had_recurse = TRUE;
+    if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+    zerofirstcu = firstcu;
+    zerofirstcuflags = firstcuflags;
+    break;
+
+
+    /* ===============================================================*/
+    /* Handle capturing parentheses; the number is the meta argument. */
+
+    case META_CAPTURE:
+    bravalue = OP_CBRA;
+    skipunits = IMM2_SIZE;
+    PUT2(code, 1+LINK_SIZE, meta_arg);
+    cb->lastcapture = meta_arg;
+    goto GROUP_PROCESS_NOTE_EMPTY;
+
+
+    /* ===============================================================*/
+    /* Handle escape sequence items. For ones like \d, the ESC_values are
+    arranged to be the same as the corresponding OP_values in the default case
+    when PCRE2_UCP is not set (which is the only case in which they will appear
+    here).
+
+    Note: \Q and \E are never seen here, as they were dealt with in
+    parse_pattern(). Neither are numerical back references or recursions, which
+    were turned into META_BACKREF or META_RECURSE items, respectively. \k and
+    \g, when followed by names, are turned into META_BACKREF_BYNAME or
+    META_RECURSE_BYNAME. */
+
+    case META_ESCAPE:
+
+    /* We can test for escape sequences that consume a character because their
+    values lie between ESC_b and ESC_Z; this may have to change if any new ones
+    are ever created. For these sequences, we disable the setting of a first
+    character if it hasn't already been set. */
+
+    if (meta_arg > ESC_b && meta_arg < ESC_Z)
+      {
+      matched_char = TRUE;
+      if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+      }
+
+    /* Set values to reset to if this is followed by a zero repeat. */
+
+    zerofirstcu = firstcu;
+    zerofirstcuflags = firstcuflags;
+    zeroreqcu = reqcu;
+    zeroreqcuflags = reqcuflags;
+
+    /* If Unicode is not supported, \P and \p are not allowed and are
+    faulted at parse time, so will never appear here. */
+
+#ifdef SUPPORT_UNICODE
+    if (meta_arg == ESC_P || meta_arg == ESC_p)
+      {
+      uint32_t ptype = *(++pptr) >> 16;
+      uint32_t pdata = *pptr & 0xffff;
+
+      /* The special case of \p{Any} is compiled to OP_ALLANY so as to benefit
+      from the auto-anchoring code. */
+
+      if (meta_arg == ESC_p && ptype == PT_ANY)
+        {
+        *code++ = OP_ALLANY;
+        }
+      else
+        {
+        *code++ = (meta_arg == ESC_p)? OP_PROP : OP_NOTPROP;
+        *code++ = ptype;
+        *code++ = pdata;
+        }
+      break;  /* End META_ESCAPE */
+      }
+#endif
+
+    /* For the rest (including \X when Unicode is supported - if not it's
+    faulted at parse time), the OP value is the escape value when PCRE2_UCP is
+    not set; if it is set, these escapes do not show up here because they are
+    converted into Unicode property tests in parse_regex(). Note that \b and \B
+    do a one-character lookbehind, and \A also behaves as if it does. */
+
+    if (meta_arg == ESC_C) cb->external_flags |= PCRE2_HASBKC; /* Record */
+    if ((meta_arg == ESC_b || meta_arg == ESC_B || meta_arg == ESC_A) &&
+         cb->max_lookbehind == 0)
+      cb->max_lookbehind = 1;
+
+    /* In non-UTF mode, and for both 32-bit modes, we turn \C into OP_ALLANY
+    instead of OP_ANYBYTE so that it works in DFA mode and in lookbehinds. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+    *code++ = (meta_arg == ESC_C)? OP_ALLANY : meta_arg;
+#else
+    *code++ = (!utf && meta_arg == ESC_C)? OP_ALLANY : meta_arg;
+#endif
+    break;  /* End META_ESCAPE */
+
+
+    /* ===================================================================*/
+    /* Handle an unrecognized meta value. A parsed pattern value less than
+    META_END is a literal. Otherwise we have a problem. */
+
+    default:
+    if (meta >= META_END)
+      {
+#ifdef DEBUG_SHOW_PARSED
+      fprintf(stderr, "** Unrecognized parsed pattern item 0x%.8x\n", *pptr);
+#endif
+      *errorcodeptr = ERR89;  /* Internal error - unrecognized. */
+      return 0;
+      }
+
+    /* Handle a literal character. We come here by goto in the case of a
+    32-bit, non-UTF character whose value is greater than META_END. */
+
+    NORMAL_CHAR:
+    meta = *pptr;     /* Get the full 32 bits */
+    NORMAL_CHAR_SET:  /* Character is already in meta */
+    matched_char = TRUE;
+
+    /* For caseless UTF or UCP mode, check whether this character has more than
+    one other case. If so, generate a special OP_PROP item instead of OP_CHARI.
+    */
+
+#ifdef SUPPORT_UNICODE
+    if ((utf||ucp) && (options & PCRE2_CASELESS) != 0)
+      {
+      uint32_t caseset = UCD_CASESET(meta);
+      if (caseset != 0)
+        {
+        *code++ = OP_PROP;
+        *code++ = PT_CLIST;
+        *code++ = caseset;
+        if (firstcuflags == REQ_UNSET)
+          firstcuflags = zerofirstcuflags = REQ_NONE;
+        break;  /* End handling this meta item */
+        }
+      }
+#endif
+
+    /* Caseful matches, or caseless and not one of the multicase characters. We
+    come here by goto in the case of a positive class that contains only
+    case-partners of a character with just two cases; matched_char has already
+    been set TRUE and options fudged if necessary. */
+
+    CLASS_CASELESS_CHAR:
+
+    /* Get the character's code units into mcbuffer, with the length in
+    mclength. When not in UTF mode, the length is always 1. */
+
+#ifdef SUPPORT_UNICODE
+    if (utf) mclength = PRIV(ord2utf)(meta, mcbuffer); else
+#endif
+      {
+      mclength = 1;
+      mcbuffer[0] = meta;
+      }
+
+    /* Generate the appropriate code */
+
+    *code++ = ((options & PCRE2_CASELESS) != 0)? OP_CHARI : OP_CHAR;
+    memcpy(code, mcbuffer, CU2BYTES(mclength));
+    code += mclength;
+
+    /* Remember if \r or \n were seen */
+
+    if (mcbuffer[0] == CHAR_CR || mcbuffer[0] == CHAR_NL)
+      cb->external_flags |= PCRE2_HASCRORLF;
+
+    /* Set the first and required code units appropriately. If no previous
+    first code unit, set it from this character, but revert to none on a zero
+    repeat. Otherwise, leave the firstcu value alone, and don't change it on
+    a zero repeat. */
+
+    if (firstcuflags == REQ_UNSET)
+      {
+      zerofirstcuflags = REQ_NONE;
+      zeroreqcu = reqcu;
+      zeroreqcuflags = reqcuflags;
+
+      /* If the character is more than one code unit long, we can set a single
+      firstcu only if it is not to be matched caselessly. Multiple possible
+      starting code units may be picked up later in the studying code. */
+
+      if (mclength == 1 || req_caseopt == 0)
+        {
+        firstcu = mcbuffer[0];
+        firstcuflags = req_caseopt;
+        if (mclength != 1)
+          {
+          reqcu = code[-1];
+          reqcuflags = cb->req_varyopt;
+          }
+        }
+      else firstcuflags = reqcuflags = REQ_NONE;
+      }
+
+    /* firstcu was previously set; we can set reqcu only if the length is
+    1 or the matching is caseful. */
+
+    else
+      {
+      zerofirstcu = firstcu;
+      zerofirstcuflags = firstcuflags;
+      zeroreqcu = reqcu;
+      zeroreqcuflags = reqcuflags;
+      if (mclength == 1 || req_caseopt == 0)
+        {
+        reqcu = code[-1];
+        reqcuflags = req_caseopt | cb->req_varyopt;
+        }
+      }
+
+    /* If caselessness was temporarily instated, reset it. */
+
+    if (reset_caseful)
+      {
+      options &= ~PCRE2_CASELESS;
+      req_caseopt = 0;
+      reset_caseful = FALSE;
+      }
+
+    break;    /* End literal character handling */
+    }         /* End of big switch */
+  }           /* End of big loop */
+
+/* Control never reaches here. */
+}
+
+
+
+/*************************************************
+*   Compile regex: a sequence of alternatives    *
+*************************************************/
+
+/* On entry, pptr is pointing past the bracket meta, but on return it points to
+the closing bracket or META_END. The code variable is pointing at the code unit
+into which the BRA operator has been stored. This function is used during the
+pre-compile phase when we are trying to find out the amount of memory needed,
+as well as during the real compile phase. The value of lengthptr distinguishes
+the two phases.
+
+Arguments:
+  options           option bits, including any changes for this subpattern
+  codeptr           -> the address of the current code pointer
+  pptrptr           -> the address of the current parsed pattern pointer
+  errorcodeptr      -> pointer to error code variable
+  skipunits         skip this many code units at start (for brackets and OP_COND)
+  firstcuptr        place to put the first required code unit
+  firstcuflagsptr   place to put the first code unit flags, or a negative number
+  reqcuptr          place to put the last required code unit
+  reqcuflagsptr     place to put the last required code unit flags, or a negative number
+  bcptr             pointer to the chain of currently open branches
+  cb                points to the data block with tables pointers etc.
+  lengthptr         NULL during the real compile phase
+                    points to length accumulator during pre-compile phase
+
+Returns:            0 There has been an error
+                   +1 Success, this group must match at least one character
+                   -1 Success, this group may match an empty string
+*/
+
+static int
+compile_regex(uint32_t options, PCRE2_UCHAR **codeptr, uint32_t **pptrptr,
+  int *errorcodeptr, uint32_t skipunits, uint32_t *firstcuptr,
+  int32_t *firstcuflagsptr, uint32_t *reqcuptr,int32_t *reqcuflagsptr,
+  branch_chain *bcptr, compile_block *cb, PCRE2_SIZE *lengthptr)
+{
+PCRE2_UCHAR *code = *codeptr;
+PCRE2_UCHAR *last_branch = code;
+PCRE2_UCHAR *start_bracket = code;
+BOOL lookbehind;
+open_capitem capitem;
+int capnumber = 0;
+int okreturn = 1;
+uint32_t *pptr = *pptrptr;
+uint32_t firstcu, reqcu;
+uint32_t lookbehindlength;
+int32_t firstcuflags, reqcuflags;
+uint32_t branchfirstcu, branchreqcu;
+int32_t branchfirstcuflags, branchreqcuflags;
+PCRE2_SIZE length;
+branch_chain bc;
+
+/* If set, call the external function that checks for stack availability. */
+
+if (cb->cx->stack_guard != NULL &&
+    cb->cx->stack_guard(cb->parens_depth, cb->cx->stack_guard_data))
+  {
+  *errorcodeptr= ERR33;
+  return 0;
+  }
+
+/* Miscellaneous initialization */
+
+bc.outer = bcptr;
+bc.current_branch = code;
+
+firstcu = reqcu = 0;
+firstcuflags = reqcuflags = REQ_UNSET;
+
+/* Accumulate the length for use in the pre-compile phase. Start with the
+length of the BRA and KET and any extra code units that are required at the
+beginning. We accumulate in a local variable to save frequent testing of
+lengthptr for NULL. We cannot do this by looking at the value of 'code' at the
+start and end of each alternative, because compiled items are discarded during
+the pre-compile phase so that the workspace is not exceeded. */
+
+length = 2 + 2*LINK_SIZE + skipunits;
+
+/* Remember if this is a lookbehind assertion, and if it is, save its length
+and skip over the pattern offset. */
+
+lookbehind = *code == OP_ASSERTBACK ||
+             *code == OP_ASSERTBACK_NOT ||
+             *code == OP_ASSERTBACK_NA;
+
+if (lookbehind)
+  {
+  lookbehindlength = META_DATA(pptr[-1]);
+  pptr += SIZEOFFSET;
+  }
+else lookbehindlength = 0;
+
+/* If this is a capturing subpattern, add to the chain of open capturing items
+so that we can detect them if (*ACCEPT) is encountered. Note that only OP_CBRA
+need be tested here; changing this opcode to one of its variants, e.g.
+OP_SCBRAPOS, happens later, after the group has been compiled. */
+
+if (*code == OP_CBRA)
+  {
+  capnumber = GET2(code, 1 + LINK_SIZE);
+  capitem.number = capnumber;
+  capitem.next = cb->open_caps;
+  capitem.assert_depth = cb->assert_depth;
+  cb->open_caps = &capitem;
+  }
+
+/* Offset is set zero to mark that this bracket is still open */
+
+PUT(code, 1, 0);
+code += 1 + LINK_SIZE + skipunits;
+
+/* Loop for each alternative branch */
+
+for (;;)
+  {
+  int branch_return;
+
+  /* Insert OP_REVERSE if this is as lookbehind assertion. */
+
+  if (lookbehind && lookbehindlength > 0)
+    {
+    *code++ = OP_REVERSE;
+    PUTINC(code, 0, lookbehindlength);
+    length += 1 + LINK_SIZE;
+    }
+
+  /* Now compile the branch; in the pre-compile phase its length gets added
+  into the length. */
+
+  if ((branch_return =
+        compile_branch(&options, &code, &pptr, errorcodeptr, &branchfirstcu,
+          &branchfirstcuflags, &branchreqcu, &branchreqcuflags, &bc,
+          cb, (lengthptr == NULL)? NULL : &length)) == 0)
+    return 0;
+
+  /* If a branch can match an empty string, so can the whole group. */
+
+  if (branch_return < 0) okreturn = -1;
+
+  /* In the real compile phase, there is some post-processing to be done. */
+
+  if (lengthptr == NULL)
+    {
+    /* If this is the first branch, the firstcu and reqcu values for the
+    branch become the values for the regex. */
+
+    if (*last_branch != OP_ALT)
+      {
+      firstcu = branchfirstcu;
+      firstcuflags = branchfirstcuflags;
+      reqcu = branchreqcu;
+      reqcuflags = branchreqcuflags;
+      }
+
+    /* If this is not the first branch, the first char and reqcu have to
+    match the values from all the previous branches, except that if the
+    previous value for reqcu didn't have REQ_VARY set, it can still match,
+    and we set REQ_VARY for the group from this branch's value. */
+
+    else
+      {
+      /* If we previously had a firstcu, but it doesn't match the new branch,
+      we have to abandon the firstcu for the regex, but if there was
+      previously no reqcu, it takes on the value of the old firstcu. */
+
+      if (firstcuflags != branchfirstcuflags || firstcu != branchfirstcu)
+        {
+        if (firstcuflags >= 0)
+          {
+          if (reqcuflags < 0)
+            {
+            reqcu = firstcu;
+            reqcuflags = firstcuflags;
+            }
+          }
+        firstcuflags = REQ_NONE;
+        }
+
+      /* If we (now or from before) have no firstcu, a firstcu from the
+      branch becomes a reqcu if there isn't a branch reqcu. */
+
+      if (firstcuflags < 0 && branchfirstcuflags >= 0 &&
+          branchreqcuflags < 0)
+        {
+        branchreqcu = branchfirstcu;
+        branchreqcuflags = branchfirstcuflags;
+        }
+
+      /* Now ensure that the reqcus match */
+
+      if (((reqcuflags & ~REQ_VARY) != (branchreqcuflags & ~REQ_VARY)) ||
+          reqcu != branchreqcu)
+        reqcuflags = REQ_NONE;
+      else
+        {
+        reqcu = branchreqcu;
+        reqcuflags |= branchreqcuflags; /* To "or" REQ_VARY if present */
+        }
+      }
+    }
+
+  /* Handle reaching the end of the expression, either ')' or end of pattern.
+  In the real compile phase, go back through the alternative branches and
+  reverse the chain of offsets, with the field in the BRA item now becoming an
+  offset to the first alternative. If there are no alternatives, it points to
+  the end of the group. The length in the terminating ket is always the length
+  of the whole bracketed item. Return leaving the pointer at the terminating
+  char. */
+
+  if (META_CODE(*pptr) != META_ALT)
+    {
+    if (lengthptr == NULL)
+      {
+      PCRE2_SIZE branch_length = code - last_branch;
+      do
+        {
+        PCRE2_SIZE prev_length = GET(last_branch, 1);
+        PUT(last_branch, 1, branch_length);
+        branch_length = prev_length;
+        last_branch -= branch_length;
+        }
+      while (branch_length > 0);
+      }
+
+    /* Fill in the ket */
+
+    *code = OP_KET;
+    PUT(code, 1, (int)(code - start_bracket));
+    code += 1 + LINK_SIZE;
+
+    /* If it was a capturing subpattern, remove the block from the chain. */
+
+    if (capnumber > 0) cb->open_caps = cb->open_caps->next;
+
+    /* Set values to pass back */
+
+    *codeptr = code;
+    *pptrptr = pptr;
+    *firstcuptr = firstcu;
+    *firstcuflagsptr = firstcuflags;
+    *reqcuptr = reqcu;
+    *reqcuflagsptr = reqcuflags;
+    if (lengthptr != NULL)
+      {
+      if (OFLOW_MAX - *lengthptr < length)
+        {
+        *errorcodeptr = ERR20;
+        return 0;
+        }
+      *lengthptr += length;
+      }
+    return okreturn;
+    }
+
+  /* Another branch follows. In the pre-compile phase, we can move the code
+  pointer back to where it was for the start of the first branch. (That is,
+  pretend that each branch is the only one.)
+
+  In the real compile phase, insert an ALT node. Its length field points back
+  to the previous branch while the bracket remains open. At the end the chain
+  is reversed. It's done like this so that the start of the bracket has a
+  zero offset until it is closed, making it possible to detect recursion. */
+
+  if (lengthptr != NULL)
+    {
+    code = *codeptr + 1 + LINK_SIZE + skipunits;
+    length += 1 + LINK_SIZE;
+    }
+  else
+    {
+    *code = OP_ALT;
+    PUT(code, 1, (int)(code - last_branch));
+    bc.current_branch = last_branch = code;
+    code += 1 + LINK_SIZE;
+    }
+
+  /* Set the lookbehind length (if not in a lookbehind the value will be zero)
+  and then advance past the vertical bar. */
+
+  lookbehindlength = META_DATA(*pptr);
+  pptr++;
+  }
+/* Control never reaches here */
+}
+
+
+
+/*************************************************
+*          Check for anchored pattern            *
+*************************************************/
+
+/* Try to find out if this is an anchored regular expression. Consider each
+alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket
+all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then
+it's anchored. However, if this is a multiline pattern, then only OP_SOD will
+be found, because ^ generates OP_CIRCM in that mode.
+
+We can also consider a regex to be anchored if OP_SOM starts all its branches.
+This is the code for \G, which means "match at start of match position, taking
+into account the match offset".
+
+A branch is also implicitly anchored if it starts with .* and DOTALL is set,
+because that will try the rest of the pattern at all possible matching points,
+so there is no point trying again.... er ....
+
+.... except when the .* appears inside capturing parentheses, and there is a
+subsequent back reference to those parentheses. We haven't enough information
+to catch that case precisely.
+
+At first, the best we could do was to detect when .* was in capturing brackets
+and the highest back reference was greater than or equal to that level.
+However, by keeping a bitmap of the first 31 back references, we can catch some
+of the more common cases more precisely.
+
+... A second exception is when the .* appears inside an atomic group, because
+this prevents the number of characters it matches from being adjusted.
+
+Arguments:
+  code           points to start of the compiled pattern
+  bracket_map    a bitmap of which brackets we are inside while testing; this
+                   handles up to substring 31; after that we just have to take
+                   the less precise approach
+  cb             points to the compile data block
+  atomcount      atomic group level
+  inassert       TRUE if in an assertion
+
+Returns:     TRUE or FALSE
+*/
+
+static BOOL
+is_anchored(PCRE2_SPTR code, unsigned int bracket_map, compile_block *cb,
+  int atomcount, BOOL inassert)
+{
+do {
+   PCRE2_SPTR scode = first_significant_code(
+     code + PRIV(OP_lengths)[*code], FALSE);
+   int op = *scode;
+
+   /* Non-capturing brackets */
+
+   if (op == OP_BRA  || op == OP_BRAPOS ||
+       op == OP_SBRA || op == OP_SBRAPOS)
+     {
+     if (!is_anchored(scode, bracket_map, cb, atomcount, inassert))
+       return FALSE;
+     }
+
+   /* Capturing brackets */
+
+   else if (op == OP_CBRA  || op == OP_CBRAPOS ||
+            op == OP_SCBRA || op == OP_SCBRAPOS)
+     {
+     int n = GET2(scode, 1+LINK_SIZE);
+     int new_map = bracket_map | ((n < 32)? (1u << n) : 1);
+     if (!is_anchored(scode, new_map, cb, atomcount, inassert)) return FALSE;
+     }
+
+   /* Positive forward assertion */
+
+   else if (op == OP_ASSERT || op == OP_ASSERT_NA)
+     {
+     if (!is_anchored(scode, bracket_map, cb, atomcount, TRUE)) return FALSE;
+     }
+
+   /* Condition. If there is no second branch, it can't be anchored. */
+
+   else if (op == OP_COND || op == OP_SCOND)
+     {
+     if (scode[GET(scode,1)] != OP_ALT) return FALSE;
+     if (!is_anchored(scode, bracket_map, cb, atomcount, inassert))
+       return FALSE;
+     }
+
+   /* Atomic groups */
+
+   else if (op == OP_ONCE)
+     {
+     if (!is_anchored(scode, bracket_map, cb, atomcount + 1, inassert))
+       return FALSE;
+     }
+
+   /* .* is not anchored unless DOTALL is set (which generates OP_ALLANY) and
+   it isn't in brackets that are or may be referenced or inside an atomic
+   group or an assertion. Also the pattern must not contain *PRUNE or *SKIP,
+   because these break the feature. Consider, for example, /(?s).*?(*PRUNE)b/
+   with the subject "aab", which matches "b", i.e. not at the start of a line.
+   There is also an option that disables auto-anchoring. */
+
+   else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR ||
+             op == OP_TYPEPOSSTAR))
+     {
+     if (scode[1] != OP_ALLANY || (bracket_map & cb->backref_map) != 0 ||
+         atomcount > 0 || cb->had_pruneorskip || inassert ||
+         (cb->external_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0)
+       return FALSE;
+     }
+
+   /* Check for explicit anchoring */
+
+   else if (op != OP_SOD && op != OP_SOM && op != OP_CIRC) return FALSE;
+
+   code += GET(code, 1);
+   }
+while (*code == OP_ALT);   /* Loop for each alternative */
+return TRUE;
+}
+
+
+
+/*************************************************
+*         Check for starting with ^ or .*        *
+*************************************************/
+
+/* This is called to find out if every branch starts with ^ or .* so that
+"first char" processing can be done to speed things up in multiline
+matching and for non-DOTALL patterns that start with .* (which must start at
+the beginning or after \n). As in the case of is_anchored() (see above), we
+have to take account of back references to capturing brackets that contain .*
+because in that case we can't make the assumption. Also, the appearance of .*
+inside atomic brackets or in an assertion, or in a pattern that contains *PRUNE
+or *SKIP does not count, because once again the assumption no longer holds.
+
+Arguments:
+  code           points to start of the compiled pattern or a group
+  bracket_map    a bitmap of which brackets we are inside while testing; this
+                   handles up to substring 31; after that we just have to take
+                   the less precise approach
+  cb             points to the compile data
+  atomcount      atomic group level
+  inassert       TRUE if in an assertion
+
+Returns:         TRUE or FALSE
+*/
+
+static BOOL
+is_startline(PCRE2_SPTR code, unsigned int bracket_map, compile_block *cb,
+  int atomcount, BOOL inassert)
+{
+do {
+   PCRE2_SPTR scode = first_significant_code(
+     code + PRIV(OP_lengths)[*code], FALSE);
+   int op = *scode;
+
+   /* If we are at the start of a conditional assertion group, *both* the
+   conditional assertion *and* what follows the condition must satisfy the test
+   for start of line. Other kinds of condition fail. Note that there may be an
+   auto-callout at the start of a condition. */
+
+   if (op == OP_COND)
+     {
+     scode += 1 + LINK_SIZE;
+
+     if (*scode == OP_CALLOUT) scode += PRIV(OP_lengths)[OP_CALLOUT];
+       else if (*scode == OP_CALLOUT_STR) scode += GET(scode, 1 + 2*LINK_SIZE);
+
+     switch (*scode)
+       {
+       case OP_CREF:
+       case OP_DNCREF:
+       case OP_RREF:
+       case OP_DNRREF:
+       case OP_FAIL:
+       case OP_FALSE:
+       case OP_TRUE:
+       return FALSE;
+
+       default:     /* Assertion */
+       if (!is_startline(scode, bracket_map, cb, atomcount, TRUE)) return FALSE;
+       do scode += GET(scode, 1); while (*scode == OP_ALT);
+       scode += 1 + LINK_SIZE;
+       break;
+       }
+     scode = first_significant_code(scode, FALSE);
+     op = *scode;
+     }
+
+   /* Non-capturing brackets */
+
+   if (op == OP_BRA  || op == OP_BRAPOS ||
+       op == OP_SBRA || op == OP_SBRAPOS)
+     {
+     if (!is_startline(scode, bracket_map, cb, atomcount, inassert))
+       return FALSE;
+     }
+
+   /* Capturing brackets */
+
+   else if (op == OP_CBRA  || op == OP_CBRAPOS ||
+            op == OP_SCBRA || op == OP_SCBRAPOS)
+     {
+     int n = GET2(scode, 1+LINK_SIZE);
+     int new_map = bracket_map | ((n < 32)? (1u << n) : 1);
+     if (!is_startline(scode, new_map, cb, atomcount, inassert)) return FALSE;
+     }
+
+   /* Positive forward assertions */
+
+   else if (op == OP_ASSERT || op == OP_ASSERT_NA)
+     {
+     if (!is_startline(scode, bracket_map, cb, atomcount, TRUE))
+       return FALSE;
+     }
+
+   /* Atomic brackets */
+
+   else if (op == OP_ONCE)
+     {
+     if (!is_startline(scode, bracket_map, cb, atomcount + 1, inassert))
+       return FALSE;
+     }
+
+   /* .* means "start at start or after \n" if it isn't in atomic brackets or
+   brackets that may be referenced or an assertion, and as long as the pattern
+   does not contain *PRUNE or *SKIP, because these break the feature. Consider,
+   for example, /.*?a(*PRUNE)b/ with the subject "aab", which matches "ab",
+   i.e. not at the start of a line. There is also an option that disables this
+   optimization. */
+
+   else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR)
+     {
+     if (scode[1] != OP_ANY || (bracket_map & cb->backref_map) != 0 ||
+         atomcount > 0 || cb->had_pruneorskip || inassert ||
+         (cb->external_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0)
+       return FALSE;
+     }
+
+   /* Check for explicit circumflex; anything else gives a FALSE result. Note
+   in particular that this includes atomic brackets OP_ONCE because the number
+   of characters matched by .* cannot be adjusted inside them. */
+
+   else if (op != OP_CIRC && op != OP_CIRCM) return FALSE;
+
+   /* Move on to the next alternative */
+
+   code += GET(code, 1);
+   }
+while (*code == OP_ALT);  /* Loop for each alternative */
+return TRUE;
+}
+
+
+
+/*************************************************
+*   Scan compiled regex for recursion reference  *
+*************************************************/
+
+/* This function scans through a compiled pattern until it finds an instance of
+OP_RECURSE.
+
+Arguments:
+  code        points to start of expression
+  utf         TRUE in UTF mode
+
+Returns:      pointer to the opcode for OP_RECURSE, or NULL if not found
+*/
+
+static PCRE2_SPTR
+find_recurse(PCRE2_SPTR code, BOOL utf)
+{
+for (;;)
+  {
+  PCRE2_UCHAR c = *code;
+  if (c == OP_END) return NULL;
+  if (c == OP_RECURSE) return code;
+
+  /* XCLASS is used for classes that cannot be represented just by a bit map.
+  This includes negated single high-valued characters. CALLOUT_STR is used for
+  callouts with string arguments. In both cases the length in the table is
+  zero; the actual length is stored in the compiled code. */
+
+  if (c == OP_XCLASS) code += GET(code, 1);
+    else if (c == OP_CALLOUT_STR) code += GET(code, 1 + 2*LINK_SIZE);
+
+  /* Otherwise, we can get the item's length from the table, except that for
+  repeated character types, we have to test for \p and \P, which have an extra
+  two code units of parameters, and for MARK/PRUNE/SKIP/THEN with an argument,
+  we must add in its length. */
+
+  else
+    {
+    switch(c)
+      {
+      case OP_TYPESTAR:
+      case OP_TYPEMINSTAR:
+      case OP_TYPEPLUS:
+      case OP_TYPEMINPLUS:
+      case OP_TYPEQUERY:
+      case OP_TYPEMINQUERY:
+      case OP_TYPEPOSSTAR:
+      case OP_TYPEPOSPLUS:
+      case OP_TYPEPOSQUERY:
+      if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2;
+      break;
+
+      case OP_TYPEPOSUPTO:
+      case OP_TYPEUPTO:
+      case OP_TYPEMINUPTO:
+      case OP_TYPEEXACT:
+      if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
+        code += 2;
+      break;
+
+      case OP_MARK:
+      case OP_COMMIT_ARG:
+      case OP_PRUNE_ARG:
+      case OP_SKIP_ARG:
+      case OP_THEN_ARG:
+      code += code[1];
+      break;
+      }
+
+    /* Add in the fixed length from the table */
+
+    code += PRIV(OP_lengths)[c];
+
+    /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may
+    be followed by a multi-unit character. The length in the table is a
+    minimum, so we have to arrange to skip the extra units. */
+
+#ifdef MAYBE_UTF_MULTI
+    if (utf) switch(c)
+      {
+      case OP_CHAR:
+      case OP_CHARI:
+      case OP_NOT:
+      case OP_NOTI:
+      case OP_EXACT:
+      case OP_EXACTI:
+      case OP_NOTEXACT:
+      case OP_NOTEXACTI:
+      case OP_UPTO:
+      case OP_UPTOI:
+      case OP_NOTUPTO:
+      case OP_NOTUPTOI:
+      case OP_MINUPTO:
+      case OP_MINUPTOI:
+      case OP_NOTMINUPTO:
+      case OP_NOTMINUPTOI:
+      case OP_POSUPTO:
+      case OP_POSUPTOI:
+      case OP_NOTPOSUPTO:
+      case OP_NOTPOSUPTOI:
+      case OP_STAR:
+      case OP_STARI:
+      case OP_NOTSTAR:
+      case OP_NOTSTARI:
+      case OP_MINSTAR:
+      case OP_MINSTARI:
+      case OP_NOTMINSTAR:
+      case OP_NOTMINSTARI:
+      case OP_POSSTAR:
+      case OP_POSSTARI:
+      case OP_NOTPOSSTAR:
+      case OP_NOTPOSSTARI:
+      case OP_PLUS:
+      case OP_PLUSI:
+      case OP_NOTPLUS:
+      case OP_NOTPLUSI:
+      case OP_MINPLUS:
+      case OP_MINPLUSI:
+      case OP_NOTMINPLUS:
+      case OP_NOTMINPLUSI:
+      case OP_POSPLUS:
+      case OP_POSPLUSI:
+      case OP_NOTPOSPLUS:
+      case OP_NOTPOSPLUSI:
+      case OP_QUERY:
+      case OP_QUERYI:
+      case OP_NOTQUERY:
+      case OP_NOTQUERYI:
+      case OP_MINQUERY:
+      case OP_MINQUERYI:
+      case OP_NOTMINQUERY:
+      case OP_NOTMINQUERYI:
+      case OP_POSQUERY:
+      case OP_POSQUERYI:
+      case OP_NOTPOSQUERY:
+      case OP_NOTPOSQUERYI:
+      if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
+      break;
+      }
+#else
+    (void)(utf);  /* Keep compiler happy by referencing function argument */
+#endif  /* MAYBE_UTF_MULTI */
+    }
+  }
+}
+
+
+
+/*************************************************
+*    Check for asserted fixed first code unit    *
+*************************************************/
+
+/* During compilation, the "first code unit" settings from forward assertions
+are discarded, because they can cause conflicts with actual literals that
+follow. However, if we end up without a first code unit setting for an
+unanchored pattern, it is worth scanning the regex to see if there is an
+initial asserted first code unit. If all branches start with the same asserted
+code unit, or with a non-conditional bracket all of whose alternatives start
+with the same asserted code unit (recurse ad lib), then we return that code
+unit, with the flags set to zero or REQ_CASELESS; otherwise return zero with
+REQ_NONE in the flags.
+
+Arguments:
+  code       points to start of compiled pattern
+  flags      points to the first code unit flags
+  inassert   non-zero if in an assertion
+
+Returns:     the fixed first code unit, or 0 with REQ_NONE in flags
+*/
+
+static uint32_t
+find_firstassertedcu(PCRE2_SPTR code, int32_t *flags, uint32_t inassert)
+{
+uint32_t c = 0;
+int cflags = REQ_NONE;
+
+*flags = REQ_NONE;
+do {
+   uint32_t d;
+   int dflags;
+   int xl = (*code == OP_CBRA || *code == OP_SCBRA ||
+             *code == OP_CBRAPOS || *code == OP_SCBRAPOS)? IMM2_SIZE:0;
+   PCRE2_SPTR scode = first_significant_code(code + 1+LINK_SIZE + xl, TRUE);
+   PCRE2_UCHAR op = *scode;
+
+   switch(op)
+     {
+     default:
+     return 0;
+
+     case OP_BRA:
+     case OP_BRAPOS:
+     case OP_CBRA:
+     case OP_SCBRA:
+     case OP_CBRAPOS:
+     case OP_SCBRAPOS:
+     case OP_ASSERT:
+     case OP_ASSERT_NA:
+     case OP_ONCE:
+     case OP_SCRIPT_RUN:
+     d = find_firstassertedcu(scode, &dflags, inassert +
+       ((op == OP_ASSERT || op == OP_ASSERT_NA)?1:0));
+     if (dflags < 0)
+       return 0;
+     if (cflags < 0) { c = d; cflags = dflags; }
+       else if (c != d || cflags != dflags) return 0;
+     break;
+
+     case OP_EXACT:
+     scode += IMM2_SIZE;
+     /* Fall through */
+
+     case OP_CHAR:
+     case OP_PLUS:
+     case OP_MINPLUS:
+     case OP_POSPLUS:
+     if (inassert == 0) return 0;
+     if (cflags < 0) { c = scode[1]; cflags = 0; }
+       else if (c != scode[1]) return 0;
+     break;
+
+     case OP_EXACTI:
+     scode += IMM2_SIZE;
+     /* Fall through */
+
+     case OP_CHARI:
+     case OP_PLUSI:
+     case OP_MINPLUSI:
+     case OP_POSPLUSI:
+     if (inassert == 0) return 0;
+
+     /* If the character is more than one code unit long, we cannot set its
+     first code unit when matching caselessly. Later scanning may pick up
+     multiple code units. */
+
+#ifdef SUPPORT_UNICODE
+#if PCRE2_CODE_UNIT_WIDTH == 8
+     if (scode[1] >= 0x80) return 0;
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+     if (scode[1] >= 0xd800 && scode[1] <= 0xdfff) return 0;
+#endif
+#endif
+
+     if (cflags < 0) { c = scode[1]; cflags = REQ_CASELESS; }
+       else if (c != scode[1]) return 0;
+     break;
+     }
+
+   code += GET(code, 1);
+   }
+while (*code == OP_ALT);
+
+*flags = cflags;
+return c;
+}
+
+
+
+/*************************************************
+*     Add an entry to the name/number table      *
+*************************************************/
+
+/* This function is called between compiling passes to add an entry to the
+name/number table, maintaining alphabetical order. Checking for permitted
+and forbidden duplicates has already been done.
+
+Arguments:
+  cb           the compile data block
+  name         the name to add
+  length       the length of the name
+  groupno      the group number
+  tablecount   the count of names in the table so far
+
+Returns:       nothing
+*/
+
+static void
+add_name_to_table(compile_block *cb, PCRE2_SPTR name, int length,
+  unsigned int groupno, uint32_t tablecount)
+{
+uint32_t i;
+PCRE2_UCHAR *slot = cb->name_table;
+
+for (i = 0; i < tablecount; i++)
+  {
+  int crc = memcmp(name, slot+IMM2_SIZE, CU2BYTES(length));
+  if (crc == 0 && slot[IMM2_SIZE+length] != 0)
+    crc = -1; /* Current name is a substring */
+
+  /* Make space in the table and break the loop for an earlier name. For a
+  duplicate or later name, carry on. We do this for duplicates so that in the
+  simple case (when ?(| is not used) they are in order of their numbers. In all
+  cases they are in the order in which they appear in the pattern. */
+
+  if (crc < 0)
+    {
+    (void)memmove(slot + cb->name_entry_size, slot,
+      CU2BYTES((tablecount - i) * cb->name_entry_size));
+    break;
+    }
+
+  /* Continue the loop for a later or duplicate name */
+
+  slot += cb->name_entry_size;
+  }
+
+PUT2(slot, 0, groupno);
+memcpy(slot + IMM2_SIZE, name, CU2BYTES(length));
+
+/* Add a terminating zero and fill the rest of the slot with zeroes so that
+the memory is all initialized. Otherwise valgrind moans about uninitialized
+memory when saving serialized compiled patterns. */
+
+memset(slot + IMM2_SIZE + length, 0,
+  CU2BYTES(cb->name_entry_size - length - IMM2_SIZE));
+}
+
+
+
+/*************************************************
+*             Skip in parsed pattern             *
+*************************************************/
+
+/* This function is called to skip parts of the parsed pattern when finding the
+length of a lookbehind branch. It is called after (*ACCEPT) and (*FAIL) to find
+the end of the branch, it is called to skip over an internal lookaround or
+(DEFINE) group, and it is also called to skip to the end of a class, during
+which it will never encounter nested groups (but there's no need to have
+special code for that).
+
+When called to find the end of a branch or group, pptr must point to the first
+meta code inside the branch, not the branch-starting code. In other cases it
+can point to the item that causes the function to be called.
+
+Arguments:
+  pptr       current pointer to skip from
+  skiptype   PSKIP_CLASS when skipping to end of class
+             PSKIP_ALT when META_ALT ends the skip
+             PSKIP_KET when only META_KET ends the skip
+
+Returns:     new value of pptr
+             NULL if META_END is reached - should never occur
+               or for an unknown meta value - likewise
+*/
+
+static uint32_t *
+parsed_skip(uint32_t *pptr, uint32_t skiptype)
+{
+uint32_t nestlevel = 0;
+
+for (;; pptr++)
+  {
+  uint32_t meta = META_CODE(*pptr);
+
+  switch(meta)
+    {
+    default:  /* Just skip over most items */
+    if (meta < META_END) continue;  /* Literal */
+    break;
+
+    /* This should never occur. */
+
+    case META_END:
+    return NULL;
+
+    /* The data for these items is variable in length. */
+
+    case META_BACKREF:  /* Offset is present only if group >= 10 */
+    if (META_DATA(*pptr) >= 10) pptr += SIZEOFFSET;
+    break;
+
+    case META_ESCAPE:   /* A few escapes are followed by data items. */
+    switch (META_DATA(*pptr))
+      {
+      case ESC_P:
+      case ESC_p:
+      pptr += 1;
+      break;
+
+      case ESC_g:
+      case ESC_k:
+      pptr += 1 + SIZEOFFSET;
+      break;
+      }
+    break;
+
+    case META_MARK:     /* Add the length of the name. */
+    case META_COMMIT_ARG:
+    case META_PRUNE_ARG:
+    case META_SKIP_ARG:
+    case META_THEN_ARG:
+    pptr += pptr[1];
+    break;
+
+    /* These are the "active" items in this loop. */
+
+    case META_CLASS_END:
+    if (skiptype == PSKIP_CLASS) return pptr;
+    break;
+
+    case META_ATOMIC:
+    case META_CAPTURE:
+    case META_COND_ASSERT:
+    case META_COND_DEFINE:
+    case META_COND_NAME:
+    case META_COND_NUMBER:
+    case META_COND_RNAME:
+    case META_COND_RNUMBER:
+    case META_COND_VERSION:
+    case META_LOOKAHEAD:
+    case META_LOOKAHEADNOT:
+    case META_LOOKAHEAD_NA:
+    case META_LOOKBEHIND:
+    case META_LOOKBEHINDNOT:
+    case META_LOOKBEHIND_NA:
+    case META_NOCAPTURE:
+    case META_SCRIPT_RUN:
+    nestlevel++;
+    break;
+
+    case META_ALT:
+    if (nestlevel == 0 && skiptype == PSKIP_ALT) return pptr;
+    break;
+
+    case META_KET:
+    if (nestlevel == 0) return pptr;
+    nestlevel--;
+    break;
+    }
+
+  /* The extra data item length for each meta is in a table. */
+
+  meta = (meta >> 16) & 0x7fff;
+  if (meta >= sizeof(meta_extra_lengths)) return NULL;
+  pptr += meta_extra_lengths[meta];
+  }
+/* Control never reaches here */
+return pptr;
+}
+
+
+
+/*************************************************
+*       Find length of a parsed group            *
+*************************************************/
+
+/* This is called for nested groups within a branch of a lookbehind whose
+length is being computed. If all the branches in the nested group have the same
+length, that is OK. On entry, the pointer must be at the first element after
+the group initializing code. On exit it points to OP_KET. Caching is used to
+improve processing speed when the same capturing group occurs many times.
+
+Arguments:
+  pptrptr     pointer to pointer in the parsed pattern
+  isinline    FALSE if a reference or recursion; TRUE for inline group
+  errcodeptr  pointer to the errorcode
+  lcptr       pointer to the loop counter
+  group       number of captured group or -1 for a non-capturing group
+  recurses    chain of recurse_check to catch mutual recursion
+  cb          pointer to the compile data
+
+Returns:      the group length or a negative number
+*/
+
+static int
+get_grouplength(uint32_t **pptrptr, BOOL isinline, int *errcodeptr, int *lcptr,
+   int group, parsed_recurse_check *recurses, compile_block *cb)
+{
+int branchlength;
+int grouplength = -1;
+
+/* The cache can be used only if there is no possibility of there being two
+groups with the same number. We do not need to set the end pointer for a group
+that is being processed as a back reference or recursion, but we must do so for
+an inline group. */
+
+if (group > 0 && (cb->external_flags & PCRE2_DUPCAPUSED) == 0)
+  {
+  uint32_t groupinfo = cb->groupinfo[group];
+  if ((groupinfo & GI_NOT_FIXED_LENGTH) != 0) return -1;
+  if ((groupinfo & GI_SET_FIXED_LENGTH) != 0)
+    {
+    if (isinline) *pptrptr = parsed_skip(*pptrptr, PSKIP_KET);
+    return groupinfo & GI_FIXED_LENGTH_MASK;
+    }
+  }
+
+/* Scan the group. In this case we find the end pointer of necessity. */
+
+for(;;)
+  {
+  branchlength = get_branchlength(pptrptr, errcodeptr, lcptr, recurses, cb);
+  if (branchlength < 0) goto ISNOTFIXED;
+  if (grouplength == -1) grouplength = branchlength;
+    else if (grouplength != branchlength) goto ISNOTFIXED;
+  if (**pptrptr == META_KET) break;
+  *pptrptr += 1;   /* Skip META_ALT */
+  }
+
+if (group > 0)
+  cb->groupinfo[group] |= (uint32_t)(GI_SET_FIXED_LENGTH | grouplength);
+return grouplength;
+
+ISNOTFIXED:
+if (group > 0) cb->groupinfo[group] |= GI_NOT_FIXED_LENGTH;
+return -1;
+}
+
+
+
+/*************************************************
+*        Find length of a parsed branch          *
+*************************************************/
+
+/* Return a fixed length for a branch in a lookbehind, giving an error if the
+length is not fixed. On entry, *pptrptr points to the first element inside the
+branch. On exit it is set to point to the ALT or KET.
+
+Arguments:
+  pptrptr     pointer to pointer in the parsed pattern
+  errcodeptr  pointer to error code
+  lcptr       pointer to loop counter
+  recurses    chain of recurse_check to catch mutual recursion
+  cb          pointer to compile block
+
+Returns:      the length, or a negative value on error
+*/
+
+static int
+get_branchlength(uint32_t **pptrptr, int *errcodeptr, int *lcptr,
+  parsed_recurse_check *recurses, compile_block *cb)
+{
+int branchlength = 0;
+int grouplength;
+uint32_t lastitemlength = 0;
+uint32_t *pptr = *pptrptr;
+PCRE2_SIZE offset;
+parsed_recurse_check this_recurse;
+
+/* A large and/or complex regex can take too long to process. This can happen
+more often when (?| groups are present in the pattern because their length
+cannot be cached. */
+
+if ((*lcptr)++ > 2000)
+  {
+  *errcodeptr = ERR35;  /* Lookbehind is too complicated */
+  return -1;
+  }
+
+/* Scan the branch, accumulating the length. */
+
+for (;; pptr++)
+  {
+  parsed_recurse_check *r;
+  uint32_t *gptr, *gptrend;
+  uint32_t escape;
+  uint32_t group = 0;
+  uint32_t itemlength = 0;
+
+  if (*pptr < META_END)
+    {
+    itemlength = 1;
+    }
+
+  else switch (META_CODE(*pptr))
+    {
+    case META_KET:
+    case META_ALT:
+    goto EXIT;
+
+    /* (*ACCEPT) and (*FAIL) terminate the branch, but we must skip to the
+    actual termination. */
+
+    case META_ACCEPT:
+    case META_FAIL:
+    pptr = parsed_skip(pptr, PSKIP_ALT);
+    if (pptr == NULL) goto PARSED_SKIP_FAILED;
+    goto EXIT;
+
+    case META_MARK:
+    case META_COMMIT_ARG:
+    case META_PRUNE_ARG:
+    case META_SKIP_ARG:
+    case META_THEN_ARG:
+    pptr += pptr[1] + 1;
+    break;
+
+    case META_CIRCUMFLEX:
+    case META_COMMIT:
+    case META_DOLLAR:
+    case META_PRUNE:
+    case META_SKIP:
+    case META_THEN:
+    break;
+
+    case META_OPTIONS:
+    pptr += 1;
+    break;
+
+    case META_BIGVALUE:
+    itemlength = 1;
+    pptr += 1;
+    break;
+
+    case META_CLASS:
+    case META_CLASS_NOT:
+    itemlength = 1;
+    pptr = parsed_skip(pptr, PSKIP_CLASS);
+    if (pptr == NULL) goto PARSED_SKIP_FAILED;
+    break;
+
+    case META_CLASS_EMPTY_NOT:
+    case META_DOT:
+    itemlength = 1;
+    break;
+
+    case META_CALLOUT_NUMBER:
+    pptr += 3;
+    break;
+
+    case META_CALLOUT_STRING:
+    pptr += 3 + SIZEOFFSET;
+    break;
+
+    /* Only some escapes consume a character. Of those, \R and \X are never
+    allowed because they might match more than character. \C is allowed only in
+    32-bit and non-UTF 8/16-bit modes. */
+
+    case META_ESCAPE:
+    escape = META_DATA(*pptr);
+    if (escape == ESC_R || escape == ESC_X) return -1;
+    if (escape > ESC_b && escape < ESC_Z)
+      {
+#if PCRE2_CODE_UNIT_WIDTH != 32
+      if ((cb->external_options & PCRE2_UTF) != 0 && escape == ESC_C)
+        {
+        *errcodeptr = ERR36;
+        return -1;
+        }
+#endif
+      itemlength = 1;
+      if (escape == ESC_p || escape == ESC_P) pptr++;  /* Skip prop data */
+      }
+    break;
+
+    /* Lookaheads do not contribute to the length of this branch, but they may
+    contain lookbehinds within them whose lengths need to be set. */
+
+    case META_LOOKAHEAD:
+    case META_LOOKAHEADNOT:
+    case META_LOOKAHEAD_NA:
+    *errcodeptr = check_lookbehinds(pptr + 1, &pptr, recurses, cb);
+    if (*errcodeptr != 0) return -1;
+
+    /* Ignore any qualifiers that follow a lookahead assertion. */
+
+    switch (pptr[1])
+      {
+      case META_ASTERISK:
+      case META_ASTERISK_PLUS:
+      case META_ASTERISK_QUERY:
+      case META_PLUS:
+      case META_PLUS_PLUS:
+      case META_PLUS_QUERY:
+      case META_QUERY:
+      case META_QUERY_PLUS:
+      case META_QUERY_QUERY:
+      pptr++;
+      break;
+
+      case META_MINMAX:
+      case META_MINMAX_PLUS:
+      case META_MINMAX_QUERY:
+      pptr += 3;
+      break;
+
+      default:
+      break;
+      }
+    break;
+
+    /* A nested lookbehind does not contribute any length to this lookbehind,
+    but must itself be checked and have its lengths set. */
+
+    case META_LOOKBEHIND:
+    case META_LOOKBEHINDNOT:
+    case META_LOOKBEHIND_NA:
+    if (!set_lookbehind_lengths(&pptr, errcodeptr, lcptr, recurses, cb))
+      return -1;
+    break;
+
+    /* Back references and recursions are handled by very similar code. At this
+    stage, the names generated in the parsing pass are available, but the main
+    name table has not yet been created. So for the named varieties, scan the
+    list of names in order to get the number of the first one in the pattern,
+    and whether or not this name is duplicated. */
+
+    case META_BACKREF_BYNAME:
+    if ((cb->external_options & PCRE2_MATCH_UNSET_BACKREF) != 0)
+      goto ISNOTFIXED;
+    /* Fall through */
+
+    case META_RECURSE_BYNAME:
+      {
+      int i;
+      PCRE2_SPTR name;
+      BOOL is_dupname = FALSE;
+      named_group *ng = cb->named_groups;
+      uint32_t meta_code = META_CODE(*pptr);
+      uint32_t length = *(++pptr);
+
+      GETPLUSOFFSET(offset, pptr);
+      name = cb->start_pattern + offset;
+      for (i = 0; i < cb->names_found; i++, ng++)
+        {
+        if (length == ng->length && PRIV(strncmp)(name, ng->name, length) == 0)
+          {
+          group = ng->number;
+          is_dupname = ng->isdup;
+          break;
+          }
+        }
+
+      if (group == 0)
+        {
+        *errcodeptr = ERR15;  /* Non-existent subpattern */
+        cb->erroroffset = offset;
+        return -1;
+        }
+
+      /* A numerical back reference can be fixed length if duplicate capturing
+      groups are not being used. A non-duplicate named back reference can also
+      be handled. */
+
+      if (meta_code == META_RECURSE_BYNAME ||
+          (!is_dupname && (cb->external_flags & PCRE2_DUPCAPUSED) == 0))
+        goto RECURSE_OR_BACKREF_LENGTH;  /* Handle as a numbered version. */
+      }
+    goto ISNOTFIXED;                     /* Duplicate name or number */
+
+    /* The offset values for back references < 10 are in a separate vector
+    because otherwise they would use more than two parsed pattern elements on
+    64-bit systems. */
+
+    case META_BACKREF:
+    if ((cb->external_options & PCRE2_MATCH_UNSET_BACKREF) != 0 ||
+        (cb->external_flags & PCRE2_DUPCAPUSED) != 0)
+      goto ISNOTFIXED;
+    group = META_DATA(*pptr);
+    if (group < 10)
+      {
+      offset = cb->small_ref_offset[group];
+      goto RECURSE_OR_BACKREF_LENGTH;
+      }
+
+    /* Fall through */
+    /* For groups >= 10 - picking up group twice does no harm. */
+
+    /* A true recursion implies not fixed length, but a subroutine call may
+    be OK. Back reference "recursions" are also failed. */
+
+    case META_RECURSE:
+    group = META_DATA(*pptr);
+    GETPLUSOFFSET(offset, pptr);
+
+    RECURSE_OR_BACKREF_LENGTH:
+    if (group > cb->bracount)
+      {
+      cb->erroroffset = offset;
+      *errcodeptr = ERR15;  /* Non-existent subpattern */
+      return -1;
+      }
+    if (group == 0) goto ISNOTFIXED;  /* Local recursion */
+    for (gptr = cb->parsed_pattern; *gptr != META_END; gptr++)
+      {
+      if (META_CODE(*gptr) == META_BIGVALUE) gptr++;
+        else if (*gptr == (META_CAPTURE | group)) break;
+      }
+
+    /* We must start the search for the end of the group at the first meta code
+    inside the group. Otherwise it will be treated as an enclosed group. */
+
+    gptrend = parsed_skip(gptr + 1, PSKIP_KET);
+    if (gptrend == NULL) goto PARSED_SKIP_FAILED;
+    if (pptr > gptr && pptr < gptrend) goto ISNOTFIXED;  /* Local recursion */
+    for (r = recurses; r != NULL; r = r->prev) if (r->groupptr == gptr) break;
+    if (r != NULL) goto ISNOTFIXED;   /* Mutual recursion */
+    this_recurse.prev = recurses;
+    this_recurse.groupptr = gptr;
+
+    /* We do not need to know the position of the end of the group, that is,
+    gptr is not used after the call to get_grouplength(). Setting the second
+    argument FALSE stops it scanning for the end when the length can be found
+    in the cache. */
+
+    gptr++;
+    grouplength = get_grouplength(&gptr, FALSE, errcodeptr, lcptr, group,
+      &this_recurse, cb);
+    if (grouplength < 0)
+      {
+      if (*errcodeptr == 0) goto ISNOTFIXED;
+      return -1;  /* Error already set */
+      }
+    itemlength = grouplength;
+    break;
+
+    /* A (DEFINE) group is never obeyed inline and so it does not contribute to
+    the length of this branch. Skip from the following item to the next
+    unpaired ket. */
+
+    case META_COND_DEFINE:
+    pptr = parsed_skip(pptr + 1, PSKIP_KET);
+    break;
+
+    /* Check other nested groups - advance past the initial data for each type
+    and then seek a fixed length with get_grouplength(). */
+
+    case META_COND_NAME:
+    case META_COND_NUMBER:
+    case META_COND_RNAME:
+    case META_COND_RNUMBER:
+    pptr += 2 + SIZEOFFSET;
+    goto CHECK_GROUP;
+
+    case META_COND_ASSERT:
+    pptr += 1;
+    goto CHECK_GROUP;
+
+    case META_COND_VERSION:
+    pptr += 4;
+    goto CHECK_GROUP;
+
+    case META_CAPTURE:
+    group = META_DATA(*pptr);
+    /* Fall through */
+
+    case META_ATOMIC:
+    case META_NOCAPTURE:
+    case META_SCRIPT_RUN:
+    pptr++;
+    CHECK_GROUP:
+    grouplength = get_grouplength(&pptr, TRUE, errcodeptr, lcptr, group,
+      recurses, cb);
+    if (grouplength < 0) return -1;
+    itemlength = grouplength;
+    break;
+
+    /* Exact repetition is OK; variable repetition is not. A repetition of zero
+    must subtract the length that has already been added. */
+
+    case META_MINMAX:
+    case META_MINMAX_PLUS:
+    case META_MINMAX_QUERY:
+    if (pptr[1] == pptr[2])
+      {
+      switch(pptr[1])
+        {
+        case 0:
+        branchlength -= lastitemlength;
+        break;
+
+        case 1:
+        itemlength = 0;
+        break;
+
+        default:  /* Check for integer overflow */
+        if (lastitemlength != 0 &&  /* Should not occur, but just in case */
+            INT_MAX/lastitemlength < pptr[1] - 1)
+          {
+          *errcodeptr = ERR87;  /* Integer overflow; lookbehind too big */
+          return -1;
+          }
+        itemlength = (pptr[1] - 1) * lastitemlength;
+        break;
+        }
+      pptr += 2;
+      break;
+      }
+    /* Fall through */
+
+    /* Any other item means this branch does not have a fixed length. */
+
+    default:
+    ISNOTFIXED:
+    *errcodeptr = ERR25;   /* Not fixed length */
+    return -1;
+    }
+
+  /* Add the item length to the branchlength, checking for integer overflow and
+  for the branch length exceeding the limit. */
+
+  if (INT_MAX - branchlength < (int)itemlength ||
+      (branchlength += itemlength) > LOOKBEHIND_MAX)
+    {
+    *errcodeptr = ERR87;
+    return -1;
+    }
+
+  /* Save this item length for use if the next item is a quantifier. */
+
+  lastitemlength = itemlength;
+  }
+
+EXIT:
+*pptrptr = pptr;
+return branchlength;
+
+PARSED_SKIP_FAILED:
+*errcodeptr = ERR90;
+return -1;
+}
+
+
+
+/*************************************************
+*        Set lengths in a lookbehind             *
+*************************************************/
+
+/* This function is called for each lookbehind, to set the lengths in its
+branches. An error occurs if any branch does not have a fixed length that is
+less than the maximum (65535). On exit, the pointer must be left on the final
+ket.
+
+The function also maintains the max_lookbehind value. Any lookbehind branch
+that contains a nested lookbehind may actually look further back than the
+length of the branch. The additional amount is passed back from
+get_branchlength() as an "extra" value.
+
+Arguments:
+  pptrptr     pointer to pointer in the parsed pattern
+  errcodeptr  pointer to error code
+  lcptr       pointer to loop counter
+  recurses    chain of recurse_check to catch mutual recursion
+  cb          pointer to compile block
+
+Returns:      TRUE if all is well
+              FALSE otherwise, with error code and offset set
+*/
+
+static BOOL
+set_lookbehind_lengths(uint32_t **pptrptr, int *errcodeptr, int *lcptr,
+  parsed_recurse_check *recurses, compile_block *cb)
+{
+PCRE2_SIZE offset;
+int branchlength;
+uint32_t *bptr = *pptrptr;
+
+READPLUSOFFSET(offset, bptr);  /* Offset for error messages */
+*pptrptr += SIZEOFFSET;
+
+do
+  {
+  *pptrptr += 1;
+  branchlength = get_branchlength(pptrptr, errcodeptr, lcptr, recurses, cb);
+  if (branchlength < 0)
+    {
+    /* The errorcode and offset may already be set from a nested lookbehind. */
+    if (*errcodeptr == 0) *errcodeptr = ERR25;
+    if (cb->erroroffset == PCRE2_UNSET) cb->erroroffset = offset;
+    return FALSE;
+    }
+  if (branchlength > cb->max_lookbehind) cb->max_lookbehind = branchlength;
+  *bptr |= branchlength;  /* branchlength never more than 65535 */
+  bptr = *pptrptr;
+  }
+while (*bptr == META_ALT);
+
+return TRUE;
+}
+
+
+
+/*************************************************
+*         Check parsed pattern lookbehinds       *
+*************************************************/
+
+/* This function is called at the end of parsing a pattern if any lookbehinds
+were encountered. It scans the parsed pattern for them, calling
+set_lookbehind_lengths() for each one. At the start, the errorcode is zero and
+the error offset is marked unset. The enables the functions above not to
+override settings from deeper nestings.
+
+This function is called recursively from get_branchlength() for lookaheads in
+order to process any lookbehinds that they may contain. It stops when it hits a
+non-nested closing parenthesis in this case, returning a pointer to it.
+
+Arguments
+  pptr      points to where to start (start of pattern or start of lookahead)
+  retptr    if not NULL, return the ket pointer here
+  recurses  chain of recurse_check to catch mutual recursion
+  cb        points to the compile block
+
+Returns:    0 on success, or an errorcode (cb->erroroffset will be set)
+*/
+
+static int
+check_lookbehinds(uint32_t *pptr, uint32_t **retptr,
+  parsed_recurse_check *recurses, compile_block *cb)
+{
+int errorcode = 0;
+int loopcount = 0;
+int nestlevel = 0;
+
+cb->erroroffset = PCRE2_UNSET;
+
+for (; *pptr != META_END; pptr++)
+  {
+  if (*pptr < META_END) continue;  /* Literal */
+
+  switch (META_CODE(*pptr))
+    {
+    default:
+    return ERR70;  /* Unrecognized meta code */
+
+    case META_ESCAPE:
+    if (*pptr - META_ESCAPE == ESC_P || *pptr - META_ESCAPE == ESC_p)
+      pptr += 1;
+    break;
+
+    case META_KET:
+    if (--nestlevel < 0)
+      {
+      if (retptr != NULL) *retptr = pptr;
+      return 0;
+      }
+    break;
+
+    case META_ATOMIC:
+    case META_CAPTURE:
+    case META_COND_ASSERT:
+    case META_LOOKAHEAD:
+    case META_LOOKAHEADNOT:
+    case META_LOOKAHEAD_NA:
+    case META_NOCAPTURE:
+    case META_SCRIPT_RUN:
+    nestlevel++;
+    break;
+
+    case META_ACCEPT:
+    case META_ALT:
+    case META_ASTERISK:
+    case META_ASTERISK_PLUS:
+    case META_ASTERISK_QUERY:
+    case META_BACKREF:
+    case META_CIRCUMFLEX:
+    case META_CLASS:
+    case META_CLASS_EMPTY:
+    case META_CLASS_EMPTY_NOT:
+    case META_CLASS_END:
+    case META_CLASS_NOT:
+    case META_COMMIT:
+    case META_DOLLAR:
+    case META_DOT:
+    case META_FAIL:
+    case META_PLUS:
+    case META_PLUS_PLUS:
+    case META_PLUS_QUERY:
+    case META_PRUNE:
+    case META_QUERY:
+    case META_QUERY_PLUS:
+    case META_QUERY_QUERY:
+    case META_RANGE_ESCAPED:
+    case META_RANGE_LITERAL:
+    case META_SKIP:
+    case META_THEN:
+    break;
+
+    case META_RECURSE:
+    pptr += SIZEOFFSET;
+    break;
+
+    case META_BACKREF_BYNAME:
+    case META_RECURSE_BYNAME:
+    pptr += 1 + SIZEOFFSET;
+    break;
+
+    case META_COND_DEFINE:
+    pptr += SIZEOFFSET;
+    nestlevel++;
+    break;
+
+    case META_COND_NAME:
+    case META_COND_NUMBER:
+    case META_COND_RNAME:
+    case META_COND_RNUMBER:
+    pptr += 1 + SIZEOFFSET;
+    nestlevel++;
+    break;
+
+    case META_COND_VERSION:
+    pptr += 3;
+    nestlevel++;
+    break;
+
+    case META_CALLOUT_STRING:
+    pptr += 3 + SIZEOFFSET;
+    break;
+
+    case META_BIGVALUE:
+    case META_OPTIONS:
+    case META_POSIX:
+    case META_POSIX_NEG:
+    pptr += 1;
+    break;
+
+    case META_MINMAX:
+    case META_MINMAX_QUERY:
+    case META_MINMAX_PLUS:
+    pptr += 2;
+    break;
+
+    case META_CALLOUT_NUMBER:
+    pptr += 3;
+    break;
+
+    case META_MARK:
+    case META_COMMIT_ARG:
+    case META_PRUNE_ARG:
+    case META_SKIP_ARG:
+    case META_THEN_ARG:
+    pptr += 1 + pptr[1];
+    break;
+
+    case META_LOOKBEHIND:
+    case META_LOOKBEHINDNOT:
+    case META_LOOKBEHIND_NA:
+    if (!set_lookbehind_lengths(&pptr, &errorcode, &loopcount, recurses, cb))
+      return errorcode;
+    break;
+    }
+  }
+
+return 0;
+}
+
+
+
+/*************************************************
+*     External function to compile a pattern     *
+*************************************************/
+
+/* This function reads a regular expression in the form of a string and returns
+a pointer to a block of store holding a compiled version of the expression.
+
+Arguments:
+  pattern       the regular expression
+  patlen        the length of the pattern, or PCRE2_ZERO_TERMINATED
+  options       option bits
+  errorptr      pointer to errorcode
+  erroroffset   pointer to error offset
+  ccontext      points to a compile context or is NULL
+
+Returns:        pointer to compiled data block, or NULL on error,
+                with errorcode and erroroffset set
+*/
+
+PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION
+pcre2_compile(PCRE2_SPTR pattern, PCRE2_SIZE patlen, uint32_t options,
+   int *errorptr, PCRE2_SIZE *erroroffset, pcre2_compile_context *ccontext)
+{
+BOOL utf;                             /* Set TRUE for UTF mode */
+BOOL ucp;                             /* Set TRUE for UCP mode */
+BOOL has_lookbehind = FALSE;          /* Set TRUE if a lookbehind is found */
+BOOL zero_terminated;                 /* Set TRUE for zero-terminated pattern */
+pcre2_real_code *re = NULL;           /* What we will return */
+compile_block cb;                     /* "Static" compile-time data */
+const uint8_t *tables;                /* Char tables base pointer */
+
+PCRE2_UCHAR *code;                    /* Current pointer in compiled code */
+PCRE2_SPTR codestart;                 /* Start of compiled code */
+PCRE2_SPTR ptr;                       /* Current pointer in pattern */
+uint32_t *pptr;                       /* Current pointer in parsed pattern */
+
+PCRE2_SIZE length = 1;                /* Allow for final END opcode */
+PCRE2_SIZE usedlength;                /* Actual length used */
+PCRE2_SIZE re_blocksize;              /* Size of memory block */
+PCRE2_SIZE big32count = 0;            /* 32-bit literals >= 0x80000000 */
+PCRE2_SIZE parsed_size_needed;        /* Needed for parsed pattern */
+
+int32_t firstcuflags, reqcuflags;     /* Type of first/req code unit */
+uint32_t firstcu, reqcu;              /* Value of first/req code unit */
+uint32_t setflags = 0;                /* NL and BSR set flags */
+
+uint32_t skipatstart;                 /* When checking (*UTF) etc */
+uint32_t limit_heap  = UINT32_MAX;
+uint32_t limit_match = UINT32_MAX;    /* Unset match limits */
+uint32_t limit_depth = UINT32_MAX;
+
+int newline = 0;                      /* Unset; can be set by the pattern */
+int bsr = 0;                          /* Unset; can be set by the pattern */
+int errorcode = 0;                    /* Initialize to avoid compiler warn */
+int regexrc;                          /* Return from compile */
+
+uint32_t i;                           /* Local loop counter */
+
+/* Comments at the head of this file explain about these variables. */
+
+uint32_t stack_groupinfo[GROUPINFO_DEFAULT_SIZE];
+uint32_t stack_parsed_pattern[PARSED_PATTERN_DEFAULT_SIZE];
+named_group named_groups[NAMED_GROUP_LIST_SIZE];
+
+/* The workspace is used in different ways in the different compiling phases.
+It needs to be 16-bit aligned for the preliminary parsing scan. */
+
+uint32_t c16workspace[C16_WORK_SIZE];
+PCRE2_UCHAR *cworkspace = (PCRE2_UCHAR *)c16workspace;
+
+
+/* -------------- Check arguments and set up the pattern ----------------- */
+
+/* There must be error code and offset pointers. */
+
+if (errorptr == NULL || erroroffset == NULL) return NULL;
+*errorptr = ERR0;
+*erroroffset = 0;
+
+/* There must be a pattern! */
+
+if (pattern == NULL)
+  {
+  *errorptr = ERR16;
+  return NULL;
+  }
+
+/* A NULL compile context means "use a default context" */
+
+if (ccontext == NULL)
+  ccontext = (pcre2_compile_context *)(&PRIV(default_compile_context));
+
+/* PCRE2_MATCH_INVALID_UTF implies UTF */
+
+if ((options & PCRE2_MATCH_INVALID_UTF) != 0) options |= PCRE2_UTF;
+
+/* Check that all undefined public option bits are zero. */
+
+if ((options & ~PUBLIC_COMPILE_OPTIONS) != 0 ||
+    (ccontext->extra_options & ~PUBLIC_COMPILE_EXTRA_OPTIONS) != 0)
+  {
+  *errorptr = ERR17;
+  return NULL;
+  }
+
+if ((options & PCRE2_LITERAL) != 0 &&
+    ((options & ~PUBLIC_LITERAL_COMPILE_OPTIONS) != 0 ||
+     (ccontext->extra_options & ~PUBLIC_LITERAL_COMPILE_EXTRA_OPTIONS) != 0))
+  {
+  *errorptr = ERR92;
+  return NULL;
+  }
+
+/* A zero-terminated pattern is indicated by the special length value
+PCRE2_ZERO_TERMINATED. Check for an overlong pattern. */
+
+if ((zero_terminated = (patlen == PCRE2_ZERO_TERMINATED)))
+  patlen = PRIV(strlen)(pattern);
+
+if (patlen > ccontext->max_pattern_length)
+  {
+  *errorptr = ERR88;
+  return NULL;
+  }
+
+/* From here on, all returns from this function should end up going via the
+EXIT label. */
+
+
+/* ------------ Initialize the "static" compile data -------------- */
+
+tables = (ccontext->tables != NULL)? ccontext->tables : PRIV(default_tables);
+
+cb.lcc = tables + lcc_offset;          /* Individual */
+cb.fcc = tables + fcc_offset;          /*   character */
+cb.cbits = tables + cbits_offset;      /*      tables */
+cb.ctypes = tables + ctypes_offset;
+
+cb.assert_depth = 0;
+cb.bracount = 0;
+cb.cx = ccontext;
+cb.dupnames = FALSE;
+cb.end_pattern = pattern + patlen;
+cb.erroroffset = 0;
+cb.external_flags = 0;
+cb.external_options = options;
+cb.groupinfo = stack_groupinfo;
+cb.had_recurse = FALSE;
+cb.lastcapture = 0;
+cb.max_lookbehind = 0;
+cb.name_entry_size = 0;
+cb.name_table = NULL;
+cb.named_groups = named_groups;
+cb.named_group_list_size = NAMED_GROUP_LIST_SIZE;
+cb.names_found = 0;
+cb.open_caps = NULL;
+cb.parens_depth = 0;
+cb.parsed_pattern = stack_parsed_pattern;
+cb.req_varyopt = 0;
+cb.start_code = cworkspace;
+cb.start_pattern = pattern;
+cb.start_workspace = cworkspace;
+cb.workspace_size = COMPILE_WORK_SIZE;
+
+/* Maximum back reference and backref bitmap. The bitmap records up to 31 back
+references to help in deciding whether (.*) can be treated as anchored or not.
+*/
+
+cb.top_backref = 0;
+cb.backref_map = 0;
+
+/* Escape sequences \1 to \9 are always back references, but as they are only
+two characters long, only two elements can be used in the parsed_pattern
+vector. The first contains the reference, and we'd like to use the second to
+record the offset in the pattern, so that forward references to non-existent
+groups can be diagnosed later with an offset. However, on 64-bit systems,
+PCRE2_SIZE won't fit. Instead, we have a vector of offsets for the first
+occurrence of \1 to \9, indexed by the second parsed_pattern value. All other
+references have enough space for the offset to be put into the parsed pattern.
+*/
+
+for (i = 0; i < 10; i++) cb.small_ref_offset[i] = PCRE2_UNSET;
+
+
+/* --------------- Start looking at the pattern --------------- */
+
+/* Unless PCRE2_LITERAL is set, check for global one-time option settings at
+the start of the pattern, and remember the offset to the actual regex. With
+valgrind support, make the terminator of a zero-terminated pattern
+inaccessible. This catches bugs that would otherwise only show up for
+non-zero-terminated patterns. */
+
+#ifdef SUPPORT_VALGRIND
+if (zero_terminated) VALGRIND_MAKE_MEM_NOACCESS(pattern + patlen, CU2BYTES(1));
+#endif
+
+ptr = pattern;
+skipatstart = 0;
+
+if ((options & PCRE2_LITERAL) == 0)
+  {
+  while (patlen - skipatstart >= 2 &&
+         ptr[skipatstart] == CHAR_LEFT_PARENTHESIS &&
+         ptr[skipatstart+1] == CHAR_ASTERISK)
+    {
+    for (i = 0; i < sizeof(pso_list)/sizeof(pso); i++)
+      {
+      uint32_t c, pp;
+      pso *p = pso_list + i;
+
+      if (patlen - skipatstart - 2 >= p->length &&
+          PRIV(strncmp_c8)(ptr + skipatstart + 2, (char *)(p->name),
+            p->length) == 0)
+        {
+        skipatstart += p->length + 2;
+        switch(p->type)
+          {
+          case PSO_OPT:
+          cb.external_options |= p->value;
+          break;
+
+          case PSO_FLG:
+          setflags |= p->value;
+          break;
+
+          case PSO_NL:
+          newline = p->value;
+          setflags |= PCRE2_NL_SET;
+          break;
+
+          case PSO_BSR:
+          bsr = p->value;
+          setflags |= PCRE2_BSR_SET;
+          break;
+
+          case PSO_LIMM:
+          case PSO_LIMD:
+          case PSO_LIMH:
+          c = 0;
+          pp = skipatstart;
+          if (!IS_DIGIT(ptr[pp]))
+            {
+            errorcode = ERR60;
+            ptr += pp;
+            goto HAD_EARLY_ERROR;
+            }
+          while (IS_DIGIT(ptr[pp]))
+            {
+            if (c > UINT32_MAX / 10 - 1) break;   /* Integer overflow */
+            c = c*10 + (ptr[pp++] - CHAR_0);
+            }
+          if (ptr[pp++] != CHAR_RIGHT_PARENTHESIS)
+            {
+            errorcode = ERR60;
+            ptr += pp;
+            goto HAD_EARLY_ERROR;
+            }
+          if (p->type == PSO_LIMH) limit_heap = c;
+            else if (p->type == PSO_LIMM) limit_match = c;
+            else limit_depth = c;
+          skipatstart += pp - skipatstart;
+          break;
+          }
+        break;   /* Out of the table scan loop */
+        }
+      }
+    if (i >= sizeof(pso_list)/sizeof(pso)) break;   /* Out of pso loop */
+    }
+  }
+
+/* End of pattern-start options; advance to start of real regex. */
+
+ptr += skipatstart;
+
+/* Can't support UTF or UCP if PCRE2 was built without Unicode support. */
+
+#ifndef SUPPORT_UNICODE
+if ((cb.external_options & (PCRE2_UTF|PCRE2_UCP)) != 0)
+  {
+  errorcode = ERR32;
+  goto HAD_EARLY_ERROR;
+  }
+#endif
+
+/* Check UTF. We have the original options in 'options', with that value as
+modified by (*UTF) etc in cb->external_options. The extra option
+PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES is not permitted in UTF-16 mode because the
+surrogate code points cannot be represented in UTF-16. */
+
+utf = (cb.external_options & PCRE2_UTF) != 0;
+if (utf)
+  {
+  if ((options & PCRE2_NEVER_UTF) != 0)
+    {
+    errorcode = ERR74;
+    goto HAD_EARLY_ERROR;
+    }
+  if ((options & PCRE2_NO_UTF_CHECK) == 0 &&
+       (errorcode = PRIV(valid_utf)(pattern, patlen, erroroffset)) != 0)
+    goto HAD_ERROR;  /* Offset was set by valid_utf() */
+
+#if PCRE2_CODE_UNIT_WIDTH == 16
+  if ((ccontext->extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) != 0)
+    {
+    errorcode = ERR91;
+    goto HAD_EARLY_ERROR;
+    }
+#endif
+  }
+
+/* Check UCP lockout. */
+
+ucp = (cb.external_options & PCRE2_UCP) != 0;
+if (ucp && (cb.external_options & PCRE2_NEVER_UCP) != 0)
+  {
+  errorcode = ERR75;
+  goto HAD_EARLY_ERROR;
+  }
+
+/* Process the BSR setting. */
+
+if (bsr == 0) bsr = ccontext->bsr_convention;
+
+/* Process the newline setting. */
+
+if (newline == 0) newline = ccontext->newline_convention;
+cb.nltype = NLTYPE_FIXED;
+switch(newline)
+  {
+  case PCRE2_NEWLINE_CR:
+  cb.nllen = 1;
+  cb.nl[0] = CHAR_CR;
+  break;
+
+  case PCRE2_NEWLINE_LF:
+  cb.nllen = 1;
+  cb.nl[0] = CHAR_NL;
+  break;
+
+  case PCRE2_NEWLINE_NUL:
+  cb.nllen = 1;
+  cb.nl[0] = CHAR_NUL;
+  break;
+
+  case PCRE2_NEWLINE_CRLF:
+  cb.nllen = 2;
+  cb.nl[0] = CHAR_CR;
+  cb.nl[1] = CHAR_NL;
+  break;
+
+  case PCRE2_NEWLINE_ANY:
+  cb.nltype = NLTYPE_ANY;
+  break;
+
+  case PCRE2_NEWLINE_ANYCRLF:
+  cb.nltype = NLTYPE_ANYCRLF;
+  break;
+
+  default:
+  errorcode = ERR56;
+  goto HAD_EARLY_ERROR;
+  }
+
+/* Pre-scan the pattern to do two things: (1) Discover the named groups and
+their numerical equivalents, so that this information is always available for
+the remaining processing. (2) At the same time, parse the pattern and put a
+processed version into the parsed_pattern vector. This has escapes interpreted
+and comments removed (amongst other things).
+
+In all but one case, when PCRE2_AUTO_CALLOUT is not set, the number of unsigned
+32-bit ints in the parsed pattern is bounded by the length of the pattern plus
+one (for the terminator) plus four if PCRE2_EXTRA_WORD or PCRE2_EXTRA_LINE is
+set. The exceptional case is when running in 32-bit, non-UTF mode, when literal
+characters greater than META_END (0x80000000) have to be coded as two units. In
+this case, therefore, we scan the pattern to check for such values. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+if (!utf)
+  {
+  PCRE2_SPTR p;
+  for (p = ptr; p < cb.end_pattern; p++) if (*p >= META_END) big32count++;
+  }
+#endif
+
+/* Ensure that the parsed pattern buffer is big enough. When PCRE2_AUTO_CALLOUT
+is set we have to assume a numerical callout (4 elements) for each character
+plus one at the end. This is overkill, but memory is plentiful these days. For
+many smaller patterns the vector on the stack (which was set up above) can be
+used. */
+
+parsed_size_needed = patlen - skipatstart + big32count;
+
+if ((ccontext->extra_options &
+     (PCRE2_EXTRA_MATCH_WORD|PCRE2_EXTRA_MATCH_LINE)) != 0)
+  parsed_size_needed += 4;
+
+if ((options & PCRE2_AUTO_CALLOUT) != 0)
+  parsed_size_needed = (parsed_size_needed + 1) * 5;
+
+if (parsed_size_needed >= PARSED_PATTERN_DEFAULT_SIZE)
+  {
+  uint32_t *heap_parsed_pattern = ccontext->memctl.malloc(
+    (parsed_size_needed + 1) * sizeof(uint32_t), ccontext->memctl.memory_data);
+  if (heap_parsed_pattern == NULL)
+    {
+    *errorptr = ERR21;
+    goto EXIT;
+    }
+  cb.parsed_pattern = heap_parsed_pattern;
+  }
+cb.parsed_pattern_end = cb.parsed_pattern + parsed_size_needed + 1;
+
+/* Do the parsing scan. */
+
+errorcode = parse_regex(ptr, cb.external_options, &has_lookbehind, &cb);
+if (errorcode != 0) goto HAD_CB_ERROR;
+
+/* Workspace is needed to remember information about numbered groups: whether a
+group can match an empty string and what its fixed length is. This is done to
+avoid the possibility of recursive references causing very long compile times
+when checking these features. Unnumbered groups do not have this exposure since
+they cannot be referenced. We use an indexed vector for this purpose. If there
+are sufficiently few groups, the default vector on the stack, as set up above,
+can be used. Otherwise we have to get/free a special vector. The vector must be
+initialized to zero. */
+
+if (cb.bracount >= GROUPINFO_DEFAULT_SIZE)
+  {
+  cb.groupinfo = ccontext->memctl.malloc(
+    (cb.bracount + 1)*sizeof(uint32_t), ccontext->memctl.memory_data);
+  if (cb.groupinfo == NULL)
+    {
+    errorcode = ERR21;
+    cb.erroroffset = 0;
+    goto HAD_CB_ERROR;
+    }
+  }
+memset(cb.groupinfo, 0, (cb.bracount + 1) * sizeof(uint32_t));
+
+/* If there were any lookbehinds, scan the parsed pattern to figure out their
+lengths. */
+
+if (has_lookbehind)
+  {
+  errorcode = check_lookbehinds(cb.parsed_pattern, NULL, NULL, &cb);
+  if (errorcode != 0) goto HAD_CB_ERROR;
+  }
+
+/* For debugging, there is a function that shows the parsed data vector. */
+
+#ifdef DEBUG_SHOW_PARSED
+fprintf(stderr, "+++ Pre-scan complete:\n");
+show_parsed(&cb);
+#endif
+
+/* For debugging capturing information this code can be enabled. */
+
+#ifdef DEBUG_SHOW_CAPTURES
+  {
+  named_group *ng = cb.named_groups;
+  fprintf(stderr, "+++Captures: %d\n", cb.bracount);
+  for (i = 0; i < cb.names_found; i++, ng++)
+    {
+    fprintf(stderr, "+++%3d %.*s\n", ng->number, ng->length, ng->name);
+    }
+  }
+#endif
+
+/* Pretend to compile the pattern while actually just accumulating the amount
+of memory required in the 'length' variable. This behaviour is triggered by
+passing a non-NULL final argument to compile_regex(). We pass a block of
+workspace (cworkspace) for it to compile parts of the pattern into; the
+compiled code is discarded when it is no longer needed, so hopefully this
+workspace will never overflow, though there is a test for its doing so.
+
+On error, errorcode will be set non-zero, so we don't need to look at the
+result of the function. The initial options have been put into the cb block,
+but we still have to pass a separate options variable (the first argument)
+because the options may change as the pattern is processed. */
+
+cb.erroroffset = patlen;   /* For any subsequent errors that do not set it */
+pptr = cb.parsed_pattern;
+code = cworkspace;
+*code = OP_BRA;
+
+(void)compile_regex(cb.external_options, &code, &pptr, &errorcode, 0, &firstcu,
+   &firstcuflags, &reqcu, &reqcuflags, NULL, &cb, &length);
+
+if (errorcode != 0) goto HAD_CB_ERROR;  /* Offset is in cb.erroroffset */
+
+/* This should be caught in compile_regex(), but just in case... */
+
+if (length > MAX_PATTERN_SIZE)
+  {
+  errorcode = ERR20;
+  goto HAD_CB_ERROR;
+  }
+
+/* Compute the size of, and then get and initialize, the data block for storing
+the compiled pattern and names table. Integer overflow should no longer be
+possible because nowadays we limit the maximum value of cb.names_found and
+cb.name_entry_size. */
+
+re_blocksize = sizeof(pcre2_real_code) +
+  CU2BYTES(length +
+  (PCRE2_SIZE)cb.names_found * (PCRE2_SIZE)cb.name_entry_size);
+re = (pcre2_real_code *)
+  ccontext->memctl.malloc(re_blocksize, ccontext->memctl.memory_data);
+if (re == NULL)
+  {
+  errorcode = ERR21;
+  goto HAD_CB_ERROR;
+  }
+
+/* The compiler may put padding at the end of the pcre2_real_code structure in
+order to round it up to a multiple of 4 or 8 bytes. This means that when a
+compiled pattern is copied (for example, when serialized) undefined bytes are
+read, and this annoys debuggers such as valgrind. To avoid this, we explicitly
+write to the last 8 bytes of the structure before setting the fields. */
+
+memset((char *)re + sizeof(pcre2_real_code) - 8, 0, 8);
+re->memctl = ccontext->memctl;
+re->tables = tables;
+re->executable_jit = NULL;
+memset(re->start_bitmap, 0, 32 * sizeof(uint8_t));
+re->blocksize = re_blocksize;
+re->magic_number = MAGIC_NUMBER;
+re->compile_options = options;
+re->overall_options = cb.external_options;
+re->extra_options = ccontext->extra_options;
+re->flags = PCRE2_CODE_UNIT_WIDTH/8 | cb.external_flags | setflags;
+re->limit_heap = limit_heap;
+re->limit_match = limit_match;
+re->limit_depth = limit_depth;
+re->first_codeunit = 0;
+re->last_codeunit = 0;
+re->bsr_convention = bsr;
+re->newline_convention = newline;
+re->max_lookbehind = 0;
+re->minlength = 0;
+re->top_bracket = 0;
+re->top_backref = 0;
+re->name_entry_size = cb.name_entry_size;
+re->name_count = cb.names_found;
+
+/* The basic block is immediately followed by the name table, and the compiled
+code follows after that. */
+
+codestart = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code)) +
+  re->name_entry_size * re->name_count;
+
+/* Update the compile data block for the actual compile. The starting points of
+the name/number translation table and of the code are passed around in the
+compile data block. The start/end pattern and initial options are already set
+from the pre-compile phase, as is the name_entry_size field. */
+
+cb.parens_depth = 0;
+cb.assert_depth = 0;
+cb.lastcapture = 0;
+cb.name_table = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code));
+cb.start_code = codestart;
+cb.req_varyopt = 0;
+cb.had_accept = FALSE;
+cb.had_pruneorskip = FALSE;
+cb.open_caps = NULL;
+
+/* If any named groups were found, create the name/number table from the list
+created in the pre-pass. */
+
+if (cb.names_found > 0)
+  {
+  named_group *ng = cb.named_groups;
+  for (i = 0; i < cb.names_found; i++, ng++)
+    add_name_to_table(&cb, ng->name, ng->length, ng->number, i);
+  }
+
+/* Set up a starting, non-extracting bracket, then compile the expression. On
+error, errorcode will be set non-zero, so we don't need to look at the result
+of the function here. */
+
+pptr = cb.parsed_pattern;
+code = (PCRE2_UCHAR *)codestart;
+*code = OP_BRA;
+regexrc = compile_regex(re->overall_options, &code, &pptr, &errorcode, 0,
+  &firstcu, &firstcuflags, &reqcu, &reqcuflags, NULL, &cb, NULL);
+if (regexrc < 0) re->flags |= PCRE2_MATCH_EMPTY;
+re->top_bracket = cb.bracount;
+re->top_backref = cb.top_backref;
+re->max_lookbehind = cb.max_lookbehind;
+
+if (cb.had_accept)
+  {
+  reqcu = 0;                     /* Must disable after (*ACCEPT) */
+  reqcuflags = REQ_NONE;
+  re->flags |= PCRE2_HASACCEPT;  /* Disables minimum length */
+  }
+
+/* Fill in the final opcode and check for disastrous overflow. If no overflow,
+but the estimated length exceeds the really used length, adjust the value of
+re->blocksize, and if valgrind support is configured, mark the extra allocated
+memory as unaddressable, so that any out-of-bound reads can be detected. */
+
+*code++ = OP_END;
+usedlength = code - codestart;
+if (usedlength > length) errorcode = ERR23; else
+  {
+  re->blocksize -= CU2BYTES(length - usedlength);
+#ifdef SUPPORT_VALGRIND
+  VALGRIND_MAKE_MEM_NOACCESS(code, CU2BYTES(length - usedlength));
+#endif
+  }
+
+/* Scan the pattern for recursion/subroutine calls and convert the group
+numbers into offsets. Maintain a small cache so that repeated groups containing
+recursions are efficiently handled. */
+
+#define RSCAN_CACHE_SIZE 8
+
+if (errorcode == 0 && cb.had_recurse)
+  {
+  PCRE2_UCHAR *rcode;
+  PCRE2_SPTR rgroup;
+  unsigned int ccount = 0;
+  int start = RSCAN_CACHE_SIZE;
+  recurse_cache rc[RSCAN_CACHE_SIZE];
+
+  for (rcode = (PCRE2_UCHAR *)find_recurse(codestart, utf);
+       rcode != NULL;
+       rcode = (PCRE2_UCHAR *)find_recurse(rcode + 1 + LINK_SIZE, utf))
+    {
+    int p, groupnumber;
+
+    groupnumber = (int)GET(rcode, 1);
+    if (groupnumber == 0) rgroup = codestart; else
+      {
+      PCRE2_SPTR search_from = codestart;
+      rgroup = NULL;
+      for (i = 0, p = start; i < ccount; i++, p = (p + 1) & 7)
+        {
+        if (groupnumber == rc[p].groupnumber)
+          {
+          rgroup = rc[p].group;
+          break;
+          }
+
+        /* Group n+1 must always start to the right of group n, so we can save
+        search time below when the new group number is greater than any of the
+        previously found groups. */
+
+        if (groupnumber > rc[p].groupnumber) search_from = rc[p].group;
+        }
+
+      if (rgroup == NULL)
+        {
+        rgroup = PRIV(find_bracket)(search_from, utf, groupnumber);
+        if (rgroup == NULL)
+          {
+          errorcode = ERR53;
+          break;
+          }
+        if (--start < 0) start = RSCAN_CACHE_SIZE - 1;
+        rc[start].groupnumber = groupnumber;
+        rc[start].group = rgroup;
+        if (ccount < RSCAN_CACHE_SIZE) ccount++;
+        }
+      }
+
+    PUT(rcode, 1, rgroup - codestart);
+    }
+  }
+
+/* In rare debugging situations we sometimes need to look at the compiled code
+at this stage. */
+
+#ifdef DEBUG_CALL_PRINTINT
+pcre2_printint(re, stderr, TRUE);
+fprintf(stderr, "Length=%lu Used=%lu\n", length, usedlength);
+#endif
+
+/* Unless disabled, check whether any single character iterators can be
+auto-possessified. The function overwrites the appropriate opcode values, so
+the type of the pointer must be cast. NOTE: the intermediate variable "temp" is
+used in this code because at least one compiler gives a warning about loss of
+"const" attribute if the cast (PCRE2_UCHAR *)codestart is used directly in the
+function call. */
+
+if (errorcode == 0 && (re->overall_options & PCRE2_NO_AUTO_POSSESS) == 0)
+  {
+  PCRE2_UCHAR *temp = (PCRE2_UCHAR *)codestart;
+  if (PRIV(auto_possessify)(temp, &cb) != 0) errorcode = ERR80;
+  }
+
+/* Failed to compile, or error while post-processing. */
+
+if (errorcode != 0) goto HAD_CB_ERROR;
+
+/* Successful compile. If the anchored option was not passed, set it if
+we can determine that the pattern is anchored by virtue of ^ characters or \A
+or anything else, such as starting with non-atomic .* when DOTALL is set and
+there are no occurrences of *PRUNE or *SKIP (though there is an option to
+disable this case). */
+
+if ((re->overall_options & PCRE2_ANCHORED) == 0 &&
+     is_anchored(codestart, 0, &cb, 0, FALSE))
+  re->overall_options |= PCRE2_ANCHORED;
+
+/* Set up the first code unit or startline flag, the required code unit, and
+then study the pattern. This code need not be obeyed if PCRE2_NO_START_OPTIMIZE
+is set, as the data it would create will not be used. Note that a first code
+unit (but not the startline flag) is useful for anchored patterns because it
+can still give a quick "no match" and also avoid searching for a last code
+unit. */
+
+if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0)
+  {
+  int minminlength = 0;  /* For minimal minlength from first/required CU */
+
+  /* If we do not have a first code unit, see if there is one that is asserted
+  (these are not saved during the compile because they can cause conflicts with
+  actual literals that follow). */
+
+  if (firstcuflags < 0)
+    firstcu = find_firstassertedcu(codestart, &firstcuflags, 0);
+
+  /* Save the data for a first code unit. The existence of one means the
+  minimum length must be at least 1. */
+
+  if (firstcuflags >= 0)
+    {
+    re->first_codeunit = firstcu;
+    re->flags |= PCRE2_FIRSTSET;
+    minminlength++;
+
+    /* Handle caseless first code units. */
+
+    if ((firstcuflags & REQ_CASELESS) != 0)
+      {
+      if (firstcu < 128 || (!utf && !ucp && firstcu < 255))
+        {
+        if (cb.fcc[firstcu] != firstcu) re->flags |= PCRE2_FIRSTCASELESS;
+        }
+
+      /* The first code unit is > 128 in UTF or UCP mode, or > 255 otherwise.
+      In 8-bit UTF mode, codepoints in the range 128-255 are introductory code
+      points and cannot have another case, but if UCP is set they may do. */
+
+#ifdef SUPPORT_UNICODE
+#if PCRE2_CODE_UNIT_WIDTH == 8
+      else if (ucp && !utf && UCD_OTHERCASE(firstcu) != firstcu)
+        re->flags |= PCRE2_FIRSTCASELESS;
+#else
+      else if ((utf || ucp) && firstcu <= MAX_UTF_CODE_POINT &&
+               UCD_OTHERCASE(firstcu) != firstcu)
+        re->flags |= PCRE2_FIRSTCASELESS;
+#endif
+#endif  /* SUPPORT_UNICODE */
+      }
+    }
+
+  /* When there is no first code unit, for non-anchored patterns, see if we can
+  set the PCRE2_STARTLINE flag. This is helpful for multiline matches when all
+  branches start with ^ and also when all branches start with non-atomic .* for
+  non-DOTALL matches when *PRUNE and SKIP are not present. (There is an option
+  that disables this case.) */
+
+  else if ((re->overall_options & PCRE2_ANCHORED) == 0 &&
+           is_startline(codestart, 0, &cb, 0, FALSE))
+    re->flags |= PCRE2_STARTLINE;
+
+  /* Handle the "required code unit", if one is set. In the UTF case we can
+  increment the minimum minimum length only if we are sure this really is a
+  different character and not a non-starting code unit of the first character,
+  because the minimum length count is in characters, not code units. */
+
+  if (reqcuflags >= 0)
+    {
+#if PCRE2_CODE_UNIT_WIDTH == 16
+    if ((re->overall_options & PCRE2_UTF) == 0 ||   /* Not UTF */
+        firstcuflags < 0 ||                         /* First not set */
+        (firstcu & 0xf800) != 0xd800 ||             /* First not surrogate */
+        (reqcu & 0xfc00) != 0xdc00)                 /* Req not low surrogate */
+#elif PCRE2_CODE_UNIT_WIDTH == 8
+    if ((re->overall_options & PCRE2_UTF) == 0 ||   /* Not UTF */
+        firstcuflags < 0 ||                         /* First not set */
+        (firstcu & 0x80) == 0 ||                    /* First is ASCII */
+        (reqcu & 0x80) == 0)                        /* Req is ASCII */
+#endif
+      {
+      minminlength++;
+      }
+
+    /* In the case of an anchored pattern, set up the value only if it follows
+    a variable length item in the pattern. */
+
+    if ((re->overall_options & PCRE2_ANCHORED) == 0 ||
+        (reqcuflags & REQ_VARY) != 0)
+      {
+      re->last_codeunit = reqcu;
+      re->flags |= PCRE2_LASTSET;
+
+      /* Handle caseless required code units as for first code units (above). */
+
+      if ((reqcuflags & REQ_CASELESS) != 0)
+        {
+        if (reqcu < 128 || (!utf && !ucp && reqcu < 255))
+          {
+          if (cb.fcc[reqcu] != reqcu) re->flags |= PCRE2_LASTCASELESS;
+          }
+#ifdef SUPPORT_UNICODE
+#if PCRE2_CODE_UNIT_WIDTH == 8
+      else if (ucp && !utf && UCD_OTHERCASE(reqcu) != reqcu)
+        re->flags |= PCRE2_LASTCASELESS;
+#else
+      else if ((utf || ucp) && reqcu <= MAX_UTF_CODE_POINT &&
+               UCD_OTHERCASE(reqcu) != reqcu)
+        re->flags |= PCRE2_LASTCASELESS;
+#endif
+#endif  /* SUPPORT_UNICODE */
+        }
+      }
+    }
+
+  /* Study the compiled pattern to set up information such as a bitmap of
+  starting code units and a minimum matching length. */
+
+  if (PRIV(study)(re) != 0)
+    {
+    errorcode = ERR31;
+    goto HAD_CB_ERROR;
+    }
+
+  /* If study() set a bitmap of starting code units, it implies a minimum
+  length of at least one. */
+
+  if ((re->flags & PCRE2_FIRSTMAPSET) != 0 && minminlength == 0)
+    minminlength = 1;
+
+  /* If the minimum length set (or not set) by study() is less than the minimum
+  implied by required code units, override it. */
+
+  if (re->minlength < minminlength) re->minlength = minminlength;
+  }   /* End of start-of-match optimizations. */
+
+/* Control ends up here in all cases. When running under valgrind, make a
+pattern's terminating zero defined again. If memory was obtained for the parsed
+version of the pattern, free it before returning. Also free the list of named
+groups if a larger one had to be obtained, and likewise the group information
+vector. */
+
+EXIT:
+#ifdef SUPPORT_VALGRIND
+if (zero_terminated) VALGRIND_MAKE_MEM_DEFINED(pattern + patlen, CU2BYTES(1));
+#endif
+if (cb.parsed_pattern != stack_parsed_pattern)
+  ccontext->memctl.free(cb.parsed_pattern, ccontext->memctl.memory_data);
+if (cb.named_group_list_size > NAMED_GROUP_LIST_SIZE)
+  ccontext->memctl.free((void *)cb.named_groups, ccontext->memctl.memory_data);
+if (cb.groupinfo != stack_groupinfo)
+  ccontext->memctl.free((void *)cb.groupinfo, ccontext->memctl.memory_data);
+return re;    /* Will be NULL after an error */
+
+/* Errors discovered in parse_regex() set the offset value in the compile
+block. Errors discovered before it is called must compute it from the ptr
+value. After parse_regex() is called, the offset in the compile block is set to
+the end of the pattern, but certain errors in compile_regex() may reset it if
+an offset is available in the parsed pattern. */
+
+HAD_CB_ERROR:
+ptr = pattern + cb.erroroffset;
+
+HAD_EARLY_ERROR:
+*erroroffset = ptr - pattern;
+
+HAD_ERROR:
+*errorptr = errorcode;
+pcre2_code_free(re);
+re = NULL;
+goto EXIT;
+}
+
+/* End of pcre2_compile.c */
diff --git a/src/c/pcre2/src/pcre2_config.c b/src/c/pcre2/src/pcre2_config.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_config.c
@@ -0,0 +1,252 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2020 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* Save the configured link size, which is in bytes. In 16-bit and 32-bit modes
+its value gets changed by pcre2_intmodedep.h (included by pcre2_internal.h) to
+be in code units. */
+
+static int configured_link_size = LINK_SIZE;
+
+#include "pcre2_internal.h"
+
+/* These macros are the standard way of turning unquoted text into C strings.
+They allow macros like PCRE2_MAJOR to be defined without quotes, which is
+convenient for user programs that want to test their values. */
+
+#define STRING(a)  # a
+#define XSTRING(s) STRING(s)
+
+
+/*************************************************
+* Return info about what features are configured *
+*************************************************/
+
+/* If where is NULL, the length of memory required is returned.
+
+Arguments:
+  what             what information is required
+  where            where to put the information
+
+Returns:           0 if a numerical value is returned
+                   >= 0 if a string value
+                   PCRE2_ERROR_BADOPTION if "where" not recognized
+                     or JIT target requested when JIT not enabled
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_config(uint32_t what, void *where)
+{
+if (where == NULL)  /* Requests a length */
+  {
+  switch(what)
+    {
+    default:
+    return PCRE2_ERROR_BADOPTION;
+
+    case PCRE2_CONFIG_BSR:
+    case PCRE2_CONFIG_COMPILED_WIDTHS:
+    case PCRE2_CONFIG_DEPTHLIMIT:
+    case PCRE2_CONFIG_HEAPLIMIT:
+    case PCRE2_CONFIG_JIT:
+    case PCRE2_CONFIG_LINKSIZE:
+    case PCRE2_CONFIG_MATCHLIMIT:
+    case PCRE2_CONFIG_NEVER_BACKSLASH_C:
+    case PCRE2_CONFIG_NEWLINE:
+    case PCRE2_CONFIG_PARENSLIMIT:
+    case PCRE2_CONFIG_STACKRECURSE:    /* Obsolete */
+    case PCRE2_CONFIG_TABLES_LENGTH:
+    case PCRE2_CONFIG_UNICODE:
+    return sizeof(uint32_t);
+
+    /* These are handled below */
+
+    case PCRE2_CONFIG_JITTARGET:
+    case PCRE2_CONFIG_UNICODE_VERSION:
+    case PCRE2_CONFIG_VERSION:
+    break;
+    }
+  }
+
+switch (what)
+  {
+  default:
+  return PCRE2_ERROR_BADOPTION;
+
+  case PCRE2_CONFIG_BSR:
+#ifdef BSR_ANYCRLF
+  *((uint32_t *)where) = PCRE2_BSR_ANYCRLF;
+#else
+  *((uint32_t *)where) = PCRE2_BSR_UNICODE;
+#endif
+  break;
+
+  case PCRE2_CONFIG_COMPILED_WIDTHS:
+  *((uint32_t *)where) = 0
+#ifdef SUPPORT_PCRE2_8
+  + 1
+#endif
+#ifdef SUPPORT_PCRE2_16
+  + 2
+#endif
+#ifdef SUPPORT_PCRE2_32
+  + 4
+#endif
+  ;
+  break;
+
+  case PCRE2_CONFIG_DEPTHLIMIT:
+  *((uint32_t *)where) = MATCH_LIMIT_DEPTH;
+  break;
+
+  case PCRE2_CONFIG_HEAPLIMIT:
+  *((uint32_t *)where) = HEAP_LIMIT;
+  break;
+
+  case PCRE2_CONFIG_JIT:
+#ifdef SUPPORT_JIT
+  *((uint32_t *)where) = 1;
+#else
+  *((uint32_t *)where) = 0;
+#endif
+  break;
+
+  case PCRE2_CONFIG_JITTARGET:
+#ifdef SUPPORT_JIT
+    {
+    const char *v = PRIV(jit_get_target)();
+    return (int)(1 + ((where == NULL)?
+      strlen(v) : PRIV(strcpy_c8)((PCRE2_UCHAR *)where, v)));
+    }
+#else
+  return PCRE2_ERROR_BADOPTION;
+#endif
+
+  case PCRE2_CONFIG_LINKSIZE:
+  *((uint32_t *)where) = (uint32_t)configured_link_size;
+  break;
+
+  case PCRE2_CONFIG_MATCHLIMIT:
+  *((uint32_t *)where) = MATCH_LIMIT;
+  break;
+
+  case PCRE2_CONFIG_NEWLINE:
+  *((uint32_t *)where) = NEWLINE_DEFAULT;
+  break;
+
+  case PCRE2_CONFIG_NEVER_BACKSLASH_C:
+#ifdef NEVER_BACKSLASH_C
+  *((uint32_t *)where) = 1;
+#else
+  *((uint32_t *)where) = 0;
+#endif
+  break;
+
+  case PCRE2_CONFIG_PARENSLIMIT:
+  *((uint32_t *)where) = PARENS_NEST_LIMIT;
+  break;
+
+  /* This is now obsolete. The stack is no longer used via recursion for
+  handling backtracking in pcre2_match(). */
+
+  case PCRE2_CONFIG_STACKRECURSE:
+  *((uint32_t *)where) = 0;
+  break;
+
+  case PCRE2_CONFIG_TABLES_LENGTH:
+  *((uint32_t *)where) = TABLES_LENGTH;
+  break;
+
+  case PCRE2_CONFIG_UNICODE_VERSION:
+    {
+#if defined SUPPORT_UNICODE
+    const char *v = PRIV(unicode_version);
+#else
+    const char *v = "Unicode not supported";
+#endif
+    return (int)(1 + ((where == NULL)?
+      strlen(v) : PRIV(strcpy_c8)((PCRE2_UCHAR *)where, v)));
+   }
+  break;
+
+  case PCRE2_CONFIG_UNICODE:
+#if defined SUPPORT_UNICODE
+  *((uint32_t *)where) = 1;
+#else
+  *((uint32_t *)where) = 0;
+#endif
+  break;
+
+  /* The hackery in setting "v" below is to cope with the case when
+  PCRE2_PRERELEASE is set to an empty string (which it is for real releases).
+  If the second alternative is used in this case, it does not leave a space
+  before the date. On the other hand, if all four macros are put into a single
+  XSTRING when PCRE2_PRERELEASE is not empty, an unwanted space is inserted.
+  There are problems using an "obvious" approach like this:
+
+     XSTRING(PCRE2_MAJOR) "." XSTRING(PCRE_MINOR)
+     XSTRING(PCRE2_PRERELEASE) " " XSTRING(PCRE_DATE)
+
+  because, when PCRE2_PRERELEASE is empty, this leads to an attempted expansion
+  of STRING(). The C standard states: "If (before argument substitution) any
+  argument consists of no preprocessing tokens, the behavior is undefined." It
+  turns out the gcc treats this case as a single empty string - which is what
+  we really want - but Visual C grumbles about the lack of an argument for the
+  macro. Unfortunately, both are within their rights. As there seems to be no
+  way to test for a macro's value being empty at compile time, we have to
+  resort to a runtime test. */
+
+  case PCRE2_CONFIG_VERSION:
+    {
+    const char *v = (XSTRING(Z PCRE2_PRERELEASE)[1] == 0)?
+      XSTRING(PCRE2_MAJOR.PCRE2_MINOR PCRE2_DATE) :
+      XSTRING(PCRE2_MAJOR.PCRE2_MINOR) XSTRING(PCRE2_PRERELEASE PCRE2_DATE);
+    return (int)(1 + ((where == NULL)?
+      strlen(v) : PRIV(strcpy_c8)((PCRE2_UCHAR *)where, v)));
+    }
+  }
+
+return 0;
+}
+
+/* End of pcre2_config.c */
diff --git a/src/c/pcre2/src/pcre2_context.c b/src/c/pcre2/src/pcre2_context.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_context.c
@@ -0,0 +1,488 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+
+/*************************************************
+*          Default malloc/free functions         *
+*************************************************/
+
+/* Ignore the "user data" argument in each case. */
+
+static void *default_malloc(size_t size, void *data)
+{
+(void)data;
+return malloc(size);
+}
+
+
+static void default_free(void *block, void *data)
+{
+(void)data;
+free(block);
+}
+
+
+
+/*************************************************
+*        Get a block and save memory control     *
+*************************************************/
+
+/* This internal function is called to get a block of memory in which the
+memory control data is to be stored at the start for future use.
+
+Arguments:
+  size        amount of memory required
+  memctl      pointer to a memctl block or NULL
+
+Returns:      pointer to memory or NULL on failure
+*/
+
+extern void *
+PRIV(memctl_malloc)(size_t size, pcre2_memctl *memctl)
+{
+pcre2_memctl *newmemctl;
+void *yield = (memctl == NULL)? malloc(size) :
+  memctl->malloc(size, memctl->memory_data);
+if (yield == NULL) return NULL;
+newmemctl = (pcre2_memctl *)yield;
+if (memctl == NULL)
+  {
+  newmemctl->malloc = default_malloc;
+  newmemctl->free = default_free;
+  newmemctl->memory_data = NULL;
+  }
+else *newmemctl = *memctl;
+return yield;
+}
+
+
+
+/*************************************************
+*          Create and initialize contexts        *
+*************************************************/
+
+/* Initializing for compile and match contexts is done in separate, private
+functions so that these can be called from functions such as pcre2_compile()
+when an external context is not supplied. The initializing functions have an
+option to set up default memory management. */
+
+PCRE2_EXP_DEFN pcre2_general_context * PCRE2_CALL_CONVENTION
+pcre2_general_context_create(void *(*private_malloc)(size_t, void *),
+  void (*private_free)(void *, void *), void *memory_data)
+{
+pcre2_general_context *gcontext;
+if (private_malloc == NULL) private_malloc = default_malloc;
+if (private_free == NULL) private_free = default_free;
+gcontext = private_malloc(sizeof(pcre2_real_general_context), memory_data);
+if (gcontext == NULL) return NULL;
+gcontext->memctl.malloc = private_malloc;
+gcontext->memctl.free = private_free;
+gcontext->memctl.memory_data = memory_data;
+return gcontext;
+}
+
+
+/* A default compile context is set up to save having to initialize at run time
+when no context is supplied to the compile function. */
+
+const pcre2_compile_context PRIV(default_compile_context) = {
+  { default_malloc, default_free, NULL },    /* Default memory handling */
+  NULL,                                      /* Stack guard */
+  NULL,                                      /* Stack guard data */
+  PRIV(default_tables),                      /* Character tables */
+  PCRE2_UNSET,                               /* Max pattern length */
+  BSR_DEFAULT,                               /* Backslash R default */
+  NEWLINE_DEFAULT,                           /* Newline convention */
+  PARENS_NEST_LIMIT,                         /* As it says */
+  0 };                                       /* Extra options */
+
+/* The create function copies the default into the new memory, but must
+override the default memory handling functions if a gcontext was provided. */
+
+PCRE2_EXP_DEFN pcre2_compile_context * PCRE2_CALL_CONVENTION
+pcre2_compile_context_create(pcre2_general_context *gcontext)
+{
+pcre2_compile_context *ccontext = PRIV(memctl_malloc)(
+  sizeof(pcre2_real_compile_context), (pcre2_memctl *)gcontext);
+if (ccontext == NULL) return NULL;
+*ccontext = PRIV(default_compile_context);
+if (gcontext != NULL)
+  *((pcre2_memctl *)ccontext) = *((pcre2_memctl *)gcontext);
+return ccontext;
+}
+
+
+/* A default match context is set up to save having to initialize at run time
+when no context is supplied to a match function. */
+
+const pcre2_match_context PRIV(default_match_context) = {
+  { default_malloc, default_free, NULL },
+#ifdef SUPPORT_JIT
+  NULL,          /* JIT callback */
+  NULL,          /* JIT callback data */
+#endif
+  NULL,          /* Callout function */
+  NULL,          /* Callout data */
+  NULL,          /* Substitute callout function */
+  NULL,          /* Substitute callout data */
+  PCRE2_UNSET,   /* Offset limit */
+  HEAP_LIMIT,
+  MATCH_LIMIT,
+  MATCH_LIMIT_DEPTH };
+
+/* The create function copies the default into the new memory, but must
+override the default memory handling functions if a gcontext was provided. */
+
+PCRE2_EXP_DEFN pcre2_match_context * PCRE2_CALL_CONVENTION
+pcre2_match_context_create(pcre2_general_context *gcontext)
+{
+pcre2_match_context *mcontext = PRIV(memctl_malloc)(
+  sizeof(pcre2_real_match_context), (pcre2_memctl *)gcontext);
+if (mcontext == NULL) return NULL;
+*mcontext = PRIV(default_match_context);
+if (gcontext != NULL)
+  *((pcre2_memctl *)mcontext) = *((pcre2_memctl *)gcontext);
+return mcontext;
+}
+
+
+/* A default convert context is set up to save having to initialize at run time
+when no context is supplied to the convert function. */
+
+const pcre2_convert_context PRIV(default_convert_context) = {
+  { default_malloc, default_free, NULL },    /* Default memory handling */
+#ifdef _WIN32
+  CHAR_BACKSLASH,                            /* Default path separator */
+  CHAR_GRAVE_ACCENT                          /* Default escape character */
+#else  /* Not Windows */
+  CHAR_SLASH,                                /* Default path separator */
+  CHAR_BACKSLASH                             /* Default escape character */
+#endif
+  };
+
+/* The create function copies the default into the new memory, but must
+override the default memory handling functions if a gcontext was provided. */
+
+PCRE2_EXP_DEFN pcre2_convert_context * PCRE2_CALL_CONVENTION
+pcre2_convert_context_create(pcre2_general_context *gcontext)
+{
+pcre2_convert_context *ccontext = PRIV(memctl_malloc)(
+  sizeof(pcre2_real_convert_context), (pcre2_memctl *)gcontext);
+if (ccontext == NULL) return NULL;
+*ccontext = PRIV(default_convert_context);
+if (gcontext != NULL)
+  *((pcre2_memctl *)ccontext) = *((pcre2_memctl *)gcontext);
+return ccontext;
+}
+
+
+/*************************************************
+*              Context copy functions            *
+*************************************************/
+
+PCRE2_EXP_DEFN pcre2_general_context * PCRE2_CALL_CONVENTION
+pcre2_general_context_copy(pcre2_general_context *gcontext)
+{
+pcre2_general_context *new =
+  gcontext->memctl.malloc(sizeof(pcre2_real_general_context),
+  gcontext->memctl.memory_data);
+if (new == NULL) return NULL;
+memcpy(new, gcontext, sizeof(pcre2_real_general_context));
+return new;
+}
+
+
+PCRE2_EXP_DEFN pcre2_compile_context * PCRE2_CALL_CONVENTION
+pcre2_compile_context_copy(pcre2_compile_context *ccontext)
+{
+pcre2_compile_context *new =
+  ccontext->memctl.malloc(sizeof(pcre2_real_compile_context),
+  ccontext->memctl.memory_data);
+if (new == NULL) return NULL;
+memcpy(new, ccontext, sizeof(pcre2_real_compile_context));
+return new;
+}
+
+
+PCRE2_EXP_DEFN pcre2_match_context * PCRE2_CALL_CONVENTION
+pcre2_match_context_copy(pcre2_match_context *mcontext)
+{
+pcre2_match_context *new =
+  mcontext->memctl.malloc(sizeof(pcre2_real_match_context),
+  mcontext->memctl.memory_data);
+if (new == NULL) return NULL;
+memcpy(new, mcontext, sizeof(pcre2_real_match_context));
+return new;
+}
+
+
+
+PCRE2_EXP_DEFN pcre2_convert_context * PCRE2_CALL_CONVENTION
+pcre2_convert_context_copy(pcre2_convert_context *ccontext)
+{
+pcre2_convert_context *new =
+  ccontext->memctl.malloc(sizeof(pcre2_real_convert_context),
+  ccontext->memctl.memory_data);
+if (new == NULL) return NULL;
+memcpy(new, ccontext, sizeof(pcre2_real_convert_context));
+return new;
+}
+
+
+/*************************************************
+*              Context free functions            *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_general_context_free(pcre2_general_context *gcontext)
+{
+if (gcontext != NULL)
+  gcontext->memctl.free(gcontext, gcontext->memctl.memory_data);
+}
+
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_compile_context_free(pcre2_compile_context *ccontext)
+{
+if (ccontext != NULL)
+  ccontext->memctl.free(ccontext, ccontext->memctl.memory_data);
+}
+
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_match_context_free(pcre2_match_context *mcontext)
+{
+if (mcontext != NULL)
+  mcontext->memctl.free(mcontext, mcontext->memctl.memory_data);
+}
+
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_convert_context_free(pcre2_convert_context *ccontext)
+{
+if (ccontext != NULL)
+  ccontext->memctl.free(ccontext, ccontext->memctl.memory_data);
+}
+
+
+/*************************************************
+*             Set values in contexts             *
+*************************************************/
+
+/* All these functions return 0 for success or PCRE2_ERROR_BADDATA if invalid
+data is given. Only some of the functions are able to test the validity of the
+data. */
+
+
+/* ------------ Compile context ------------ */
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_character_tables(pcre2_compile_context *ccontext,
+  const uint8_t *tables)
+{
+ccontext->tables = tables;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_bsr(pcre2_compile_context *ccontext, uint32_t value)
+{
+switch(value)
+  {
+  case PCRE2_BSR_ANYCRLF:
+  case PCRE2_BSR_UNICODE:
+  ccontext->bsr_convention = value;
+  return 0;
+
+  default:
+  return PCRE2_ERROR_BADDATA;
+  }
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_max_pattern_length(pcre2_compile_context *ccontext, PCRE2_SIZE length)
+{
+ccontext->max_pattern_length = length;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_newline(pcre2_compile_context *ccontext, uint32_t newline)
+{
+switch(newline)
+  {
+  case PCRE2_NEWLINE_CR:
+  case PCRE2_NEWLINE_LF:
+  case PCRE2_NEWLINE_CRLF:
+  case PCRE2_NEWLINE_ANY:
+  case PCRE2_NEWLINE_ANYCRLF:
+  case PCRE2_NEWLINE_NUL:
+  ccontext->newline_convention = newline;
+  return 0;
+
+  default:
+  return PCRE2_ERROR_BADDATA;
+  }
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_parens_nest_limit(pcre2_compile_context *ccontext, uint32_t limit)
+{
+ccontext->parens_nest_limit = limit;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_compile_extra_options(pcre2_compile_context *ccontext, uint32_t options)
+{
+ccontext->extra_options = options;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_compile_recursion_guard(pcre2_compile_context *ccontext,
+  int (*guard)(uint32_t, void *), void *user_data)
+{
+ccontext->stack_guard = guard;
+ccontext->stack_guard_data = user_data;
+return 0;
+}
+
+
+/* ------------ Match context ------------ */
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_callout(pcre2_match_context *mcontext,
+  int (*callout)(pcre2_callout_block *, void *), void *callout_data)
+{
+mcontext->callout = callout;
+mcontext->callout_data = callout_data;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_substitute_callout(pcre2_match_context *mcontext,
+  int (*substitute_callout)(pcre2_substitute_callout_block *, void *),
+    void *substitute_callout_data)
+{
+mcontext->substitute_callout = substitute_callout;
+mcontext->substitute_callout_data = substitute_callout_data;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_heap_limit(pcre2_match_context *mcontext, uint32_t limit)
+{
+mcontext->heap_limit = limit;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_match_limit(pcre2_match_context *mcontext, uint32_t limit)
+{
+mcontext->match_limit = limit;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_depth_limit(pcre2_match_context *mcontext, uint32_t limit)
+{
+mcontext->depth_limit = limit;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_offset_limit(pcre2_match_context *mcontext, PCRE2_SIZE limit)
+{
+mcontext->offset_limit = limit;
+return 0;
+}
+
+/* This function became obsolete at release 10.30. It is kept as a synonym for
+backwards compatibility. */
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_recursion_limit(pcre2_match_context *mcontext, uint32_t limit)
+{
+return pcre2_set_depth_limit(mcontext, limit);
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_recursion_memory_management(pcre2_match_context *mcontext,
+  void *(*mymalloc)(size_t, void *), void (*myfree)(void *, void *),
+  void *mydata)
+{
+(void)mcontext;
+(void)mymalloc;
+(void)myfree;
+(void)mydata;
+return 0;
+}
+
+/* ------------ Convert context ------------ */
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_glob_separator(pcre2_convert_context *ccontext, uint32_t separator)
+{
+if (separator != CHAR_SLASH && separator != CHAR_BACKSLASH &&
+    separator != CHAR_DOT) return PCRE2_ERROR_BADDATA;
+ccontext->glob_separator = separator;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_glob_escape(pcre2_convert_context *ccontext, uint32_t escape)
+{
+if (escape > 255 || (escape != 0 && !ispunct(escape)))
+  return PCRE2_ERROR_BADDATA;
+ccontext->glob_escape = escape;
+return 0;
+}
+
+/* End of pcre2_context.c */
+
diff --git a/src/c/pcre2/src/pcre2_convert.c b/src/c/pcre2/src/pcre2_convert.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_convert.c
@@ -0,0 +1,1182 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+#define TYPE_OPTIONS (PCRE2_CONVERT_GLOB| \
+  PCRE2_CONVERT_POSIX_BASIC|PCRE2_CONVERT_POSIX_EXTENDED)
+
+#define ALL_OPTIONS (PCRE2_CONVERT_UTF|PCRE2_CONVERT_NO_UTF_CHECK| \
+  PCRE2_CONVERT_GLOB_NO_WILD_SEPARATOR| \
+  PCRE2_CONVERT_GLOB_NO_STARSTAR| \
+  TYPE_OPTIONS)
+
+#define DUMMY_BUFFER_SIZE 100
+
+/* Generated pattern fragments */
+
+#define STR_BACKSLASH_A STR_BACKSLASH STR_A
+#define STR_BACKSLASH_z STR_BACKSLASH STR_z
+#define STR_COLON_RIGHT_SQUARE_BRACKET STR_COLON STR_RIGHT_SQUARE_BRACKET
+#define STR_DOT_STAR_LOOKBEHIND STR_DOT STR_ASTERISK STR_LEFT_PARENTHESIS STR_QUESTION_MARK STR_LESS_THAN_SIGN STR_EQUALS_SIGN
+#define STR_LOOKAHEAD_NOT_DOT STR_LEFT_PARENTHESIS STR_QUESTION_MARK STR_EXCLAMATION_MARK STR_BACKSLASH STR_DOT STR_RIGHT_PARENTHESIS
+#define STR_QUERY_s STR_LEFT_PARENTHESIS STR_QUESTION_MARK STR_s STR_RIGHT_PARENTHESIS
+#define STR_STAR_NUL STR_LEFT_PARENTHESIS STR_ASTERISK STR_N STR_U STR_L STR_RIGHT_PARENTHESIS
+
+/* States for range and POSIX processing */
+
+enum { RANGE_NOT_STARTED, RANGE_STARTING, RANGE_STARTED };
+enum { POSIX_START_REGEX, POSIX_ANCHORED, POSIX_NOT_BRACKET,
+       POSIX_CLASS_NOT_STARTED, POSIX_CLASS_STARTING, POSIX_CLASS_STARTED };
+
+/* Macro to add a character string to the output buffer, checking for overflow. */
+
+#define PUTCHARS(string) \
+  { \
+  for (s = (char *)(string); *s != 0; s++) \
+    { \
+    if (p >= endp) return PCRE2_ERROR_NOMEMORY; \
+    *p++ = *s; \
+    } \
+  }
+
+/* Literals that must be escaped: \ ? * + | . ^ $ { } [ ] ( ) */
+
+static const char *pcre2_escaped_literals =
+  STR_BACKSLASH STR_QUESTION_MARK STR_ASTERISK STR_PLUS
+  STR_VERTICAL_LINE STR_DOT STR_CIRCUMFLEX_ACCENT STR_DOLLAR_SIGN
+  STR_LEFT_CURLY_BRACKET STR_RIGHT_CURLY_BRACKET
+  STR_LEFT_SQUARE_BRACKET STR_RIGHT_SQUARE_BRACKET
+  STR_LEFT_PARENTHESIS STR_RIGHT_PARENTHESIS;
+
+/* Recognized escaped metacharacters in POSIX basic patterns. */
+
+static const char *posix_meta_escapes =
+  STR_LEFT_PARENTHESIS STR_RIGHT_PARENTHESIS
+  STR_LEFT_CURLY_BRACKET STR_RIGHT_CURLY_BRACKET
+  STR_1 STR_2 STR_3 STR_4 STR_5 STR_6 STR_7 STR_8 STR_9;
+
+
+
+/*************************************************
+*           Convert a POSIX pattern              *
+*************************************************/
+
+/* This function handles both basic and extended POSIX patterns.
+
+Arguments:
+  pattype        the pattern type
+  pattern        the pattern
+  plength        length in code units
+  utf            TRUE if UTF
+  use_buffer     where to put the output
+  use_length     length of use_buffer
+  bufflenptr     where to put the used length
+  dummyrun       TRUE if a dummy run
+  ccontext       the convert context
+
+Returns:         0 => success
+                !0 => error code
+*/
+
+static int
+convert_posix(uint32_t pattype, PCRE2_SPTR pattern, PCRE2_SIZE plength,
+  BOOL utf, PCRE2_UCHAR *use_buffer, PCRE2_SIZE use_length,
+  PCRE2_SIZE *bufflenptr, BOOL dummyrun, pcre2_convert_context *ccontext)
+{
+char *s;
+PCRE2_SPTR posix = pattern;
+PCRE2_UCHAR *p = use_buffer;
+PCRE2_UCHAR *pp = p;
+PCRE2_UCHAR *endp = p + use_length - 1;  /* Allow for trailing zero */
+PCRE2_SIZE convlength = 0;
+
+uint32_t bracount = 0;
+uint32_t posix_state = POSIX_START_REGEX;
+uint32_t lastspecial = 0;
+BOOL extended = (pattype & PCRE2_CONVERT_POSIX_EXTENDED) != 0;
+BOOL nextisliteral = FALSE;
+
+(void)utf;       /* Not used when Unicode not supported */
+(void)ccontext;  /* Not currently used */
+
+/* Initialize default for error offset as end of input. */
+
+*bufflenptr = plength;
+PUTCHARS(STR_STAR_NUL);
+
+/* Now scan the input. */
+
+while (plength > 0)
+  {
+  uint32_t c, sc;
+  int clength = 1;
+
+  /* Add in the length of the last item, then, if in the dummy run, pull the
+  pointer back to the start of the (temporary) buffer and then remember the
+  start of the next item. */
+
+  convlength += p - pp;
+  if (dummyrun) p = use_buffer;
+  pp = p;
+
+  /* Pick up the next character */
+
+#ifndef SUPPORT_UNICODE
+  c = *posix;
+#else
+  GETCHARLENTEST(c, posix, clength);
+#endif
+  posix += clength;
+  plength -= clength;
+
+  sc = nextisliteral? 0 : c;
+  nextisliteral = FALSE;
+
+  /* Handle a character within a class. */
+
+  if (posix_state >= POSIX_CLASS_NOT_STARTED)
+    {
+    if (c == CHAR_RIGHT_SQUARE_BRACKET)
+      {
+      PUTCHARS(STR_RIGHT_SQUARE_BRACKET);
+      posix_state = POSIX_NOT_BRACKET;
+      }
+
+    /* Not the end of the class */
+
+    else
+      {
+      switch (posix_state)
+        {
+        case POSIX_CLASS_STARTED:
+        if (c <= 127 && islower(c)) break;  /* Remain in started state */
+        posix_state = POSIX_CLASS_NOT_STARTED;
+        if (c == CHAR_COLON  && plength > 0 &&
+            *posix == CHAR_RIGHT_SQUARE_BRACKET)
+          {
+          PUTCHARS(STR_COLON_RIGHT_SQUARE_BRACKET);
+          plength--;
+          posix++;
+          continue;    /* With next character after :] */
+          }
+        /* Fall through */
+
+        case POSIX_CLASS_NOT_STARTED:
+        if (c == CHAR_LEFT_SQUARE_BRACKET)
+          posix_state = POSIX_CLASS_STARTING;
+        break;
+
+        case POSIX_CLASS_STARTING:
+        if (c == CHAR_COLON) posix_state = POSIX_CLASS_STARTED;
+        break;
+        }
+
+      if (c == CHAR_BACKSLASH) PUTCHARS(STR_BACKSLASH);
+      if (p + clength > endp) return PCRE2_ERROR_NOMEMORY;
+      memcpy(p, posix - clength, CU2BYTES(clength));
+      p += clength;
+      }
+    }
+
+  /* Handle a character not within a class. */
+
+  else switch(sc)
+    {
+    case CHAR_LEFT_SQUARE_BRACKET:
+    PUTCHARS(STR_LEFT_SQUARE_BRACKET);
+
+#ifdef NEVER
+    /* We could handle special cases [[:<:]] and [[:>:]] (which PCRE does
+    support) but they are not part of POSIX 1003.1. */
+
+    if (plength >= 6)
+      {
+      if (posix[0] == CHAR_LEFT_SQUARE_BRACKET &&
+          posix[1] == CHAR_COLON &&
+          (posix[2] == CHAR_LESS_THAN_SIGN ||
+           posix[2] == CHAR_GREATER_THAN_SIGN) &&
+          posix[3] == CHAR_COLON &&
+          posix[4] == CHAR_RIGHT_SQUARE_BRACKET &&
+          posix[5] == CHAR_RIGHT_SQUARE_BRACKET)
+        {
+        if (p + 6 > endp) return PCRE2_ERROR_NOMEMORY;
+        memcpy(p, posix, CU2BYTES(6));
+        p += 6;
+        posix += 6;
+        plength -= 6;
+        continue;  /* With next character */
+        }
+      }
+#endif
+
+    /* Handle start of "normal" character classes */
+
+    posix_state = POSIX_CLASS_NOT_STARTED;
+
+    /* Handle ^ and ] as first characters */
+
+    if (plength > 0)
+      {
+      if (*posix == CHAR_CIRCUMFLEX_ACCENT)
+        {
+        posix++;
+        plength--;
+        PUTCHARS(STR_CIRCUMFLEX_ACCENT);
+        }
+      if (plength > 0 && *posix == CHAR_RIGHT_SQUARE_BRACKET)
+        {
+        posix++;
+        plength--;
+        PUTCHARS(STR_RIGHT_SQUARE_BRACKET);
+        }
+      }
+    break;
+
+    case CHAR_BACKSLASH:
+    if (plength == 0) return PCRE2_ERROR_END_BACKSLASH;
+    if (extended) nextisliteral = TRUE; else
+      {
+      if (*posix < 127 && strchr(posix_meta_escapes, *posix) != NULL)
+        {
+        if (isdigit(*posix)) PUTCHARS(STR_BACKSLASH);
+        if (p + 1 > endp) return PCRE2_ERROR_NOMEMORY;
+        lastspecial = *p++ = *posix++;
+        plength--;
+        }
+      else nextisliteral = TRUE;
+      }
+    break;
+
+    case CHAR_RIGHT_PARENTHESIS:
+    if (!extended || bracount == 0) goto ESCAPE_LITERAL;
+    bracount--;
+    goto COPY_SPECIAL;
+
+    case CHAR_LEFT_PARENTHESIS:
+    bracount++;
+    /* Fall through */
+
+    case CHAR_QUESTION_MARK:
+    case CHAR_PLUS:
+    case CHAR_LEFT_CURLY_BRACKET:
+    case CHAR_RIGHT_CURLY_BRACKET:
+    case CHAR_VERTICAL_LINE:
+    if (!extended) goto ESCAPE_LITERAL;
+    /* Fall through */
+
+    case CHAR_DOT:
+    case CHAR_DOLLAR_SIGN:
+    posix_state = POSIX_NOT_BRACKET;
+    COPY_SPECIAL:
+    lastspecial = c;
+    if (p + 1 > endp) return PCRE2_ERROR_NOMEMORY;
+    *p++ = c;
+    break;
+
+    case CHAR_ASTERISK:
+    if (lastspecial != CHAR_ASTERISK)
+      {
+      if (!extended && (posix_state < POSIX_NOT_BRACKET ||
+          lastspecial == CHAR_LEFT_PARENTHESIS))
+        goto ESCAPE_LITERAL;
+      goto COPY_SPECIAL;
+      }
+    break;   /* Ignore second and subsequent asterisks */
+
+    case CHAR_CIRCUMFLEX_ACCENT:
+    if (extended) goto COPY_SPECIAL;
+    if (posix_state == POSIX_START_REGEX ||
+        lastspecial == CHAR_LEFT_PARENTHESIS)
+      {
+      posix_state = POSIX_ANCHORED;
+      goto COPY_SPECIAL;
+      }
+    /* Fall through */
+
+    default:
+    if (c < 128 && strchr(pcre2_escaped_literals, c) != NULL)
+      {
+      ESCAPE_LITERAL:
+      PUTCHARS(STR_BACKSLASH);
+      }
+    lastspecial = 0xff;  /* Indicates nothing special */
+    if (p + clength > endp) return PCRE2_ERROR_NOMEMORY;
+    memcpy(p, posix - clength, CU2BYTES(clength));
+    p += clength;
+    posix_state = POSIX_NOT_BRACKET;
+    break;
+    }
+  }
+
+if (posix_state >= POSIX_CLASS_NOT_STARTED)
+  return PCRE2_ERROR_MISSING_SQUARE_BRACKET;
+convlength += p - pp;        /* Final segment */
+*bufflenptr = convlength;
+*p++ = 0;
+return 0;
+}
+
+
+/*************************************************
+*           Convert a glob pattern               *
+*************************************************/
+
+/* Context for writing the output into a buffer. */
+
+typedef struct pcre2_output_context {
+  PCRE2_UCHAR *output;                  /* current output position */
+  PCRE2_SPTR output_end;                /* output end */
+  PCRE2_SIZE output_size;               /* size of the output */
+  uint8_t out_str[8];                   /* string copied to the output */
+} pcre2_output_context;
+
+
+/* Write a character into the output.
+
+Arguments:
+  out            output context
+  chr            the next character
+*/
+
+static void
+convert_glob_write(pcre2_output_context *out, PCRE2_UCHAR chr)
+{
+out->output_size++;
+
+if (out->output < out->output_end)
+  *out->output++ = chr;
+}
+
+
+/* Write a string into the output.
+
+Arguments:
+  out            output context
+  length         length of out->out_str
+*/
+
+static void
+convert_glob_write_str(pcre2_output_context *out, PCRE2_SIZE length)
+{
+uint8_t *out_str = out->out_str;
+PCRE2_UCHAR *output = out->output;
+PCRE2_SPTR output_end = out->output_end;
+PCRE2_SIZE output_size = out->output_size;
+
+do
+  {
+  output_size++;
+
+  if (output < output_end)
+    *output++ = *out_str++;
+  }
+while (--length != 0);
+
+out->output = output;
+out->output_size = output_size;
+}
+
+
+/* Prints the separator into the output.
+
+Arguments:
+  out            output context
+  separator      glob separator
+  with_escape    backslash is needed before separator
+*/
+
+static void
+convert_glob_print_separator(pcre2_output_context *out,
+  PCRE2_UCHAR separator, BOOL with_escape)
+{
+if (with_escape)
+  convert_glob_write(out, CHAR_BACKSLASH);
+
+convert_glob_write(out, separator);
+}
+
+
+/* Prints a wildcard into the output.
+
+Arguments:
+  out            output context
+  separator      glob separator
+  with_escape    backslash is needed before separator
+*/
+
+static void
+convert_glob_print_wildcard(pcre2_output_context *out,
+  PCRE2_UCHAR separator, BOOL with_escape)
+{
+out->out_str[0] = CHAR_LEFT_SQUARE_BRACKET;
+out->out_str[1] = CHAR_CIRCUMFLEX_ACCENT;
+convert_glob_write_str(out, 2);
+
+convert_glob_print_separator(out, separator, with_escape);
+
+convert_glob_write(out, CHAR_RIGHT_SQUARE_BRACKET);
+}
+
+
+/* Parse a posix class.
+
+Arguments:
+  from           starting point of scanning the range
+  pattern_end    end of pattern
+  out            output context
+
+Returns:  >0 => class index
+          0  => malformed class
+*/
+
+static int
+convert_glob_parse_class(PCRE2_SPTR *from, PCRE2_SPTR pattern_end,
+  pcre2_output_context *out)
+{
+static const char *posix_classes = "alnum:alpha:ascii:blank:cntrl:digit:"
+  "graph:lower:print:punct:space:upper:word:xdigit:";
+PCRE2_SPTR start = *from + 1;
+PCRE2_SPTR pattern = start;
+const char *class_ptr;
+PCRE2_UCHAR c;
+int class_index;
+
+while (TRUE)
+  {
+  if (pattern >= pattern_end) return 0;
+
+  c = *pattern++;
+
+  if (c < CHAR_a || c > CHAR_z) break;
+  }
+
+if (c != CHAR_COLON || pattern >= pattern_end ||
+    *pattern != CHAR_RIGHT_SQUARE_BRACKET)
+  return 0;
+
+class_ptr = posix_classes;
+class_index = 1;
+
+while (TRUE)
+  {
+  if (*class_ptr == CHAR_NUL) return 0;
+
+  pattern = start;
+
+  while (*pattern == (PCRE2_UCHAR) *class_ptr)
+    {
+    if (*pattern == CHAR_COLON)
+      {
+      pattern += 2;
+      start -= 2;
+
+      do convert_glob_write(out, *start++); while (start < pattern);
+
+      *from = pattern;
+      return class_index;
+      }
+    pattern++;
+    class_ptr++;
+    }
+
+  while (*class_ptr != CHAR_COLON) class_ptr++;
+  class_ptr++;
+  class_index++;
+  }
+}
+
+/* Checks whether the character is in the class.
+
+Arguments:
+  class_index    class index
+  c              character
+
+Returns:   !0 => character is found in the class
+            0 => otherwise
+*/
+
+static BOOL
+convert_glob_char_in_class(int class_index, PCRE2_UCHAR c)
+{
+switch (class_index)
+  {
+  case 1: return isalnum(c);
+  case 2: return isalpha(c);
+  case 3: return 1;
+  case 4: return c == CHAR_HT || c == CHAR_SPACE;
+  case 5: return iscntrl(c);
+  case 6: return isdigit(c);
+  case 7: return isgraph(c);
+  case 8: return islower(c);
+  case 9: return isprint(c);
+  case 10: return ispunct(c);
+  case 11: return isspace(c);
+  case 12: return isupper(c);
+  case 13: return isalnum(c) || c == CHAR_UNDERSCORE;
+  default: return isxdigit(c);
+  }
+}
+
+/* Parse a range of characters.
+
+Arguments:
+  from           starting point of scanning the range
+  pattern_end    end of pattern
+  out            output context
+  separator      glob separator
+  with_escape    backslash is needed before separator
+
+Returns:         0 => success
+                !0 => error code
+*/
+
+static int
+convert_glob_parse_range(PCRE2_SPTR *from, PCRE2_SPTR pattern_end,
+  pcre2_output_context *out, BOOL utf, PCRE2_UCHAR separator,
+  BOOL with_escape, PCRE2_UCHAR escape, BOOL no_wildsep)
+{
+BOOL is_negative = FALSE;
+BOOL separator_seen = FALSE;
+BOOL has_prev_c;
+PCRE2_SPTR pattern = *from;
+PCRE2_SPTR char_start = NULL;
+uint32_t c, prev_c;
+int len, class_index;
+
+(void)utf; /* Avoid compiler warning. */
+
+if (pattern >= pattern_end)
+  {
+  *from = pattern;
+  return PCRE2_ERROR_MISSING_SQUARE_BRACKET;
+  }
+
+if (*pattern == CHAR_EXCLAMATION_MARK
+    || *pattern == CHAR_CIRCUMFLEX_ACCENT)
+  {
+  pattern++;
+
+  if (pattern >= pattern_end)
+    {
+    *from = pattern;
+    return PCRE2_ERROR_MISSING_SQUARE_BRACKET;
+    }
+
+  is_negative = TRUE;
+
+  out->out_str[0] = CHAR_LEFT_SQUARE_BRACKET;
+  out->out_str[1] = CHAR_CIRCUMFLEX_ACCENT;
+  len = 2;
+
+  if (!no_wildsep)
+    {
+    if (with_escape)
+      {
+      out->out_str[len] = CHAR_BACKSLASH;
+      len++;
+      }
+    out->out_str[len] = (uint8_t) separator;
+    }
+
+  convert_glob_write_str(out, len + 1);
+  }
+else
+  convert_glob_write(out, CHAR_LEFT_SQUARE_BRACKET);
+
+has_prev_c = FALSE;
+prev_c = 0;
+
+if (*pattern == CHAR_RIGHT_SQUARE_BRACKET)
+  {
+  out->out_str[0] = CHAR_BACKSLASH;
+  out->out_str[1] = CHAR_RIGHT_SQUARE_BRACKET;
+  convert_glob_write_str(out, 2);
+  has_prev_c = TRUE;
+  prev_c = CHAR_RIGHT_SQUARE_BRACKET;
+  pattern++;
+  }
+
+while (pattern < pattern_end)
+  {
+  char_start = pattern;
+  GETCHARINCTEST(c, pattern);
+
+  if (c == CHAR_RIGHT_SQUARE_BRACKET)
+    {
+    convert_glob_write(out, c);
+
+    if (!is_negative && !no_wildsep && separator_seen)
+      {
+      out->out_str[0] = CHAR_LEFT_PARENTHESIS;
+      out->out_str[1] = CHAR_QUESTION_MARK;
+      out->out_str[2] = CHAR_LESS_THAN_SIGN;
+      out->out_str[3] = CHAR_EXCLAMATION_MARK;
+      convert_glob_write_str(out, 4);
+
+      convert_glob_print_separator(out, separator, with_escape);
+      convert_glob_write(out, CHAR_RIGHT_PARENTHESIS);
+      }
+
+    *from = pattern;
+    return 0;
+    }
+
+  if (pattern >= pattern_end) break;
+
+  if (c == CHAR_LEFT_SQUARE_BRACKET && *pattern == CHAR_COLON)
+    {
+    *from = pattern;
+    class_index = convert_glob_parse_class(from, pattern_end, out);
+
+    if (class_index != 0)
+      {
+      pattern = *from;
+
+      has_prev_c = FALSE;
+      prev_c = 0;
+
+      if (!is_negative &&
+          convert_glob_char_in_class (class_index, separator))
+        separator_seen = TRUE;
+      continue;
+      }
+    }
+  else if (c == CHAR_MINUS && has_prev_c &&
+           *pattern != CHAR_RIGHT_SQUARE_BRACKET)
+    {
+    convert_glob_write(out, CHAR_MINUS);
+
+    char_start = pattern;
+    GETCHARINCTEST(c, pattern);
+
+    if (pattern >= pattern_end) break;
+
+    if (escape != 0 && c == escape)
+      {
+      char_start = pattern;
+      GETCHARINCTEST(c, pattern);
+      }
+    else if (c == CHAR_LEFT_SQUARE_BRACKET && *pattern == CHAR_COLON)
+      {
+      *from = pattern;
+      return PCRE2_ERROR_CONVERT_SYNTAX;
+      }
+
+    if (prev_c > c)
+      {
+      *from = pattern;
+      return PCRE2_ERROR_CONVERT_SYNTAX;
+      }
+
+    if (prev_c < separator && separator < c) separator_seen = TRUE;
+
+    has_prev_c = FALSE;
+    prev_c = 0;
+    }
+  else
+    {
+    if (escape != 0 && c == escape)
+      {
+      char_start = pattern;
+      GETCHARINCTEST(c, pattern);
+
+      if (pattern >= pattern_end) break;
+      }
+
+    has_prev_c = TRUE;
+    prev_c = c;
+    }
+
+  if (c == CHAR_LEFT_SQUARE_BRACKET || c == CHAR_RIGHT_SQUARE_BRACKET ||
+      c == CHAR_BACKSLASH || c == CHAR_MINUS)
+    convert_glob_write(out, CHAR_BACKSLASH);
+
+  if (c == separator) separator_seen = TRUE;
+
+  do convert_glob_write(out, *char_start++); while (char_start < pattern);
+  }
+
+*from = pattern;
+return PCRE2_ERROR_MISSING_SQUARE_BRACKET;
+}
+
+
+/* Prints a (*COMMIT) into the output.
+
+Arguments:
+  out            output context
+*/
+
+static void
+convert_glob_print_commit(pcre2_output_context *out)
+{
+out->out_str[0] = CHAR_LEFT_PARENTHESIS;
+out->out_str[1] = CHAR_ASTERISK;
+out->out_str[2] = CHAR_C;
+out->out_str[3] = CHAR_O;
+out->out_str[4] = CHAR_M;
+out->out_str[5] = CHAR_M;
+out->out_str[6] = CHAR_I;
+out->out_str[7] = CHAR_T;
+convert_glob_write_str(out, 8);
+convert_glob_write(out, CHAR_RIGHT_PARENTHESIS);
+}
+
+
+/* Bash glob converter.
+
+Arguments:
+  pattype        the pattern type
+  pattern        the pattern
+  plength        length in code units
+  utf            TRUE if UTF
+  use_buffer     where to put the output
+  use_length     length of use_buffer
+  bufflenptr     where to put the used length
+  dummyrun       TRUE if a dummy run
+  ccontext       the convert context
+
+Returns:         0 => success
+                !0 => error code
+*/
+
+static int
+convert_glob(uint32_t options, PCRE2_SPTR pattern, PCRE2_SIZE plength,
+  BOOL utf, PCRE2_UCHAR *use_buffer, PCRE2_SIZE use_length,
+  PCRE2_SIZE *bufflenptr, BOOL dummyrun, pcre2_convert_context *ccontext)
+{
+pcre2_output_context out;
+PCRE2_SPTR pattern_start = pattern;
+PCRE2_SPTR pattern_end = pattern + plength;
+PCRE2_UCHAR separator = ccontext->glob_separator;
+PCRE2_UCHAR escape = ccontext->glob_escape;
+PCRE2_UCHAR c;
+BOOL no_wildsep = (options & PCRE2_CONVERT_GLOB_NO_WILD_SEPARATOR) != 0;
+BOOL no_starstar = (options & PCRE2_CONVERT_GLOB_NO_STARSTAR) != 0;
+BOOL in_atomic = FALSE;
+BOOL after_starstar = FALSE;
+BOOL no_slash_z = FALSE;
+BOOL with_escape, is_start, after_separator;
+int result = 0;
+
+(void)utf; /* Avoid compiler warning. */
+
+#ifdef SUPPORT_UNICODE
+if (utf && (separator >= 128 || escape >= 128))
+  {
+  /* Currently only ASCII characters are supported. */
+  *bufflenptr = 0;
+  return PCRE2_ERROR_CONVERT_SYNTAX;
+  }
+#endif
+
+with_escape = strchr(pcre2_escaped_literals, separator) != NULL;
+
+/* Initialize default for error offset as end of input. */
+out.output = use_buffer;
+out.output_end = use_buffer + use_length;
+out.output_size = 0;
+
+out.out_str[0] = CHAR_LEFT_PARENTHESIS;
+out.out_str[1] = CHAR_QUESTION_MARK;
+out.out_str[2] = CHAR_s;
+out.out_str[3] = CHAR_RIGHT_PARENTHESIS;
+convert_glob_write_str(&out, 4);
+
+is_start = TRUE;
+
+if (pattern < pattern_end && pattern[0] == CHAR_ASTERISK)
+  {
+  if (no_wildsep)
+    is_start = FALSE;
+  else if (!no_starstar && pattern + 1 < pattern_end &&
+           pattern[1] == CHAR_ASTERISK)
+    is_start = FALSE;
+  }
+
+if (is_start)
+  {
+  out.out_str[0] = CHAR_BACKSLASH;
+  out.out_str[1] = CHAR_A;
+  convert_glob_write_str(&out, 2);
+  }
+
+while (pattern < pattern_end)
+  {
+  c = *pattern++;
+
+  if (c == CHAR_ASTERISK)
+    {
+    is_start = pattern == pattern_start + 1;
+
+    if (in_atomic)
+      {
+      convert_glob_write(&out, CHAR_RIGHT_PARENTHESIS);
+      in_atomic = FALSE;
+      }
+
+    if (!no_starstar && pattern < pattern_end && *pattern == CHAR_ASTERISK)
+      {
+      after_separator = is_start || (pattern[-2] == separator);
+
+      do pattern++; while (pattern < pattern_end &&
+                           *pattern == CHAR_ASTERISK);
+
+      if (pattern >= pattern_end)
+        {
+        no_slash_z = TRUE;
+        break;
+        }
+
+      after_starstar = TRUE;
+
+      if (after_separator && escape != 0 && *pattern == escape &&
+          pattern + 1 < pattern_end && pattern[1] == separator)
+        pattern++;
+
+      if (is_start)
+        {
+        if (*pattern != separator) continue;
+
+        out.out_str[0] = CHAR_LEFT_PARENTHESIS;
+        out.out_str[1] = CHAR_QUESTION_MARK;
+        out.out_str[2] = CHAR_COLON;
+        out.out_str[3] = CHAR_BACKSLASH;
+        out.out_str[4] = CHAR_A;
+        out.out_str[5] = CHAR_VERTICAL_LINE;
+        convert_glob_write_str(&out, 6);
+
+        convert_glob_print_separator(&out, separator, with_escape);
+        convert_glob_write(&out, CHAR_RIGHT_PARENTHESIS);
+
+        pattern++;
+        continue;
+        }
+
+      convert_glob_print_commit(&out);
+
+      if (!after_separator || *pattern != separator)
+        {
+        out.out_str[0] = CHAR_DOT;
+        out.out_str[1] = CHAR_ASTERISK;
+        out.out_str[2] = CHAR_QUESTION_MARK;
+        convert_glob_write_str(&out, 3);
+        continue;
+        }
+
+      out.out_str[0] = CHAR_LEFT_PARENTHESIS;
+      out.out_str[1] = CHAR_QUESTION_MARK;
+      out.out_str[2] = CHAR_COLON;
+      out.out_str[3] = CHAR_DOT;
+      out.out_str[4] = CHAR_ASTERISK;
+      out.out_str[5] = CHAR_QUESTION_MARK;
+
+      convert_glob_write_str(&out, 6);
+
+      convert_glob_print_separator(&out, separator, with_escape);
+
+      out.out_str[0] = CHAR_RIGHT_PARENTHESIS;
+      out.out_str[1] = CHAR_QUESTION_MARK;
+      out.out_str[2] = CHAR_QUESTION_MARK;
+      convert_glob_write_str(&out, 3);
+
+      pattern++;
+      continue;
+      }
+
+    if (pattern < pattern_end && *pattern == CHAR_ASTERISK)
+      {
+      do pattern++; while (pattern < pattern_end &&
+                           *pattern == CHAR_ASTERISK);
+      }
+
+    if (no_wildsep)
+      {
+      if (pattern >= pattern_end)
+        {
+        no_slash_z = TRUE;
+        break;
+        }
+
+      /* Start check must be after the end check. */
+      if (is_start) continue;
+      }
+
+    if (!is_start)
+      {
+      if (after_starstar)
+        {
+        out.out_str[0] = CHAR_LEFT_PARENTHESIS;
+        out.out_str[1] = CHAR_QUESTION_MARK;
+        out.out_str[2] = CHAR_GREATER_THAN_SIGN;
+        convert_glob_write_str(&out, 3);
+        in_atomic = TRUE;
+        }
+      else
+        convert_glob_print_commit(&out);
+      }
+
+    if (no_wildsep)
+      convert_glob_write(&out, CHAR_DOT);
+    else
+      convert_glob_print_wildcard(&out, separator, with_escape);
+
+    out.out_str[0] = CHAR_ASTERISK;
+    out.out_str[1] = CHAR_QUESTION_MARK;
+    if (pattern >= pattern_end)
+      out.out_str[1] = CHAR_PLUS;
+    convert_glob_write_str(&out, 2);
+    continue;
+    }
+
+  if (c == CHAR_QUESTION_MARK)
+    {
+    if (no_wildsep)
+      convert_glob_write(&out, CHAR_DOT);
+    else
+      convert_glob_print_wildcard(&out, separator, with_escape);
+    continue;
+    }
+
+  if (c == CHAR_LEFT_SQUARE_BRACKET)
+    {
+    result = convert_glob_parse_range(&pattern, pattern_end,
+      &out, utf, separator, with_escape, escape, no_wildsep);
+    if (result != 0) break;
+    continue;
+    }
+
+  if (escape != 0 && c == escape)
+    {
+    if (pattern >= pattern_end)
+      {
+      result = PCRE2_ERROR_CONVERT_SYNTAX;
+      break;
+      }
+    c = *pattern++;
+    }
+
+  if (c < 128 && strchr(pcre2_escaped_literals, c) != NULL)
+    convert_glob_write(&out, CHAR_BACKSLASH);
+
+  convert_glob_write(&out, c);
+  }
+
+if (result == 0)
+  {
+  if (!no_slash_z)
+    {
+    out.out_str[0] = CHAR_BACKSLASH;
+    out.out_str[1] = CHAR_z;
+    convert_glob_write_str(&out, 2);
+    }
+
+  if (in_atomic)
+    convert_glob_write(&out, CHAR_RIGHT_PARENTHESIS);
+
+  convert_glob_write(&out, CHAR_NUL);
+
+  if (!dummyrun && out.output_size != (PCRE2_SIZE) (out.output - use_buffer))
+    result = PCRE2_ERROR_NOMEMORY;
+  }
+
+if (result != 0)
+  {
+  *bufflenptr = pattern - pattern_start;
+  return result;
+  }
+
+*bufflenptr = out.output_size - 1;
+return 0;
+}
+
+
+/*************************************************
+*                Convert pattern                 *
+*************************************************/
+
+/* This is the external-facing function for converting other forms of pattern
+into PCRE2 regular expression patterns. On error, the bufflenptr argument is
+used to return an offset in the original pattern.
+
+Arguments:
+  pattern     the input pattern
+  plength     length of input, or PCRE2_ZERO_TERMINATED
+  options     options bits
+  buffptr     pointer to pointer to output buffer
+  bufflenptr  pointer to length of output buffer
+  ccontext    convert context or NULL
+
+Returns:      0 for success, else an error code (+ve or -ve)
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_pattern_convert(PCRE2_SPTR pattern, PCRE2_SIZE plength, uint32_t options,
+  PCRE2_UCHAR **buffptr, PCRE2_SIZE *bufflenptr,
+  pcre2_convert_context *ccontext)
+{
+int i, rc;
+PCRE2_UCHAR dummy_buffer[DUMMY_BUFFER_SIZE];
+PCRE2_UCHAR *use_buffer = dummy_buffer;
+PCRE2_SIZE use_length = DUMMY_BUFFER_SIZE;
+BOOL utf = (options & PCRE2_CONVERT_UTF) != 0;
+uint32_t pattype = options & TYPE_OPTIONS;
+
+if (pattern == NULL || bufflenptr == NULL) return PCRE2_ERROR_NULL;
+
+if ((options & ~ALL_OPTIONS) != 0 ||        /* Undefined bit set */
+    (pattype & (~pattype+1)) != pattype ||  /* More than one type set */
+    pattype == 0)                           /* No type set */
+  {
+  *bufflenptr = 0;                          /* Error offset */
+  return PCRE2_ERROR_BADOPTION;
+  }
+
+if (plength == PCRE2_ZERO_TERMINATED) plength = PRIV(strlen)(pattern);
+if (ccontext == NULL) ccontext =
+  (pcre2_convert_context *)(&PRIV(default_convert_context));
+
+/* Check UTF if required. */
+
+#ifndef SUPPORT_UNICODE
+if (utf)
+  {
+  *bufflenptr = 0;  /* Error offset */
+  return PCRE2_ERROR_UNICODE_NOT_SUPPORTED;
+  }
+#else
+if (utf && (options & PCRE2_CONVERT_NO_UTF_CHECK) == 0)
+  {
+  PCRE2_SIZE erroroffset;
+  rc = PRIV(valid_utf)(pattern, plength, &erroroffset);
+  if (rc != 0)
+    {
+    *bufflenptr = erroroffset;
+    return rc;
+    }
+  }
+#endif
+
+/* If buffptr is not NULL, and what it points to is not NULL, we are being
+provided with a buffer and a length, so set them as the buffer to use. */
+
+if (buffptr != NULL && *buffptr != NULL)
+  {
+  use_buffer = *buffptr;
+  use_length = *bufflenptr;
+  }
+
+/* Call an individual converter, either just once (if a buffer was provided or
+just the length is needed), or twice (if a memory allocation is required). */
+
+for (i = 0; i < 2; i++)
+  {
+  PCRE2_UCHAR *allocated;
+  BOOL dummyrun = buffptr == NULL || *buffptr == NULL;
+
+  switch(pattype)
+    {
+    case PCRE2_CONVERT_GLOB:
+    rc = convert_glob(options & ~PCRE2_CONVERT_GLOB, pattern, plength, utf,
+      use_buffer, use_length, bufflenptr, dummyrun, ccontext);
+    break;
+
+    case PCRE2_CONVERT_POSIX_BASIC:
+    case PCRE2_CONVERT_POSIX_EXTENDED:
+    rc = convert_posix(pattype, pattern, plength, utf, use_buffer, use_length,
+      bufflenptr, dummyrun, ccontext);
+    break;
+
+    default:
+    *bufflenptr = 0;  /* Error offset */
+    return PCRE2_ERROR_INTERNAL;
+    }
+
+  if (rc != 0 ||           /* Error */
+      buffptr == NULL ||   /* Just the length is required */
+      *buffptr != NULL)    /* Buffer was provided or allocated */
+    return rc;
+
+  /* Allocate memory for the buffer, with hidden space for an allocator at
+  the start. The next time round the loop runs the conversion for real. */
+
+  allocated = PRIV(memctl_malloc)(sizeof(pcre2_memctl) +
+    (*bufflenptr + 1)*PCRE2_CODE_UNIT_WIDTH, (pcre2_memctl *)ccontext);
+  if (allocated == NULL) return PCRE2_ERROR_NOMEMORY;
+  *buffptr = (PCRE2_UCHAR *)(((char *)allocated) + sizeof(pcre2_memctl));
+
+  use_buffer = *buffptr;
+  use_length = *bufflenptr + 1;
+  }
+
+/* Control should never get here. */
+
+return PCRE2_ERROR_INTERNAL;
+}
+
+
+/*************************************************
+*            Free converted pattern              *
+*************************************************/
+
+/* This frees a converted pattern that was put in newly-allocated memory.
+
+Argument:   the converted pattern
+Returns:    nothing
+*/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_converted_pattern_free(PCRE2_UCHAR *converted)
+{
+if (converted != NULL)
+  {
+  pcre2_memctl *memctl =
+    (pcre2_memctl *)((char *)converted - sizeof(pcre2_memctl));
+  memctl->free(memctl, memctl->memory_data);
+  }
+}
+
+/* End of pcre2_convert.c */
diff --git a/src/c/pcre2/src/pcre2_dfa_match.c b/src/c/pcre2/src/pcre2_dfa_match.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_dfa_match.c
@@ -0,0 +1,3982 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2020 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains the external function pcre2_dfa_match(), which is an
+alternative matching function that uses a sort of DFA algorithm (not a true
+FSM). This is NOT Perl-compatible, but it has advantages in certain
+applications. */
+
+
+/* NOTE ABOUT PERFORMANCE: A user of this function sent some code that improved
+the performance of his patterns greatly. I could not use it as it stood, as it
+was not thread safe, and made assumptions about pattern sizes. Also, it caused
+test 7 to loop, and test 9 to crash with a segfault.
+
+The issue is the check for duplicate states, which is done by a simple linear
+search up the state list. (Grep for "duplicate" below to find the code.) For
+many patterns, there will never be many states active at one time, so a simple
+linear search is fine. In patterns that have many active states, it might be a
+bottleneck. The suggested code used an indexing scheme to remember which states
+had previously been used for each character, and avoided the linear search when
+it knew there was no chance of a duplicate. This was implemented when adding
+states to the state lists.
+
+I wrote some thread-safe, not-limited code to try something similar at the time
+of checking for duplicates (instead of when adding states), using index vectors
+on the stack. It did give a 13% improvement with one specially constructed
+pattern for certain subject strings, but on other strings and on many of the
+simpler patterns in the test suite it did worse. The major problem, I think,
+was the extra time to initialize the index. This had to be done for each call
+of internal_dfa_match(). (The supplied patch used a static vector, initialized
+only once - I suspect this was the cause of the problems with the tests.)
+
+Overall, I concluded that the gains in some cases did not outweigh the losses
+in others, so I abandoned this code. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define NLBLOCK mb             /* Block containing newline information */
+#define PSSTART start_subject  /* Field containing processed string start */
+#define PSEND   end_subject    /* Field containing processed string end */
+
+#include "pcre2_internal.h"
+
+#define PUBLIC_DFA_MATCH_OPTIONS \
+  (PCRE2_ANCHORED|PCRE2_ENDANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \
+   PCRE2_NOTEMPTY_ATSTART|PCRE2_NO_UTF_CHECK|PCRE2_PARTIAL_HARD| \
+   PCRE2_PARTIAL_SOFT|PCRE2_DFA_SHORTEST|PCRE2_DFA_RESTART| \
+   PCRE2_COPY_MATCHED_SUBJECT)
+
+
+/*************************************************
+*      Code parameters and static tables         *
+*************************************************/
+
+/* These are offsets that are used to turn the OP_TYPESTAR and friends opcodes
+into others, under special conditions. A gap of 20 between the blocks should be
+enough. The resulting opcodes don't have to be less than 256 because they are
+never stored, so we push them well clear of the normal opcodes. */
+
+#define OP_PROP_EXTRA       300
+#define OP_EXTUNI_EXTRA     320
+#define OP_ANYNL_EXTRA      340
+#define OP_HSPACE_EXTRA     360
+#define OP_VSPACE_EXTRA     380
+
+
+/* This table identifies those opcodes that are followed immediately by a
+character that is to be tested in some way. This makes it possible to
+centralize the loading of these characters. In the case of Type * etc, the
+"character" is the opcode for \D, \d, \S, \s, \W, or \w, which will always be a
+small value. Non-zero values in the table are the offsets from the opcode where
+the character is to be found. ***NOTE*** If the start of this table is
+modified, the three tables that follow must also be modified. */
+
+static const uint8_t coptable[] = {
+  0,                             /* End                                    */
+  0, 0, 0, 0, 0,                 /* \A, \G, \K, \B, \b                     */
+  0, 0, 0, 0, 0, 0,              /* \D, \d, \S, \s, \W, \w                 */
+  0, 0, 0,                       /* Any, AllAny, Anybyte                   */
+  0, 0,                          /* \P, \p                                 */
+  0, 0, 0, 0, 0,                 /* \R, \H, \h, \V, \v                     */
+  0,                             /* \X                                     */
+  0, 0, 0, 0, 0, 0,              /* \Z, \z, $, $M, ^, ^M                   */
+  1,                             /* Char                                   */
+  1,                             /* Chari                                  */
+  1,                             /* not                                    */
+  1,                             /* noti                                   */
+  /* Positive single-char repeats                                          */
+  1, 1, 1, 1, 1, 1,              /* *, *?, +, +?, ?, ??                    */
+  1+IMM2_SIZE, 1+IMM2_SIZE,      /* upto, minupto                          */
+  1+IMM2_SIZE,                   /* exact                                  */
+  1, 1, 1, 1+IMM2_SIZE,          /* *+, ++, ?+, upto+                      */
+  1, 1, 1, 1, 1, 1,              /* *I, *?I, +I, +?I, ?I, ??I              */
+  1+IMM2_SIZE, 1+IMM2_SIZE,      /* upto I, minupto I                      */
+  1+IMM2_SIZE,                   /* exact I                                */
+  1, 1, 1, 1+IMM2_SIZE,          /* *+I, ++I, ?+I, upto+I                  */
+  /* Negative single-char repeats - only for chars < 256                   */
+  1, 1, 1, 1, 1, 1,              /* NOT *, *?, +, +?, ?, ??                */
+  1+IMM2_SIZE, 1+IMM2_SIZE,      /* NOT upto, minupto                      */
+  1+IMM2_SIZE,                   /* NOT exact                              */
+  1, 1, 1, 1+IMM2_SIZE,          /* NOT *+, ++, ?+, upto+                  */
+  1, 1, 1, 1, 1, 1,              /* NOT *I, *?I, +I, +?I, ?I, ??I          */
+  1+IMM2_SIZE, 1+IMM2_SIZE,      /* NOT upto I, minupto I                  */
+  1+IMM2_SIZE,                   /* NOT exact I                            */
+  1, 1, 1, 1+IMM2_SIZE,          /* NOT *+I, ++I, ?+I, upto+I              */
+  /* Positive type repeats                                                 */
+  1, 1, 1, 1, 1, 1,              /* Type *, *?, +, +?, ?, ??               */
+  1+IMM2_SIZE, 1+IMM2_SIZE,      /* Type upto, minupto                     */
+  1+IMM2_SIZE,                   /* Type exact                             */
+  1, 1, 1, 1+IMM2_SIZE,          /* Type *+, ++, ?+, upto+                 */
+  /* Character class & ref repeats                                         */
+  0, 0, 0, 0, 0, 0,              /* *, *?, +, +?, ?, ??                    */
+  0, 0,                          /* CRRANGE, CRMINRANGE                    */
+  0, 0, 0, 0,                    /* Possessive *+, ++, ?+, CRPOSRANGE      */
+  0,                             /* CLASS                                  */
+  0,                             /* NCLASS                                 */
+  0,                             /* XCLASS - variable length               */
+  0,                             /* REF                                    */
+  0,                             /* REFI                                   */
+  0,                             /* DNREF                                  */
+  0,                             /* DNREFI                                 */
+  0,                             /* RECURSE                                */
+  0,                             /* CALLOUT                                */
+  0,                             /* CALLOUT_STR                            */
+  0,                             /* Alt                                    */
+  0,                             /* Ket                                    */
+  0,                             /* KetRmax                                */
+  0,                             /* KetRmin                                */
+  0,                             /* KetRpos                                */
+  0,                             /* Reverse                                */
+  0,                             /* Assert                                 */
+  0,                             /* Assert not                             */
+  0,                             /* Assert behind                          */
+  0,                             /* Assert behind not                      */
+  0,                             /* NA assert                              */
+  0,                             /* NA assert behind                       */
+  0,                             /* ONCE                                   */
+  0,                             /* SCRIPT_RUN                             */
+  0, 0, 0, 0, 0,                 /* BRA, BRAPOS, CBRA, CBRAPOS, COND       */
+  0, 0, 0, 0, 0,                 /* SBRA, SBRAPOS, SCBRA, SCBRAPOS, SCOND  */
+  0, 0,                          /* CREF, DNCREF                           */
+  0, 0,                          /* RREF, DNRREF                           */
+  0, 0,                          /* FALSE, TRUE                            */
+  0, 0, 0,                       /* BRAZERO, BRAMINZERO, BRAPOSZERO        */
+  0, 0, 0,                       /* MARK, PRUNE, PRUNE_ARG                 */
+  0, 0, 0, 0,                    /* SKIP, SKIP_ARG, THEN, THEN_ARG         */
+  0, 0,                          /* COMMIT, COMMIT_ARG                     */
+  0, 0, 0,                       /* FAIL, ACCEPT, ASSERT_ACCEPT            */
+  0, 0, 0                        /* CLOSE, SKIPZERO, DEFINE                */
+};
+
+/* This table identifies those opcodes that inspect a character. It is used to
+remember the fact that a character could have been inspected when the end of
+the subject is reached. ***NOTE*** If the start of this table is modified, the
+two tables that follow must also be modified. */
+
+static const uint8_t poptable[] = {
+  0,                             /* End                                    */
+  0, 0, 0, 1, 1,                 /* \A, \G, \K, \B, \b                     */
+  1, 1, 1, 1, 1, 1,              /* \D, \d, \S, \s, \W, \w                 */
+  1, 1, 1,                       /* Any, AllAny, Anybyte                   */
+  1, 1,                          /* \P, \p                                 */
+  1, 1, 1, 1, 1,                 /* \R, \H, \h, \V, \v                     */
+  1,                             /* \X                                     */
+  0, 0, 0, 0, 0, 0,              /* \Z, \z, $, $M, ^, ^M                   */
+  1,                             /* Char                                   */
+  1,                             /* Chari                                  */
+  1,                             /* not                                    */
+  1,                             /* noti                                   */
+  /* Positive single-char repeats                                          */
+  1, 1, 1, 1, 1, 1,              /* *, *?, +, +?, ?, ??                    */
+  1, 1, 1,                       /* upto, minupto, exact                   */
+  1, 1, 1, 1,                    /* *+, ++, ?+, upto+                      */
+  1, 1, 1, 1, 1, 1,              /* *I, *?I, +I, +?I, ?I, ??I              */
+  1, 1, 1,                       /* upto I, minupto I, exact I             */
+  1, 1, 1, 1,                    /* *+I, ++I, ?+I, upto+I                  */
+  /* Negative single-char repeats - only for chars < 256                   */
+  1, 1, 1, 1, 1, 1,              /* NOT *, *?, +, +?, ?, ??                */
+  1, 1, 1,                       /* NOT upto, minupto, exact               */
+  1, 1, 1, 1,                    /* NOT *+, ++, ?+, upto+                  */
+  1, 1, 1, 1, 1, 1,              /* NOT *I, *?I, +I, +?I, ?I, ??I          */
+  1, 1, 1,                       /* NOT upto I, minupto I, exact I         */
+  1, 1, 1, 1,                    /* NOT *+I, ++I, ?+I, upto+I              */
+  /* Positive type repeats                                                 */
+  1, 1, 1, 1, 1, 1,              /* Type *, *?, +, +?, ?, ??               */
+  1, 1, 1,                       /* Type upto, minupto, exact              */
+  1, 1, 1, 1,                    /* Type *+, ++, ?+, upto+                 */
+  /* Character class & ref repeats                                         */
+  1, 1, 1, 1, 1, 1,              /* *, *?, +, +?, ?, ??                    */
+  1, 1,                          /* CRRANGE, CRMINRANGE                    */
+  1, 1, 1, 1,                    /* Possessive *+, ++, ?+, CRPOSRANGE      */
+  1,                             /* CLASS                                  */
+  1,                             /* NCLASS                                 */
+  1,                             /* XCLASS - variable length               */
+  0,                             /* REF                                    */
+  0,                             /* REFI                                   */
+  0,                             /* DNREF                                  */
+  0,                             /* DNREFI                                 */
+  0,                             /* RECURSE                                */
+  0,                             /* CALLOUT                                */
+  0,                             /* CALLOUT_STR                            */
+  0,                             /* Alt                                    */
+  0,                             /* Ket                                    */
+  0,                             /* KetRmax                                */
+  0,                             /* KetRmin                                */
+  0,                             /* KetRpos                                */
+  0,                             /* Reverse                                */
+  0,                             /* Assert                                 */
+  0,                             /* Assert not                             */
+  0,                             /* Assert behind                          */
+  0,                             /* Assert behind not                      */
+  0,                             /* NA assert                              */
+  0,                             /* NA assert behind                       */
+  0,                             /* ONCE                                   */
+  0,                             /* SCRIPT_RUN                             */
+  0, 0, 0, 0, 0,                 /* BRA, BRAPOS, CBRA, CBRAPOS, COND       */
+  0, 0, 0, 0, 0,                 /* SBRA, SBRAPOS, SCBRA, SCBRAPOS, SCOND  */
+  0, 0,                          /* CREF, DNCREF                           */
+  0, 0,                          /* RREF, DNRREF                           */
+  0, 0,                          /* FALSE, TRUE                            */
+  0, 0, 0,                       /* BRAZERO, BRAMINZERO, BRAPOSZERO        */
+  0, 0, 0,                       /* MARK, PRUNE, PRUNE_ARG                 */
+  0, 0, 0, 0,                    /* SKIP, SKIP_ARG, THEN, THEN_ARG         */
+  0, 0,                          /* COMMIT, COMMIT_ARG                     */
+  0, 0, 0,                       /* FAIL, ACCEPT, ASSERT_ACCEPT            */
+  0, 0, 0                        /* CLOSE, SKIPZERO, DEFINE                */
+};
+
+/* These 2 tables allow for compact code for testing for \D, \d, \S, \s, \W,
+and \w */
+
+static const uint8_t toptable1[] = {
+  0, 0, 0, 0, 0, 0,
+  ctype_digit, ctype_digit,
+  ctype_space, ctype_space,
+  ctype_word,  ctype_word,
+  0, 0                            /* OP_ANY, OP_ALLANY */
+};
+
+static const uint8_t toptable2[] = {
+  0, 0, 0, 0, 0, 0,
+  ctype_digit, 0,
+  ctype_space, 0,
+  ctype_word,  0,
+  1, 1                            /* OP_ANY, OP_ALLANY */
+};
+
+
+/* Structure for holding data about a particular state, which is in effect the
+current data for an active path through the match tree. It must consist
+entirely of ints because the working vector we are passed, and which we put
+these structures in, is a vector of ints. */
+
+typedef struct stateblock {
+  int offset;                     /* Offset to opcode (-ve has meaning) */
+  int count;                      /* Count for repeats */
+  int data;                       /* Some use extra data */
+} stateblock;
+
+#define INTS_PER_STATEBLOCK  (int)(sizeof(stateblock)/sizeof(int))
+
+
+/* Before version 10.32 the recursive calls of internal_dfa_match() were passed
+local working space and output vectors that were created on the stack. This has
+caused issues for some patterns, especially in small-stack environments such as
+Windows. A new scheme is now in use which sets up a vector on the stack, but if
+this is too small, heap memory is used, up to the heap_limit. The main
+parameters are all numbers of ints because the workspace is a vector of ints.
+
+The size of the starting stack vector, DFA_START_RWS_SIZE, is in bytes, and is
+defined in pcre2_internal.h so as to be available to pcre2test when it is
+finding the minimum heap requirement for a match. */
+
+#define OVEC_UNIT  (sizeof(PCRE2_SIZE)/sizeof(int))
+
+#define RWS_BASE_SIZE   (DFA_START_RWS_SIZE/sizeof(int))  /* Stack vector */
+#define RWS_RSIZE       1000                    /* Work size for recursion */
+#define RWS_OVEC_RSIZE  (1000*OVEC_UNIT)        /* Ovector for recursion */
+#define RWS_OVEC_OSIZE  (2*OVEC_UNIT)           /* Ovector in other cases */
+
+/* This structure is at the start of each workspace block. */
+
+typedef struct RWS_anchor {
+  struct RWS_anchor *next;
+  uint32_t size;  /* Number of ints */
+  uint32_t free;  /* Number of ints */
+} RWS_anchor;
+
+#define RWS_ANCHOR_SIZE (sizeof(RWS_anchor)/sizeof(int))
+
+
+
+/*************************************************
+*               Process a callout                *
+*************************************************/
+
+/* This function is called to perform a callout.
+
+Arguments:
+  code              current code pointer
+  offsets           points to current capture offsets
+  current_subject   start of current subject match
+  ptr               current position in subject
+  mb                the match block
+  extracode         extra code offset when called from condition
+  lengthptr         where to return the callout length
+
+Returns:            the return from the callout
+*/
+
+static int
+do_callout(PCRE2_SPTR code, PCRE2_SIZE *offsets, PCRE2_SPTR current_subject,
+  PCRE2_SPTR ptr, dfa_match_block *mb, PCRE2_SIZE extracode,
+  PCRE2_SIZE *lengthptr)
+{
+pcre2_callout_block *cb = mb->cb;
+
+*lengthptr = (code[extracode] == OP_CALLOUT)?
+  (PCRE2_SIZE)PRIV(OP_lengths)[OP_CALLOUT] :
+  (PCRE2_SIZE)GET(code, 1 + 2*LINK_SIZE + extracode);
+
+if (mb->callout == NULL) return 0;    /* No callout provided */
+
+/* Fixed fields in the callout block are set once and for all at the start of
+matching. */
+
+cb->offset_vector    = offsets;
+cb->start_match      = (PCRE2_SIZE)(current_subject - mb->start_subject);
+cb->current_position = (PCRE2_SIZE)(ptr - mb->start_subject);
+cb->pattern_position = GET(code, 1 + extracode);
+cb->next_item_length = GET(code, 1 + LINK_SIZE + extracode);
+
+if (code[extracode] == OP_CALLOUT)
+  {
+  cb->callout_number = code[1 + 2*LINK_SIZE + extracode];
+  cb->callout_string_offset = 0;
+  cb->callout_string = NULL;
+  cb->callout_string_length = 0;
+  }
+else
+  {
+  cb->callout_number = 0;
+  cb->callout_string_offset = GET(code, 1 + 3*LINK_SIZE + extracode);
+  cb->callout_string = code + (1 + 4*LINK_SIZE + extracode) + 1;
+  cb->callout_string_length = *lengthptr - (1 + 4*LINK_SIZE) - 2;
+  }
+
+return (mb->callout)(cb, mb->callout_data);
+}
+
+
+
+/*************************************************
+*         Expand local workspace memory          *
+*************************************************/
+
+/* This function is called when internal_dfa_match() is about to be called
+recursively and there is insufficient working space left in the current
+workspace block. If there's an existing next block, use it; otherwise get a new
+block unless the heap limit is reached.
+
+Arguments:
+  rwsptr     pointer to block pointer (updated)
+  ovecsize   space needed for an ovector
+  mb         the match block
+
+Returns:     0 rwsptr has been updated
+            !0 an error code
+*/
+
+static int
+more_workspace(RWS_anchor **rwsptr, unsigned int ovecsize, dfa_match_block *mb)
+{
+RWS_anchor *rws = *rwsptr;
+RWS_anchor *new;
+
+if (rws->next != NULL)
+  {
+  new = rws->next;
+  }
+
+/* Sizes in the RWS_anchor blocks are in units of sizeof(int), but
+mb->heap_limit and mb->heap_used are in kibibytes. Play carefully, to avoid
+overflow. */
+
+else
+  {
+  uint32_t newsize = (rws->size >= UINT32_MAX/2)? UINT32_MAX/2 : rws->size * 2;
+  uint32_t newsizeK = newsize/(1024/sizeof(int));
+
+  if (newsizeK + mb->heap_used > mb->heap_limit)
+    newsizeK = (uint32_t)(mb->heap_limit - mb->heap_used);
+  newsize = newsizeK*(1024/sizeof(int));
+
+  if (newsize < RWS_RSIZE + ovecsize + RWS_ANCHOR_SIZE)
+    return PCRE2_ERROR_HEAPLIMIT;
+  new = mb->memctl.malloc(newsize*sizeof(int), mb->memctl.memory_data);
+  if (new == NULL) return PCRE2_ERROR_NOMEMORY;
+  mb->heap_used += newsizeK;
+  new->next = NULL;
+  new->size = newsize;
+  rws->next = new;
+  }
+
+new->free = new->size - RWS_ANCHOR_SIZE;
+*rwsptr = new;
+return 0;
+}
+
+
+
+/*************************************************
+*     Match a Regular Expression - DFA engine    *
+*************************************************/
+
+/* This internal function applies a compiled pattern to a subject string,
+starting at a given point, using a DFA engine. This function is called from the
+external one, possibly multiple times if the pattern is not anchored. The
+function calls itself recursively for some kinds of subpattern.
+
+Arguments:
+  mb                the match_data block with fixed information
+  this_start_code   the opening bracket of this subexpression's code
+  current_subject   where we currently are in the subject string
+  start_offset      start offset in the subject string
+  offsets           vector to contain the matching string offsets
+  offsetcount       size of same
+  workspace         vector of workspace
+  wscount           size of same
+  rlevel            function call recursion level
+
+Returns:            > 0 => number of match offset pairs placed in offsets
+                    = 0 => offsets overflowed; longest matches are present
+                     -1 => failed to match
+                   < -1 => some kind of unexpected problem
+
+The following macros are used for adding states to the two state vectors (one
+for the current character, one for the following character). */
+
+#define ADD_ACTIVE(x,y) \
+  if (active_count++ < wscount) \
+    { \
+    next_active_state->offset = (x); \
+    next_active_state->count  = (y); \
+    next_active_state++; \
+    } \
+  else return PCRE2_ERROR_DFA_WSSIZE
+
+#define ADD_ACTIVE_DATA(x,y,z) \
+  if (active_count++ < wscount) \
+    { \
+    next_active_state->offset = (x); \
+    next_active_state->count  = (y); \
+    next_active_state->data   = (z); \
+    next_active_state++; \
+    } \
+  else return PCRE2_ERROR_DFA_WSSIZE
+
+#define ADD_NEW(x,y) \
+  if (new_count++ < wscount) \
+    { \
+    next_new_state->offset = (x); \
+    next_new_state->count  = (y); \
+    next_new_state++; \
+    } \
+  else return PCRE2_ERROR_DFA_WSSIZE
+
+#define ADD_NEW_DATA(x,y,z) \
+  if (new_count++ < wscount) \
+    { \
+    next_new_state->offset = (x); \
+    next_new_state->count  = (y); \
+    next_new_state->data   = (z); \
+    next_new_state++; \
+    } \
+  else return PCRE2_ERROR_DFA_WSSIZE
+
+/* And now, here is the code */
+
+static int
+internal_dfa_match(
+  dfa_match_block *mb,
+  PCRE2_SPTR this_start_code,
+  PCRE2_SPTR current_subject,
+  PCRE2_SIZE start_offset,
+  PCRE2_SIZE *offsets,
+  uint32_t offsetcount,
+  int *workspace,
+  int wscount,
+  uint32_t rlevel,
+  int *RWS)
+{
+stateblock *active_states, *new_states, *temp_states;
+stateblock *next_active_state, *next_new_state;
+const uint8_t *ctypes, *lcc, *fcc;
+PCRE2_SPTR ptr;
+PCRE2_SPTR end_code;
+dfa_recursion_info new_recursive;
+int active_count, new_count, match_count;
+
+/* Some fields in the mb block are frequently referenced, so we load them into
+independent variables in the hope that this will perform better. */
+
+PCRE2_SPTR start_subject = mb->start_subject;
+PCRE2_SPTR end_subject = mb->end_subject;
+PCRE2_SPTR start_code = mb->start_code;
+
+#ifdef SUPPORT_UNICODE
+BOOL utf = (mb->poptions & PCRE2_UTF) != 0;
+BOOL utf_or_ucp = utf || (mb->poptions & PCRE2_UCP) != 0;
+#else
+BOOL utf = FALSE;
+#endif
+
+BOOL reset_could_continue = FALSE;
+
+if (mb->match_call_count++ >= mb->match_limit) return PCRE2_ERROR_MATCHLIMIT;
+if (rlevel++ > mb->match_limit_depth) return PCRE2_ERROR_DEPTHLIMIT;
+offsetcount &= (uint32_t)(-2);  /* Round down */
+
+wscount -= 2;
+wscount = (wscount - (wscount % (INTS_PER_STATEBLOCK * 2))) /
+          (2 * INTS_PER_STATEBLOCK);
+
+ctypes = mb->tables + ctypes_offset;
+lcc = mb->tables + lcc_offset;
+fcc = mb->tables + fcc_offset;
+
+match_count = PCRE2_ERROR_NOMATCH;   /* A negative number */
+
+active_states = (stateblock *)(workspace + 2);
+next_new_state = new_states = active_states + wscount;
+new_count = 0;
+
+/* The first thing in any (sub) pattern is a bracket of some sort. Push all
+the alternative states onto the list, and find out where the end is. This
+makes is possible to use this function recursively, when we want to stop at a
+matching internal ket rather than at the end.
+
+If we are dealing with a backward assertion we have to find out the maximum
+amount to move back, and set up each alternative appropriately. */
+
+if (*this_start_code == OP_ASSERTBACK || *this_start_code == OP_ASSERTBACK_NOT)
+  {
+  size_t max_back = 0;
+  size_t gone_back;
+
+  end_code = this_start_code;
+  do
+    {
+    size_t back = (size_t)GET(end_code, 2+LINK_SIZE);
+    if (back > max_back) max_back = back;
+    end_code += GET(end_code, 1);
+    }
+  while (*end_code == OP_ALT);
+
+  /* If we can't go back the amount required for the longest lookbehind
+  pattern, go back as far as we can; some alternatives may still be viable. */
+
+#ifdef SUPPORT_UNICODE
+  /* In character mode we have to step back character by character */
+
+  if (utf)
+    {
+    for (gone_back = 0; gone_back < max_back; gone_back++)
+      {
+      if (current_subject <= start_subject) break;
+      current_subject--;
+      ACROSSCHAR(current_subject > start_subject, current_subject,
+        current_subject--);
+      }
+    }
+  else
+#endif
+
+  /* In byte-mode we can do this quickly. */
+
+    {
+    size_t current_offset = (size_t)(current_subject - start_subject);
+    gone_back = (current_offset < max_back)? current_offset : max_back;
+    current_subject -= gone_back;
+    }
+
+  /* Save the earliest consulted character */
+
+  if (current_subject < mb->start_used_ptr)
+    mb->start_used_ptr = current_subject;
+
+  /* Now we can process the individual branches. There will be an OP_REVERSE at
+  the start of each branch, except when the length of the branch is zero. */
+
+  end_code = this_start_code;
+  do
+    {
+    uint32_t revlen = (end_code[1+LINK_SIZE] == OP_REVERSE)? 1 + LINK_SIZE : 0;
+    size_t back = (revlen == 0)? 0 : (size_t)GET(end_code, 2+LINK_SIZE);
+    if (back <= gone_back)
+      {
+      int bstate = (int)(end_code - start_code + 1 + LINK_SIZE + revlen);
+      ADD_NEW_DATA(-bstate, 0, (int)(gone_back - back));
+      }
+    end_code += GET(end_code, 1);
+    }
+  while (*end_code == OP_ALT);
+ }
+
+/* This is the code for a "normal" subpattern (not a backward assertion). The
+start of a whole pattern is always one of these. If we are at the top level,
+we may be asked to restart matching from the same point that we reached for a
+previous partial match. We still have to scan through the top-level branches to
+find the end state. */
+
+else
+  {
+  end_code = this_start_code;
+
+  /* Restarting */
+
+  if (rlevel == 1 && (mb->moptions & PCRE2_DFA_RESTART) != 0)
+    {
+    do { end_code += GET(end_code, 1); } while (*end_code == OP_ALT);
+    new_count = workspace[1];
+    if (!workspace[0])
+      memcpy(new_states, active_states, (size_t)new_count * sizeof(stateblock));
+    }
+
+  /* Not restarting */
+
+  else
+    {
+    int length = 1 + LINK_SIZE +
+      ((*this_start_code == OP_CBRA || *this_start_code == OP_SCBRA ||
+        *this_start_code == OP_CBRAPOS || *this_start_code == OP_SCBRAPOS)
+        ? IMM2_SIZE:0);
+    do
+      {
+      ADD_NEW((int)(end_code - start_code + length), 0);
+      end_code += GET(end_code, 1);
+      length = 1 + LINK_SIZE;
+      }
+    while (*end_code == OP_ALT);
+    }
+  }
+
+workspace[0] = 0;    /* Bit indicating which vector is current */
+
+/* Loop for scanning the subject */
+
+ptr = current_subject;
+for (;;)
+  {
+  int i, j;
+  int clen, dlen;
+  uint32_t c, d;
+  int forced_fail = 0;
+  BOOL partial_newline = FALSE;
+  BOOL could_continue = reset_could_continue;
+  reset_could_continue = FALSE;
+
+  if (ptr > mb->last_used_ptr) mb->last_used_ptr = ptr;
+
+  /* Make the new state list into the active state list and empty the
+  new state list. */
+
+  temp_states = active_states;
+  active_states = new_states;
+  new_states = temp_states;
+  active_count = new_count;
+  new_count = 0;
+
+  workspace[0] ^= 1;              /* Remember for the restarting feature */
+  workspace[1] = active_count;
+
+  /* Set the pointers for adding new states */
+
+  next_active_state = active_states + active_count;
+  next_new_state = new_states;
+
+  /* Load the current character from the subject outside the loop, as many
+  different states may want to look at it, and we assume that at least one
+  will. */
+
+  if (ptr < end_subject)
+    {
+    clen = 1;        /* Number of data items in the character */
+#ifdef SUPPORT_UNICODE
+    GETCHARLENTEST(c, ptr, clen);
+#else
+    c = *ptr;
+#endif  /* SUPPORT_UNICODE */
+    }
+  else
+    {
+    clen = 0;        /* This indicates the end of the subject */
+    c = NOTACHAR;    /* This value should never actually be used */
+    }
+
+  /* Scan up the active states and act on each one. The result of an action
+  may be to add more states to the currently active list (e.g. on hitting a
+  parenthesis) or it may be to put states on the new list, for considering
+  when we move the character pointer on. */
+
+  for (i = 0; i < active_count; i++)
+    {
+    stateblock *current_state = active_states + i;
+    BOOL caseless = FALSE;
+    PCRE2_SPTR code;
+    uint32_t codevalue;
+    int state_offset = current_state->offset;
+    int rrc;
+    int count;
+
+    /* A negative offset is a special case meaning "hold off going to this
+    (negated) state until the number of characters in the data field have
+    been skipped". If the could_continue flag was passed over from a previous
+    state, arrange for it to passed on. */
+
+    if (state_offset < 0)
+      {
+      if (current_state->data > 0)
+        {
+        ADD_NEW_DATA(state_offset, current_state->count,
+          current_state->data - 1);
+        if (could_continue) reset_could_continue = TRUE;
+        continue;
+        }
+      else
+        {
+        current_state->offset = state_offset = -state_offset;
+        }
+      }
+
+    /* Check for a duplicate state with the same count, and skip if found.
+    See the note at the head of this module about the possibility of improving
+    performance here. */
+
+    for (j = 0; j < i; j++)
+      {
+      if (active_states[j].offset == state_offset &&
+          active_states[j].count == current_state->count)
+        goto NEXT_ACTIVE_STATE;
+      }
+
+    /* The state offset is the offset to the opcode */
+
+    code = start_code + state_offset;
+    codevalue = *code;
+
+    /* If this opcode inspects a character, but we are at the end of the
+    subject, remember the fact for use when testing for a partial match. */
+
+    if (clen == 0 && poptable[codevalue] != 0)
+      could_continue = TRUE;
+
+    /* If this opcode is followed by an inline character, load it. It is
+    tempting to test for the presence of a subject character here, but that
+    is wrong, because sometimes zero repetitions of the subject are
+    permitted.
+
+    We also use this mechanism for opcodes such as OP_TYPEPLUS that take an
+    argument that is not a data character - but is always one byte long because
+    the values are small. We have to take special action to deal with  \P, \p,
+    \H, \h, \V, \v and \X in this case. To keep the other cases fast, convert
+    these ones to new opcodes. */
+
+    if (coptable[codevalue] > 0)
+      {
+      dlen = 1;
+#ifdef SUPPORT_UNICODE
+      if (utf) { GETCHARLEN(d, (code + coptable[codevalue]), dlen); } else
+#endif  /* SUPPORT_UNICODE */
+      d = code[coptable[codevalue]];
+      if (codevalue >= OP_TYPESTAR)
+        {
+        switch(d)
+          {
+          case OP_ANYBYTE: return PCRE2_ERROR_DFA_UITEM;
+          case OP_NOTPROP:
+          case OP_PROP: codevalue += OP_PROP_EXTRA; break;
+          case OP_ANYNL: codevalue += OP_ANYNL_EXTRA; break;
+          case OP_EXTUNI: codevalue += OP_EXTUNI_EXTRA; break;
+          case OP_NOT_HSPACE:
+          case OP_HSPACE: codevalue += OP_HSPACE_EXTRA; break;
+          case OP_NOT_VSPACE:
+          case OP_VSPACE: codevalue += OP_VSPACE_EXTRA; break;
+          default: break;
+          }
+        }
+      }
+    else
+      {
+      dlen = 0;         /* Not strictly necessary, but compilers moan */
+      d = NOTACHAR;     /* if these variables are not set. */
+      }
+
+
+    /* Now process the individual opcodes */
+
+    switch (codevalue)
+      {
+/* ========================================================================== */
+      /* These cases are never obeyed. This is a fudge that causes a compile-
+      time error if the vectors coptable or poptable, which are indexed by
+      opcode, are not the correct length. It seems to be the only way to do
+      such a check at compile time, as the sizeof() operator does not work
+      in the C preprocessor. */
+
+      case OP_TABLE_LENGTH:
+      case OP_TABLE_LENGTH +
+        ((sizeof(coptable) == OP_TABLE_LENGTH) &&
+         (sizeof(poptable) == OP_TABLE_LENGTH)):
+      return 0;
+
+/* ========================================================================== */
+      /* Reached a closing bracket. If not at the end of the pattern, carry
+      on with the next opcode. For repeating opcodes, also add the repeat
+      state. Note that KETRPOS will always be encountered at the end of the
+      subpattern, because the possessive subpattern repeats are always handled
+      using recursive calls. Thus, it never adds any new states.
+
+      At the end of the (sub)pattern, unless we have an empty string and
+      PCRE2_NOTEMPTY is set, or PCRE2_NOTEMPTY_ATSTART is set and we are at the
+      start of the subject, save the match data, shifting up all previous
+      matches so we always have the longest first. */
+
+      case OP_KET:
+      case OP_KETRMIN:
+      case OP_KETRMAX:
+      case OP_KETRPOS:
+      if (code != end_code)
+        {
+        ADD_ACTIVE(state_offset + 1 + LINK_SIZE, 0);
+        if (codevalue != OP_KET)
+          {
+          ADD_ACTIVE(state_offset - (int)GET(code, 1), 0);
+          }
+        }
+      else
+        {
+        if (ptr > current_subject ||
+            ((mb->moptions & PCRE2_NOTEMPTY) == 0 &&
+              ((mb->moptions & PCRE2_NOTEMPTY_ATSTART) == 0 ||
+                current_subject > start_subject + mb->start_offset)))
+          {
+          if (match_count < 0) match_count = (offsetcount >= 2)? 1 : 0;
+            else if (match_count > 0 && ++match_count * 2 > (int)offsetcount)
+              match_count = 0;
+          count = ((match_count == 0)? (int)offsetcount : match_count * 2) - 2;
+          if (count > 0) (void)memmove(offsets + 2, offsets,
+            (size_t)count * sizeof(PCRE2_SIZE));
+          if (offsetcount >= 2)
+            {
+            offsets[0] = (PCRE2_SIZE)(current_subject - start_subject);
+            offsets[1] = (PCRE2_SIZE)(ptr - start_subject);
+            }
+          if ((mb->moptions & PCRE2_DFA_SHORTEST) != 0) return match_count;
+          }
+        }
+      break;
+
+/* ========================================================================== */
+      /* These opcodes add to the current list of states without looking
+      at the current character. */
+
+      /*-----------------------------------------------------------------*/
+      case OP_ALT:
+      do { code += GET(code, 1); } while (*code == OP_ALT);
+      ADD_ACTIVE((int)(code - start_code), 0);
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_BRA:
+      case OP_SBRA:
+      do
+        {
+        ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE), 0);
+        code += GET(code, 1);
+        }
+      while (*code == OP_ALT);
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_CBRA:
+      case OP_SCBRA:
+      ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE + IMM2_SIZE),  0);
+      code += GET(code, 1);
+      while (*code == OP_ALT)
+        {
+        ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE),  0);
+        code += GET(code, 1);
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_BRAZERO:
+      case OP_BRAMINZERO:
+      ADD_ACTIVE(state_offset + 1, 0);
+      code += 1 + GET(code, 2);
+      while (*code == OP_ALT) code += GET(code, 1);
+      ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE), 0);
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_SKIPZERO:
+      code += 1 + GET(code, 2);
+      while (*code == OP_ALT) code += GET(code, 1);
+      ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE), 0);
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_CIRC:
+      if (ptr == start_subject && (mb->moptions & PCRE2_NOTBOL) == 0)
+        { ADD_ACTIVE(state_offset + 1, 0); }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_CIRCM:
+      if ((ptr == start_subject && (mb->moptions & PCRE2_NOTBOL) == 0) ||
+          ((ptr != end_subject || (mb->poptions & PCRE2_ALT_CIRCUMFLEX) != 0 )
+            && WAS_NEWLINE(ptr)))
+        { ADD_ACTIVE(state_offset + 1, 0); }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_EOD:
+      if (ptr >= end_subject)
+        {
+        if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+          return PCRE2_ERROR_PARTIAL;
+        else { ADD_ACTIVE(state_offset + 1, 0); }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_SOD:
+      if (ptr == start_subject) { ADD_ACTIVE(state_offset + 1, 0); }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_SOM:
+      if (ptr == start_subject + start_offset) { ADD_ACTIVE(state_offset + 1, 0); }
+      break;
+
+
+/* ========================================================================== */
+      /* These opcodes inspect the next subject character, and sometimes
+      the previous one as well, but do not have an argument. The variable
+      clen contains the length of the current character and is zero if we are
+      at the end of the subject. */
+
+      /*-----------------------------------------------------------------*/
+      case OP_ANY:
+      if (clen > 0 && !IS_NEWLINE(ptr))
+        {
+        if (ptr + 1 >= mb->end_subject &&
+            (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
+            NLBLOCK->nltype == NLTYPE_FIXED &&
+            NLBLOCK->nllen == 2 &&
+            c == NLBLOCK->nl[0])
+          {
+          could_continue = partial_newline = TRUE;
+          }
+        else
+          {
+          ADD_NEW(state_offset + 1, 0);
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_ALLANY:
+      if (clen > 0)
+        { ADD_NEW(state_offset + 1, 0); }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_EODN:
+      if (clen == 0 || (IS_NEWLINE(ptr) && ptr == end_subject - mb->nllen))
+        {
+        if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+          return PCRE2_ERROR_PARTIAL;
+        ADD_ACTIVE(state_offset + 1, 0);
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_DOLL:
+      if ((mb->moptions & PCRE2_NOTEOL) == 0)
+        {
+        if (clen == 0 && (mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+          could_continue = TRUE;
+        else if (clen == 0 ||
+            ((mb->poptions & PCRE2_DOLLAR_ENDONLY) == 0 && IS_NEWLINE(ptr) &&
+               (ptr == end_subject - mb->nllen)
+            ))
+          { ADD_ACTIVE(state_offset + 1, 0); }
+        else if (ptr + 1 >= mb->end_subject &&
+                 (mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0 &&
+                 NLBLOCK->nltype == NLTYPE_FIXED &&
+                 NLBLOCK->nllen == 2 &&
+                 c == NLBLOCK->nl[0])
+          {
+          if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+            {
+            reset_could_continue = TRUE;
+            ADD_NEW_DATA(-(state_offset + 1), 0, 1);
+            }
+          else could_continue = partial_newline = TRUE;
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_DOLLM:
+      if ((mb->moptions & PCRE2_NOTEOL) == 0)
+        {
+        if (clen == 0 && (mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+          could_continue = TRUE;
+        else if (clen == 0 ||
+            ((mb->poptions & PCRE2_DOLLAR_ENDONLY) == 0 && IS_NEWLINE(ptr)))
+          { ADD_ACTIVE(state_offset + 1, 0); }
+        else if (ptr + 1 >= mb->end_subject &&
+                 (mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0 &&
+                 NLBLOCK->nltype == NLTYPE_FIXED &&
+                 NLBLOCK->nllen == 2 &&
+                 c == NLBLOCK->nl[0])
+          {
+          if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+            {
+            reset_could_continue = TRUE;
+            ADD_NEW_DATA(-(state_offset + 1), 0, 1);
+            }
+          else could_continue = partial_newline = TRUE;
+          }
+        }
+      else if (IS_NEWLINE(ptr))
+        { ADD_ACTIVE(state_offset + 1, 0); }
+      break;
+
+      /*-----------------------------------------------------------------*/
+
+      case OP_DIGIT:
+      case OP_WHITESPACE:
+      case OP_WORDCHAR:
+      if (clen > 0 && c < 256 &&
+            ((ctypes[c] & toptable1[codevalue]) ^ toptable2[codevalue]) != 0)
+        { ADD_NEW(state_offset + 1, 0); }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_NOT_DIGIT:
+      case OP_NOT_WHITESPACE:
+      case OP_NOT_WORDCHAR:
+      if (clen > 0 && (c >= 256 ||
+            ((ctypes[c] & toptable1[codevalue]) ^ toptable2[codevalue]) != 0))
+        { ADD_NEW(state_offset + 1, 0); }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_WORD_BOUNDARY:
+      case OP_NOT_WORD_BOUNDARY:
+        {
+        int left_word, right_word;
+
+        if (ptr > start_subject)
+          {
+          PCRE2_SPTR temp = ptr - 1;
+          if (temp < mb->start_used_ptr) mb->start_used_ptr = temp;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+          if (utf) { BACKCHAR(temp); }
+#endif
+          GETCHARTEST(d, temp);
+#ifdef SUPPORT_UNICODE
+          if ((mb->poptions & PCRE2_UCP) != 0)
+            {
+            if (d == '_') left_word = TRUE; else
+              {
+              uint32_t cat = UCD_CATEGORY(d);
+              left_word = (cat == ucp_L || cat == ucp_N);
+              }
+            }
+          else
+#endif
+          left_word = d < 256 && (ctypes[d] & ctype_word) != 0;
+          }
+        else left_word = FALSE;
+
+        if (clen > 0)
+          {
+          if (ptr >= mb->last_used_ptr)
+            {
+            PCRE2_SPTR temp = ptr + 1;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+            if (utf) { FORWARDCHARTEST(temp, mb->end_subject); }
+#endif
+            mb->last_used_ptr = temp;
+            }
+#ifdef SUPPORT_UNICODE
+          if ((mb->poptions & PCRE2_UCP) != 0)
+            {
+            if (c == '_') right_word = TRUE; else
+              {
+              uint32_t cat = UCD_CATEGORY(c);
+              right_word = (cat == ucp_L || cat == ucp_N);
+              }
+            }
+          else
+#endif
+          right_word = c < 256 && (ctypes[c] & ctype_word) != 0;
+          }
+        else right_word = FALSE;
+
+        if ((left_word == right_word) == (codevalue == OP_NOT_WORD_BOUNDARY))
+          { ADD_ACTIVE(state_offset + 1, 0); }
+        }
+      break;
+
+
+      /*-----------------------------------------------------------------*/
+      /* Check the next character by Unicode property. We will get here only
+      if the support is in the binary; otherwise a compile-time error occurs.
+      */
+
+#ifdef SUPPORT_UNICODE
+      case OP_PROP:
+      case OP_NOTPROP:
+      if (clen > 0)
+        {
+        BOOL OK;
+        const uint32_t *cp;
+        const ucd_record * prop = GET_UCD(c);
+        switch(code[1])
+          {
+          case PT_ANY:
+          OK = TRUE;
+          break;
+
+          case PT_LAMP:
+          OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
+               prop->chartype == ucp_Lt;
+          break;
+
+          case PT_GC:
+          OK = PRIV(ucp_gentype)[prop->chartype] == code[2];
+          break;
+
+          case PT_PC:
+          OK = prop->chartype == code[2];
+          break;
+
+          case PT_SC:
+          OK = prop->script == code[2];
+          break;
+
+          /* These are specials for combination cases. */
+
+          case PT_ALNUM:
+          OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+               PRIV(ucp_gentype)[prop->chartype] == ucp_N;
+          break;
+
+          /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+          which means that Perl space and POSIX space are now identical. PCRE
+          was changed at release 8.34. */
+
+          case PT_SPACE:    /* Perl space */
+          case PT_PXSPACE:  /* POSIX space */
+          switch(c)
+            {
+            HSPACE_CASES:
+            VSPACE_CASES:
+            OK = TRUE;
+            break;
+
+            default:
+            OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z;
+            break;
+            }
+          break;
+
+          case PT_WORD:
+          OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+               PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
+               c == CHAR_UNDERSCORE;
+          break;
+
+          case PT_CLIST:
+          cp = PRIV(ucd_caseless_sets) + code[2];
+          for (;;)
+            {
+            if (c < *cp) { OK = FALSE; break; }
+            if (c == *cp++) { OK = TRUE; break; }
+            }
+          break;
+
+          case PT_UCNC:
+          OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT ||
+               c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) ||
+               c >= 0xe000;
+          break;
+
+          /* Should never occur, but keep compilers from grumbling. */
+
+          default:
+          OK = codevalue != OP_PROP;
+          break;
+          }
+
+        if (OK == (codevalue == OP_PROP)) { ADD_NEW(state_offset + 3, 0); }
+        }
+      break;
+#endif
+
+
+
+/* ========================================================================== */
+      /* These opcodes likewise inspect the subject character, but have an
+      argument that is not a data character. It is one of these opcodes:
+      OP_ANY, OP_ALLANY, OP_DIGIT, OP_NOT_DIGIT, OP_WHITESPACE, OP_NOT_SPACE,
+      OP_WORDCHAR, OP_NOT_WORDCHAR. The value is loaded into d. */
+
+      case OP_TYPEPLUS:
+      case OP_TYPEMINPLUS:
+      case OP_TYPEPOSPLUS:
+      count = current_state->count;  /* Already matched */
+      if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); }
+      if (clen > 0)
+        {
+        if (d == OP_ANY && ptr + 1 >= mb->end_subject &&
+            (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
+            NLBLOCK->nltype == NLTYPE_FIXED &&
+            NLBLOCK->nllen == 2 &&
+            c == NLBLOCK->nl[0])
+          {
+          could_continue = partial_newline = TRUE;
+          }
+        else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) ||
+            (c < 256 &&
+              (d != OP_ANY || !IS_NEWLINE(ptr)) &&
+              ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0))
+          {
+          if (count > 0 && codevalue == OP_TYPEPOSPLUS)
+            {
+            active_count--;            /* Remove non-match possibility */
+            next_active_state--;
+            }
+          count++;
+          ADD_NEW(state_offset, count);
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_TYPEQUERY:
+      case OP_TYPEMINQUERY:
+      case OP_TYPEPOSQUERY:
+      ADD_ACTIVE(state_offset + 2, 0);
+      if (clen > 0)
+        {
+        if (d == OP_ANY && ptr + 1 >= mb->end_subject &&
+            (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
+            NLBLOCK->nltype == NLTYPE_FIXED &&
+            NLBLOCK->nllen == 2 &&
+            c == NLBLOCK->nl[0])
+          {
+          could_continue = partial_newline = TRUE;
+          }
+        else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) ||
+            (c < 256 &&
+              (d != OP_ANY || !IS_NEWLINE(ptr)) &&
+              ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0))
+          {
+          if (codevalue == OP_TYPEPOSQUERY)
+            {
+            active_count--;            /* Remove non-match possibility */
+            next_active_state--;
+            }
+          ADD_NEW(state_offset + 2, 0);
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_TYPESTAR:
+      case OP_TYPEMINSTAR:
+      case OP_TYPEPOSSTAR:
+      ADD_ACTIVE(state_offset + 2, 0);
+      if (clen > 0)
+        {
+        if (d == OP_ANY && ptr + 1 >= mb->end_subject &&
+            (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
+            NLBLOCK->nltype == NLTYPE_FIXED &&
+            NLBLOCK->nllen == 2 &&
+            c == NLBLOCK->nl[0])
+          {
+          could_continue = partial_newline = TRUE;
+          }
+        else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) ||
+            (c < 256 &&
+              (d != OP_ANY || !IS_NEWLINE(ptr)) &&
+              ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0))
+          {
+          if (codevalue == OP_TYPEPOSSTAR)
+            {
+            active_count--;            /* Remove non-match possibility */
+            next_active_state--;
+            }
+          ADD_NEW(state_offset, 0);
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_TYPEEXACT:
+      count = current_state->count;  /* Number already matched */
+      if (clen > 0)
+        {
+        if (d == OP_ANY && ptr + 1 >= mb->end_subject &&
+            (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
+            NLBLOCK->nltype == NLTYPE_FIXED &&
+            NLBLOCK->nllen == 2 &&
+            c == NLBLOCK->nl[0])
+          {
+          could_continue = partial_newline = TRUE;
+          }
+        else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) ||
+            (c < 256 &&
+              (d != OP_ANY || !IS_NEWLINE(ptr)) &&
+              ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0))
+          {
+          if (++count >= (int)GET2(code, 1))
+            { ADD_NEW(state_offset + 1 + IMM2_SIZE + 1, 0); }
+          else
+            { ADD_NEW(state_offset, count); }
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_TYPEUPTO:
+      case OP_TYPEMINUPTO:
+      case OP_TYPEPOSUPTO:
+      ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0);
+      count = current_state->count;  /* Number already matched */
+      if (clen > 0)
+        {
+        if (d == OP_ANY && ptr + 1 >= mb->end_subject &&
+            (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
+            NLBLOCK->nltype == NLTYPE_FIXED &&
+            NLBLOCK->nllen == 2 &&
+            c == NLBLOCK->nl[0])
+          {
+          could_continue = partial_newline = TRUE;
+          }
+        else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) ||
+            (c < 256 &&
+              (d != OP_ANY || !IS_NEWLINE(ptr)) &&
+              ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0))
+          {
+          if (codevalue == OP_TYPEPOSUPTO)
+            {
+            active_count--;           /* Remove non-match possibility */
+            next_active_state--;
+            }
+          if (++count >= (int)GET2(code, 1))
+            { ADD_NEW(state_offset + 2 + IMM2_SIZE, 0); }
+          else
+            { ADD_NEW(state_offset, count); }
+          }
+        }
+      break;
+
+/* ========================================================================== */
+      /* These are virtual opcodes that are used when something like
+      OP_TYPEPLUS has OP_PROP, OP_NOTPROP, OP_ANYNL, or OP_EXTUNI as its
+      argument. It keeps the code above fast for the other cases. The argument
+      is in the d variable. */
+
+#ifdef SUPPORT_UNICODE
+      case OP_PROP_EXTRA + OP_TYPEPLUS:
+      case OP_PROP_EXTRA + OP_TYPEMINPLUS:
+      case OP_PROP_EXTRA + OP_TYPEPOSPLUS:
+      count = current_state->count;           /* Already matched */
+      if (count > 0) { ADD_ACTIVE(state_offset + 4, 0); }
+      if (clen > 0)
+        {
+        BOOL OK;
+        const uint32_t *cp;
+        const ucd_record * prop = GET_UCD(c);
+        switch(code[2])
+          {
+          case PT_ANY:
+          OK = TRUE;
+          break;
+
+          case PT_LAMP:
+          OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
+            prop->chartype == ucp_Lt;
+          break;
+
+          case PT_GC:
+          OK = PRIV(ucp_gentype)[prop->chartype] == code[3];
+          break;
+
+          case PT_PC:
+          OK = prop->chartype == code[3];
+          break;
+
+          case PT_SC:
+          OK = prop->script == code[3];
+          break;
+
+          /* These are specials for combination cases. */
+
+          case PT_ALNUM:
+          OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+               PRIV(ucp_gentype)[prop->chartype] == ucp_N;
+          break;
+
+          /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+          which means that Perl space and POSIX space are now identical. PCRE
+          was changed at release 8.34. */
+
+          case PT_SPACE:    /* Perl space */
+          case PT_PXSPACE:  /* POSIX space */
+          switch(c)
+            {
+            HSPACE_CASES:
+            VSPACE_CASES:
+            OK = TRUE;
+            break;
+
+            default:
+            OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z;
+            break;
+            }
+          break;
+
+          case PT_WORD:
+          OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+               PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
+               c == CHAR_UNDERSCORE;
+          break;
+
+          case PT_CLIST:
+          cp = PRIV(ucd_caseless_sets) + code[3];
+          for (;;)
+            {
+            if (c < *cp) { OK = FALSE; break; }
+            if (c == *cp++) { OK = TRUE; break; }
+            }
+          break;
+
+          case PT_UCNC:
+          OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT ||
+               c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) ||
+               c >= 0xe000;
+          break;
+
+          /* Should never occur, but keep compilers from grumbling. */
+
+          default:
+          OK = codevalue != OP_PROP;
+          break;
+          }
+
+        if (OK == (d == OP_PROP))
+          {
+          if (count > 0 && codevalue == OP_PROP_EXTRA + OP_TYPEPOSPLUS)
+            {
+            active_count--;           /* Remove non-match possibility */
+            next_active_state--;
+            }
+          count++;
+          ADD_NEW(state_offset, count);
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_EXTUNI_EXTRA + OP_TYPEPLUS:
+      case OP_EXTUNI_EXTRA + OP_TYPEMINPLUS:
+      case OP_EXTUNI_EXTRA + OP_TYPEPOSPLUS:
+      count = current_state->count;  /* Already matched */
+      if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); }
+      if (clen > 0)
+        {
+        int ncount = 0;
+        if (count > 0 && codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSPLUS)
+          {
+          active_count--;           /* Remove non-match possibility */
+          next_active_state--;
+          }
+        (void)PRIV(extuni)(c, ptr + clen, mb->start_subject, end_subject, utf,
+          &ncount);
+        count++;
+        ADD_NEW_DATA(-state_offset, count, ncount);
+        }
+      break;
+#endif
+
+      /*-----------------------------------------------------------------*/
+      case OP_ANYNL_EXTRA + OP_TYPEPLUS:
+      case OP_ANYNL_EXTRA + OP_TYPEMINPLUS:
+      case OP_ANYNL_EXTRA + OP_TYPEPOSPLUS:
+      count = current_state->count;  /* Already matched */
+      if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); }
+      if (clen > 0)
+        {
+        int ncount = 0;
+        switch (c)
+          {
+          case CHAR_VT:
+          case CHAR_FF:
+          case CHAR_NEL:
+#ifndef EBCDIC
+          case 0x2028:
+          case 0x2029:
+#endif  /* Not EBCDIC */
+          if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break;
+          goto ANYNL01;
+
+          case CHAR_CR:
+          if (ptr + 1 < end_subject && UCHAR21TEST(ptr + 1) == CHAR_LF) ncount = 1;
+          /* Fall through */
+
+          ANYNL01:
+          case CHAR_LF:
+          if (count > 0 && codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSPLUS)
+            {
+            active_count--;           /* Remove non-match possibility */
+            next_active_state--;
+            }
+          count++;
+          ADD_NEW_DATA(-state_offset, count, ncount);
+          break;
+
+          default:
+          break;
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_VSPACE_EXTRA + OP_TYPEPLUS:
+      case OP_VSPACE_EXTRA + OP_TYPEMINPLUS:
+      case OP_VSPACE_EXTRA + OP_TYPEPOSPLUS:
+      count = current_state->count;  /* Already matched */
+      if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); }
+      if (clen > 0)
+        {
+        BOOL OK;
+        switch (c)
+          {
+          VSPACE_CASES:
+          OK = TRUE;
+          break;
+
+          default:
+          OK = FALSE;
+          break;
+          }
+
+        if (OK == (d == OP_VSPACE))
+          {
+          if (count > 0 && codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSPLUS)
+            {
+            active_count--;           /* Remove non-match possibility */
+            next_active_state--;
+            }
+          count++;
+          ADD_NEW_DATA(-state_offset, count, 0);
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_HSPACE_EXTRA + OP_TYPEPLUS:
+      case OP_HSPACE_EXTRA + OP_TYPEMINPLUS:
+      case OP_HSPACE_EXTRA + OP_TYPEPOSPLUS:
+      count = current_state->count;  /* Already matched */
+      if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); }
+      if (clen > 0)
+        {
+        BOOL OK;
+        switch (c)
+          {
+          HSPACE_CASES:
+          OK = TRUE;
+          break;
+
+          default:
+          OK = FALSE;
+          break;
+          }
+
+        if (OK == (d == OP_HSPACE))
+          {
+          if (count > 0 && codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSPLUS)
+            {
+            active_count--;           /* Remove non-match possibility */
+            next_active_state--;
+            }
+          count++;
+          ADD_NEW_DATA(-state_offset, count, 0);
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+#ifdef SUPPORT_UNICODE
+      case OP_PROP_EXTRA + OP_TYPEQUERY:
+      case OP_PROP_EXTRA + OP_TYPEMINQUERY:
+      case OP_PROP_EXTRA + OP_TYPEPOSQUERY:
+      count = 4;
+      goto QS1;
+
+      case OP_PROP_EXTRA + OP_TYPESTAR:
+      case OP_PROP_EXTRA + OP_TYPEMINSTAR:
+      case OP_PROP_EXTRA + OP_TYPEPOSSTAR:
+      count = 0;
+
+      QS1:
+
+      ADD_ACTIVE(state_offset + 4, 0);
+      if (clen > 0)
+        {
+        BOOL OK;
+        const uint32_t *cp;
+        const ucd_record * prop = GET_UCD(c);
+        switch(code[2])
+          {
+          case PT_ANY:
+          OK = TRUE;
+          break;
+
+          case PT_LAMP:
+          OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
+            prop->chartype == ucp_Lt;
+          break;
+
+          case PT_GC:
+          OK = PRIV(ucp_gentype)[prop->chartype] == code[3];
+          break;
+
+          case PT_PC:
+          OK = prop->chartype == code[3];
+          break;
+
+          case PT_SC:
+          OK = prop->script == code[3];
+          break;
+
+          /* These are specials for combination cases. */
+
+          case PT_ALNUM:
+          OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+               PRIV(ucp_gentype)[prop->chartype] == ucp_N;
+          break;
+
+          /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+          which means that Perl space and POSIX space are now identical. PCRE
+          was changed at release 8.34. */
+
+          case PT_SPACE:    /* Perl space */
+          case PT_PXSPACE:  /* POSIX space */
+          switch(c)
+            {
+            HSPACE_CASES:
+            VSPACE_CASES:
+            OK = TRUE;
+            break;
+
+            default:
+            OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z;
+            break;
+            }
+          break;
+
+          case PT_WORD:
+          OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+               PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
+               c == CHAR_UNDERSCORE;
+          break;
+
+          case PT_CLIST:
+          cp = PRIV(ucd_caseless_sets) + code[3];
+          for (;;)
+            {
+            if (c < *cp) { OK = FALSE; break; }
+            if (c == *cp++) { OK = TRUE; break; }
+            }
+          break;
+
+          case PT_UCNC:
+          OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT ||
+               c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) ||
+               c >= 0xe000;
+          break;
+
+          /* Should never occur, but keep compilers from grumbling. */
+
+          default:
+          OK = codevalue != OP_PROP;
+          break;
+          }
+
+        if (OK == (d == OP_PROP))
+          {
+          if (codevalue == OP_PROP_EXTRA + OP_TYPEPOSSTAR ||
+              codevalue == OP_PROP_EXTRA + OP_TYPEPOSQUERY)
+            {
+            active_count--;           /* Remove non-match possibility */
+            next_active_state--;
+            }
+          ADD_NEW(state_offset + count, 0);
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_EXTUNI_EXTRA + OP_TYPEQUERY:
+      case OP_EXTUNI_EXTRA + OP_TYPEMINQUERY:
+      case OP_EXTUNI_EXTRA + OP_TYPEPOSQUERY:
+      count = 2;
+      goto QS2;
+
+      case OP_EXTUNI_EXTRA + OP_TYPESTAR:
+      case OP_EXTUNI_EXTRA + OP_TYPEMINSTAR:
+      case OP_EXTUNI_EXTRA + OP_TYPEPOSSTAR:
+      count = 0;
+
+      QS2:
+
+      ADD_ACTIVE(state_offset + 2, 0);
+      if (clen > 0)
+        {
+        int ncount = 0;
+        if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSSTAR ||
+            codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSQUERY)
+          {
+          active_count--;           /* Remove non-match possibility */
+          next_active_state--;
+          }
+        (void)PRIV(extuni)(c, ptr + clen, mb->start_subject, end_subject, utf,
+          &ncount);
+        ADD_NEW_DATA(-(state_offset + count), 0, ncount);
+        }
+      break;
+#endif
+
+      /*-----------------------------------------------------------------*/
+      case OP_ANYNL_EXTRA + OP_TYPEQUERY:
+      case OP_ANYNL_EXTRA + OP_TYPEMINQUERY:
+      case OP_ANYNL_EXTRA + OP_TYPEPOSQUERY:
+      count = 2;
+      goto QS3;
+
+      case OP_ANYNL_EXTRA + OP_TYPESTAR:
+      case OP_ANYNL_EXTRA + OP_TYPEMINSTAR:
+      case OP_ANYNL_EXTRA + OP_TYPEPOSSTAR:
+      count = 0;
+
+      QS3:
+      ADD_ACTIVE(state_offset + 2, 0);
+      if (clen > 0)
+        {
+        int ncount = 0;
+        switch (c)
+          {
+          case CHAR_VT:
+          case CHAR_FF:
+          case CHAR_NEL:
+#ifndef EBCDIC
+          case 0x2028:
+          case 0x2029:
+#endif  /* Not EBCDIC */
+          if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break;
+          goto ANYNL02;
+
+          case CHAR_CR:
+          if (ptr + 1 < end_subject && UCHAR21TEST(ptr + 1) == CHAR_LF) ncount = 1;
+          /* Fall through */
+
+          ANYNL02:
+          case CHAR_LF:
+          if (codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSSTAR ||
+              codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSQUERY)
+            {
+            active_count--;           /* Remove non-match possibility */
+            next_active_state--;
+            }
+          ADD_NEW_DATA(-(state_offset + (int)count), 0, ncount);
+          break;
+
+          default:
+          break;
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_VSPACE_EXTRA + OP_TYPEQUERY:
+      case OP_VSPACE_EXTRA + OP_TYPEMINQUERY:
+      case OP_VSPACE_EXTRA + OP_TYPEPOSQUERY:
+      count = 2;
+      goto QS4;
+
+      case OP_VSPACE_EXTRA + OP_TYPESTAR:
+      case OP_VSPACE_EXTRA + OP_TYPEMINSTAR:
+      case OP_VSPACE_EXTRA + OP_TYPEPOSSTAR:
+      count = 0;
+
+      QS4:
+      ADD_ACTIVE(state_offset + 2, 0);
+      if (clen > 0)
+        {
+        BOOL OK;
+        switch (c)
+          {
+          VSPACE_CASES:
+          OK = TRUE;
+          break;
+
+          default:
+          OK = FALSE;
+          break;
+          }
+        if (OK == (d == OP_VSPACE))
+          {
+          if (codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSSTAR ||
+              codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSQUERY)
+            {
+            active_count--;           /* Remove non-match possibility */
+            next_active_state--;
+            }
+          ADD_NEW_DATA(-(state_offset + (int)count), 0, 0);
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_HSPACE_EXTRA + OP_TYPEQUERY:
+      case OP_HSPACE_EXTRA + OP_TYPEMINQUERY:
+      case OP_HSPACE_EXTRA + OP_TYPEPOSQUERY:
+      count = 2;
+      goto QS5;
+
+      case OP_HSPACE_EXTRA + OP_TYPESTAR:
+      case OP_HSPACE_EXTRA + OP_TYPEMINSTAR:
+      case OP_HSPACE_EXTRA + OP_TYPEPOSSTAR:
+      count = 0;
+
+      QS5:
+      ADD_ACTIVE(state_offset + 2, 0);
+      if (clen > 0)
+        {
+        BOOL OK;
+        switch (c)
+          {
+          HSPACE_CASES:
+          OK = TRUE;
+          break;
+
+          default:
+          OK = FALSE;
+          break;
+          }
+
+        if (OK == (d == OP_HSPACE))
+          {
+          if (codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSSTAR ||
+              codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSQUERY)
+            {
+            active_count--;           /* Remove non-match possibility */
+            next_active_state--;
+            }
+          ADD_NEW_DATA(-(state_offset + (int)count), 0, 0);
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+#ifdef SUPPORT_UNICODE
+      case OP_PROP_EXTRA + OP_TYPEEXACT:
+      case OP_PROP_EXTRA + OP_TYPEUPTO:
+      case OP_PROP_EXTRA + OP_TYPEMINUPTO:
+      case OP_PROP_EXTRA + OP_TYPEPOSUPTO:
+      if (codevalue != OP_PROP_EXTRA + OP_TYPEEXACT)
+        { ADD_ACTIVE(state_offset + 1 + IMM2_SIZE + 3, 0); }
+      count = current_state->count;  /* Number already matched */
+      if (clen > 0)
+        {
+        BOOL OK;
+        const uint32_t *cp;
+        const ucd_record * prop = GET_UCD(c);
+        switch(code[1 + IMM2_SIZE + 1])
+          {
+          case PT_ANY:
+          OK = TRUE;
+          break;
+
+          case PT_LAMP:
+          OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
+            prop->chartype == ucp_Lt;
+          break;
+
+          case PT_GC:
+          OK = PRIV(ucp_gentype)[prop->chartype] == code[1 + IMM2_SIZE + 2];
+          break;
+
+          case PT_PC:
+          OK = prop->chartype == code[1 + IMM2_SIZE + 2];
+          break;
+
+          case PT_SC:
+          OK = prop->script == code[1 + IMM2_SIZE + 2];
+          break;
+
+          /* These are specials for combination cases. */
+
+          case PT_ALNUM:
+          OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+               PRIV(ucp_gentype)[prop->chartype] == ucp_N;
+          break;
+
+          /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+          which means that Perl space and POSIX space are now identical. PCRE
+          was changed at release 8.34. */
+
+          case PT_SPACE:    /* Perl space */
+          case PT_PXSPACE:  /* POSIX space */
+          switch(c)
+            {
+            HSPACE_CASES:
+            VSPACE_CASES:
+            OK = TRUE;
+            break;
+
+            default:
+            OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z;
+            break;
+            }
+          break;
+
+          case PT_WORD:
+          OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+               PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
+               c == CHAR_UNDERSCORE;
+          break;
+
+          case PT_CLIST:
+          cp = PRIV(ucd_caseless_sets) + code[1 + IMM2_SIZE + 2];
+          for (;;)
+            {
+            if (c < *cp) { OK = FALSE; break; }
+            if (c == *cp++) { OK = TRUE; break; }
+            }
+          break;
+
+          case PT_UCNC:
+          OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT ||
+               c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) ||
+               c >= 0xe000;
+          break;
+
+          /* Should never occur, but keep compilers from grumbling. */
+
+          default:
+          OK = codevalue != OP_PROP;
+          break;
+          }
+
+        if (OK == (d == OP_PROP))
+          {
+          if (codevalue == OP_PROP_EXTRA + OP_TYPEPOSUPTO)
+            {
+            active_count--;           /* Remove non-match possibility */
+            next_active_state--;
+            }
+          if (++count >= (int)GET2(code, 1))
+            { ADD_NEW(state_offset + 1 + IMM2_SIZE + 3, 0); }
+          else
+            { ADD_NEW(state_offset, count); }
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_EXTUNI_EXTRA + OP_TYPEEXACT:
+      case OP_EXTUNI_EXTRA + OP_TYPEUPTO:
+      case OP_EXTUNI_EXTRA + OP_TYPEMINUPTO:
+      case OP_EXTUNI_EXTRA + OP_TYPEPOSUPTO:
+      if (codevalue != OP_EXTUNI_EXTRA + OP_TYPEEXACT)
+        { ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); }
+      count = current_state->count;  /* Number already matched */
+      if (clen > 0)
+        {
+        PCRE2_SPTR nptr;
+        int ncount = 0;
+        if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSUPTO)
+          {
+          active_count--;           /* Remove non-match possibility */
+          next_active_state--;
+          }
+        nptr = PRIV(extuni)(c, ptr + clen, mb->start_subject, end_subject, utf,
+          &ncount);
+        if (nptr >= end_subject && (mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+            reset_could_continue = TRUE;
+        if (++count >= (int)GET2(code, 1))
+          { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, ncount); }
+        else
+          { ADD_NEW_DATA(-state_offset, count, ncount); }
+        }
+      break;
+#endif
+
+      /*-----------------------------------------------------------------*/
+      case OP_ANYNL_EXTRA + OP_TYPEEXACT:
+      case OP_ANYNL_EXTRA + OP_TYPEUPTO:
+      case OP_ANYNL_EXTRA + OP_TYPEMINUPTO:
+      case OP_ANYNL_EXTRA + OP_TYPEPOSUPTO:
+      if (codevalue != OP_ANYNL_EXTRA + OP_TYPEEXACT)
+        { ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); }
+      count = current_state->count;  /* Number already matched */
+      if (clen > 0)
+        {
+        int ncount = 0;
+        switch (c)
+          {
+          case CHAR_VT:
+          case CHAR_FF:
+          case CHAR_NEL:
+#ifndef EBCDIC
+          case 0x2028:
+          case 0x2029:
+#endif  /* Not EBCDIC */
+          if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break;
+          goto ANYNL03;
+
+          case CHAR_CR:
+          if (ptr + 1 < end_subject && UCHAR21TEST(ptr + 1) == CHAR_LF) ncount = 1;
+          /* Fall through */
+
+          ANYNL03:
+          case CHAR_LF:
+          if (codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSUPTO)
+            {
+            active_count--;           /* Remove non-match possibility */
+            next_active_state--;
+            }
+          if (++count >= (int)GET2(code, 1))
+            { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, ncount); }
+          else
+            { ADD_NEW_DATA(-state_offset, count, ncount); }
+          break;
+
+          default:
+          break;
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_VSPACE_EXTRA + OP_TYPEEXACT:
+      case OP_VSPACE_EXTRA + OP_TYPEUPTO:
+      case OP_VSPACE_EXTRA + OP_TYPEMINUPTO:
+      case OP_VSPACE_EXTRA + OP_TYPEPOSUPTO:
+      if (codevalue != OP_VSPACE_EXTRA + OP_TYPEEXACT)
+        { ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); }
+      count = current_state->count;  /* Number already matched */
+      if (clen > 0)
+        {
+        BOOL OK;
+        switch (c)
+          {
+          VSPACE_CASES:
+          OK = TRUE;
+          break;
+
+          default:
+          OK = FALSE;
+          }
+
+        if (OK == (d == OP_VSPACE))
+          {
+          if (codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSUPTO)
+            {
+            active_count--;           /* Remove non-match possibility */
+            next_active_state--;
+            }
+          if (++count >= (int)GET2(code, 1))
+            { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, 0); }
+          else
+            { ADD_NEW_DATA(-state_offset, count, 0); }
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_HSPACE_EXTRA + OP_TYPEEXACT:
+      case OP_HSPACE_EXTRA + OP_TYPEUPTO:
+      case OP_HSPACE_EXTRA + OP_TYPEMINUPTO:
+      case OP_HSPACE_EXTRA + OP_TYPEPOSUPTO:
+      if (codevalue != OP_HSPACE_EXTRA + OP_TYPEEXACT)
+        { ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); }
+      count = current_state->count;  /* Number already matched */
+      if (clen > 0)
+        {
+        BOOL OK;
+        switch (c)
+          {
+          HSPACE_CASES:
+          OK = TRUE;
+          break;
+
+          default:
+          OK = FALSE;
+          break;
+          }
+
+        if (OK == (d == OP_HSPACE))
+          {
+          if (codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSUPTO)
+            {
+            active_count--;           /* Remove non-match possibility */
+            next_active_state--;
+            }
+          if (++count >= (int)GET2(code, 1))
+            { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, 0); }
+          else
+            { ADD_NEW_DATA(-state_offset, count, 0); }
+          }
+        }
+      break;
+
+/* ========================================================================== */
+      /* These opcodes are followed by a character that is usually compared
+      to the current subject character; it is loaded into d. We still get
+      here even if there is no subject character, because in some cases zero
+      repetitions are permitted. */
+
+      /*-----------------------------------------------------------------*/
+      case OP_CHAR:
+      if (clen > 0 && c == d) { ADD_NEW(state_offset + dlen + 1, 0); }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_CHARI:
+      if (clen == 0) break;
+
+#ifdef SUPPORT_UNICODE
+      if (utf_or_ucp)
+        {
+        if (c == d) { ADD_NEW(state_offset + dlen + 1, 0); } else
+          {
+          unsigned int othercase;
+          if (c < 128)
+            othercase = fcc[c];
+          else
+            othercase = UCD_OTHERCASE(c);
+          if (d == othercase) { ADD_NEW(state_offset + dlen + 1, 0); }
+          }
+        }
+      else
+#endif  /* SUPPORT_UNICODE */
+      /* Not UTF or UCP mode */
+        {
+        if (TABLE_GET(c, lcc, c) == TABLE_GET(d, lcc, d))
+          { ADD_NEW(state_offset + 2, 0); }
+        }
+      break;
+
+
+#ifdef SUPPORT_UNICODE
+      /*-----------------------------------------------------------------*/
+      /* This is a tricky one because it can match more than one character.
+      Find out how many characters to skip, and then set up a negative state
+      to wait for them to pass before continuing. */
+
+      case OP_EXTUNI:
+      if (clen > 0)
+        {
+        int ncount = 0;
+        PCRE2_SPTR nptr = PRIV(extuni)(c, ptr + clen, mb->start_subject,
+          end_subject, utf, &ncount);
+        if (nptr >= end_subject && (mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+            reset_could_continue = TRUE;
+        ADD_NEW_DATA(-(state_offset + 1), 0, ncount);
+        }
+      break;
+#endif
+
+      /*-----------------------------------------------------------------*/
+      /* This is a tricky like EXTUNI because it too can match more than one
+      character (when CR is followed by LF). In this case, set up a negative
+      state to wait for one character to pass before continuing. */
+
+      case OP_ANYNL:
+      if (clen > 0) switch(c)
+        {
+        case CHAR_VT:
+        case CHAR_FF:
+        case CHAR_NEL:
+#ifndef EBCDIC
+        case 0x2028:
+        case 0x2029:
+#endif  /* Not EBCDIC */
+        if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break;
+        /* Fall through */
+
+        case CHAR_LF:
+        ADD_NEW(state_offset + 1, 0);
+        break;
+
+        case CHAR_CR:
+        if (ptr + 1 >= end_subject)
+          {
+          ADD_NEW(state_offset + 1, 0);
+          if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+            reset_could_continue = TRUE;
+          }
+        else if (UCHAR21TEST(ptr + 1) == CHAR_LF)
+          {
+          ADD_NEW_DATA(-(state_offset + 1), 0, 1);
+          }
+        else
+          {
+          ADD_NEW(state_offset + 1, 0);
+          }
+        break;
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_NOT_VSPACE:
+      if (clen > 0) switch(c)
+        {
+        VSPACE_CASES:
+        break;
+
+        default:
+        ADD_NEW(state_offset + 1, 0);
+        break;
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_VSPACE:
+      if (clen > 0) switch(c)
+        {
+        VSPACE_CASES:
+        ADD_NEW(state_offset + 1, 0);
+        break;
+
+        default:
+        break;
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_NOT_HSPACE:
+      if (clen > 0) switch(c)
+        {
+        HSPACE_CASES:
+        break;
+
+        default:
+        ADD_NEW(state_offset + 1, 0);
+        break;
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_HSPACE:
+      if (clen > 0) switch(c)
+        {
+        HSPACE_CASES:
+        ADD_NEW(state_offset + 1, 0);
+        break;
+
+        default:
+        break;
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      /* Match a negated single character casefully. */
+
+      case OP_NOT:
+      if (clen > 0 && c != d) { ADD_NEW(state_offset + dlen + 1, 0); }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      /* Match a negated single character caselessly. */
+
+      case OP_NOTI:
+      if (clen > 0)
+        {
+        uint32_t otherd;
+#ifdef SUPPORT_UNICODE
+        if (utf_or_ucp && d >= 128)
+          otherd = UCD_OTHERCASE(d);
+        else
+#endif  /* SUPPORT_UNICODE */
+        otherd = TABLE_GET(d, fcc, d);
+        if (c != d && c != otherd)
+          { ADD_NEW(state_offset + dlen + 1, 0); }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_PLUSI:
+      case OP_MINPLUSI:
+      case OP_POSPLUSI:
+      case OP_NOTPLUSI:
+      case OP_NOTMINPLUSI:
+      case OP_NOTPOSPLUSI:
+      caseless = TRUE;
+      codevalue -= OP_STARI - OP_STAR;
+
+      /* Fall through */
+      case OP_PLUS:
+      case OP_MINPLUS:
+      case OP_POSPLUS:
+      case OP_NOTPLUS:
+      case OP_NOTMINPLUS:
+      case OP_NOTPOSPLUS:
+      count = current_state->count;  /* Already matched */
+      if (count > 0) { ADD_ACTIVE(state_offset + dlen + 1, 0); }
+      if (clen > 0)
+        {
+        uint32_t otherd = NOTACHAR;
+        if (caseless)
+          {
+#ifdef SUPPORT_UNICODE
+          if (utf_or_ucp && d >= 128)
+            otherd = UCD_OTHERCASE(d);
+          else
+#endif  /* SUPPORT_UNICODE */
+          otherd = TABLE_GET(d, fcc, d);
+          }
+        if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
+          {
+          if (count > 0 &&
+              (codevalue == OP_POSPLUS || codevalue == OP_NOTPOSPLUS))
+            {
+            active_count--;             /* Remove non-match possibility */
+            next_active_state--;
+            }
+          count++;
+          ADD_NEW(state_offset, count);
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_QUERYI:
+      case OP_MINQUERYI:
+      case OP_POSQUERYI:
+      case OP_NOTQUERYI:
+      case OP_NOTMINQUERYI:
+      case OP_NOTPOSQUERYI:
+      caseless = TRUE;
+      codevalue -= OP_STARI - OP_STAR;
+      /* Fall through */
+      case OP_QUERY:
+      case OP_MINQUERY:
+      case OP_POSQUERY:
+      case OP_NOTQUERY:
+      case OP_NOTMINQUERY:
+      case OP_NOTPOSQUERY:
+      ADD_ACTIVE(state_offset + dlen + 1, 0);
+      if (clen > 0)
+        {
+        uint32_t otherd = NOTACHAR;
+        if (caseless)
+          {
+#ifdef SUPPORT_UNICODE
+          if (utf_or_ucp && d >= 128)
+            otherd = UCD_OTHERCASE(d);
+          else
+#endif  /* SUPPORT_UNICODE */
+          otherd = TABLE_GET(d, fcc, d);
+          }
+        if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
+          {
+          if (codevalue == OP_POSQUERY || codevalue == OP_NOTPOSQUERY)
+            {
+            active_count--;            /* Remove non-match possibility */
+            next_active_state--;
+            }
+          ADD_NEW(state_offset + dlen + 1, 0);
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_STARI:
+      case OP_MINSTARI:
+      case OP_POSSTARI:
+      case OP_NOTSTARI:
+      case OP_NOTMINSTARI:
+      case OP_NOTPOSSTARI:
+      caseless = TRUE;
+      codevalue -= OP_STARI - OP_STAR;
+      /* Fall through */
+      case OP_STAR:
+      case OP_MINSTAR:
+      case OP_POSSTAR:
+      case OP_NOTSTAR:
+      case OP_NOTMINSTAR:
+      case OP_NOTPOSSTAR:
+      ADD_ACTIVE(state_offset + dlen + 1, 0);
+      if (clen > 0)
+        {
+        uint32_t otherd = NOTACHAR;
+        if (caseless)
+          {
+#ifdef SUPPORT_UNICODE
+          if (utf_or_ucp && d >= 128)
+            otherd = UCD_OTHERCASE(d);
+          else
+#endif  /* SUPPORT_UNICODE */
+          otherd = TABLE_GET(d, fcc, d);
+          }
+        if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
+          {
+          if (codevalue == OP_POSSTAR || codevalue == OP_NOTPOSSTAR)
+            {
+            active_count--;            /* Remove non-match possibility */
+            next_active_state--;
+            }
+          ADD_NEW(state_offset, 0);
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_EXACTI:
+      case OP_NOTEXACTI:
+      caseless = TRUE;
+      codevalue -= OP_STARI - OP_STAR;
+      /* Fall through */
+      case OP_EXACT:
+      case OP_NOTEXACT:
+      count = current_state->count;  /* Number already matched */
+      if (clen > 0)
+        {
+        uint32_t otherd = NOTACHAR;
+        if (caseless)
+          {
+#ifdef SUPPORT_UNICODE
+          if (utf_or_ucp && d >= 128)
+            otherd = UCD_OTHERCASE(d);
+          else
+#endif  /* SUPPORT_UNICODE */
+          otherd = TABLE_GET(d, fcc, d);
+          }
+        if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
+          {
+          if (++count >= (int)GET2(code, 1))
+            { ADD_NEW(state_offset + dlen + 1 + IMM2_SIZE, 0); }
+          else
+            { ADD_NEW(state_offset, count); }
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_UPTOI:
+      case OP_MINUPTOI:
+      case OP_POSUPTOI:
+      case OP_NOTUPTOI:
+      case OP_NOTMINUPTOI:
+      case OP_NOTPOSUPTOI:
+      caseless = TRUE;
+      codevalue -= OP_STARI - OP_STAR;
+      /* Fall through */
+      case OP_UPTO:
+      case OP_MINUPTO:
+      case OP_POSUPTO:
+      case OP_NOTUPTO:
+      case OP_NOTMINUPTO:
+      case OP_NOTPOSUPTO:
+      ADD_ACTIVE(state_offset + dlen + 1 + IMM2_SIZE, 0);
+      count = current_state->count;  /* Number already matched */
+      if (clen > 0)
+        {
+        uint32_t otherd = NOTACHAR;
+        if (caseless)
+          {
+#ifdef SUPPORT_UNICODE
+          if (utf_or_ucp && d >= 128)
+            otherd = UCD_OTHERCASE(d);
+          else
+#endif  /* SUPPORT_UNICODE */
+          otherd = TABLE_GET(d, fcc, d);
+          }
+        if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
+          {
+          if (codevalue == OP_POSUPTO || codevalue == OP_NOTPOSUPTO)
+            {
+            active_count--;             /* Remove non-match possibility */
+            next_active_state--;
+            }
+          if (++count >= (int)GET2(code, 1))
+            { ADD_NEW(state_offset + dlen + 1 + IMM2_SIZE, 0); }
+          else
+            { ADD_NEW(state_offset, count); }
+          }
+        }
+      break;
+
+
+/* ========================================================================== */
+      /* These are the class-handling opcodes */
+
+      case OP_CLASS:
+      case OP_NCLASS:
+      case OP_XCLASS:
+        {
+        BOOL isinclass = FALSE;
+        int next_state_offset;
+        PCRE2_SPTR ecode;
+
+        /* For a simple class, there is always just a 32-byte table, and we
+        can set isinclass from it. */
+
+        if (codevalue != OP_XCLASS)
+          {
+          ecode = code + 1 + (32 / sizeof(PCRE2_UCHAR));
+          if (clen > 0)
+            {
+            isinclass = (c > 255)? (codevalue == OP_NCLASS) :
+              ((((uint8_t *)(code + 1))[c/8] & (1u << (c&7))) != 0);
+            }
+          }
+
+        /* An extended class may have a table or a list of single characters,
+        ranges, or both, and it may be positive or negative. There's a
+        function that sorts all this out. */
+
+        else
+         {
+         ecode = code + GET(code, 1);
+         if (clen > 0) isinclass = PRIV(xclass)(c, code + 1 + LINK_SIZE, utf);
+         }
+
+        /* At this point, isinclass is set for all kinds of class, and ecode
+        points to the byte after the end of the class. If there is a
+        quantifier, this is where it will be. */
+
+        next_state_offset = (int)(ecode - start_code);
+
+        switch (*ecode)
+          {
+          case OP_CRSTAR:
+          case OP_CRMINSTAR:
+          case OP_CRPOSSTAR:
+          ADD_ACTIVE(next_state_offset + 1, 0);
+          if (isinclass)
+            {
+            if (*ecode == OP_CRPOSSTAR)
+              {
+              active_count--;           /* Remove non-match possibility */
+              next_active_state--;
+              }
+            ADD_NEW(state_offset, 0);
+            }
+          break;
+
+          case OP_CRPLUS:
+          case OP_CRMINPLUS:
+          case OP_CRPOSPLUS:
+          count = current_state->count;  /* Already matched */
+          if (count > 0) { ADD_ACTIVE(next_state_offset + 1, 0); }
+          if (isinclass)
+            {
+            if (count > 0 && *ecode == OP_CRPOSPLUS)
+              {
+              active_count--;           /* Remove non-match possibility */
+              next_active_state--;
+              }
+            count++;
+            ADD_NEW(state_offset, count);
+            }
+          break;
+
+          case OP_CRQUERY:
+          case OP_CRMINQUERY:
+          case OP_CRPOSQUERY:
+          ADD_ACTIVE(next_state_offset + 1, 0);
+          if (isinclass)
+            {
+            if (*ecode == OP_CRPOSQUERY)
+              {
+              active_count--;           /* Remove non-match possibility */
+              next_active_state--;
+              }
+            ADD_NEW(next_state_offset + 1, 0);
+            }
+          break;
+
+          case OP_CRRANGE:
+          case OP_CRMINRANGE:
+          case OP_CRPOSRANGE:
+          count = current_state->count;  /* Already matched */
+          if (count >= (int)GET2(ecode, 1))
+            { ADD_ACTIVE(next_state_offset + 1 + 2 * IMM2_SIZE, 0); }
+          if (isinclass)
+            {
+            int max = (int)GET2(ecode, 1 + IMM2_SIZE);
+
+            if (*ecode == OP_CRPOSRANGE && count >= (int)GET2(ecode, 1))
+              {
+              active_count--;           /* Remove non-match possibility */
+              next_active_state--;
+              }
+
+            if (++count >= max && max != 0)   /* Max 0 => no limit */
+              { ADD_NEW(next_state_offset + 1 + 2 * IMM2_SIZE, 0); }
+            else
+              { ADD_NEW(state_offset, count); }
+            }
+          break;
+
+          default:
+          if (isinclass) { ADD_NEW(next_state_offset, 0); }
+          break;
+          }
+        }
+      break;
+
+/* ========================================================================== */
+      /* These are the opcodes for fancy brackets of various kinds. We have
+      to use recursion in order to handle them. The "always failing" assertion
+      (?!) is optimised to OP_FAIL when compiling, so we have to support that,
+      though the other "backtracking verbs" are not supported. */
+
+      case OP_FAIL:
+      forced_fail++;    /* Count FAILs for multiple states */
+      break;
+
+      case OP_ASSERT:
+      case OP_ASSERT_NOT:
+      case OP_ASSERTBACK:
+      case OP_ASSERTBACK_NOT:
+        {
+        int rc;
+        int *local_workspace;
+        PCRE2_SIZE *local_offsets;
+        PCRE2_SPTR endasscode = code + GET(code, 1);
+        RWS_anchor *rws = (RWS_anchor *)RWS;
+
+        if (rws->free < RWS_RSIZE + RWS_OVEC_OSIZE)
+          {
+          rc = more_workspace(&rws, RWS_OVEC_OSIZE, mb);
+          if (rc != 0) return rc;
+          RWS = (int *)rws;
+          }
+
+        local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
+        local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
+        rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;
+
+        while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1);
+
+        rc = internal_dfa_match(
+          mb,                                   /* static match data */
+          code,                                 /* this subexpression's code */
+          ptr,                                  /* where we currently are */
+          (PCRE2_SIZE)(ptr - start_subject),    /* start offset */
+          local_offsets,                        /* offset vector */
+          RWS_OVEC_OSIZE/OVEC_UNIT,             /* size of same */
+          local_workspace,                      /* workspace vector */
+          RWS_RSIZE,                            /* size of same */
+          rlevel,                               /* function recursion level */
+          RWS);                                 /* recursion workspace */
+
+        rws->free += RWS_RSIZE + RWS_OVEC_OSIZE;
+
+        if (rc < 0 && rc != PCRE2_ERROR_NOMATCH) return rc;
+        if ((rc >= 0) == (codevalue == OP_ASSERT || codevalue == OP_ASSERTBACK))
+            { ADD_ACTIVE((int)(endasscode + LINK_SIZE + 1 - start_code), 0); }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_COND:
+      case OP_SCOND:
+        {
+        int codelink = (int)GET(code, 1);
+        PCRE2_UCHAR condcode;
+
+        /* Because of the way auto-callout works during compile, a callout item
+        is inserted between OP_COND and an assertion condition. This does not
+        happen for the other conditions. */
+
+        if (code[LINK_SIZE + 1] == OP_CALLOUT
+            || code[LINK_SIZE + 1] == OP_CALLOUT_STR)
+          {
+          PCRE2_SIZE callout_length;
+          rrc = do_callout(code, offsets, current_subject, ptr, mb,
+            1 + LINK_SIZE, &callout_length);
+          if (rrc < 0) return rrc;                 /* Abandon */
+          if (rrc > 0) break;                      /* Fail this thread */
+          code += callout_length;                  /* Skip callout data */
+          }
+
+        condcode = code[LINK_SIZE+1];
+
+        /* Back reference conditions and duplicate named recursion conditions
+        are not supported */
+
+        if (condcode == OP_CREF || condcode == OP_DNCREF ||
+            condcode == OP_DNRREF)
+          return PCRE2_ERROR_DFA_UCOND;
+
+        /* The DEFINE condition is always false, and the assertion (?!) is
+        converted to OP_FAIL. */
+
+        if (condcode == OP_FALSE || condcode == OP_FAIL)
+          { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); }
+
+        /* There is also an always-true condition */
+
+        else if (condcode == OP_TRUE)
+          { ADD_ACTIVE(state_offset + LINK_SIZE + 2, 0); }
+
+        /* The only supported version of OP_RREF is for the value RREF_ANY,
+        which means "test if in any recursion". We can't test for specifically
+        recursed groups. */
+
+        else if (condcode == OP_RREF)
+          {
+          unsigned int value = GET2(code, LINK_SIZE + 2);
+          if (value != RREF_ANY) return PCRE2_ERROR_DFA_UCOND;
+          if (mb->recursive != NULL)
+            { ADD_ACTIVE(state_offset + LINK_SIZE + 2 + IMM2_SIZE, 0); }
+          else { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); }
+          }
+
+        /* Otherwise, the condition is an assertion */
+
+        else
+          {
+          int rc;
+          int *local_workspace;
+          PCRE2_SIZE *local_offsets;
+          PCRE2_SPTR asscode = code + LINK_SIZE + 1;
+          PCRE2_SPTR endasscode = asscode + GET(asscode, 1);
+          RWS_anchor *rws = (RWS_anchor *)RWS;
+
+          if (rws->free < RWS_RSIZE + RWS_OVEC_OSIZE)
+            {
+            rc = more_workspace(&rws, RWS_OVEC_OSIZE, mb);
+            if (rc != 0) return rc;
+            RWS = (int *)rws;
+            }
+
+          local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
+          local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
+          rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;
+
+          while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1);
+
+          rc = internal_dfa_match(
+            mb,                                   /* fixed match data */
+            asscode,                              /* this subexpression's code */
+            ptr,                                  /* where we currently are */
+            (PCRE2_SIZE)(ptr - start_subject),    /* start offset */
+            local_offsets,                        /* offset vector */
+            RWS_OVEC_OSIZE/OVEC_UNIT,             /* size of same */
+            local_workspace,                      /* workspace vector */
+            RWS_RSIZE,                            /* size of same */
+            rlevel,                               /* function recursion level */
+            RWS);                                 /* recursion workspace */
+
+          rws->free += RWS_RSIZE + RWS_OVEC_OSIZE;
+
+          if (rc < 0 && rc != PCRE2_ERROR_NOMATCH) return rc;
+          if ((rc >= 0) ==
+                (condcode == OP_ASSERT || condcode == OP_ASSERTBACK))
+            { ADD_ACTIVE((int)(endasscode + LINK_SIZE + 1 - start_code), 0); }
+          else
+            { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); }
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_RECURSE:
+        {
+        int rc;
+        int *local_workspace;
+        PCRE2_SIZE *local_offsets;
+        RWS_anchor *rws = (RWS_anchor *)RWS;
+        dfa_recursion_info *ri;
+        PCRE2_SPTR callpat = start_code + GET(code, 1);
+        uint32_t recno = (callpat == mb->start_code)? 0 :
+          GET2(callpat, 1 + LINK_SIZE);
+
+        if (rws->free < RWS_RSIZE + RWS_OVEC_RSIZE)
+          {
+          rc = more_workspace(&rws, RWS_OVEC_RSIZE, mb);
+          if (rc != 0) return rc;
+          RWS = (int *)rws;
+          }
+
+        local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
+        local_workspace = ((int *)local_offsets) + RWS_OVEC_RSIZE;
+        rws->free -= RWS_RSIZE + RWS_OVEC_RSIZE;
+
+        /* Check for repeating a recursion without advancing the subject
+        pointer. This should catch convoluted mutual recursions. (Some simple
+        cases are caught at compile time.) */
+
+        for (ri = mb->recursive; ri != NULL; ri = ri->prevrec)
+          if (recno == ri->group_num && ptr == ri->subject_position)
+            return PCRE2_ERROR_RECURSELOOP;
+
+        /* Remember this recursion and where we started it so as to
+        catch infinite loops. */
+
+        new_recursive.group_num = recno;
+        new_recursive.subject_position = ptr;
+        new_recursive.prevrec = mb->recursive;
+        mb->recursive = &new_recursive;
+
+        rc = internal_dfa_match(
+          mb,                                   /* fixed match data */
+          callpat,                              /* this subexpression's code */
+          ptr,                                  /* where we currently are */
+          (PCRE2_SIZE)(ptr - start_subject),    /* start offset */
+          local_offsets,                        /* offset vector */
+          RWS_OVEC_RSIZE/OVEC_UNIT,             /* size of same */
+          local_workspace,                      /* workspace vector */
+          RWS_RSIZE,                            /* size of same */
+          rlevel,                               /* function recursion level */
+          RWS);                                 /* recursion workspace */
+
+        rws->free += RWS_RSIZE + RWS_OVEC_RSIZE;
+        mb->recursive = new_recursive.prevrec;  /* Done this recursion */
+
+        /* Ran out of internal offsets */
+
+        if (rc == 0) return PCRE2_ERROR_DFA_RECURSE;
+
+        /* For each successful matched substring, set up the next state with a
+        count of characters to skip before trying it. Note that the count is in
+        characters, not bytes. */
+
+        if (rc > 0)
+          {
+          for (rc = rc*2 - 2; rc >= 0; rc -= 2)
+            {
+            PCRE2_SIZE charcount = local_offsets[rc+1] - local_offsets[rc];
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+            if (utf)
+              {
+              PCRE2_SPTR p = start_subject + local_offsets[rc];
+              PCRE2_SPTR pp = start_subject + local_offsets[rc+1];
+              while (p < pp) if (NOT_FIRSTCU(*p++)) charcount--;
+              }
+#endif
+            if (charcount > 0)
+              {
+              ADD_NEW_DATA(-(state_offset + LINK_SIZE + 1), 0,
+                (int)(charcount - 1));
+              }
+            else
+              {
+              ADD_ACTIVE(state_offset + LINK_SIZE + 1, 0);
+              }
+            }
+          }
+        else if (rc != PCRE2_ERROR_NOMATCH) return rc;
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_BRAPOS:
+      case OP_SBRAPOS:
+      case OP_CBRAPOS:
+      case OP_SCBRAPOS:
+      case OP_BRAPOSZERO:
+        {
+        int rc;
+        int *local_workspace;
+        PCRE2_SIZE *local_offsets;
+        PCRE2_SIZE charcount, matched_count;
+        PCRE2_SPTR local_ptr = ptr;
+        RWS_anchor *rws = (RWS_anchor *)RWS;
+        BOOL allow_zero;
+
+        if (rws->free < RWS_RSIZE + RWS_OVEC_OSIZE)
+          {
+          rc = more_workspace(&rws, RWS_OVEC_OSIZE, mb);
+          if (rc != 0) return rc;
+          RWS = (int *)rws;
+          }
+
+        local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
+        local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
+        rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;
+
+        if (codevalue == OP_BRAPOSZERO)
+          {
+          allow_zero = TRUE;
+          codevalue = *(++code);  /* Codevalue will be one of above BRAs */
+          }
+        else allow_zero = FALSE;
+
+        /* Loop to match the subpattern as many times as possible as if it were
+        a complete pattern. */
+
+        for (matched_count = 0;; matched_count++)
+          {
+          rc = internal_dfa_match(
+            mb,                                   /* fixed match data */
+            code,                                 /* this subexpression's code */
+            local_ptr,                            /* where we currently are */
+            (PCRE2_SIZE)(ptr - start_subject),    /* start offset */
+            local_offsets,                        /* offset vector */
+            RWS_OVEC_OSIZE/OVEC_UNIT,             /* size of same */
+            local_workspace,                      /* workspace vector */
+            RWS_RSIZE,                            /* size of same */
+            rlevel,                               /* function recursion level */
+            RWS);                                 /* recursion workspace */
+
+          /* Failed to match */
+
+          if (rc < 0)
+            {
+            if (rc != PCRE2_ERROR_NOMATCH) return rc;
+            break;
+            }
+
+          /* Matched: break the loop if zero characters matched. */
+
+          charcount = local_offsets[1] - local_offsets[0];
+          if (charcount == 0) break;
+          local_ptr += charcount;    /* Advance temporary position ptr */
+          }
+
+        rws->free += RWS_RSIZE + RWS_OVEC_OSIZE;
+
+        /* At this point we have matched the subpattern matched_count
+        times, and local_ptr is pointing to the character after the end of the
+        last match. */
+
+        if (matched_count > 0 || allow_zero)
+          {
+          PCRE2_SPTR end_subpattern = code;
+          int next_state_offset;
+
+          do { end_subpattern += GET(end_subpattern, 1); }
+            while (*end_subpattern == OP_ALT);
+          next_state_offset =
+            (int)(end_subpattern - start_code + LINK_SIZE + 1);
+
+          /* Optimization: if there are no more active states, and there
+          are no new states yet set up, then skip over the subject string
+          right here, to save looping. Otherwise, set up the new state to swing
+          into action when the end of the matched substring is reached. */
+
+          if (i + 1 >= active_count && new_count == 0)
+            {
+            ptr = local_ptr;
+            clen = 0;
+            ADD_NEW(next_state_offset, 0);
+            }
+          else
+            {
+            PCRE2_SPTR p = ptr;
+            PCRE2_SPTR pp = local_ptr;
+            charcount = (PCRE2_SIZE)(pp - p);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+            if (utf) while (p < pp) if (NOT_FIRSTCU(*p++)) charcount--;
+#endif
+            ADD_NEW_DATA(-next_state_offset, 0, (int)(charcount - 1));
+            }
+          }
+        }
+      break;
+
+      /*-----------------------------------------------------------------*/
+      case OP_ONCE:
+        {
+        int rc;
+        int *local_workspace;
+        PCRE2_SIZE *local_offsets;
+        RWS_anchor *rws = (RWS_anchor *)RWS;
+
+        if (rws->free < RWS_RSIZE + RWS_OVEC_OSIZE)
+          {
+          rc = more_workspace(&rws, RWS_OVEC_OSIZE, mb);
+          if (rc != 0) return rc;
+          RWS = (int *)rws;
+          }
+
+        local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
+        local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
+        rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;
+
+        rc = internal_dfa_match(
+          mb,                                   /* fixed match data */
+          code,                                 /* this subexpression's code */
+          ptr,                                  /* where we currently are */
+          (PCRE2_SIZE)(ptr - start_subject),    /* start offset */
+          local_offsets,                        /* offset vector */
+          RWS_OVEC_OSIZE/OVEC_UNIT,             /* size of same */
+          local_workspace,                      /* workspace vector */
+          RWS_RSIZE,                            /* size of same */
+          rlevel,                               /* function recursion level */
+          RWS);                                 /* recursion workspace */
+
+        rws->free += RWS_RSIZE + RWS_OVEC_OSIZE;
+
+        if (rc >= 0)
+          {
+          PCRE2_SPTR end_subpattern = code;
+          PCRE2_SIZE charcount = local_offsets[1] - local_offsets[0];
+          int next_state_offset, repeat_state_offset;
+
+          do { end_subpattern += GET(end_subpattern, 1); }
+            while (*end_subpattern == OP_ALT);
+          next_state_offset =
+            (int)(end_subpattern - start_code + LINK_SIZE + 1);
+
+          /* If the end of this subpattern is KETRMAX or KETRMIN, we must
+          arrange for the repeat state also to be added to the relevant list.
+          Calculate the offset, or set -1 for no repeat. */
+
+          repeat_state_offset = (*end_subpattern == OP_KETRMAX ||
+                                 *end_subpattern == OP_KETRMIN)?
+            (int)(end_subpattern - start_code - GET(end_subpattern, 1)) : -1;
+
+          /* If we have matched an empty string, add the next state at the
+          current character pointer. This is important so that the duplicate
+          checking kicks in, which is what breaks infinite loops that match an
+          empty string. */
+
+          if (charcount == 0)
+            {
+            ADD_ACTIVE(next_state_offset, 0);
+            }
+
+          /* Optimization: if there are no more active states, and there
+          are no new states yet set up, then skip over the subject string
+          right here, to save looping. Otherwise, set up the new state to swing
+          into action when the end of the matched substring is reached. */
+
+          else if (i + 1 >= active_count && new_count == 0)
+            {
+            ptr += charcount;
+            clen = 0;
+            ADD_NEW(next_state_offset, 0);
+
+            /* If we are adding a repeat state at the new character position,
+            we must fudge things so that it is the only current state.
+            Otherwise, it might be a duplicate of one we processed before, and
+            that would cause it to be skipped. */
+
+            if (repeat_state_offset >= 0)
+              {
+              next_active_state = active_states;
+              active_count = 0;
+              i = -1;
+              ADD_ACTIVE(repeat_state_offset, 0);
+              }
+            }
+          else
+            {
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+            if (utf)
+              {
+              PCRE2_SPTR p = start_subject + local_offsets[0];
+              PCRE2_SPTR pp = start_subject + local_offsets[1];
+              while (p < pp) if (NOT_FIRSTCU(*p++)) charcount--;
+              }
+#endif
+            ADD_NEW_DATA(-next_state_offset, 0, (int)(charcount - 1));
+            if (repeat_state_offset >= 0)
+              { ADD_NEW_DATA(-repeat_state_offset, 0, (int)(charcount - 1)); }
+            }
+          }
+        else if (rc != PCRE2_ERROR_NOMATCH) return rc;
+        }
+      break;
+
+
+/* ========================================================================== */
+      /* Handle callouts */
+
+      case OP_CALLOUT:
+      case OP_CALLOUT_STR:
+        {
+        PCRE2_SIZE callout_length;
+        rrc = do_callout(code, offsets, current_subject, ptr, mb, 0,
+          &callout_length);
+        if (rrc < 0) return rrc;   /* Abandon */
+        if (rrc == 0)
+          { ADD_ACTIVE(state_offset + (int)callout_length, 0); }
+        }
+      break;
+
+
+/* ========================================================================== */
+      default:        /* Unsupported opcode */
+      return PCRE2_ERROR_DFA_UITEM;
+      }
+
+    NEXT_ACTIVE_STATE: continue;
+
+    }      /* End of loop scanning active states */
+
+  /* We have finished the processing at the current subject character. If no
+  new states have been set for the next character, we have found all the
+  matches that we are going to find. If partial matching has been requested,
+  check for appropriate conditions.
+
+  The "forced_ fail" variable counts the number of (*F) encountered for the
+  character. If it is equal to the original active_count (saved in
+  workspace[1]) it means that (*F) was found on every active state. In this
+  case we don't want to give a partial match.
+
+  The "could_continue" variable is true if a state could have continued but
+  for the fact that the end of the subject was reached. */
+
+  if (new_count <= 0)
+    {
+    if (could_continue &&                            /* Some could go on, and */
+        forced_fail != workspace[1] &&               /* Not all forced fail & */
+        (                                            /* either... */
+        (mb->moptions & PCRE2_PARTIAL_HARD) != 0      /* Hard partial */
+        ||                                           /* or... */
+        ((mb->moptions & PCRE2_PARTIAL_SOFT) != 0 &&  /* Soft partial and */
+         match_count < 0)                             /* no matches */
+        ) &&                                         /* And... */
+        (
+        partial_newline ||                   /* Either partial NL */
+          (                                  /* or ... */
+          ptr >= end_subject &&              /* End of subject and */
+            (                                  /* either */
+            ptr > mb->start_used_ptr ||        /* Inspected non-empty string */
+            mb->allowemptypartial              /* or pattern has lookbehind */
+            )                                  /* or could match empty */
+          )
+        ))
+      match_count = PCRE2_ERROR_PARTIAL;
+    break;  /* Exit from loop along the subject string */
+    }
+
+  /* One or more states are active for the next character. */
+
+  ptr += clen;    /* Advance to next subject character */
+  }               /* Loop to move along the subject string */
+
+/* Control gets here from "break" a few lines above. If we have a match and
+PCRE2_ENDANCHORED is set, the match fails. */
+
+if (match_count >= 0 &&
+    ((mb->moptions | mb->poptions) & PCRE2_ENDANCHORED) != 0 &&
+    ptr < end_subject)
+  match_count = PCRE2_ERROR_NOMATCH;
+
+return match_count;
+}
+
+
+
+/*************************************************
+*     Match a pattern using the DFA algorithm    *
+*************************************************/
+
+/* This function matches a compiled pattern to a subject string, using the
+alternate matching algorithm that finds all matches at once.
+
+Arguments:
+  code          points to the compiled pattern
+  subject       subject string
+  length        length of subject string
+  startoffset   where to start matching in the subject
+  options       option bits
+  match_data    points to a match data structure
+  gcontext      points to a match context
+  workspace     pointer to workspace
+  wscount       size of workspace
+
+Returns:        > 0 => number of match offset pairs placed in offsets
+                = 0 => offsets overflowed; longest matches are present
+                 -1 => failed to match
+               < -1 => some kind of unexpected problem
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_dfa_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length,
+  PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data,
+  pcre2_match_context *mcontext, int *workspace, PCRE2_SIZE wscount)
+{
+int rc;
+int was_zero_terminated = 0;
+
+const pcre2_real_code *re = (const pcre2_real_code *)code;
+
+PCRE2_SPTR start_match;
+PCRE2_SPTR end_subject;
+PCRE2_SPTR bumpalong_limit;
+PCRE2_SPTR req_cu_ptr;
+
+BOOL utf, anchored, startline, firstline;
+BOOL has_first_cu = FALSE;
+BOOL has_req_cu = FALSE;
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+BOOL memchr_not_found_first_cu = FALSE;
+BOOL memchr_not_found_first_cu2 = FALSE;
+#endif
+
+PCRE2_UCHAR first_cu = 0;
+PCRE2_UCHAR first_cu2 = 0;
+PCRE2_UCHAR req_cu = 0;
+PCRE2_UCHAR req_cu2 = 0;
+
+const uint8_t *start_bits = NULL;
+
+/* We need to have mb pointing to a match block, because the IS_NEWLINE macro
+is used below, and it expects NLBLOCK to be defined as a pointer. */
+
+pcre2_callout_block cb;
+dfa_match_block actual_match_block;
+dfa_match_block *mb = &actual_match_block;
+
+/* Set up a starting block of memory for use during recursive calls to
+internal_dfa_match(). By putting this on the stack, it minimizes resource use
+in the case when it is not needed. If this is too small, more memory is
+obtained from the heap. At the start of each block is an anchor structure.*/
+
+int base_recursion_workspace[RWS_BASE_SIZE];
+RWS_anchor *rws = (RWS_anchor *)base_recursion_workspace;
+rws->next = NULL;
+rws->size = RWS_BASE_SIZE;
+rws->free = RWS_BASE_SIZE - RWS_ANCHOR_SIZE;
+
+/* A length equal to PCRE2_ZERO_TERMINATED implies a zero-terminated
+subject string. */
+
+if (length == PCRE2_ZERO_TERMINATED)
+  {
+  length = PRIV(strlen)(subject);
+  was_zero_terminated = 1;
+  }
+
+/* Plausibility checks */
+
+if ((options & ~PUBLIC_DFA_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION;
+if (re == NULL || subject == NULL || workspace == NULL || match_data == NULL)
+  return PCRE2_ERROR_NULL;
+if (wscount < 20) return PCRE2_ERROR_DFA_WSSIZE;
+if (start_offset > length) return PCRE2_ERROR_BADOFFSET;
+
+/* Partial matching and PCRE2_ENDANCHORED are currently not allowed at the same
+time. */
+
+if ((options & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0 &&
+   ((re->overall_options | options) & PCRE2_ENDANCHORED) != 0)
+  return PCRE2_ERROR_BADOPTION;
+
+/* Invalid UTF support is not available for DFA matching. */
+
+if ((re->overall_options & PCRE2_MATCH_INVALID_UTF) != 0)
+  return PCRE2_ERROR_DFA_UINVALID_UTF;
+
+/* Check that the first field in the block is the magic number. If it is not,
+return with PCRE2_ERROR_BADMAGIC. */
+
+if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
+
+/* Check the code unit width. */
+
+if ((re->flags & PCRE2_MODE_MASK) != PCRE2_CODE_UNIT_WIDTH/8)
+  return PCRE2_ERROR_BADMODE;
+
+/* PCRE2_NOTEMPTY and PCRE2_NOTEMPTY_ATSTART are match-time flags in the
+options variable for this function. Users of PCRE2 who are not calling the
+function directly would like to have a way of setting these flags, in the same
+way that they can set pcre2_compile() flags like PCRE2_NO_AUTOPOSSESS with
+constructions like (*NO_AUTOPOSSESS). To enable this, (*NOTEMPTY) and
+(*NOTEMPTY_ATSTART) set bits in the pattern's "flag" function which can now be
+transferred to the options for this function. The bits are guaranteed to be
+adjacent, but do not have the same values. This bit of Boolean trickery assumes
+that the match-time bits are not more significant than the flag bits. If by
+accident this is not the case, a compile-time division by zero error will
+occur. */
+
+#define FF (PCRE2_NOTEMPTY_SET|PCRE2_NE_ATST_SET)
+#define OO (PCRE2_NOTEMPTY|PCRE2_NOTEMPTY_ATSTART)
+options |= (re->flags & FF) / ((FF & (~FF+1)) / (OO & (~OO+1)));
+#undef FF
+#undef OO
+
+/* If restarting after a partial match, do some sanity checks on the contents
+of the workspace. */
+
+if ((options & PCRE2_DFA_RESTART) != 0)
+  {
+  if ((workspace[0] & (-2)) != 0 || workspace[1] < 1 ||
+    workspace[1] > (int)((wscount - 2)/INTS_PER_STATEBLOCK))
+      return PCRE2_ERROR_DFA_BADRESTART;
+  }
+
+/* Set some local values */
+
+utf = (re->overall_options & PCRE2_UTF) != 0;
+start_match = subject + start_offset;
+end_subject = subject + length;
+req_cu_ptr = start_match - 1;
+anchored = (options & (PCRE2_ANCHORED|PCRE2_DFA_RESTART)) != 0 ||
+  (re->overall_options & PCRE2_ANCHORED) != 0;
+
+/* The "must be at the start of a line" flags are used in a loop when finding
+where to start. */
+
+startline = (re->flags & PCRE2_STARTLINE) != 0;
+firstline = (re->overall_options & PCRE2_FIRSTLINE) != 0;
+bumpalong_limit = end_subject;
+
+/* Initialize and set up the fixed fields in the callout block, with a pointer
+in the match block. */
+
+mb->cb = &cb;
+cb.version = 2;
+cb.subject = subject;
+cb.subject_length = (PCRE2_SIZE)(end_subject - subject);
+cb.callout_flags = 0;
+cb.capture_top      = 1;      /* No capture support */
+cb.capture_last     = 0;
+cb.mark             = NULL;   /* No (*MARK) support */
+
+/* Get data from the match context, if present, and fill in the remaining
+fields in the match block. It is an error to set an offset limit without
+setting the flag at compile time. */
+
+if (mcontext == NULL)
+  {
+  mb->callout = NULL;
+  mb->memctl = re->memctl;
+  mb->match_limit = PRIV(default_match_context).match_limit;
+  mb->match_limit_depth = PRIV(default_match_context).depth_limit;
+  mb->heap_limit = PRIV(default_match_context).heap_limit;
+  }
+else
+  {
+  if (mcontext->offset_limit != PCRE2_UNSET)
+    {
+    if ((re->overall_options & PCRE2_USE_OFFSET_LIMIT) == 0)
+      return PCRE2_ERROR_BADOFFSETLIMIT;
+    bumpalong_limit = subject + mcontext->offset_limit;
+    }
+  mb->callout = mcontext->callout;
+  mb->callout_data = mcontext->callout_data;
+  mb->memctl = mcontext->memctl;
+  mb->match_limit = mcontext->match_limit;
+  mb->match_limit_depth = mcontext->depth_limit;
+  mb->heap_limit = mcontext->heap_limit;
+  }
+
+if (mb->match_limit > re->limit_match)
+  mb->match_limit = re->limit_match;
+
+if (mb->match_limit_depth > re->limit_depth)
+  mb->match_limit_depth = re->limit_depth;
+
+if (mb->heap_limit > re->limit_heap)
+  mb->heap_limit = re->limit_heap;
+
+mb->start_code = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)) +
+  re->name_count * re->name_entry_size;
+mb->tables = re->tables;
+mb->start_subject = subject;
+mb->end_subject = end_subject;
+mb->start_offset = start_offset;
+mb->allowemptypartial = (re->max_lookbehind > 0) ||
+  (re->flags & PCRE2_MATCH_EMPTY) != 0;
+mb->moptions = options;
+mb->poptions = re->overall_options;
+mb->match_call_count = 0;
+mb->heap_used = 0;
+
+/* Process the \R and newline settings. */
+
+mb->bsr_convention = re->bsr_convention;
+mb->nltype = NLTYPE_FIXED;
+switch(re->newline_convention)
+  {
+  case PCRE2_NEWLINE_CR:
+  mb->nllen = 1;
+  mb->nl[0] = CHAR_CR;
+  break;
+
+  case PCRE2_NEWLINE_LF:
+  mb->nllen = 1;
+  mb->nl[0] = CHAR_NL;
+  break;
+
+  case PCRE2_NEWLINE_NUL:
+  mb->nllen = 1;
+  mb->nl[0] = CHAR_NUL;
+  break;
+
+  case PCRE2_NEWLINE_CRLF:
+  mb->nllen = 2;
+  mb->nl[0] = CHAR_CR;
+  mb->nl[1] = CHAR_NL;
+  break;
+
+  case PCRE2_NEWLINE_ANY:
+  mb->nltype = NLTYPE_ANY;
+  break;
+
+  case PCRE2_NEWLINE_ANYCRLF:
+  mb->nltype = NLTYPE_ANYCRLF;
+  break;
+
+  default: return PCRE2_ERROR_INTERNAL;
+  }
+
+/* Check a UTF string for validity if required. For 8-bit and 16-bit strings,
+we must also check that a starting offset does not point into the middle of a
+multiunit character. We check only the portion of the subject that is going to
+be inspected during matching - from the offset minus the maximum back reference
+to the given length. This saves time when a small part of a large subject is
+being matched by the use of a starting offset. Note that the maximum lookbehind
+is a number of characters, not code units. */
+
+#ifdef SUPPORT_UNICODE
+if (utf && (options & PCRE2_NO_UTF_CHECK) == 0)
+  {
+  PCRE2_SPTR check_subject = start_match;  /* start_match includes offset */
+
+  if (start_offset > 0)
+    {
+#if PCRE2_CODE_UNIT_WIDTH != 32
+    unsigned int i;
+    if (start_match < end_subject && NOT_FIRSTCU(*start_match))
+      return PCRE2_ERROR_BADUTFOFFSET;
+    for (i = re->max_lookbehind; i > 0 && check_subject > subject; i--)
+      {
+      check_subject--;
+      while (check_subject > subject &&
+#if PCRE2_CODE_UNIT_WIDTH == 8
+      (*check_subject & 0xc0) == 0x80)
+#else  /* 16-bit */
+      (*check_subject & 0xfc00) == 0xdc00)
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+        check_subject--;
+      }
+#else   /* In the 32-bit library, one code unit equals one character. */
+    check_subject -= re->max_lookbehind;
+    if (check_subject < subject) check_subject = subject;
+#endif  /* PCRE2_CODE_UNIT_WIDTH != 32 */
+    }
+
+  /* Validate the relevant portion of the subject. After an error, adjust the
+  offset to be an absolute offset in the whole string. */
+
+  match_data->rc = PRIV(valid_utf)(check_subject,
+    length - (PCRE2_SIZE)(check_subject - subject), &(match_data->startchar));
+  if (match_data->rc != 0)
+    {
+    match_data->startchar += (PCRE2_SIZE)(check_subject - subject);
+    return match_data->rc;
+    }
+  }
+#endif  /* SUPPORT_UNICODE */
+
+/* Set up the first code unit to match, if available. If there's no first code
+unit there may be a bitmap of possible first characters. */
+
+if ((re->flags & PCRE2_FIRSTSET) != 0)
+  {
+  has_first_cu = TRUE;
+  first_cu = first_cu2 = (PCRE2_UCHAR)(re->first_codeunit);
+  if ((re->flags & PCRE2_FIRSTCASELESS) != 0)
+    {
+    first_cu2 = TABLE_GET(first_cu, mb->tables + fcc_offset, first_cu);
+#ifdef SUPPORT_UNICODE
+#if PCRE2_CODE_UNIT_WIDTH == 8
+    if (first_cu > 127 && !utf && (re->overall_options & PCRE2_UCP) != 0)
+      first_cu2 = (PCRE2_UCHAR)UCD_OTHERCASE(first_cu);
+#else
+    if (first_cu > 127 && (utf || (re->overall_options & PCRE2_UCP) != 0))
+      first_cu2 = (PCRE2_UCHAR)UCD_OTHERCASE(first_cu);
+#endif
+#endif  /* SUPPORT_UNICODE */
+    }
+  }
+else
+  if (!startline && (re->flags & PCRE2_FIRSTMAPSET) != 0)
+    start_bits = re->start_bitmap;
+
+/* There may be a "last known required code unit" set. */
+
+if ((re->flags & PCRE2_LASTSET) != 0)
+  {
+  has_req_cu = TRUE;
+  req_cu = req_cu2 = (PCRE2_UCHAR)(re->last_codeunit);
+  if ((re->flags & PCRE2_LASTCASELESS) != 0)
+    {
+    req_cu2 = TABLE_GET(req_cu, mb->tables + fcc_offset, req_cu);
+#ifdef SUPPORT_UNICODE
+#if PCRE2_CODE_UNIT_WIDTH == 8
+    if (req_cu > 127 && !utf && (re->overall_options & PCRE2_UCP) != 0)
+      req_cu2 = (PCRE2_UCHAR)UCD_OTHERCASE(req_cu);
+#else
+    if (req_cu > 127 && (utf || (re->overall_options & PCRE2_UCP) != 0))
+      req_cu2 = (PCRE2_UCHAR)UCD_OTHERCASE(req_cu);
+#endif
+#endif  /* SUPPORT_UNICODE */
+    }
+  }
+
+/* If the match data block was previously used with PCRE2_COPY_MATCHED_SUBJECT,
+free the memory that was obtained. */
+
+if ((match_data->flags & PCRE2_MD_COPIED_SUBJECT) != 0)
+  {
+  match_data->memctl.free((void *)match_data->subject,
+    match_data->memctl.memory_data);
+  match_data->flags &= ~PCRE2_MD_COPIED_SUBJECT;
+  }
+
+/* Fill in fields that are always returned in the match data. */
+
+match_data->code = re;
+match_data->subject = NULL;  /* Default for no match */
+match_data->mark = NULL;
+match_data->matchedby = PCRE2_MATCHEDBY_DFA_INTERPRETER;
+
+/* Call the main matching function, looping for a non-anchored regex after a
+failed match. If not restarting, perform certain optimizations at the start of
+a match. */
+
+for (;;)
+  {
+  /* ----------------- Start of match optimizations ---------------- */
+
+  /* There are some optimizations that avoid running the match if a known
+  starting point is not found, or if a known later code unit is not present.
+  However, there is an option (settable at compile time) that disables
+  these, for testing and for ensuring that all callouts do actually occur.
+  The optimizations must also be avoided when restarting a DFA match. */
+
+  if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0 &&
+      (options & PCRE2_DFA_RESTART) == 0)
+    {
+    /* If firstline is TRUE, the start of the match is constrained to the first
+    line of a multiline string. That is, the match must be before or at the
+    first newline following the start of matching. Temporarily adjust
+    end_subject so that we stop the optimization scans for a first code unit
+    immediately after the first character of a newline (the first code unit can
+    legitimately be a newline). If the match fails at the newline, later code
+    breaks this loop. */
+
+    if (firstline)
+      {
+      PCRE2_SPTR t = start_match;
+#ifdef SUPPORT_UNICODE
+      if (utf)
+        {
+        while (t < end_subject && !IS_NEWLINE(t))
+          {
+          t++;
+          ACROSSCHAR(t < end_subject, t, t++);
+          }
+        }
+      else
+#endif
+      while (t < end_subject && !IS_NEWLINE(t)) t++;
+      end_subject = t;
+      }
+
+    /* Anchored: check the first code unit if one is recorded. This may seem
+    pointless but it can help in detecting a no match case without scanning for
+    the required code unit. */
+
+    if (anchored)
+      {
+      if (has_first_cu || start_bits != NULL)
+        {
+        BOOL ok = start_match < end_subject;
+        if (ok)
+          {
+          PCRE2_UCHAR c = UCHAR21TEST(start_match);
+          ok = has_first_cu && (c == first_cu || c == first_cu2);
+          if (!ok && start_bits != NULL)
+            {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+            if (c > 255) c = 255;
+#endif
+            ok = (start_bits[c/8] & (1u << (c&7))) != 0;
+            }
+          }
+        if (!ok) break;
+        }
+      }
+
+    /* Not anchored. Advance to a unique first code unit if there is one. In
+    8-bit mode, the use of memchr() gives a big speed up, even though we have
+    to call it twice in caseless mode, in order to find the earliest occurrence
+    of the character in either of its cases. If a call to memchr() that
+    searches the rest of the subject fails to find one case, remember that in
+    order not to keep on repeating the search. This can make a huge difference
+    when the strings are very long and only one case is present. */
+
+    else
+      {
+      if (has_first_cu)
+        {
+        if (first_cu != first_cu2)  /* Caseless */
+          {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+          PCRE2_UCHAR smc;
+          while (start_match < end_subject &&
+                (smc = UCHAR21TEST(start_match)) != first_cu &&
+                  smc != first_cu2)
+            start_match++;
+
+#else  /* 8-bit code units */
+          PCRE2_SPTR pp1 = NULL;
+          PCRE2_SPTR pp2 = NULL;
+          PCRE2_SIZE cu2size = end_subject - start_match;
+
+          if (!memchr_not_found_first_cu)
+            {
+            pp1 = memchr(start_match, first_cu, end_subject - start_match);
+            if (pp1 == NULL) memchr_not_found_first_cu = TRUE;
+              else cu2size = pp1 - start_match;
+            }
+
+          /* If pp1 is not NULL, we have arranged to search only as far as pp1,
+          to see if the other case is earlier, so we can set "not found" only
+          when both searches have returned NULL. */
+
+          if (!memchr_not_found_first_cu2)
+            {
+            pp2 = memchr(start_match, first_cu2, cu2size);
+            memchr_not_found_first_cu2 = (pp2 == NULL && pp1 == NULL);
+            }
+
+          if (pp1 == NULL)
+            start_match = (pp2 == NULL)? end_subject : pp2;
+          else
+            start_match = (pp2 == NULL || pp1 < pp2)? pp1 : pp2;
+#endif
+          }
+
+        /* The caseful case */
+
+        else
+          {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+          while (start_match < end_subject && UCHAR21TEST(start_match) !=
+                 first_cu)
+            start_match++;
+#else  /* 8-bit code units */
+          start_match = memchr(start_match, first_cu, end_subject - start_match);
+          if (start_match == NULL) start_match = end_subject;
+#endif
+          }
+
+        /* If we can't find the required code unit, having reached the true end
+        of the subject, break the bumpalong loop, to force a match failure,
+        except when doing partial matching, when we let the next cycle run at
+        the end of the subject. To see why, consider the pattern /(?<=abc)def/,
+        which partially matches "abc", even though the string does not contain
+        the starting character "d". If we have not reached the true end of the
+        subject (PCRE2_FIRSTLINE caused end_subject to be temporarily modified)
+        we also let the cycle run, because the matching string is legitimately
+        allowed to start with the first code unit of a newline. */
+
+        if ((mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) == 0 &&
+            start_match >= mb->end_subject)
+          break;
+        }
+
+      /* If there's no first code unit, advance to just after a linebreak for a
+      multiline match if required. */
+
+      else if (startline)
+        {
+        if (start_match > mb->start_subject + start_offset)
+          {
+#ifdef SUPPORT_UNICODE
+          if (utf)
+            {
+            while (start_match < end_subject && !WAS_NEWLINE(start_match))
+              {
+              start_match++;
+              ACROSSCHAR(start_match < end_subject, start_match, start_match++);
+              }
+            }
+          else
+#endif
+          while (start_match < end_subject && !WAS_NEWLINE(start_match))
+            start_match++;
+
+          /* If we have just passed a CR and the newline option is ANY or
+          ANYCRLF, and we are now at a LF, advance the match position by one
+          more code unit. */
+
+          if (start_match[-1] == CHAR_CR &&
+               (mb->nltype == NLTYPE_ANY || mb->nltype == NLTYPE_ANYCRLF) &&
+               start_match < end_subject &&
+               UCHAR21TEST(start_match) == CHAR_NL)
+            start_match++;
+          }
+        }
+
+      /* If there's no first code unit or a requirement for a multiline line
+      start, advance to a non-unique first code unit if any have been
+      identified. The bitmap contains only 256 bits. When code units are 16 or
+      32 bits wide, all code units greater than 254 set the 255 bit. */
+
+      else if (start_bits != NULL)
+        {
+        while (start_match < end_subject)
+          {
+          uint32_t c = UCHAR21TEST(start_match);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+          if (c > 255) c = 255;
+#endif
+          if ((start_bits[c/8] & (1u << (c&7))) != 0) break;
+          start_match++;
+          }
+
+        /* See comment above in first_cu checking about the next line. */
+
+        if ((mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) == 0 &&
+            start_match >= mb->end_subject)
+          break;
+        }
+      }  /* End of first code unit handling */
+
+    /* Restore fudged end_subject */
+
+    end_subject = mb->end_subject;
+
+    /* The following two optimizations are disabled for partial matching. */
+
+    if ((mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) == 0)
+      {
+      PCRE2_SPTR p;
+
+      /* The minimum matching length is a lower bound; no actual string of that
+      length may actually match the pattern. Although the value is, strictly,
+      in characters, we treat it as code units to avoid spending too much time
+      in this optimization. */
+
+      if (end_subject - start_match < re->minlength) goto NOMATCH_EXIT;
+
+      /* If req_cu is set, we know that that code unit must appear in the
+      subject for the match to succeed. If the first code unit is set, req_cu
+      must be later in the subject; otherwise the test starts at the match
+      point. This optimization can save a huge amount of backtracking in
+      patterns with nested unlimited repeats that aren't going to match.
+      Writing separate code for cased/caseless versions makes it go faster, as
+      does using an autoincrement and backing off on a match. As in the case of
+      the first code unit, using memchr() in the 8-bit library gives a big
+      speed up. Unlike the first_cu check above, we do not need to call
+      memchr() twice in the caseless case because we only need to check for the
+      presence of the character in either case, not find the first occurrence.
+
+      The search can be skipped if the code unit was found later than the
+      current starting point in a previous iteration of the bumpalong loop.
+
+      HOWEVER: when the subject string is very, very long, searching to its end
+      can take a long time, and give bad performance on quite ordinary
+      patterns. This showed up when somebody was matching something like
+      /^\d+C/ on a 32-megabyte string... so we don't do this when the string is
+      sufficiently long, but it's worth searching a lot more for unanchored
+      patterns. */
+
+      p = start_match + (has_first_cu? 1:0);
+      if (has_req_cu && p > req_cu_ptr)
+        {
+        PCRE2_SIZE check_length = end_subject - start_match;
+
+        if (check_length < REQ_CU_MAX ||
+              (!anchored && check_length < REQ_CU_MAX * 1000))
+          {
+          if (req_cu != req_cu2)  /* Caseless */
+            {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+            while (p < end_subject)
+              {
+              uint32_t pp = UCHAR21INCTEST(p);
+              if (pp == req_cu || pp == req_cu2) { p--; break; }
+              }
+#else  /* 8-bit code units */
+            PCRE2_SPTR pp = p;
+            p = memchr(pp, req_cu, end_subject - pp);
+            if (p == NULL)
+              {
+              p = memchr(pp, req_cu2, end_subject - pp);
+              if (p == NULL) p = end_subject;
+              }
+#endif /* PCRE2_CODE_UNIT_WIDTH != 8 */
+            }
+
+          /* The caseful case */
+
+          else
+            {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+            while (p < end_subject)
+              {
+              if (UCHAR21INCTEST(p) == req_cu) { p--; break; }
+              }
+
+#else  /* 8-bit code units */
+            p = memchr(p, req_cu, end_subject - p);
+            if (p == NULL) p = end_subject;
+#endif
+            }
+
+          /* If we can't find the required code unit, break the matching loop,
+          forcing a match failure. */
+
+          if (p >= end_subject) break;
+
+          /* If we have found the required code unit, save the point where we
+          found it, so that we don't search again next time round the loop if
+          the start hasn't passed this code unit yet. */
+
+          req_cu_ptr = p;
+          }
+        }
+      }
+    }
+
+  /* ------------ End of start of match optimizations ------------ */
+
+  /* Give no match if we have passed the bumpalong limit. */
+
+  if (start_match > bumpalong_limit) break;
+
+  /* OK, now we can do the business */
+
+  mb->start_used_ptr = start_match;
+  mb->last_used_ptr = start_match;
+  mb->recursive = NULL;
+
+  rc = internal_dfa_match(
+    mb,                           /* fixed match data */
+    mb->start_code,               /* this subexpression's code */
+    start_match,                  /* where we currently are */
+    start_offset,                 /* start offset in subject */
+    match_data->ovector,          /* offset vector */
+    (uint32_t)match_data->oveccount * 2,  /* actual size of same */
+    workspace,                    /* workspace vector */
+    (int)wscount,                 /* size of same */
+    0,                            /* function recurse level */
+    base_recursion_workspace);    /* initial workspace for recursion */
+
+  /* Anything other than "no match" means we are done, always; otherwise, carry
+  on only if not anchored. */
+
+  if (rc != PCRE2_ERROR_NOMATCH || anchored)
+    {
+    if (rc == PCRE2_ERROR_PARTIAL && match_data->oveccount > 0)
+      {
+      match_data->ovector[0] = (PCRE2_SIZE)(start_match - subject);
+      match_data->ovector[1] = (PCRE2_SIZE)(end_subject - subject);
+      }
+    match_data->leftchar = (PCRE2_SIZE)(mb->start_used_ptr - subject);
+    match_data->rightchar = (PCRE2_SIZE)( mb->last_used_ptr - subject);
+    match_data->startchar = (PCRE2_SIZE)(start_match - subject);
+    match_data->rc = rc;
+
+    if (rc >= 0 &&(options & PCRE2_COPY_MATCHED_SUBJECT) != 0)
+      {
+      length = CU2BYTES(length + was_zero_terminated);
+      match_data->subject = match_data->memctl.malloc(length,
+        match_data->memctl.memory_data);
+      if (match_data->subject == NULL) return PCRE2_ERROR_NOMEMORY;
+      memcpy((void *)match_data->subject, subject, length);
+      match_data->flags |= PCRE2_MD_COPIED_SUBJECT;
+      }
+    else
+      {
+      if (rc >= 0 || rc == PCRE2_ERROR_PARTIAL) match_data->subject = subject;
+      }
+    goto EXIT;
+    }
+
+  /* Advance to the next subject character unless we are at the end of a line
+  and firstline is set. */
+
+  if (firstline && IS_NEWLINE(start_match)) break;
+  start_match++;
+#ifdef SUPPORT_UNICODE
+  if (utf)
+    {
+    ACROSSCHAR(start_match < end_subject, start_match, start_match++);
+    }
+#endif
+  if (start_match > end_subject) break;
+
+  /* If we have just passed a CR and we are now at a LF, and the pattern does
+  not contain any explicit matches for \r or \n, and the newline option is CRLF
+  or ANY or ANYCRLF, advance the match position by one more character. */
+
+  if (UCHAR21TEST(start_match - 1) == CHAR_CR &&
+      start_match < end_subject &&
+      UCHAR21TEST(start_match) == CHAR_NL &&
+      (re->flags & PCRE2_HASCRORLF) == 0 &&
+        (mb->nltype == NLTYPE_ANY ||
+         mb->nltype == NLTYPE_ANYCRLF ||
+         mb->nllen == 2))
+    start_match++;
+
+  }   /* "Bumpalong" loop */
+
+NOMATCH_EXIT:
+rc = PCRE2_ERROR_NOMATCH;
+
+EXIT:
+while (rws->next != NULL)
+  {
+  RWS_anchor *next = rws->next;
+  rws->next = next->next;
+  mb->memctl.free(next, mb->memctl.memory_data);
+  }
+
+return rc;
+}
+
+/* End of pcre2_dfa_match.c */
diff --git a/src/c/pcre2/src/pcre2_dftables.c b/src/c/pcre2/src/pcre2_dftables.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_dftables.c
@@ -0,0 +1,303 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2020 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This is a freestanding support program to generate a file containing
+character tables for PCRE2. The tables are built using the pcre2_maketables()
+function, which is part of the PCRE2 API. By default, the system's "C" locale
+is used rather than what the building user happens to have set, but the -L
+option can be used to select the current locale from the LC_ALL environment
+variable. By default, the tables are written in source form, but if -b is
+given, they are written in binary. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+
+#define PCRE2_CODE_UNIT_WIDTH 0   /* Must be set, but not relevant here */
+#include "pcre2_internal.h"
+
+#define PCRE2_DFTABLES            /* pcre2_maketables.c notices this */
+#include "pcre2_maketables.c"
+
+
+static char *classlist[] =
+  {
+  "space", "xdigit", "digit", "upper", "lower",
+  "word", "graph", "print", "punct", "cntrl"
+  };
+
+
+
+/*************************************************
+*                  Usage                         *
+*************************************************/
+
+static void
+usage(void)
+{
+(void)fprintf(stderr,
+  "Usage: pcre2_dftables [options] <output file>\n"
+  "  -b    Write output in binary (default is source code)\n"
+  "  -L    Use locale from LC_ALL (default is \"C\" locale)\n"
+  );
+}
+
+
+
+/*************************************************
+*                Entry point                     *
+*************************************************/
+
+int main(int argc, char **argv)
+{
+FILE *f;
+int i;
+int nclass = 0;
+BOOL binary = FALSE;
+char *env = "C";
+const unsigned char *tables;
+const unsigned char *base_of_tables;
+
+/* Process options */
+
+for (i = 1; i < argc; i++)
+  {
+  unsigned char *arg = (unsigned char *)argv[i];
+  if (*arg != '-') break;
+
+  if (strcmp(arg, "-help") == 0 || strcmp(arg, "--help") == 0)
+    {
+    usage();
+    return 0;
+    }
+
+  else if (strcmp(arg, "-L") == 0)
+    {
+    if (setlocale(LC_ALL, "") == NULL)
+      {
+      (void)fprintf(stderr, "pcre2_dftables: setlocale() failed\n");
+      return 1;
+      }
+    env = getenv("LC_ALL");
+    }
+
+  else if (strcmp(arg, "-b") == 0)
+    binary = TRUE;
+
+  else
+    {
+    (void)fprintf(stderr, "pcre2_dftables: unrecognized option %s\n", arg);
+    return 1;
+    }
+  }
+
+if (i != argc - 1)
+  {
+  (void)fprintf(stderr, "pcre2_dftables: one filename argument is required\n");
+  return 1;
+  }
+
+/* Make the tables */
+
+tables = maketables();
+base_of_tables = tables;
+
+f = fopen(argv[i], "wb");
+if (f == NULL)
+  {
+  fprintf(stderr, "pcre2_dftables: failed to open %s for writing\n", argv[1]);
+  return 1;
+  }
+
+/* If -b was specified, we write the tables in binary. */
+
+if (binary)
+  {
+  int yield = 0;
+  size_t len = fwrite(tables, 1, TABLES_LENGTH, f);
+  if (len != TABLES_LENGTH)
+    {
+    (void)fprintf(stderr, "pcre2_dftables: fwrite() returned wrong length %d "
+     "instead of %d\n", (int)len, TABLES_LENGTH);
+    yield = 1;
+    }
+  fclose(f);
+  free((void *)base_of_tables);
+  return yield;
+  }
+
+/* Write the tables as source code for inclusion in the PCRE2 library. There
+are several fprintf() calls here, because gcc in pedantic mode complains about
+the very long string otherwise. */
+
+(void)fprintf(f,
+  "/*************************************************\n"
+  "*      Perl-Compatible Regular Expressions       *\n"
+  "*************************************************/\n\n"
+  "/* This file was automatically written by the pcre2_dftables auxiliary\n"
+  "program. It contains character tables that are used when no external\n"
+  "tables are passed to PCRE2 by the application that calls it. The tables\n"
+  "are used only for characters whose code values are less than 256. */\n\n");
+
+(void)fprintf(f,
+  "/* This set of tables was written in the %s locale. */\n\n", env);
+
+(void)fprintf(f,
+  "/* The pcre2_ftables program (which is distributed with PCRE2) can be used\n"
+  "to build alternative versions of this file. This is necessary if you are\n"
+  "running in an EBCDIC environment, or if you want to default to a different\n"
+  "encoding, for example ISO-8859-1. When pcre2_dftables is run, it creates\n"
+  "these tables in the \"C\" locale by default. This happens automatically if\n"
+  "PCRE2 is configured with --enable-rebuild-chartables. However, you can run\n"
+  "pcre2_dftables manually with the -L option to build tables using the LC_ALL\n"
+  "locale. */\n\n");
+
+/* Force config.h in z/OS */
+
+#if defined NATIVE_ZOS
+(void)fprintf(f,
+  "/* For z/OS, config.h is forced */\n"
+  "#ifndef HAVE_CONFIG_H\n"
+  "#define HAVE_CONFIG_H 1\n"
+  "#endif\n\n");
+#endif
+
+(void)fprintf(f,
+  "/* The following #include is present because without it gcc 4.x may remove\n"
+  "the array definition from the final binary if PCRE2 is built into a static\n"
+  "library and dead code stripping is activated. This leads to link errors.\n"
+  "Pulling in the header ensures that the array gets flagged as \"someone\n"
+  "outside this compilation unit might reference this\" and so it will always\n"
+  "be supplied to the linker. */\n\n");
+
+(void)fprintf(f,
+  "#ifdef HAVE_CONFIG_H\n"
+  "#include \"config.h\"\n"
+  "#endif\n\n"
+  "#include \"pcre2_internal.h\"\n\n");
+
+(void)fprintf(f,
+  "const uint8_t PRIV(default_tables)[] = {\n\n"
+  "/* This table is a lower casing table. */\n\n");
+
+(void)fprintf(f, "  ");
+for (i = 0; i < 256; i++)
+  {
+  if ((i & 7) == 0 && i != 0) fprintf(f, "\n  ");
+  fprintf(f, "%3d", *tables++);
+  if (i != 255) fprintf(f, ",");
+  }
+(void)fprintf(f, ",\n\n");
+
+(void)fprintf(f, "/* This table is a case flipping table. */\n\n");
+
+(void)fprintf(f, "  ");
+for (i = 0; i < 256; i++)
+  {
+  if ((i & 7) == 0 && i != 0) fprintf(f, "\n  ");
+  fprintf(f, "%3d", *tables++);
+  if (i != 255) fprintf(f, ",");
+  }
+(void)fprintf(f, ",\n\n");
+
+(void)fprintf(f,
+  "/* This table contains bit maps for various character classes. Each map is 32\n"
+  "bytes long and the bits run from the least significant end of each byte. The\n"
+  "classes that have their own maps are: space, xdigit, digit, upper, lower, word,\n"
+  "graph, print, punct, and cntrl. Other classes are built from combinations. */\n\n");
+
+(void)fprintf(f, "  ");
+for (i = 0; i < cbit_length; i++)
+  {
+  if ((i & 7) == 0 && i != 0)
+    {
+    if ((i & 31) == 0) (void)fprintf(f, "\n");
+    if ((i & 24) == 8) (void)fprintf(f, "  /* %s */", classlist[nclass++]);
+    (void)fprintf(f, "\n  ");
+    }
+  (void)fprintf(f, "0x%02x", *tables++);
+  if (i != cbit_length - 1) (void)fprintf(f, ",");
+  }
+(void)fprintf(f, ",\n\n");
+
+(void)fprintf(f,
+  "/* This table identifies various classes of character by individual bits:\n"
+  "  0x%02x   white space character\n"
+  "  0x%02x   letter\n"
+  "  0x%02x   lower case letter\n"
+  "  0x%02x   decimal digit\n"
+  "  0x%02x   alphanumeric or '_'\n*/\n\n",
+  ctype_space, ctype_letter, ctype_lcletter, ctype_digit, ctype_word);
+
+(void)fprintf(f, "  ");
+for (i = 0; i < 256; i++)
+  {
+  if ((i & 7) == 0 && i != 0)
+    {
+    (void)fprintf(f, " /* ");
+    if (isprint(i-8)) (void)fprintf(f, " %c -", i-8);
+      else (void)fprintf(f, "%3d-", i-8);
+    if (isprint(i-1)) (void)fprintf(f, " %c ", i-1);
+      else (void)fprintf(f, "%3d", i-1);
+    (void)fprintf(f, " */\n  ");
+    }
+  (void)fprintf(f, "0x%02x", *tables++);
+  if (i != 255) (void)fprintf(f, ",");
+  }
+
+(void)fprintf(f, "};/* ");
+if (isprint(i-8)) (void)fprintf(f, " %c -", i-8);
+  else (void)fprintf(f, "%3d-", i-8);
+if (isprint(i-1)) (void)fprintf(f, " %c ", i-1);
+  else (void)fprintf(f, "%3d", i-1);
+(void)fprintf(f, " */\n\n/* End of pcre2_chartables.c */\n");
+
+fclose(f);
+free((void *)base_of_tables);
+return 0;
+}
+
+/* End of pcre2_dftables.c */
diff --git a/src/c/pcre2/src/pcre2_error.c b/src/c/pcre2/src/pcre2_error.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_error.c
@@ -0,0 +1,340 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2019 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+#define STRING(a)  # a
+#define XSTRING(s) STRING(s)
+
+/* The texts of compile-time error messages. Compile-time error numbers start
+at COMPILE_ERROR_BASE (100).
+
+This used to be a table of strings, but in order to reduce the number of
+relocations needed when a shared library is loaded dynamically, it is now one
+long string. We cannot use a table of offsets, because the lengths of inserts
+such as XSTRING(MAX_NAME_SIZE) are not known. Instead,
+pcre2_get_error_message() counts through to the one it wants - this isn't a
+performance issue because these strings are used only when there is an error.
+
+Each substring ends with \0 to insert a null character. This includes the final
+substring, so that the whole string ends with \0\0, which can be detected when
+counting through. */
+
+static const unsigned char compile_error_texts[] =
+  "no error\0"
+  "\\ at end of pattern\0"
+  "\\c at end of pattern\0"
+  "unrecognized character follows \\\0"
+  "numbers out of order in {} quantifier\0"
+  /* 5 */
+  "number too big in {} quantifier\0"
+  "missing terminating ] for character class\0"
+  "escape sequence is invalid in character class\0"
+  "range out of order in character class\0"
+  "quantifier does not follow a repeatable item\0"
+  /* 10 */
+  "internal error: unexpected repeat\0"
+  "unrecognized character after (? or (?-\0"
+  "POSIX named classes are supported only within a class\0"
+  "POSIX collating elements are not supported\0"
+  "missing closing parenthesis\0"
+  /* 15 */
+  "reference to non-existent subpattern\0"
+  "pattern passed as NULL\0"
+  "unrecognised compile-time option bit(s)\0"
+  "missing ) after (?# comment\0"
+  "parentheses are too deeply nested\0"
+  /* 20 */
+  "regular expression is too large\0"
+  "failed to allocate heap memory\0"
+  "unmatched closing parenthesis\0"
+  "internal error: code overflow\0"
+  "missing closing parenthesis for condition\0"
+  /* 25 */
+  "lookbehind assertion is not fixed length\0"
+  "a relative value of zero is not allowed\0"
+  "conditional subpattern contains more than two branches\0"
+  "assertion expected after (?( or (?(?C)\0"
+  "digit expected after (?+ or (?-\0"
+  /* 30 */
+  "unknown POSIX class name\0"
+  "internal error in pcre2_study(): should not occur\0"
+  "this version of PCRE2 does not have Unicode support\0"
+  "parentheses are too deeply nested (stack check)\0"
+  "character code point value in \\x{} or \\o{} is too large\0"
+  /* 35 */
+  "lookbehind is too complicated\0"
+  "\\C is not allowed in a lookbehind assertion in UTF-" XSTRING(PCRE2_CODE_UNIT_WIDTH) " mode\0"
+  "PCRE2 does not support \\F, \\L, \\l, \\N{name}, \\U, or \\u\0"
+  "number after (?C is greater than 255\0"
+  "closing parenthesis for (?C expected\0"
+  /* 40 */
+  "invalid escape sequence in (*VERB) name\0"
+  "unrecognized character after (?P\0"
+  "syntax error in subpattern name (missing terminator?)\0"
+  "two named subpatterns have the same name (PCRE2_DUPNAMES not set)\0"
+  "subpattern name must start with a non-digit\0"
+  /* 45 */
+  "this version of PCRE2 does not have support for \\P, \\p, or \\X\0"
+  "malformed \\P or \\p sequence\0"
+  "unknown property name after \\P or \\p\0"
+  "subpattern name is too long (maximum " XSTRING(MAX_NAME_SIZE) " code units)\0"
+  "too many named subpatterns (maximum " XSTRING(MAX_NAME_COUNT) ")\0"
+  /* 50 */
+  "invalid range in character class\0"
+  "octal value is greater than \\377 in 8-bit non-UTF-8 mode\0"
+  "internal error: overran compiling workspace\0"
+  "internal error: previously-checked referenced subpattern not found\0"
+  "DEFINE subpattern contains more than one branch\0"
+  /* 55 */
+  "missing opening brace after \\o\0"
+  "internal error: unknown newline setting\0"
+  "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number\0"
+  "(?R (recursive pattern call) must be followed by a closing parenthesis\0"
+  /* "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)\0" */
+  "obsolete error (should not occur)\0"  /* Was the above */
+  /* 60 */
+  "(*VERB) not recognized or malformed\0"
+  "subpattern number is too big\0"
+  "subpattern name expected\0"
+  "internal error: parsed pattern overflow\0"
+  "non-octal character in \\o{} (closing brace missing?)\0"
+  /* 65 */
+  "different names for subpatterns of the same number are not allowed\0"
+  "(*MARK) must have an argument\0"
+  "non-hex character in \\x{} (closing brace missing?)\0"
+#ifndef EBCDIC
+  "\\c must be followed by a printable ASCII character\0"
+#else
+  "\\c must be followed by a letter or one of [\\]^_?\0"
+#endif
+  "\\k is not followed by a braced, angle-bracketed, or quoted name\0"
+  /* 70 */
+  "internal error: unknown meta code in check_lookbehinds()\0"
+  "\\N is not supported in a class\0"
+  "callout string is too long\0"
+  "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)\0"
+  "using UTF is disabled by the application\0"
+  /* 75 */
+  "using UCP is disabled by the application\0"
+  "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)\0"
+  "character code point value in \\u.... sequence is too large\0"
+  "digits missing in \\x{} or \\o{} or \\N{U+}\0"
+  "syntax error or number too big in (?(VERSION condition\0"
+  /* 80 */
+  "internal error: unknown opcode in auto_possessify()\0"
+  "missing terminating delimiter for callout with string argument\0"
+  "unrecognized string delimiter follows (?C\0"
+  "using \\C is disabled by the application\0"
+  "(?| and/or (?J: or (?x: parentheses are too deeply nested\0"
+  /* 85 */
+  "using \\C is disabled in this PCRE2 library\0"
+  "regular expression is too complicated\0"
+  "lookbehind assertion is too long\0"
+  "pattern string is longer than the limit set by the application\0"
+  "internal error: unknown code in parsed pattern\0"
+  /* 90 */
+  "internal error: bad code value in parsed_skip()\0"
+  "PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES is not allowed in UTF-16 mode\0"
+  "invalid option bits with PCRE2_LITERAL\0"
+  "\\N{U+dddd} is supported only in Unicode (UTF) mode\0"
+  "invalid hyphen in option setting\0"
+  /* 95 */
+  "(*alpha_assertion) not recognized\0"
+  "script runs require Unicode support, which this version of PCRE2 does not have\0"
+  "too many capturing groups (maximum 65535)\0"
+  "atomic assertion expected after (?( or (?(?C)\0"
+  ;
+
+/* Match-time and UTF error texts are in the same format. */
+
+static const unsigned char match_error_texts[] =
+  "no error\0"
+  "no match\0"
+  "partial match\0"
+  "UTF-8 error: 1 byte missing at end\0"
+  "UTF-8 error: 2 bytes missing at end\0"
+  /* 5 */
+  "UTF-8 error: 3 bytes missing at end\0"
+  "UTF-8 error: 4 bytes missing at end\0"
+  "UTF-8 error: 5 bytes missing at end\0"
+  "UTF-8 error: byte 2 top bits not 0x80\0"
+  "UTF-8 error: byte 3 top bits not 0x80\0"
+  /* 10 */
+  "UTF-8 error: byte 4 top bits not 0x80\0"
+  "UTF-8 error: byte 5 top bits not 0x80\0"
+  "UTF-8 error: byte 6 top bits not 0x80\0"
+  "UTF-8 error: 5-byte character is not allowed (RFC 3629)\0"
+  "UTF-8 error: 6-byte character is not allowed (RFC 3629)\0"
+  /* 15 */
+  "UTF-8 error: code points greater than 0x10ffff are not defined\0"
+  "UTF-8 error: code points 0xd800-0xdfff are not defined\0"
+  "UTF-8 error: overlong 2-byte sequence\0"
+  "UTF-8 error: overlong 3-byte sequence\0"
+  "UTF-8 error: overlong 4-byte sequence\0"
+  /* 20 */
+  "UTF-8 error: overlong 5-byte sequence\0"
+  "UTF-8 error: overlong 6-byte sequence\0"
+  "UTF-8 error: isolated byte with 0x80 bit set\0"
+  "UTF-8 error: illegal byte (0xfe or 0xff)\0"
+  "UTF-16 error: missing low surrogate at end\0"
+  /* 25 */
+  "UTF-16 error: invalid low surrogate\0"
+  "UTF-16 error: isolated low surrogate\0"
+  "UTF-32 error: code points 0xd800-0xdfff are not defined\0"
+  "UTF-32 error: code points greater than 0x10ffff are not defined\0"
+  "bad data value\0"
+  /* 30 */
+  "patterns do not all use the same character tables\0"
+  "magic number missing\0"
+  "pattern compiled in wrong mode: 8/16/32-bit error\0"
+  "bad offset value\0"
+  "bad option value\0"
+  /* 35 */
+  "invalid replacement string\0"
+  "bad offset into UTF string\0"
+  "callout error code\0"              /* Never returned by PCRE2 itself */
+  "invalid data in workspace for DFA restart\0"
+  "too much recursion for DFA matching\0"
+  /* 40 */
+  "backreference condition or recursion test is not supported for DFA matching\0"
+  "function is not supported for DFA matching\0"
+  "pattern contains an item that is not supported for DFA matching\0"
+  "workspace size exceeded in DFA matching\0"
+  "internal error - pattern overwritten?\0"
+  /* 45 */
+  "bad JIT option\0"
+  "JIT stack limit reached\0"
+  "match limit exceeded\0"
+  "no more memory\0"
+  "unknown substring\0"
+  /* 50 */
+  "non-unique substring name\0"
+  "NULL argument passed\0"
+  "nested recursion at the same subject position\0"
+  "matching depth limit exceeded\0"
+  "requested value is not available\0"
+  /* 55 */
+  "requested value is not set\0"
+  "offset limit set without PCRE2_USE_OFFSET_LIMIT\0"
+  "bad escape sequence in replacement string\0"
+  "expected closing curly bracket in replacement string\0"
+  "bad substitution in replacement string\0"
+  /* 60 */
+  "match with end before start or start moved backwards is not supported\0"
+  "too many replacements (more than INT_MAX)\0"
+  "bad serialized data\0"
+  "heap limit exceeded\0"
+  "invalid syntax\0"
+  /* 65 */
+  "internal error - duplicate substitution match\0"
+  "PCRE2_MATCH_INVALID_UTF is not supported for DFA matching\0"
+  ;
+
+
+/*************************************************
+*            Return error message                *
+*************************************************/
+
+/* This function copies an error message into a buffer whose units are of an
+appropriate width. Error numbers are positive for compile-time errors, and
+negative for match-time errors (except for UTF errors), but the numbers are all
+distinct.
+
+Arguments:
+  enumber       error number
+  buffer        where to put the message (zero terminated)
+  size          size of the buffer in code units
+
+Returns:        length of message if all is well
+                negative on error
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_get_error_message(int enumber, PCRE2_UCHAR *buffer, PCRE2_SIZE size)
+{
+const unsigned char *message;
+PCRE2_SIZE i;
+int n;
+
+if (size == 0) return PCRE2_ERROR_NOMEMORY;
+
+if (enumber >= COMPILE_ERROR_BASE)  /* Compile error */
+  {
+  message = compile_error_texts;
+  n = enumber - COMPILE_ERROR_BASE;
+  }
+else if (enumber < 0)               /* Match or UTF error */
+  {
+  message = match_error_texts;
+  n = -enumber;
+  }
+else                                /* Invalid error number */
+  {
+  message = (unsigned char *)"\0";  /* Empty message list */
+  n = 1;
+  }
+
+for (; n > 0; n--)
+  {
+  while (*message++ != CHAR_NUL) {};
+  if (*message == CHAR_NUL) return PCRE2_ERROR_BADDATA;
+  }
+
+for (i = 0; *message != 0; i++)
+  {
+  if (i >= size - 1)
+    {
+    buffer[i] = 0;     /* Terminate partial message */
+    return PCRE2_ERROR_NOMEMORY;
+    }
+  buffer[i] = *message++;
+  }
+
+buffer[i] = 0;
+return (int)i;
+}
+
+/* End of pcre2_error.c */
diff --git a/src/c/pcre2/src/pcre2_extuni.c b/src/c/pcre2/src/pcre2_extuni.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_extuni.c
@@ -0,0 +1,148 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2019 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains an internal function that is used to match a Unicode
+extended grapheme sequence. It is used by both pcre2_match() and
+pcre2_def_match(). However, it is called only when Unicode support is being
+compiled. Nevertheless, we provide a dummy function when there is no Unicode
+support, because some compilers do not like functionless source files. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "pcre2_internal.h"
+
+
+/* Dummy function */
+
+#ifndef SUPPORT_UNICODE
+PCRE2_SPTR
+PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR start_subject,
+  PCRE2_SPTR end_subject, BOOL utf, int *xcount)
+{
+(void)c;
+(void)eptr;
+(void)start_subject;
+(void)end_subject;
+(void)utf;
+(void)xcount;
+return NULL;
+}
+#else
+
+
+/*************************************************
+*      Match an extended grapheme sequence       *
+*************************************************/
+
+/*
+Arguments:
+  c              the first character
+  eptr           pointer to next character
+  start_subject  pointer to start of subject
+  end_subject    pointer to end of subject
+  utf            TRUE if in UTF mode
+  xcount         pointer to count of additional characters,
+                   or NULL if count not needed
+
+Returns:         pointer after the end of the sequence
+*/
+
+PCRE2_SPTR
+PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR start_subject,
+  PCRE2_SPTR end_subject, BOOL utf, int *xcount)
+{
+int lgb = UCD_GRAPHBREAK(c);
+
+while (eptr < end_subject)
+  {
+  int rgb;
+  int len = 1;
+  if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); }
+  rgb = UCD_GRAPHBREAK(c);
+  if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break;
+
+  /* Not breaking between Regional Indicators is allowed only if there
+  are an even number of preceding RIs. */
+
+  if (lgb == ucp_gbRegionalIndicator && rgb == ucp_gbRegionalIndicator)
+    {
+    int ricount = 0;
+    PCRE2_SPTR bptr = eptr - 1;
+    if (utf) BACKCHAR(bptr);
+
+    /* bptr is pointing to the left-hand character */
+
+    while (bptr > start_subject)
+      {
+      bptr--;
+      if (utf)
+        {
+        BACKCHAR(bptr);
+        GETCHAR(c, bptr);
+        }
+      else
+      c = *bptr;
+      if (UCD_GRAPHBREAK(c) != ucp_gbRegionalIndicator) break;
+      ricount++;
+      }
+    if ((ricount & 1) != 0) break;  /* Grapheme break required */
+    }
+
+  /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this
+  allows any number of them before a following Extended_Pictographic. */
+
+  if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) ||
+       lgb != ucp_gbExtended_Pictographic)
+    lgb = rgb;
+
+  eptr += len;
+  if (xcount != NULL) *xcount += 1;
+  }
+
+return eptr;
+}
+
+#endif  /* SUPPORT_UNICODE */
+
+/* End of pcre2_extuni.c */
diff --git a/src/c/pcre2/src/pcre2_find_bracket.c b/src/c/pcre2/src/pcre2_find_bracket.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_find_bracket.c
@@ -0,0 +1,219 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains a single function that scans through a compiled pattern
+until it finds a capturing bracket with the given number, or, if the number is
+negative, an instance of OP_REVERSE for a lookbehind. The function is called
+from pcre2_compile.c and also from pcre2_study.c when finding the minimum
+matching length. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+/*************************************************
+*    Scan compiled regex for specific bracket    *
+*************************************************/
+
+/*
+Arguments:
+  code        points to start of expression
+  utf         TRUE in UTF mode
+  number      the required bracket number or negative to find a lookbehind
+
+Returns:      pointer to the opcode for the bracket, or NULL if not found
+*/
+
+PCRE2_SPTR
+PRIV(find_bracket)(PCRE2_SPTR code, BOOL utf, int number)
+{
+for (;;)
+  {
+  PCRE2_UCHAR c = *code;
+
+  if (c == OP_END) return NULL;
+
+  /* XCLASS is used for classes that cannot be represented just by a bit map.
+  This includes negated single high-valued characters. CALLOUT_STR is used for
+  callouts with string arguments. In both cases the length in the table is
+  zero; the actual length is stored in the compiled code. */
+
+  if (c == OP_XCLASS) code += GET(code, 1);
+    else if (c == OP_CALLOUT_STR) code += GET(code, 1 + 2*LINK_SIZE);
+
+  /* Handle lookbehind */
+
+  else if (c == OP_REVERSE)
+    {
+    if (number < 0) return (PCRE2_UCHAR *)code;
+    code += PRIV(OP_lengths)[c];
+    }
+
+  /* Handle capturing bracket */
+
+  else if (c == OP_CBRA || c == OP_SCBRA ||
+           c == OP_CBRAPOS || c == OP_SCBRAPOS)
+    {
+    int n = (int)GET2(code, 1+LINK_SIZE);
+    if (n == number) return (PCRE2_UCHAR *)code;
+    code += PRIV(OP_lengths)[c];
+    }
+
+  /* Otherwise, we can get the item's length from the table, except that for
+  repeated character types, we have to test for \p and \P, which have an extra
+  two bytes of parameters, and for MARK/PRUNE/SKIP/THEN with an argument, we
+  must add in its length. */
+
+  else
+    {
+    switch(c)
+      {
+      case OP_TYPESTAR:
+      case OP_TYPEMINSTAR:
+      case OP_TYPEPLUS:
+      case OP_TYPEMINPLUS:
+      case OP_TYPEQUERY:
+      case OP_TYPEMINQUERY:
+      case OP_TYPEPOSSTAR:
+      case OP_TYPEPOSPLUS:
+      case OP_TYPEPOSQUERY:
+      if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2;
+      break;
+
+      case OP_TYPEUPTO:
+      case OP_TYPEMINUPTO:
+      case OP_TYPEEXACT:
+      case OP_TYPEPOSUPTO:
+      if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
+        code += 2;
+      break;
+
+      case OP_MARK:
+      case OP_COMMIT_ARG:
+      case OP_PRUNE_ARG:
+      case OP_SKIP_ARG:
+      case OP_THEN_ARG:
+      code += code[1];
+      break;
+      }
+
+    /* Add in the fixed length from the table */
+
+    code += PRIV(OP_lengths)[c];
+
+  /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may be
+  followed by a multi-byte character. The length in the table is a minimum, so
+  we have to arrange to skip the extra bytes. */
+
+#ifdef MAYBE_UTF_MULTI
+    if (utf) switch(c)
+      {
+      case OP_CHAR:
+      case OP_CHARI:
+      case OP_NOT:
+      case OP_NOTI:
+      case OP_EXACT:
+      case OP_EXACTI:
+      case OP_NOTEXACT:
+      case OP_NOTEXACTI:
+      case OP_UPTO:
+      case OP_UPTOI:
+      case OP_NOTUPTO:
+      case OP_NOTUPTOI:
+      case OP_MINUPTO:
+      case OP_MINUPTOI:
+      case OP_NOTMINUPTO:
+      case OP_NOTMINUPTOI:
+      case OP_POSUPTO:
+      case OP_POSUPTOI:
+      case OP_NOTPOSUPTO:
+      case OP_NOTPOSUPTOI:
+      case OP_STAR:
+      case OP_STARI:
+      case OP_NOTSTAR:
+      case OP_NOTSTARI:
+      case OP_MINSTAR:
+      case OP_MINSTARI:
+      case OP_NOTMINSTAR:
+      case OP_NOTMINSTARI:
+      case OP_POSSTAR:
+      case OP_POSSTARI:
+      case OP_NOTPOSSTAR:
+      case OP_NOTPOSSTARI:
+      case OP_PLUS:
+      case OP_PLUSI:
+      case OP_NOTPLUS:
+      case OP_NOTPLUSI:
+      case OP_MINPLUS:
+      case OP_MINPLUSI:
+      case OP_NOTMINPLUS:
+      case OP_NOTMINPLUSI:
+      case OP_POSPLUS:
+      case OP_POSPLUSI:
+      case OP_NOTPOSPLUS:
+      case OP_NOTPOSPLUSI:
+      case OP_QUERY:
+      case OP_QUERYI:
+      case OP_NOTQUERY:
+      case OP_NOTQUERYI:
+      case OP_MINQUERY:
+      case OP_MINQUERYI:
+      case OP_NOTMINQUERY:
+      case OP_NOTMINQUERYI:
+      case OP_POSQUERY:
+      case OP_POSQUERYI:
+      case OP_NOTPOSQUERY:
+      case OP_NOTPOSQUERYI:
+      if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
+      break;
+      }
+#else
+    (void)(utf);  /* Keep compiler happy by referencing function argument */
+#endif  /* MAYBE_UTF_MULTI */
+    }
+  }
+}
+
+/* End of pcre2_find_bracket.c */
diff --git a/src/c/pcre2/src/pcre2_fuzzsupport.c b/src/c/pcre2/src/pcre2_fuzzsupport.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_fuzzsupport.c
@@ -0,0 +1,365 @@
+/***************************************************************************
+Fuzzer driver for PCRE2. Given an arbitrary string of bytes and a length, it
+tries to compile and match it, deriving options from the string itself. If
+STANDALONE is defined, a main program that calls the driver with the contents
+of specified files is compiled, and commentary on what is happening is output.
+If an argument starts with '=' the rest of it it is taken as a literal string
+rather than a file name. This allows easy testing of short strings.
+
+Written by Philip Hazel, October 2016
+***************************************************************************/
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include "pcre2.h"
+
+#define MAX_MATCH_SIZE 1000
+
+#define DFA_WORKSPACE_COUNT 100
+
+#define ALLOWED_COMPILE_OPTIONS \
+  (PCRE2_ANCHORED|PCRE2_ALLOW_EMPTY_CLASS|PCRE2_ALT_BSUX|PCRE2_ALT_CIRCUMFLEX| \
+   PCRE2_ALT_VERBNAMES|PCRE2_AUTO_CALLOUT|PCRE2_CASELESS|PCRE2_DOLLAR_ENDONLY| \
+   PCRE2_DOTALL|PCRE2_DUPNAMES|PCRE2_ENDANCHORED|PCRE2_EXTENDED|PCRE2_FIRSTLINE| \
+   PCRE2_MATCH_UNSET_BACKREF|PCRE2_MULTILINE|PCRE2_NEVER_BACKSLASH_C| \
+   PCRE2_NO_AUTO_CAPTURE| \
+   PCRE2_NO_AUTO_POSSESS|PCRE2_NO_DOTSTAR_ANCHOR|PCRE2_NO_START_OPTIMIZE| \
+   PCRE2_UCP|PCRE2_UNGREEDY|PCRE2_USE_OFFSET_LIMIT| \
+   PCRE2_UTF)
+
+#define ALLOWED_MATCH_OPTIONS \
+  (PCRE2_ANCHORED|PCRE2_ENDANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \
+   PCRE2_NOTEMPTY_ATSTART|PCRE2_PARTIAL_HARD| \
+   PCRE2_PARTIAL_SOFT|PCRE2_NO_JIT)
+
+/* This is the callout function. Its only purpose is to halt matching if there
+are more than 100 callouts, as one way of stopping too much time being spent on
+fruitless matches. The callout data is a pointer to the counter. */
+
+static int callout_function(pcre2_callout_block *cb, void *callout_data)
+{
+(void)cb;  /* Avoid unused parameter warning */
+*((uint32_t *)callout_data) += 1;
+return (*((uint32_t *)callout_data) > 100)? PCRE2_ERROR_CALLOUT : 0;
+}
+
+/* Putting in this apparently unnecessary prototype prevents gcc from giving a
+"no previous prototype" warning when compiling at high warning level. */
+
+int LLVMFuzzerTestOneInput(const unsigned char *, size_t);
+
+/* Here's the driving function. */
+
+int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size)
+{
+uint32_t compile_options;
+uint32_t match_options;
+pcre2_match_data *match_data = NULL;
+pcre2_match_context *match_context = NULL;
+size_t match_size;
+int dfa_workspace[DFA_WORKSPACE_COUNT];
+int r1, r2;
+int i;
+
+if (size < 1) return 0;
+
+/* Limiting the length of the subject for matching stops fruitless searches
+in large trees taking too much time. */
+
+match_size = (size > MAX_MATCH_SIZE)? MAX_MATCH_SIZE : size;
+
+/* Figure out some options to use. Initialize the random number to ensure
+repeatability. Ensure that we get a 32-bit unsigned random number for testing
+options. (RAND_MAX is required to be at least 32767, but is commonly
+2147483647, which excludes the top bit.) */
+
+srand((unsigned int)(data[size/2]));
+r1 = rand();
+r2 = rand();
+
+/* Ensure that all undefined option bits are zero (waste of time trying them)
+and also that PCRE2_NO_UTF_CHECK is unset, as there is no guarantee that the
+input is UTF-8. Also unset PCRE2_NEVER_UTF and PCRE2_NEVER_UCP as there is no
+reason to disallow UTF and UCP. Force PCRE2_NEVER_BACKSLASH_C to be set because
+\C in random patterns is highly likely to cause a crash. */
+
+compile_options =
+  ((((uint32_t)r1 << 16) | ((uint32_t)r2 & 0xffff)) & ALLOWED_COMPILE_OPTIONS) |
+  PCRE2_NEVER_BACKSLASH_C;
+  
+match_options =
+  ((((uint32_t)r1 << 16) | ((uint32_t)r2 & 0xffff)) & ALLOWED_MATCH_OPTIONS);
+  
+/* Discard partial matching if PCRE2_ENDANCHORED is set, because they are not
+allowed together and just give an immediate error return. */
+
+if (((compile_options|match_options) & PCRE2_ENDANCHORED) != 0)
+  match_options &= ~(PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT); 
+
+/* Do the compile with and without the options, and after a successful compile,
+likewise do the match with and without the options. */
+
+for (i = 0; i < 2; i++)
+  {
+  uint32_t callout_count;
+  int errorcode;
+  PCRE2_SIZE erroroffset;
+  pcre2_code *code;
+
+#ifdef STANDALONE
+  printf("Compile options %.8x never_backslash_c", compile_options);
+  printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+    ((compile_options & PCRE2_ALT_BSUX) != 0)? ",alt_bsux" : "",
+    ((compile_options & PCRE2_ALT_CIRCUMFLEX) != 0)? ",alt_circumflex" : "",
+    ((compile_options & PCRE2_ALT_VERBNAMES) != 0)? ",alt_verbnames" : "",
+    ((compile_options & PCRE2_ALLOW_EMPTY_CLASS) != 0)? ",allow_empty_class" : "",
+    ((compile_options & PCRE2_ANCHORED) != 0)? ",anchored" : "",
+    ((compile_options & PCRE2_AUTO_CALLOUT) != 0)? ",auto_callout" : "",
+    ((compile_options & PCRE2_CASELESS) != 0)? ",caseless" : "",
+    ((compile_options & PCRE2_DOLLAR_ENDONLY) != 0)? ",dollar_endonly" : "",
+    ((compile_options & PCRE2_DOTALL) != 0)? ",dotall" : "",
+    ((compile_options & PCRE2_DUPNAMES) != 0)? ",dupnames" : "",
+    ((compile_options & PCRE2_ENDANCHORED) != 0)? ",endanchored" : "",
+    ((compile_options & PCRE2_EXTENDED) != 0)? ",extended" : "",
+    ((compile_options & PCRE2_FIRSTLINE) != 0)? ",firstline" : "",
+    ((compile_options & PCRE2_MATCH_UNSET_BACKREF) != 0)? ",match_unset_backref" : "",
+    ((compile_options & PCRE2_MULTILINE) != 0)? ",multiline" : "",
+    ((compile_options & PCRE2_NEVER_UCP) != 0)? ",never_ucp" : "",
+    ((compile_options & PCRE2_NEVER_UTF) != 0)? ",never_utf" : "",
+    ((compile_options & PCRE2_NO_AUTO_CAPTURE) != 0)? ",no_auto_capture" : "",
+    ((compile_options & PCRE2_NO_AUTO_POSSESS) != 0)? ",no_auto_possess" : "",
+    ((compile_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0)? ",no_dotstar_anchor" : "",
+    ((compile_options & PCRE2_NO_UTF_CHECK) != 0)? ",no_utf_check" : "",
+    ((compile_options & PCRE2_NO_START_OPTIMIZE) != 0)? ",no_start_optimize" : "",
+    ((compile_options & PCRE2_UCP) != 0)? ",ucp" : "",
+    ((compile_options & PCRE2_UNGREEDY) != 0)? ",ungreedy" : "",
+    ((compile_options & PCRE2_USE_OFFSET_LIMIT) != 0)? ",use_offset_limit" : "",
+    ((compile_options & PCRE2_UTF) != 0)? ",utf" : "");
+#endif
+
+  code = pcre2_compile((PCRE2_SPTR)data, (PCRE2_SIZE)size, compile_options,
+    &errorcode, &erroroffset, NULL);
+
+  /* Compilation succeeded */
+
+  if (code != NULL)
+    {
+    int j;
+    uint32_t save_match_options = match_options;
+
+    /* Create match data and context blocks only when we first need them. Set
+    low match and depth limits to avoid wasting too much searching large
+    pattern trees. Almost all matches are going to fail. */
+
+    if (match_data == NULL)
+      {
+      match_data = pcre2_match_data_create(32, NULL);
+      if (match_data == NULL)
+        {
+#ifdef STANDALONE
+        printf("** Failed to create match data block\n");
+#endif
+        return 0;
+        }
+      }
+
+    if (match_context == NULL)
+      {
+      match_context = pcre2_match_context_create(NULL);
+      if (match_context == NULL)
+        {
+#ifdef STANDALONE
+        printf("** Failed to create match context block\n");
+#endif
+        return 0;
+        }
+      (void)pcre2_set_match_limit(match_context, 100);
+      (void)pcre2_set_depth_limit(match_context, 100);
+      (void)pcre2_set_callout(match_context, callout_function, &callout_count);
+      }
+
+    /* Match twice, with and without options. */
+
+    for (j = 0; j < 2; j++)
+      {
+#ifdef STANDALONE
+      printf("Match options %.8x", match_options);
+      printf("%s%s%s%s%s%s%s%s%s%s\n",
+        ((match_options & PCRE2_ANCHORED) != 0)? ",anchored" : "",
+        ((match_options & PCRE2_ENDANCHORED) != 0)? ",endanchored" : "",
+        ((match_options & PCRE2_NO_JIT) != 0)? ",no_jit" : "",
+        ((match_options & PCRE2_NO_UTF_CHECK) != 0)? ",no_utf_check" : "",
+        ((match_options & PCRE2_NOTBOL) != 0)? ",notbol" : "",
+        ((match_options & PCRE2_NOTEMPTY) != 0)? ",notempty" : "",
+        ((match_options & PCRE2_NOTEMPTY_ATSTART) != 0)? ",notempty_atstart" : "",
+        ((match_options & PCRE2_NOTEOL) != 0)? ",noteol" : "",
+        ((match_options & PCRE2_PARTIAL_HARD) != 0)? ",partial_hard" : "",
+        ((match_options & PCRE2_PARTIAL_SOFT) != 0)? ",partial_soft" : "");
+#endif
+
+      callout_count = 0;
+      errorcode = pcre2_match(code, (PCRE2_SPTR)data, (PCRE2_SIZE)match_size, 0,
+        match_options, match_data, match_context);
+
+#ifdef STANDALONE
+      if (errorcode >= 0) printf("Match returned %d\n", errorcode); else
+        {
+        unsigned char buffer[256];
+        pcre2_get_error_message(errorcode, buffer, 256);
+        printf("Match failed: error %d: %s\n", errorcode, buffer);
+        }
+#endif
+
+      match_options = 0;  /* For second time */
+      }
+
+    /* Match with DFA twice, with and without options. */
+
+    match_options = save_match_options & ~PCRE2_NO_JIT;  /* Not valid for DFA */
+
+    for (j = 0; j < 2; j++)
+      {
+#ifdef STANDALONE
+      printf("DFA match options %.8x", match_options);
+      printf("%s%s%s%s%s%s%s%s%s\n",
+        ((match_options & PCRE2_ANCHORED) != 0)? ",anchored" : "",
+        ((match_options & PCRE2_ENDANCHORED) != 0)? ",endanchored" : "",
+        ((match_options & PCRE2_NO_UTF_CHECK) != 0)? ",no_utf_check" : "",
+        ((match_options & PCRE2_NOTBOL) != 0)? ",notbol" : "",
+        ((match_options & PCRE2_NOTEMPTY) != 0)? ",notempty" : "",
+        ((match_options & PCRE2_NOTEMPTY_ATSTART) != 0)? ",notempty_atstart" : "",
+        ((match_options & PCRE2_NOTEOL) != 0)? ",noteol" : "",
+        ((match_options & PCRE2_PARTIAL_HARD) != 0)? ",partial_hard" : "",
+        ((match_options & PCRE2_PARTIAL_SOFT) != 0)? ",partial_soft" : "");
+#endif
+
+      callout_count = 0;
+      errorcode = pcre2_dfa_match(code, (PCRE2_SPTR)data,
+        (PCRE2_SIZE)match_size, 0, match_options, match_data, match_context,
+        dfa_workspace, DFA_WORKSPACE_COUNT);
+
+#ifdef STANDALONE
+      if (errorcode >= 0) printf("Match returned %d\n", errorcode); else
+        {
+        unsigned char buffer[256];
+        pcre2_get_error_message(errorcode, buffer, 256);
+        printf("Match failed: error %d: %s\n", errorcode, buffer);
+        }
+#endif
+
+      match_options = 0;  /* For second time */
+      }
+
+    match_options = save_match_options;  /* Reset for the second compile */
+    pcre2_code_free(code);
+    }
+
+  /* Compilation failed */
+
+  else
+    {
+    unsigned char buffer[256];
+    pcre2_get_error_message(errorcode, buffer, 256);
+#ifdef STANDALONE
+    printf("Error %d at offset %lu: %s\n", errorcode, erroroffset, buffer);
+#else
+    if (strstr((const char *)buffer, "internal error") != NULL) abort();
+#endif
+    }
+
+  compile_options = PCRE2_NEVER_BACKSLASH_C;  /* For second time */
+  }
+
+if (match_data != NULL) pcre2_match_data_free(match_data);
+if (match_context != NULL) pcre2_match_context_free(match_context);
+
+return 0;
+}
+
+
+/* Optional main program.  */
+
+#ifdef STANDALONE
+int main(int argc, char **argv)
+{
+int i;
+
+if (argc < 2)
+  {
+  printf("** No arguments given\n");
+  return 0;
+  }
+
+for (i = 1; i < argc; i++)
+  {
+  size_t filelen;
+  size_t readsize;
+  unsigned char *buffer;
+  FILE *f;
+
+  /* Handle a literal string. Copy to an exact size buffer so that checks for
+  overrunning work. */
+
+  if (argv[i][0] == '=')
+    {
+    readsize = strlen(argv[i]) - 1;
+    printf("------ <Literal> ------\n");
+    printf("Length = %lu\n", readsize);
+    printf("%.*s\n", (int)readsize, argv[i]+1);
+    buffer = (unsigned char *)malloc(readsize);
+    if (buffer == NULL)
+      printf("** Failed to allocate %lu bytes of memory\n", readsize);
+    else
+      {
+      memcpy(buffer, argv[i]+1, readsize);
+      LLVMFuzzerTestOneInput(buffer, readsize);
+      free(buffer);
+      }
+    continue;
+    }
+
+  /* Handle a string given in a file */
+
+  f = fopen(argv[i], "rb");
+  if (f == NULL)
+    {
+    printf("** Failed to open %s: %s\n", argv[i], strerror(errno));
+    continue;
+    }
+
+  printf("------ %s ------\n", argv[i]);
+
+  fseek(f, 0, SEEK_END);
+  filelen = ftell(f);
+  fseek(f, 0, SEEK_SET);
+
+  buffer = (unsigned char *)malloc(filelen);
+  if (buffer == NULL)
+    {
+    printf("** Failed to allocate %lu bytes of memory\n", filelen);
+    fclose(f);
+    continue;
+    }
+
+  readsize = fread(buffer, 1, filelen, f);
+  fclose(f);
+
+  if (readsize != filelen)
+    printf("** File size is %lu but fread() returned %lu\n", filelen, readsize);
+  else
+    {
+    printf("Length = %lu\n", filelen);
+    LLVMFuzzerTestOneInput(buffer, filelen);
+    }
+  free(buffer);
+  }
+
+return 0;
+}
+#endif  /* STANDALONE */
+
+/* End */
diff --git a/src/c/pcre2/src/pcre2_internal.h b/src/c/pcre2/src/pcre2_internal.h
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_internal.h
@@ -0,0 +1,2004 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE2 is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2020 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifndef PCRE2_INTERNAL_H_IDEMPOTENT_GUARD
+#define PCRE2_INTERNAL_H_IDEMPOTENT_GUARD
+
+/* We do not support both EBCDIC and Unicode at the same time. The "configure"
+script prevents both being selected, but not everybody uses "configure". EBCDIC
+is only supported for the 8-bit library, but the check for this has to be later
+in this file, because the first part is not width-dependent, and is included by
+pcre2test.c with CODE_UNIT_WIDTH == 0. */
+
+#if defined EBCDIC && defined SUPPORT_UNICODE
+#error The use of both EBCDIC and SUPPORT_UNICODE is not supported.
+#endif
+
+/* Standard C headers */
+
+#include <ctype.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Macros to make boolean values more obvious. The #ifndef is to pacify
+compiler warnings in environments where these macros are defined elsewhere.
+Unfortunately, there is no way to do the same for the typedef. */
+
+typedef int BOOL;
+#ifndef FALSE
+#define FALSE   0
+#define TRUE    1
+#endif
+
+/* Valgrind (memcheck) support */
+
+#ifdef SUPPORT_VALGRIND
+#include <valgrind/memcheck.h>
+#endif
+
+/* -ftrivial-auto-var-init support supports initializing all local variables
+to avoid some classes of bug, but this can cause an unacceptable slowdown
+for large on-stack arrays in hot functions. This macro lets us annotate
+such arrays. */
+
+#ifdef HAVE_ATTRIBUTE_UNINITIALIZED
+#define PCRE2_KEEP_UNINITIALIZED __attribute__((uninitialized))
+#else
+#define PCRE2_KEEP_UNINITIALIZED
+#endif
+
+/* Older versions of MSVC lack snprintf(). This define allows for
+warning/error-free compilation and testing with MSVC compilers back to at least
+MSVC 10/2010. Except for VC6 (which is missing some fundamentals and fails). */
+
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+#define snprintf _snprintf
+#endif
+
+/* When compiling a DLL for Windows, the exported symbols have to be declared
+using some MS magic. I found some useful information on this web page:
+http://msdn2.microsoft.com/en-us/library/y4h7bcy6(VS.80).aspx. According to the
+information there, using __declspec(dllexport) without "extern" we have a
+definition; with "extern" we have a declaration. The settings here override the
+setting in pcre2.h (which is included below); it defines only PCRE2_EXP_DECL,
+which is all that is needed for applications (they just import the symbols). We
+use:
+
+  PCRE2_EXP_DECL    for declarations
+  PCRE2_EXP_DEFN    for definitions
+
+The reason for wrapping this in #ifndef PCRE2_EXP_DECL is so that pcre2test,
+which is an application, but needs to import this file in order to "peek" at
+internals, can #include pcre2.h first to get an application's-eye view.
+
+In principle, people compiling for non-Windows, non-Unix-like (i.e. uncommon,
+special-purpose environments) might want to stick other stuff in front of
+exported symbols. That's why, in the non-Windows case, we set PCRE2_EXP_DEFN
+only if it is not already set. */
+
+#ifndef PCRE2_EXP_DECL
+#  ifdef _WIN32
+#    ifndef PCRE2_STATIC
+#      define PCRE2_EXP_DECL       extern __declspec(dllexport)
+#      define PCRE2_EXP_DEFN       __declspec(dllexport)
+#    else
+#      define PCRE2_EXP_DECL       extern
+#      define PCRE2_EXP_DEFN
+#    endif
+#  else
+#    ifdef __cplusplus
+#      define PCRE2_EXP_DECL       extern "C"
+#    else
+#      define PCRE2_EXP_DECL       extern
+#    endif
+#    ifndef PCRE2_EXP_DEFN
+#      define PCRE2_EXP_DEFN       PCRE2_EXP_DECL
+#    endif
+#  endif
+#endif
+
+/* Include the public PCRE2 header and the definitions of UCP character
+property values. This must follow the setting of PCRE2_EXP_DECL above. */
+
+#include "pcre2.h"
+#include "pcre2_ucp.h"
+
+/* When PCRE2 is compiled as a C++ library, the subject pointer can be replaced
+with a custom type. This makes it possible, for example, to allow pcre2_match()
+to process subject strings that are discontinuous by using a smart pointer
+class. It must always be possible to inspect all of the subject string in
+pcre2_match() because of the way it backtracks. */
+
+/* WARNING: This is as yet untested for PCRE2. */
+
+#ifdef CUSTOM_SUBJECT_PTR
+#undef PCRE2_SPTR
+#define PCRE2_SPTR CUSTOM_SUBJECT_PTR
+#endif
+
+/* When checking for integer overflow in pcre2_compile(), we need to handle
+large integers. If a 64-bit integer type is available, we can use that.
+Otherwise we have to cast to double, which of course requires floating point
+arithmetic. Handle this by defining a macro for the appropriate type. */
+
+#if defined INT64_MAX || defined int64_t
+#define INT64_OR_DOUBLE int64_t
+#else
+#define INT64_OR_DOUBLE double
+#endif
+
+/* External (in the C sense) functions and tables that are private to the
+libraries are always referenced using the PRIV macro. This makes it possible
+for pcre2test.c to include some of the source files from the libraries using a
+different PRIV definition to avoid name clashes. It also makes it clear in the
+code that a non-static object is being referenced. */
+
+#ifndef PRIV
+#define PRIV(name) _pcre2_##name
+#endif
+
+/* When compiling for use with the Virtual Pascal compiler, these functions
+need to have their names changed. PCRE2 must be compiled with the -DVPCOMPAT
+option on the command line. */
+
+#ifdef VPCOMPAT
+#define strlen(s)        _strlen(s)
+#define strncmp(s1,s2,m) _strncmp(s1,s2,m)
+#define memcmp(s,c,n)    _memcmp(s,c,n)
+#define memcpy(d,s,n)    _memcpy(d,s,n)
+#define memmove(d,s,n)   _memmove(d,s,n)
+#define memset(s,c,n)    _memset(s,c,n)
+#else  /* VPCOMPAT */
+
+/* Otherwise, to cope with SunOS4 and other systems that lack memmove(), define
+a macro that calls an emulating function. */
+
+#ifndef HAVE_MEMMOVE
+#undef  memmove          /* Some systems may have a macro */
+#define memmove(a, b, c) PRIV(memmove)(a, b, c)
+#endif   /* not HAVE_MEMMOVE */
+#endif   /* not VPCOMPAT */
+
+/* This is an unsigned int value that no UTF character can ever have, as
+Unicode doesn't go beyond 0x0010ffff. */
+
+#define NOTACHAR 0xffffffff
+
+/* This is the largest valid UTF/Unicode code point. */
+
+#define MAX_UTF_CODE_POINT 0x10ffff
+
+/* Compile-time positive error numbers (all except UTF errors, which are
+negative) start at this value. It should probably never be changed, in case
+some application is checking for specific numbers. There is a copy of this
+#define in pcre2posix.c (which now no longer includes this file). Ideally, a
+way of having a single definition should be found, but as the number is
+unlikely to change, this is not a pressing issue. The original reason for
+having a base other than 0 was to keep the absolute values of compile-time and
+run-time error numbers numerically different, but in the event the code does
+not rely on this. */
+
+#define COMPILE_ERROR_BASE 100
+
+/* The initial frames vector for remembering backtracking points in
+pcre2_match() is allocated on the system stack, of this size (bytes). The size
+must be a multiple of sizeof(PCRE2_SPTR) in all environments, so making it a
+multiple of 8 is best. Typical frame sizes are a few hundred bytes (it depends
+on the number of capturing parentheses) so 20KiB handles quite a few frames. A
+larger vector on the heap is obtained for patterns that need more frames. The
+maximum size of this can be limited. */
+
+#define START_FRAMES_SIZE 20480
+
+/* Similarly, for DFA matching, an initial internal workspace vector is
+allocated on the stack. */
+
+#define DFA_START_RWS_SIZE 30720
+
+/* Define the default BSR convention. */
+
+#ifdef BSR_ANYCRLF
+#define BSR_DEFAULT PCRE2_BSR_ANYCRLF
+#else
+#define BSR_DEFAULT PCRE2_BSR_UNICODE
+#endif
+
+
+/* ---------------- Basic UTF-8 macros ---------------- */
+
+/* These UTF-8 macros are always defined because they are used in pcre2test for
+handling wide characters in 16-bit and 32-bit modes, even if an 8-bit library
+is not supported. */
+
+/* Tests whether a UTF-8 code point needs extra bytes to decode. */
+
+#define HASUTF8EXTRALEN(c) ((c) >= 0xc0)
+
+/* The following macros were originally written in the form of loops that used
+data from the tables whose names start with PRIV(utf8_table). They were
+rewritten by a user so as not to use loops, because in some environments this
+gives a significant performance advantage, and it seems never to do any harm.
+*/
+
+/* Base macro to pick up the remaining bytes of a UTF-8 character, not
+advancing the pointer. */
+
+#define GETUTF8(c, eptr) \
+    { \
+    if ((c & 0x20u) == 0) \
+      c = ((c & 0x1fu) << 6) | (eptr[1] & 0x3fu); \
+    else if ((c & 0x10u) == 0) \
+      c = ((c & 0x0fu) << 12) | ((eptr[1] & 0x3fu) << 6) | (eptr[2] & 0x3fu); \
+    else if ((c & 0x08u) == 0) \
+      c = ((c & 0x07u) << 18) | ((eptr[1] & 0x3fu) << 12) | \
+      ((eptr[2] & 0x3fu) << 6) | (eptr[3] & 0x3fu); \
+    else if ((c & 0x04u) == 0) \
+      c = ((c & 0x03u) << 24) | ((eptr[1] & 0x3fu) << 18) | \
+          ((eptr[2] & 0x3fu) << 12) | ((eptr[3] & 0x3fu) << 6) | \
+          (eptr[4] & 0x3fu); \
+    else \
+      c = ((c & 0x01u) << 30) | ((eptr[1] & 0x3fu) << 24) | \
+          ((eptr[2] & 0x3fu) << 18) | ((eptr[3] & 0x3fu) << 12) | \
+          ((eptr[4] & 0x3fu) << 6) | (eptr[5] & 0x3fu); \
+    }
+
+/* Base macro to pick up the remaining bytes of a UTF-8 character, advancing
+the pointer. */
+
+#define GETUTF8INC(c, eptr) \
+    { \
+    if ((c & 0x20u) == 0) \
+      c = ((c & 0x1fu) << 6) | (*eptr++ & 0x3fu); \
+    else if ((c & 0x10u) == 0) \
+      { \
+      c = ((c & 0x0fu) << 12) | ((*eptr & 0x3fu) << 6) | (eptr[1] & 0x3fu); \
+      eptr += 2; \
+      } \
+    else if ((c & 0x08u) == 0) \
+      { \
+      c = ((c & 0x07u) << 18) | ((*eptr & 0x3fu) << 12) | \
+          ((eptr[1] & 0x3fu) << 6) | (eptr[2] & 0x3fu); \
+      eptr += 3; \
+      } \
+    else if ((c & 0x04u) == 0) \
+      { \
+      c = ((c & 0x03u) << 24) | ((*eptr & 0x3fu) << 18) | \
+          ((eptr[1] & 0x3fu) << 12) | ((eptr[2] & 0x3fu) << 6) | \
+          (eptr[3] & 0x3fu); \
+      eptr += 4; \
+      } \
+    else \
+      { \
+      c = ((c & 0x01u) << 30) | ((*eptr & 0x3fu) << 24) | \
+          ((eptr[1] & 0x3fu) << 18) | ((eptr[2] & 0x3fu) << 12) | \
+          ((eptr[3] & 0x3fu) << 6) | (eptr[4] & 0x3fu); \
+      eptr += 5; \
+      } \
+    }
+
+/* Base macro to pick up the remaining bytes of a UTF-8 character, not
+advancing the pointer, incrementing the length. */
+
+#define GETUTF8LEN(c, eptr, len) \
+    { \
+    if ((c & 0x20u) == 0) \
+      { \
+      c = ((c & 0x1fu) << 6) | (eptr[1] & 0x3fu); \
+      len++; \
+      } \
+    else if ((c & 0x10u)  == 0) \
+      { \
+      c = ((c & 0x0fu) << 12) | ((eptr[1] & 0x3fu) << 6) | (eptr[2] & 0x3fu); \
+      len += 2; \
+      } \
+    else if ((c & 0x08u)  == 0) \
+      {\
+      c = ((c & 0x07u) << 18) | ((eptr[1] & 0x3fu) << 12) | \
+          ((eptr[2] & 0x3fu) << 6) | (eptr[3] & 0x3fu); \
+      len += 3; \
+      } \
+    else if ((c & 0x04u)  == 0) \
+      { \
+      c = ((c & 0x03u) << 24) | ((eptr[1] & 0x3fu) << 18) | \
+          ((eptr[2] & 0x3fu) << 12) | ((eptr[3] & 0x3fu) << 6) | \
+          (eptr[4] & 0x3fu); \
+      len += 4; \
+      } \
+    else \
+      {\
+      c = ((c & 0x01u) << 30) | ((eptr[1] & 0x3fu) << 24) | \
+          ((eptr[2] & 0x3fu) << 18) | ((eptr[3] & 0x3fu) << 12) | \
+          ((eptr[4] & 0x3fu) << 6) | (eptr[5] & 0x3fu); \
+      len += 5; \
+      } \
+    }
+
+/* --------------- Whitespace macros ---------------- */
+
+/* Tests for Unicode horizontal and vertical whitespace characters must check a
+number of different values. Using a switch statement for this generates the
+fastest code (no loop, no memory access), and there are several places in the
+interpreter code where this happens. In order to ensure that all the case lists
+remain in step, we use macros so that there is only one place where the lists
+are defined.
+
+These values are also required as lists in pcre2_compile.c when processing \h,
+\H, \v and \V in a character class. The lists are defined in pcre2_tables.c,
+but macros that define the values are here so that all the definitions are
+together. The lists must be in ascending character order, terminated by
+NOTACHAR (which is 0xffffffff).
+
+Any changes should ensure that the various macros are kept in step with each
+other. NOTE: The values also appear in pcre2_jit_compile.c. */
+
+/* -------------- ASCII/Unicode environments -------------- */
+
+#ifndef EBCDIC
+
+/* Character U+180E (Mongolian Vowel Separator) is not included in the list of
+spaces in the Unicode file PropList.txt, and Perl does not recognize it as a
+space. However, in many other sources it is listed as a space and has been in
+PCRE (both APIs) for a long time. */
+
+#define HSPACE_LIST \
+  CHAR_HT, CHAR_SPACE, CHAR_NBSP, \
+  0x1680, 0x180e, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, \
+  0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202f, 0x205f, 0x3000, \
+  NOTACHAR
+
+#define HSPACE_MULTIBYTE_CASES \
+  case 0x1680:  /* OGHAM SPACE MARK */ \
+  case 0x180e:  /* MONGOLIAN VOWEL SEPARATOR */ \
+  case 0x2000:  /* EN QUAD */ \
+  case 0x2001:  /* EM QUAD */ \
+  case 0x2002:  /* EN SPACE */ \
+  case 0x2003:  /* EM SPACE */ \
+  case 0x2004:  /* THREE-PER-EM SPACE */ \
+  case 0x2005:  /* FOUR-PER-EM SPACE */ \
+  case 0x2006:  /* SIX-PER-EM SPACE */ \
+  case 0x2007:  /* FIGURE SPACE */ \
+  case 0x2008:  /* PUNCTUATION SPACE */ \
+  case 0x2009:  /* THIN SPACE */ \
+  case 0x200A:  /* HAIR SPACE */ \
+  case 0x202f:  /* NARROW NO-BREAK SPACE */ \
+  case 0x205f:  /* MEDIUM MATHEMATICAL SPACE */ \
+  case 0x3000   /* IDEOGRAPHIC SPACE */
+
+#define HSPACE_BYTE_CASES \
+  case CHAR_HT: \
+  case CHAR_SPACE: \
+  case CHAR_NBSP
+
+#define HSPACE_CASES \
+  HSPACE_BYTE_CASES: \
+  HSPACE_MULTIBYTE_CASES
+
+#define VSPACE_LIST \
+  CHAR_LF, CHAR_VT, CHAR_FF, CHAR_CR, CHAR_NEL, 0x2028, 0x2029, NOTACHAR
+
+#define VSPACE_MULTIBYTE_CASES \
+  case 0x2028:    /* LINE SEPARATOR */ \
+  case 0x2029     /* PARAGRAPH SEPARATOR */
+
+#define VSPACE_BYTE_CASES \
+  case CHAR_LF: \
+  case CHAR_VT: \
+  case CHAR_FF: \
+  case CHAR_CR: \
+  case CHAR_NEL
+
+#define VSPACE_CASES \
+  VSPACE_BYTE_CASES: \
+  VSPACE_MULTIBYTE_CASES
+
+/* -------------- EBCDIC environments -------------- */
+
+#else
+#define HSPACE_LIST CHAR_HT, CHAR_SPACE, CHAR_NBSP, NOTACHAR
+
+#define HSPACE_BYTE_CASES \
+  case CHAR_HT: \
+  case CHAR_SPACE: \
+  case CHAR_NBSP
+
+#define HSPACE_CASES HSPACE_BYTE_CASES
+
+#ifdef EBCDIC_NL25
+#define VSPACE_LIST \
+  CHAR_VT, CHAR_FF, CHAR_CR, CHAR_NEL, CHAR_LF, NOTACHAR
+#else
+#define VSPACE_LIST \
+  CHAR_VT, CHAR_FF, CHAR_CR, CHAR_LF, CHAR_NEL, NOTACHAR
+#endif
+
+#define VSPACE_BYTE_CASES \
+  case CHAR_LF: \
+  case CHAR_VT: \
+  case CHAR_FF: \
+  case CHAR_CR: \
+  case CHAR_NEL
+
+#define VSPACE_CASES VSPACE_BYTE_CASES
+#endif  /* EBCDIC */
+
+/* -------------- End of whitespace macros -------------- */
+
+
+/* PCRE2 is able to support several different kinds of newline (CR, LF, CRLF,
+"any" and "anycrlf" at present). The following macros are used to package up
+testing for newlines. NLBLOCK, PSSTART, and PSEND are defined in the various
+modules to indicate in which datablock the parameters exist, and what the
+start/end of string field names are. */
+
+#define NLTYPE_FIXED    0     /* Newline is a fixed length string */
+#define NLTYPE_ANY      1     /* Newline is any Unicode line ending */
+#define NLTYPE_ANYCRLF  2     /* Newline is CR, LF, or CRLF */
+
+/* This macro checks for a newline at the given position */
+
+#define IS_NEWLINE(p) \
+  ((NLBLOCK->nltype != NLTYPE_FIXED)? \
+    ((p) < NLBLOCK->PSEND && \
+     PRIV(is_newline)((p), NLBLOCK->nltype, NLBLOCK->PSEND, \
+       &(NLBLOCK->nllen), utf)) \
+    : \
+    ((p) <= NLBLOCK->PSEND - NLBLOCK->nllen && \
+     UCHAR21TEST(p) == NLBLOCK->nl[0] && \
+     (NLBLOCK->nllen == 1 || UCHAR21TEST(p+1) == NLBLOCK->nl[1])       \
+    ) \
+  )
+
+/* This macro checks for a newline immediately preceding the given position */
+
+#define WAS_NEWLINE(p) \
+  ((NLBLOCK->nltype != NLTYPE_FIXED)? \
+    ((p) > NLBLOCK->PSSTART && \
+     PRIV(was_newline)((p), NLBLOCK->nltype, NLBLOCK->PSSTART, \
+       &(NLBLOCK->nllen), utf)) \
+    : \
+    ((p) >= NLBLOCK->PSSTART + NLBLOCK->nllen && \
+     UCHAR21TEST(p - NLBLOCK->nllen) == NLBLOCK->nl[0] &&              \
+     (NLBLOCK->nllen == 1 || UCHAR21TEST(p - NLBLOCK->nllen + 1) == NLBLOCK->nl[1]) \
+    ) \
+  )
+
+/* Private flags containing information about the compiled pattern. The first
+three must not be changed, because whichever is set is actually the number of
+bytes in a code unit in that mode. */
+
+#define PCRE2_MODE8         0x00000001  /* compiled in 8 bit mode */
+#define PCRE2_MODE16        0x00000002  /* compiled in 16 bit mode */
+#define PCRE2_MODE32        0x00000004  /* compiled in 32 bit mode */
+#define PCRE2_FIRSTSET      0x00000010  /* first_code unit is set */
+#define PCRE2_FIRSTCASELESS 0x00000020  /* caseless first code unit */
+#define PCRE2_FIRSTMAPSET   0x00000040  /* bitmap of first code units is set */
+#define PCRE2_LASTSET       0x00000080  /* last code unit is set */
+#define PCRE2_LASTCASELESS  0x00000100  /* caseless last code unit */
+#define PCRE2_STARTLINE     0x00000200  /* start after \n for multiline */
+#define PCRE2_JCHANGED      0x00000400  /* j option used in pattern */
+#define PCRE2_HASCRORLF     0x00000800  /* explicit \r or \n in pattern */
+#define PCRE2_HASTHEN       0x00001000  /* pattern contains (*THEN) */
+#define PCRE2_MATCH_EMPTY   0x00002000  /* pattern can match empty string */
+#define PCRE2_BSR_SET       0x00004000  /* BSR was set in the pattern */
+#define PCRE2_NL_SET        0x00008000  /* newline was set in the pattern */
+#define PCRE2_NOTEMPTY_SET  0x00010000  /* (*NOTEMPTY) used        ) keep */
+#define PCRE2_NE_ATST_SET   0x00020000  /* (*NOTEMPTY_ATSTART) used) together */
+#define PCRE2_DEREF_TABLES  0x00040000  /* release character tables */
+#define PCRE2_NOJIT         0x00080000  /* (*NOJIT) used */
+#define PCRE2_HASBKPORX     0x00100000  /* contains \P, \p, or \X */
+#define PCRE2_DUPCAPUSED    0x00200000  /* contains (?| */
+#define PCRE2_HASBKC        0x00400000  /* contains \C */
+#define PCRE2_HASACCEPT     0x00800000  /* contains (*ACCEPT) */
+
+#define PCRE2_MODE_MASK     (PCRE2_MODE8 | PCRE2_MODE16 | PCRE2_MODE32)
+
+/* Values for the matchedby field in a match data block. */
+
+enum { PCRE2_MATCHEDBY_INTERPRETER,     /* pcre2_match() */
+       PCRE2_MATCHEDBY_DFA_INTERPRETER, /* pcre2_dfa_match() */
+       PCRE2_MATCHEDBY_JIT };           /* pcre2_jit_match() */
+
+/* Values for the flags field in a match data block. */
+
+#define PCRE2_MD_COPIED_SUBJECT  0x01u
+
+/* Magic number to provide a small check against being handed junk. */
+
+#define MAGIC_NUMBER  0x50435245UL   /* 'PCRE' */
+
+/* The maximum remaining length of subject we are prepared to search for a
+req_unit match from an anchored pattern. In 8-bit mode, memchr() is used and is
+much faster than the search loop that has to be used in 16-bit and 32-bit
+modes. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define REQ_CU_MAX       5000
+#else
+#define REQ_CU_MAX       2000
+#endif
+
+/* Offsets for the bitmap tables in the cbits set of tables. Each table
+contains a set of bits for a class map. Some classes are built by combining
+these tables. */
+
+#define cbit_space     0      /* [:space:] or \s */
+#define cbit_xdigit   32      /* [:xdigit:] */
+#define cbit_digit    64      /* [:digit:] or \d */
+#define cbit_upper    96      /* [:upper:] */
+#define cbit_lower   128      /* [:lower:] */
+#define cbit_word    160      /* [:word:] or \w */
+#define cbit_graph   192      /* [:graph:] */
+#define cbit_print   224      /* [:print:] */
+#define cbit_punct   256      /* [:punct:] */
+#define cbit_cntrl   288      /* [:cntrl:] */
+#define cbit_length  320      /* Length of the cbits table */
+
+/* Bit definitions for entries in the ctypes table. Do not change these values
+without checking pcre2_jit_compile.c, which has an assertion to ensure that
+ctype_word has the value 16. */
+
+#define ctype_space    0x01
+#define ctype_letter   0x02
+#define ctype_lcletter 0x04
+#define ctype_digit    0x08
+#define ctype_word     0x10    /* alphanumeric or '_' */
+
+/* Offsets of the various tables from the base tables pointer, and
+total length of the tables. */
+
+#define lcc_offset      0                           /* Lower case */
+#define fcc_offset    256                           /* Flip case */
+#define cbits_offset  512                           /* Character classes */
+#define ctypes_offset (cbits_offset + cbit_length)  /* Character types */
+#define TABLES_LENGTH (ctypes_offset + 256)
+
+
+/* -------------------- Character and string names ------------------------ */
+
+/* If PCRE2 is to support UTF-8 on EBCDIC platforms, we cannot use normal
+character constants like '*' because the compiler would emit their EBCDIC code,
+which is different from their ASCII/UTF-8 code. Instead we define macros for
+the characters so that they always use the ASCII/UTF-8 code when UTF-8 support
+is enabled. When UTF-8 support is not enabled, the definitions use character
+literals. Both character and string versions of each character are needed, and
+there are some longer strings as well.
+
+This means that, on EBCDIC platforms, the PCRE2 library can handle either
+EBCDIC, or UTF-8, but not both. To support both in the same compiled library
+would need different lookups depending on whether PCRE2_UTF was set or not.
+This would make it impossible to use characters in switch/case statements,
+which would reduce performance. For a theoretical use (which nobody has asked
+for) in a minority area (EBCDIC platforms), this is not sensible. Any
+application that did need both could compile two versions of the library, using
+macros to give the functions distinct names. */
+
+#ifndef SUPPORT_UNICODE
+
+/* UTF-8 support is not enabled; use the platform-dependent character literals
+so that PCRE2 works in both ASCII and EBCDIC environments, but only in non-UTF
+mode. Newline characters are problematic in EBCDIC. Though it has CR and LF
+characters, a common practice has been to use its NL (0x15) character as the
+line terminator in C-like processing environments. However, sometimes the LF
+(0x25) character is used instead, according to this Unicode document:
+
+http://unicode.org/standard/reports/tr13/tr13-5.html
+
+PCRE2 defaults EBCDIC NL to 0x15, but has a build-time option to select 0x25
+instead. Whichever is *not* chosen is defined as NEL.
+
+In both ASCII and EBCDIC environments, CHAR_NL and CHAR_LF are synonyms for the
+same code point. */
+
+#ifdef EBCDIC
+
+#ifndef EBCDIC_NL25
+#define CHAR_NL                     '\x15'
+#define CHAR_NEL                    '\x25'
+#define STR_NL                      "\x15"
+#define STR_NEL                     "\x25"
+#else
+#define CHAR_NL                     '\x25'
+#define CHAR_NEL                    '\x15'
+#define STR_NL                      "\x25"
+#define STR_NEL                     "\x15"
+#endif
+
+#define CHAR_LF                     CHAR_NL
+#define STR_LF                      STR_NL
+
+#define CHAR_ESC                    '\047'
+#define CHAR_DEL                    '\007'
+#define CHAR_NBSP                   ((unsigned char)'\x41')
+#define STR_ESC                     "\047"
+#define STR_DEL                     "\007"
+
+#else  /* Not EBCDIC */
+
+/* In ASCII/Unicode, linefeed is '\n' and we equate this to NL for
+compatibility. NEL is the Unicode newline character; make sure it is
+a positive value. */
+
+#define CHAR_LF                     '\n'
+#define CHAR_NL                     CHAR_LF
+#define CHAR_NEL                    ((unsigned char)'\x85')
+#define CHAR_ESC                    '\033'
+#define CHAR_DEL                    '\177'
+#define CHAR_NBSP                   ((unsigned char)'\xa0')
+
+#define STR_LF                      "\n"
+#define STR_NL                      STR_LF
+#define STR_NEL                     "\x85"
+#define STR_ESC                     "\033"
+#define STR_DEL                     "\177"
+
+#endif  /* EBCDIC */
+
+/* The remaining definitions work in both environments. */
+
+#define CHAR_NUL                    '\0'
+#define CHAR_HT                     '\t'
+#define CHAR_VT                     '\v'
+#define CHAR_FF                     '\f'
+#define CHAR_CR                     '\r'
+#define CHAR_BS                     '\b'
+#define CHAR_BEL                    '\a'
+
+#define CHAR_SPACE                  ' '
+#define CHAR_EXCLAMATION_MARK       '!'
+#define CHAR_QUOTATION_MARK         '"'
+#define CHAR_NUMBER_SIGN            '#'
+#define CHAR_DOLLAR_SIGN            '$'
+#define CHAR_PERCENT_SIGN           '%'
+#define CHAR_AMPERSAND              '&'
+#define CHAR_APOSTROPHE             '\''
+#define CHAR_LEFT_PARENTHESIS       '('
+#define CHAR_RIGHT_PARENTHESIS      ')'
+#define CHAR_ASTERISK               '*'
+#define CHAR_PLUS                   '+'
+#define CHAR_COMMA                  ','
+#define CHAR_MINUS                  '-'
+#define CHAR_DOT                    '.'
+#define CHAR_SLASH                  '/'
+#define CHAR_0                      '0'
+#define CHAR_1                      '1'
+#define CHAR_2                      '2'
+#define CHAR_3                      '3'
+#define CHAR_4                      '4'
+#define CHAR_5                      '5'
+#define CHAR_6                      '6'
+#define CHAR_7                      '7'
+#define CHAR_8                      '8'
+#define CHAR_9                      '9'
+#define CHAR_COLON                  ':'
+#define CHAR_SEMICOLON              ';'
+#define CHAR_LESS_THAN_SIGN         '<'
+#define CHAR_EQUALS_SIGN            '='
+#define CHAR_GREATER_THAN_SIGN      '>'
+#define CHAR_QUESTION_MARK          '?'
+#define CHAR_COMMERCIAL_AT          '@'
+#define CHAR_A                      'A'
+#define CHAR_B                      'B'
+#define CHAR_C                      'C'
+#define CHAR_D                      'D'
+#define CHAR_E                      'E'
+#define CHAR_F                      'F'
+#define CHAR_G                      'G'
+#define CHAR_H                      'H'
+#define CHAR_I                      'I'
+#define CHAR_J                      'J'
+#define CHAR_K                      'K'
+#define CHAR_L                      'L'
+#define CHAR_M                      'M'
+#define CHAR_N                      'N'
+#define CHAR_O                      'O'
+#define CHAR_P                      'P'
+#define CHAR_Q                      'Q'
+#define CHAR_R                      'R'
+#define CHAR_S                      'S'
+#define CHAR_T                      'T'
+#define CHAR_U                      'U'
+#define CHAR_V                      'V'
+#define CHAR_W                      'W'
+#define CHAR_X                      'X'
+#define CHAR_Y                      'Y'
+#define CHAR_Z                      'Z'
+#define CHAR_LEFT_SQUARE_BRACKET    '['
+#define CHAR_BACKSLASH              '\\'
+#define CHAR_RIGHT_SQUARE_BRACKET   ']'
+#define CHAR_CIRCUMFLEX_ACCENT      '^'
+#define CHAR_UNDERSCORE             '_'
+#define CHAR_GRAVE_ACCENT           '`'
+#define CHAR_a                      'a'
+#define CHAR_b                      'b'
+#define CHAR_c                      'c'
+#define CHAR_d                      'd'
+#define CHAR_e                      'e'
+#define CHAR_f                      'f'
+#define CHAR_g                      'g'
+#define CHAR_h                      'h'
+#define CHAR_i                      'i'
+#define CHAR_j                      'j'
+#define CHAR_k                      'k'
+#define CHAR_l                      'l'
+#define CHAR_m                      'm'
+#define CHAR_n                      'n'
+#define CHAR_o                      'o'
+#define CHAR_p                      'p'
+#define CHAR_q                      'q'
+#define CHAR_r                      'r'
+#define CHAR_s                      's'
+#define CHAR_t                      't'
+#define CHAR_u                      'u'
+#define CHAR_v                      'v'
+#define CHAR_w                      'w'
+#define CHAR_x                      'x'
+#define CHAR_y                      'y'
+#define CHAR_z                      'z'
+#define CHAR_LEFT_CURLY_BRACKET     '{'
+#define CHAR_VERTICAL_LINE          '|'
+#define CHAR_RIGHT_CURLY_BRACKET    '}'
+#define CHAR_TILDE                  '~'
+
+#define STR_HT                      "\t"
+#define STR_VT                      "\v"
+#define STR_FF                      "\f"
+#define STR_CR                      "\r"
+#define STR_BS                      "\b"
+#define STR_BEL                     "\a"
+
+#define STR_SPACE                   " "
+#define STR_EXCLAMATION_MARK        "!"
+#define STR_QUOTATION_MARK          "\""
+#define STR_NUMBER_SIGN             "#"
+#define STR_DOLLAR_SIGN             "$"
+#define STR_PERCENT_SIGN            "%"
+#define STR_AMPERSAND               "&"
+#define STR_APOSTROPHE              "'"
+#define STR_LEFT_PARENTHESIS        "("
+#define STR_RIGHT_PARENTHESIS       ")"
+#define STR_ASTERISK                "*"
+#define STR_PLUS                    "+"
+#define STR_COMMA                   ","
+#define STR_MINUS                   "-"
+#define STR_DOT                     "."
+#define STR_SLASH                   "/"
+#define STR_0                       "0"
+#define STR_1                       "1"
+#define STR_2                       "2"
+#define STR_3                       "3"
+#define STR_4                       "4"
+#define STR_5                       "5"
+#define STR_6                       "6"
+#define STR_7                       "7"
+#define STR_8                       "8"
+#define STR_9                       "9"
+#define STR_COLON                   ":"
+#define STR_SEMICOLON               ";"
+#define STR_LESS_THAN_SIGN          "<"
+#define STR_EQUALS_SIGN             "="
+#define STR_GREATER_THAN_SIGN       ">"
+#define STR_QUESTION_MARK           "?"
+#define STR_COMMERCIAL_AT           "@"
+#define STR_A                       "A"
+#define STR_B                       "B"
+#define STR_C                       "C"
+#define STR_D                       "D"
+#define STR_E                       "E"
+#define STR_F                       "F"
+#define STR_G                       "G"
+#define STR_H                       "H"
+#define STR_I                       "I"
+#define STR_J                       "J"
+#define STR_K                       "K"
+#define STR_L                       "L"
+#define STR_M                       "M"
+#define STR_N                       "N"
+#define STR_O                       "O"
+#define STR_P                       "P"
+#define STR_Q                       "Q"
+#define STR_R                       "R"
+#define STR_S                       "S"
+#define STR_T                       "T"
+#define STR_U                       "U"
+#define STR_V                       "V"
+#define STR_W                       "W"
+#define STR_X                       "X"
+#define STR_Y                       "Y"
+#define STR_Z                       "Z"
+#define STR_LEFT_SQUARE_BRACKET     "["
+#define STR_BACKSLASH               "\\"
+#define STR_RIGHT_SQUARE_BRACKET    "]"
+#define STR_CIRCUMFLEX_ACCENT       "^"
+#define STR_UNDERSCORE              "_"
+#define STR_GRAVE_ACCENT            "`"
+#define STR_a                       "a"
+#define STR_b                       "b"
+#define STR_c                       "c"
+#define STR_d                       "d"
+#define STR_e                       "e"
+#define STR_f                       "f"
+#define STR_g                       "g"
+#define STR_h                       "h"
+#define STR_i                       "i"
+#define STR_j                       "j"
+#define STR_k                       "k"
+#define STR_l                       "l"
+#define STR_m                       "m"
+#define STR_n                       "n"
+#define STR_o                       "o"
+#define STR_p                       "p"
+#define STR_q                       "q"
+#define STR_r                       "r"
+#define STR_s                       "s"
+#define STR_t                       "t"
+#define STR_u                       "u"
+#define STR_v                       "v"
+#define STR_w                       "w"
+#define STR_x                       "x"
+#define STR_y                       "y"
+#define STR_z                       "z"
+#define STR_LEFT_CURLY_BRACKET      "{"
+#define STR_VERTICAL_LINE           "|"
+#define STR_RIGHT_CURLY_BRACKET     "}"
+#define STR_TILDE                   "~"
+
+#define STRING_ACCEPT0               "ACCEPT\0"
+#define STRING_COMMIT0               "COMMIT\0"
+#define STRING_F0                    "F\0"
+#define STRING_FAIL0                 "FAIL\0"
+#define STRING_MARK0                 "MARK\0"
+#define STRING_PRUNE0                "PRUNE\0"
+#define STRING_SKIP0                 "SKIP\0"
+#define STRING_THEN                  "THEN"
+
+#define STRING_atomic0               "atomic\0"
+#define STRING_pla0                  "pla\0"
+#define STRING_plb0                  "plb\0"
+#define STRING_napla0                "napla\0"
+#define STRING_naplb0                "naplb\0"
+#define STRING_nla0                  "nla\0"
+#define STRING_nlb0                  "nlb\0"
+#define STRING_sr0                   "sr\0"
+#define STRING_asr0                  "asr\0"
+#define STRING_positive_lookahead0   "positive_lookahead\0"
+#define STRING_positive_lookbehind0  "positive_lookbehind\0"
+#define STRING_non_atomic_positive_lookahead0   "non_atomic_positive_lookahead\0"
+#define STRING_non_atomic_positive_lookbehind0  "non_atomic_positive_lookbehind\0"
+#define STRING_negative_lookahead0   "negative_lookahead\0"
+#define STRING_negative_lookbehind0  "negative_lookbehind\0"
+#define STRING_script_run0           "script_run\0"
+#define STRING_atomic_script_run     "atomic_script_run"
+
+#define STRING_alpha0                "alpha\0"
+#define STRING_lower0                "lower\0"
+#define STRING_upper0                "upper\0"
+#define STRING_alnum0                "alnum\0"
+#define STRING_ascii0                "ascii\0"
+#define STRING_blank0                "blank\0"
+#define STRING_cntrl0                "cntrl\0"
+#define STRING_digit0                "digit\0"
+#define STRING_graph0                "graph\0"
+#define STRING_print0                "print\0"
+#define STRING_punct0                "punct\0"
+#define STRING_space0                "space\0"
+#define STRING_word0                 "word\0"
+#define STRING_xdigit                "xdigit"
+
+#define STRING_DEFINE                "DEFINE"
+#define STRING_VERSION               "VERSION"
+#define STRING_WEIRD_STARTWORD       "[:<:]]"
+#define STRING_WEIRD_ENDWORD         "[:>:]]"
+
+#define STRING_CR_RIGHTPAR                "CR)"
+#define STRING_LF_RIGHTPAR                "LF)"
+#define STRING_CRLF_RIGHTPAR              "CRLF)"
+#define STRING_ANY_RIGHTPAR               "ANY)"
+#define STRING_ANYCRLF_RIGHTPAR           "ANYCRLF)"
+#define STRING_NUL_RIGHTPAR               "NUL)"
+#define STRING_BSR_ANYCRLF_RIGHTPAR       "BSR_ANYCRLF)"
+#define STRING_BSR_UNICODE_RIGHTPAR       "BSR_UNICODE)"
+#define STRING_UTF8_RIGHTPAR              "UTF8)"
+#define STRING_UTF16_RIGHTPAR             "UTF16)"
+#define STRING_UTF32_RIGHTPAR             "UTF32)"
+#define STRING_UTF_RIGHTPAR               "UTF)"
+#define STRING_UCP_RIGHTPAR               "UCP)"
+#define STRING_NO_AUTO_POSSESS_RIGHTPAR   "NO_AUTO_POSSESS)"
+#define STRING_NO_DOTSTAR_ANCHOR_RIGHTPAR "NO_DOTSTAR_ANCHOR)"
+#define STRING_NO_JIT_RIGHTPAR            "NO_JIT)"
+#define STRING_NO_START_OPT_RIGHTPAR      "NO_START_OPT)"
+#define STRING_NOTEMPTY_RIGHTPAR          "NOTEMPTY)"
+#define STRING_NOTEMPTY_ATSTART_RIGHTPAR  "NOTEMPTY_ATSTART)"
+#define STRING_LIMIT_HEAP_EQ              "LIMIT_HEAP="
+#define STRING_LIMIT_MATCH_EQ             "LIMIT_MATCH="
+#define STRING_LIMIT_DEPTH_EQ             "LIMIT_DEPTH="
+#define STRING_LIMIT_RECURSION_EQ         "LIMIT_RECURSION="
+#define STRING_MARK                       "MARK"
+
+#else  /* SUPPORT_UNICODE */
+
+/* UTF-8 support is enabled; always use UTF-8 (=ASCII) character codes. This
+works in both modes non-EBCDIC platforms, and on EBCDIC platforms in UTF-8 mode
+only. */
+
+#define CHAR_HT                     '\011'
+#define CHAR_VT                     '\013'
+#define CHAR_FF                     '\014'
+#define CHAR_CR                     '\015'
+#define CHAR_LF                     '\012'
+#define CHAR_NL                     CHAR_LF
+#define CHAR_NEL                    ((unsigned char)'\x85')
+#define CHAR_BS                     '\010'
+#define CHAR_BEL                    '\007'
+#define CHAR_ESC                    '\033'
+#define CHAR_DEL                    '\177'
+
+#define CHAR_NUL                    '\0'
+#define CHAR_SPACE                  '\040'
+#define CHAR_EXCLAMATION_MARK       '\041'
+#define CHAR_QUOTATION_MARK         '\042'
+#define CHAR_NUMBER_SIGN            '\043'
+#define CHAR_DOLLAR_SIGN            '\044'
+#define CHAR_PERCENT_SIGN           '\045'
+#define CHAR_AMPERSAND              '\046'
+#define CHAR_APOSTROPHE             '\047'
+#define CHAR_LEFT_PARENTHESIS       '\050'
+#define CHAR_RIGHT_PARENTHESIS      '\051'
+#define CHAR_ASTERISK               '\052'
+#define CHAR_PLUS                   '\053'
+#define CHAR_COMMA                  '\054'
+#define CHAR_MINUS                  '\055'
+#define CHAR_DOT                    '\056'
+#define CHAR_SLASH                  '\057'
+#define CHAR_0                      '\060'
+#define CHAR_1                      '\061'
+#define CHAR_2                      '\062'
+#define CHAR_3                      '\063'
+#define CHAR_4                      '\064'
+#define CHAR_5                      '\065'
+#define CHAR_6                      '\066'
+#define CHAR_7                      '\067'
+#define CHAR_8                      '\070'
+#define CHAR_9                      '\071'
+#define CHAR_COLON                  '\072'
+#define CHAR_SEMICOLON              '\073'
+#define CHAR_LESS_THAN_SIGN         '\074'
+#define CHAR_EQUALS_SIGN            '\075'
+#define CHAR_GREATER_THAN_SIGN      '\076'
+#define CHAR_QUESTION_MARK          '\077'
+#define CHAR_COMMERCIAL_AT          '\100'
+#define CHAR_A                      '\101'
+#define CHAR_B                      '\102'
+#define CHAR_C                      '\103'
+#define CHAR_D                      '\104'
+#define CHAR_E                      '\105'
+#define CHAR_F                      '\106'
+#define CHAR_G                      '\107'
+#define CHAR_H                      '\110'
+#define CHAR_I                      '\111'
+#define CHAR_J                      '\112'
+#define CHAR_K                      '\113'
+#define CHAR_L                      '\114'
+#define CHAR_M                      '\115'
+#define CHAR_N                      '\116'
+#define CHAR_O                      '\117'
+#define CHAR_P                      '\120'
+#define CHAR_Q                      '\121'
+#define CHAR_R                      '\122'
+#define CHAR_S                      '\123'
+#define CHAR_T                      '\124'
+#define CHAR_U                      '\125'
+#define CHAR_V                      '\126'
+#define CHAR_W                      '\127'
+#define CHAR_X                      '\130'
+#define CHAR_Y                      '\131'
+#define CHAR_Z                      '\132'
+#define CHAR_LEFT_SQUARE_BRACKET    '\133'
+#define CHAR_BACKSLASH              '\134'
+#define CHAR_RIGHT_SQUARE_BRACKET   '\135'
+#define CHAR_CIRCUMFLEX_ACCENT      '\136'
+#define CHAR_UNDERSCORE             '\137'
+#define CHAR_GRAVE_ACCENT           '\140'
+#define CHAR_a                      '\141'
+#define CHAR_b                      '\142'
+#define CHAR_c                      '\143'
+#define CHAR_d                      '\144'
+#define CHAR_e                      '\145'
+#define CHAR_f                      '\146'
+#define CHAR_g                      '\147'
+#define CHAR_h                      '\150'
+#define CHAR_i                      '\151'
+#define CHAR_j                      '\152'
+#define CHAR_k                      '\153'
+#define CHAR_l                      '\154'
+#define CHAR_m                      '\155'
+#define CHAR_n                      '\156'
+#define CHAR_o                      '\157'
+#define CHAR_p                      '\160'
+#define CHAR_q                      '\161'
+#define CHAR_r                      '\162'
+#define CHAR_s                      '\163'
+#define CHAR_t                      '\164'
+#define CHAR_u                      '\165'
+#define CHAR_v                      '\166'
+#define CHAR_w                      '\167'
+#define CHAR_x                      '\170'
+#define CHAR_y                      '\171'
+#define CHAR_z                      '\172'
+#define CHAR_LEFT_CURLY_BRACKET     '\173'
+#define CHAR_VERTICAL_LINE          '\174'
+#define CHAR_RIGHT_CURLY_BRACKET    '\175'
+#define CHAR_TILDE                  '\176'
+#define CHAR_NBSP                   ((unsigned char)'\xa0')
+
+#define STR_HT                      "\011"
+#define STR_VT                      "\013"
+#define STR_FF                      "\014"
+#define STR_CR                      "\015"
+#define STR_NL                      "\012"
+#define STR_BS                      "\010"
+#define STR_BEL                     "\007"
+#define STR_ESC                     "\033"
+#define STR_DEL                     "\177"
+
+#define STR_SPACE                   "\040"
+#define STR_EXCLAMATION_MARK        "\041"
+#define STR_QUOTATION_MARK          "\042"
+#define STR_NUMBER_SIGN             "\043"
+#define STR_DOLLAR_SIGN             "\044"
+#define STR_PERCENT_SIGN            "\045"
+#define STR_AMPERSAND               "\046"
+#define STR_APOSTROPHE              "\047"
+#define STR_LEFT_PARENTHESIS        "\050"
+#define STR_RIGHT_PARENTHESIS       "\051"
+#define STR_ASTERISK                "\052"
+#define STR_PLUS                    "\053"
+#define STR_COMMA                   "\054"
+#define STR_MINUS                   "\055"
+#define STR_DOT                     "\056"
+#define STR_SLASH                   "\057"
+#define STR_0                       "\060"
+#define STR_1                       "\061"
+#define STR_2                       "\062"
+#define STR_3                       "\063"
+#define STR_4                       "\064"
+#define STR_5                       "\065"
+#define STR_6                       "\066"
+#define STR_7                       "\067"
+#define STR_8                       "\070"
+#define STR_9                       "\071"
+#define STR_COLON                   "\072"
+#define STR_SEMICOLON               "\073"
+#define STR_LESS_THAN_SIGN          "\074"
+#define STR_EQUALS_SIGN             "\075"
+#define STR_GREATER_THAN_SIGN       "\076"
+#define STR_QUESTION_MARK           "\077"
+#define STR_COMMERCIAL_AT           "\100"
+#define STR_A                       "\101"
+#define STR_B                       "\102"
+#define STR_C                       "\103"
+#define STR_D                       "\104"
+#define STR_E                       "\105"
+#define STR_F                       "\106"
+#define STR_G                       "\107"
+#define STR_H                       "\110"
+#define STR_I                       "\111"
+#define STR_J                       "\112"
+#define STR_K                       "\113"
+#define STR_L                       "\114"
+#define STR_M                       "\115"
+#define STR_N                       "\116"
+#define STR_O                       "\117"
+#define STR_P                       "\120"
+#define STR_Q                       "\121"
+#define STR_R                       "\122"
+#define STR_S                       "\123"
+#define STR_T                       "\124"
+#define STR_U                       "\125"
+#define STR_V                       "\126"
+#define STR_W                       "\127"
+#define STR_X                       "\130"
+#define STR_Y                       "\131"
+#define STR_Z                       "\132"
+#define STR_LEFT_SQUARE_BRACKET     "\133"
+#define STR_BACKSLASH               "\134"
+#define STR_RIGHT_SQUARE_BRACKET    "\135"
+#define STR_CIRCUMFLEX_ACCENT       "\136"
+#define STR_UNDERSCORE              "\137"
+#define STR_GRAVE_ACCENT            "\140"
+#define STR_a                       "\141"
+#define STR_b                       "\142"
+#define STR_c                       "\143"
+#define STR_d                       "\144"
+#define STR_e                       "\145"
+#define STR_f                       "\146"
+#define STR_g                       "\147"
+#define STR_h                       "\150"
+#define STR_i                       "\151"
+#define STR_j                       "\152"
+#define STR_k                       "\153"
+#define STR_l                       "\154"
+#define STR_m                       "\155"
+#define STR_n                       "\156"
+#define STR_o                       "\157"
+#define STR_p                       "\160"
+#define STR_q                       "\161"
+#define STR_r                       "\162"
+#define STR_s                       "\163"
+#define STR_t                       "\164"
+#define STR_u                       "\165"
+#define STR_v                       "\166"
+#define STR_w                       "\167"
+#define STR_x                       "\170"
+#define STR_y                       "\171"
+#define STR_z                       "\172"
+#define STR_LEFT_CURLY_BRACKET      "\173"
+#define STR_VERTICAL_LINE           "\174"
+#define STR_RIGHT_CURLY_BRACKET     "\175"
+#define STR_TILDE                   "\176"
+
+#define STRING_ACCEPT0               STR_A STR_C STR_C STR_E STR_P STR_T "\0"
+#define STRING_COMMIT0               STR_C STR_O STR_M STR_M STR_I STR_T "\0"
+#define STRING_F0                    STR_F "\0"
+#define STRING_FAIL0                 STR_F STR_A STR_I STR_L "\0"
+#define STRING_MARK0                 STR_M STR_A STR_R STR_K "\0"
+#define STRING_PRUNE0                STR_P STR_R STR_U STR_N STR_E "\0"
+#define STRING_SKIP0                 STR_S STR_K STR_I STR_P "\0"
+#define STRING_THEN                  STR_T STR_H STR_E STR_N
+
+#define STRING_atomic0               STR_a STR_t STR_o STR_m STR_i STR_c "\0"
+#define STRING_pla0                  STR_p STR_l STR_a "\0"
+#define STRING_plb0                  STR_p STR_l STR_b "\0"
+#define STRING_napla0                STR_n STR_a STR_p STR_l STR_a "\0"
+#define STRING_naplb0                STR_n STR_a STR_p STR_l STR_b "\0"
+#define STRING_nla0                  STR_n STR_l STR_a "\0"
+#define STRING_nlb0                  STR_n STR_l STR_b "\0"
+#define STRING_sr0                   STR_s STR_r "\0"
+#define STRING_asr0                  STR_a STR_s STR_r "\0"
+#define STRING_positive_lookahead0   STR_p STR_o STR_s STR_i STR_t STR_i STR_v STR_e STR_UNDERSCORE STR_l STR_o STR_o STR_k STR_a STR_h STR_e STR_a STR_d "\0"
+#define STRING_positive_lookbehind0  STR_p STR_o STR_s STR_i STR_t STR_i STR_v STR_e STR_UNDERSCORE STR_l STR_o STR_o STR_k STR_b STR_e STR_h STR_i STR_n STR_d "\0"
+#define STRING_non_atomic_positive_lookahead0   STR_n STR_o STR_n STR_UNDERSCORE STR_a STR_t STR_o STR_m STR_i STR_c STR_UNDERSCORE STR_p STR_o STR_s STR_i STR_t STR_i STR_v STR_e STR_UNDERSCORE STR_l STR_o STR_o STR_k STR_a STR_h STR_e STR_a STR_d "\0"
+#define STRING_non_atomic_positive_lookbehind0  STR_n STR_o STR_n STR_UNDERSCORE STR_a STR_t STR_o STR_m STR_i STR_c STR_UNDERSCORE STR_p STR_o STR_s STR_i STR_t STR_i STR_v STR_e STR_UNDERSCORE STR_l STR_o STR_o STR_k STR_b STR_e STR_h STR_i STR_n STR_d "\0"
+#define STRING_negative_lookahead0   STR_n STR_e STR_g STR_a STR_t STR_i STR_v STR_e STR_UNDERSCORE STR_l STR_o STR_o STR_k STR_a STR_h STR_e STR_a STR_d "\0"
+#define STRING_negative_lookbehind0  STR_n STR_e STR_g STR_a STR_t STR_i STR_v STR_e STR_UNDERSCORE STR_l STR_o STR_o STR_k STR_b STR_e STR_h STR_i STR_n STR_d "\0"
+#define STRING_script_run0           STR_s STR_c STR_r STR_i STR_p STR_t STR_UNDERSCORE STR_r STR_u STR_n "\0"
+#define STRING_atomic_script_run     STR_a STR_t STR_o STR_m STR_i STR_c STR_UNDERSCORE STR_s STR_c STR_r STR_i STR_p STR_t STR_UNDERSCORE STR_r STR_u STR_n
+
+#define STRING_alpha0                STR_a STR_l STR_p STR_h STR_a "\0"
+#define STRING_lower0                STR_l STR_o STR_w STR_e STR_r "\0"
+#define STRING_upper0                STR_u STR_p STR_p STR_e STR_r "\0"
+#define STRING_alnum0                STR_a STR_l STR_n STR_u STR_m "\0"
+#define STRING_ascii0                STR_a STR_s STR_c STR_i STR_i "\0"
+#define STRING_blank0                STR_b STR_l STR_a STR_n STR_k "\0"
+#define STRING_cntrl0                STR_c STR_n STR_t STR_r STR_l "\0"
+#define STRING_digit0                STR_d STR_i STR_g STR_i STR_t "\0"
+#define STRING_graph0                STR_g STR_r STR_a STR_p STR_h "\0"
+#define STRING_print0                STR_p STR_r STR_i STR_n STR_t "\0"
+#define STRING_punct0                STR_p STR_u STR_n STR_c STR_t "\0"
+#define STRING_space0                STR_s STR_p STR_a STR_c STR_e "\0"
+#define STRING_word0                 STR_w STR_o STR_r STR_d       "\0"
+#define STRING_xdigit                STR_x STR_d STR_i STR_g STR_i STR_t
+
+#define STRING_DEFINE                STR_D STR_E STR_F STR_I STR_N STR_E
+#define STRING_VERSION               STR_V STR_E STR_R STR_S STR_I STR_O STR_N
+#define STRING_WEIRD_STARTWORD       STR_LEFT_SQUARE_BRACKET STR_COLON STR_LESS_THAN_SIGN STR_COLON STR_RIGHT_SQUARE_BRACKET STR_RIGHT_SQUARE_BRACKET
+#define STRING_WEIRD_ENDWORD         STR_LEFT_SQUARE_BRACKET STR_COLON STR_GREATER_THAN_SIGN STR_COLON STR_RIGHT_SQUARE_BRACKET STR_RIGHT_SQUARE_BRACKET
+
+#define STRING_CR_RIGHTPAR                STR_C STR_R STR_RIGHT_PARENTHESIS
+#define STRING_LF_RIGHTPAR                STR_L STR_F STR_RIGHT_PARENTHESIS
+#define STRING_CRLF_RIGHTPAR              STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS
+#define STRING_ANY_RIGHTPAR               STR_A STR_N STR_Y STR_RIGHT_PARENTHESIS
+#define STRING_ANYCRLF_RIGHTPAR           STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS
+#define STRING_NUL_RIGHTPAR               STR_N STR_U STR_L STR_RIGHT_PARENTHESIS
+#define STRING_BSR_ANYCRLF_RIGHTPAR       STR_B STR_S STR_R STR_UNDERSCORE STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS
+#define STRING_BSR_UNICODE_RIGHTPAR       STR_B STR_S STR_R STR_UNDERSCORE STR_U STR_N STR_I STR_C STR_O STR_D STR_E STR_RIGHT_PARENTHESIS
+#define STRING_UTF8_RIGHTPAR              STR_U STR_T STR_F STR_8 STR_RIGHT_PARENTHESIS
+#define STRING_UTF16_RIGHTPAR             STR_U STR_T STR_F STR_1 STR_6 STR_RIGHT_PARENTHESIS
+#define STRING_UTF32_RIGHTPAR             STR_U STR_T STR_F STR_3 STR_2 STR_RIGHT_PARENTHESIS
+#define STRING_UTF_RIGHTPAR               STR_U STR_T STR_F STR_RIGHT_PARENTHESIS
+#define STRING_UCP_RIGHTPAR               STR_U STR_C STR_P STR_RIGHT_PARENTHESIS
+#define STRING_NO_AUTO_POSSESS_RIGHTPAR   STR_N STR_O STR_UNDERSCORE STR_A STR_U STR_T STR_O STR_UNDERSCORE STR_P STR_O STR_S STR_S STR_E STR_S STR_S STR_RIGHT_PARENTHESIS
+#define STRING_NO_DOTSTAR_ANCHOR_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_D STR_O STR_T STR_S STR_T STR_A STR_R STR_UNDERSCORE STR_A STR_N STR_C STR_H STR_O STR_R STR_RIGHT_PARENTHESIS
+#define STRING_NO_JIT_RIGHTPAR            STR_N STR_O STR_UNDERSCORE STR_J STR_I STR_T STR_RIGHT_PARENTHESIS
+#define STRING_NO_START_OPT_RIGHTPAR      STR_N STR_O STR_UNDERSCORE STR_S STR_T STR_A STR_R STR_T STR_UNDERSCORE STR_O STR_P STR_T STR_RIGHT_PARENTHESIS
+#define STRING_NOTEMPTY_RIGHTPAR          STR_N STR_O STR_T STR_E STR_M STR_P STR_T STR_Y STR_RIGHT_PARENTHESIS
+#define STRING_NOTEMPTY_ATSTART_RIGHTPAR  STR_N STR_O STR_T STR_E STR_M STR_P STR_T STR_Y STR_UNDERSCORE STR_A STR_T STR_S STR_T STR_A STR_R STR_T STR_RIGHT_PARENTHESIS
+#define STRING_LIMIT_HEAP_EQ              STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_H STR_E STR_A STR_P STR_EQUALS_SIGN
+#define STRING_LIMIT_MATCH_EQ             STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_M STR_A STR_T STR_C STR_H STR_EQUALS_SIGN
+#define STRING_LIMIT_DEPTH_EQ             STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_D STR_E STR_P STR_T STR_H STR_EQUALS_SIGN
+#define STRING_LIMIT_RECURSION_EQ         STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_R STR_E STR_C STR_U STR_R STR_S STR_I STR_O STR_N STR_EQUALS_SIGN
+#define STRING_MARK                       STR_M STR_A STR_R STR_K
+
+#endif  /* SUPPORT_UNICODE */
+
+/* -------------------- End of character and string names -------------------*/
+
+/* -------------------- Definitions for compiled patterns -------------------*/
+
+/* Codes for different types of Unicode property */
+
+#define PT_ANY        0    /* Any property - matches all chars */
+#define PT_LAMP       1    /* L& - the union of Lu, Ll, Lt */
+#define PT_GC         2    /* Specified general characteristic (e.g. L) */
+#define PT_PC         3    /* Specified particular characteristic (e.g. Lu) */
+#define PT_SC         4    /* Script (e.g. Han) */
+#define PT_ALNUM      5    /* Alphanumeric - the union of L and N */
+#define PT_SPACE      6    /* Perl space - Z plus 9,10,12,13 */
+#define PT_PXSPACE    7    /* POSIX space - Z plus 9,10,11,12,13 */
+#define PT_WORD       8    /* Word - L plus N plus underscore */
+#define PT_CLIST      9    /* Pseudo-property: match character list */
+#define PT_UCNC      10    /* Universal Character nameable character */
+#define PT_TABSIZE   11    /* Size of square table for autopossessify tests */
+
+/* The following special properties are used only in XCLASS items, when POSIX
+classes are specified and PCRE2_UCP is set - in other words, for Unicode
+handling of these classes. They are not available via the \p or \P escapes like
+those in the above list, and so they do not take part in the autopossessifying
+table. */
+
+#define PT_PXGRAPH   11    /* [:graph:] - characters that mark the paper */
+#define PT_PXPRINT   12    /* [:print:] - [:graph:] plus non-control spaces */
+#define PT_PXPUNCT   13    /* [:punct:] - punctuation characters */
+
+/* Flag bits and data types for the extended class (OP_XCLASS) for classes that
+contain characters with values greater than 255. */
+
+#define XCL_NOT       0x01    /* Flag: this is a negative class */
+#define XCL_MAP       0x02    /* Flag: a 32-byte map is present */
+#define XCL_HASPROP   0x04    /* Flag: property checks are present. */
+
+#define XCL_END       0    /* Marks end of individual items */
+#define XCL_SINGLE    1    /* Single item (one multibyte char) follows */
+#define XCL_RANGE     2    /* A range (two multibyte chars) follows */
+#define XCL_PROP      3    /* Unicode property (2-byte property code follows) */
+#define XCL_NOTPROP   4    /* Unicode inverted property (ditto) */
+
+/* These are escaped items that aren't just an encoding of a particular data
+value such as \n. They must have non-zero values, as check_escape() returns 0
+for a data character. In the escapes[] table in pcre2_compile.c their values
+are negated in order to distinguish them from data values.
+
+They must appear here in the same order as in the opcode definitions below, up
+to ESC_z. There's a dummy for OP_ALLANY because it corresponds to "." in DOTALL
+mode rather than an escape sequence. It is also used for [^] in JavaScript
+compatibility mode, and for \C in non-utf mode. In non-DOTALL mode, "." behaves
+like \N.
+
+Negative numbers are used to encode a backreference (\1, \2, \3, etc.) in
+check_escape(). There are tests in the code for an escape greater than ESC_b
+and less than ESC_Z to detect the types that may be repeated. These are the
+types that consume characters. If any new escapes are put in between that don't
+consume a character, that code will have to change. */
+
+enum { ESC_A = 1, ESC_G, ESC_K, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s,
+       ESC_W, ESC_w, ESC_N, ESC_dum, ESC_C, ESC_P, ESC_p, ESC_R, ESC_H,
+       ESC_h, ESC_V, ESC_v, ESC_X, ESC_Z, ESC_z,
+       ESC_E, ESC_Q, ESC_g, ESC_k };
+
+
+/********************** Opcode definitions ******************/
+
+/****** NOTE NOTE NOTE ******
+
+Starting from 1 (i.e. after OP_END), the values up to OP_EOD must correspond in
+order to the list of escapes immediately above. Furthermore, values up to
+OP_DOLLM must not be changed without adjusting the table called autoposstab in
+pcre2_auto_possess.c.
+
+Whenever this list is updated, the two macro definitions that follow must be
+updated to match. The possessification table called "opcode_possessify" in
+pcre2_compile.c must also be updated, and also the tables called "coptable"
+and "poptable" in pcre2_dfa_match.c.
+
+****** NOTE NOTE NOTE ******/
+
+
+/* The values between FIRST_AUTOTAB_OP and LAST_AUTOTAB_RIGHT_OP, inclusive,
+are used in a table for deciding whether a repeated character type can be
+auto-possessified. */
+
+#define FIRST_AUTOTAB_OP       OP_NOT_DIGIT
+#define LAST_AUTOTAB_LEFT_OP   OP_EXTUNI
+#define LAST_AUTOTAB_RIGHT_OP  OP_DOLLM
+
+enum {
+  OP_END,            /* 0 End of pattern */
+
+  /* Values corresponding to backslashed metacharacters */
+
+  OP_SOD,            /* 1 Start of data: \A */
+  OP_SOM,            /* 2 Start of match (subject + offset): \G */
+  OP_SET_SOM,        /* 3 Set start of match (\K) */
+  OP_NOT_WORD_BOUNDARY,  /*  4 \B */
+  OP_WORD_BOUNDARY,      /*  5 \b */
+  OP_NOT_DIGIT,          /*  6 \D */
+  OP_DIGIT,              /*  7 \d */
+  OP_NOT_WHITESPACE,     /*  8 \S */
+  OP_WHITESPACE,         /*  9 \s */
+  OP_NOT_WORDCHAR,       /* 10 \W */
+  OP_WORDCHAR,           /* 11 \w */
+
+  OP_ANY,            /* 12 Match any character except newline (\N) */
+  OP_ALLANY,         /* 13 Match any character */
+  OP_ANYBYTE,        /* 14 Match any byte (\C); different to OP_ANY for UTF-8 */
+  OP_NOTPROP,        /* 15 \P (not Unicode property) */
+  OP_PROP,           /* 16 \p (Unicode property) */
+  OP_ANYNL,          /* 17 \R (any newline sequence) */
+  OP_NOT_HSPACE,     /* 18 \H (not horizontal whitespace) */
+  OP_HSPACE,         /* 19 \h (horizontal whitespace) */
+  OP_NOT_VSPACE,     /* 20 \V (not vertical whitespace) */
+  OP_VSPACE,         /* 21 \v (vertical whitespace) */
+  OP_EXTUNI,         /* 22 \X (extended Unicode sequence */
+  OP_EODN,           /* 23 End of data or \n at end of data (\Z) */
+  OP_EOD,            /* 24 End of data (\z) */
+
+  /* Line end assertions */
+
+  OP_DOLL,           /* 25 End of line - not multiline */
+  OP_DOLLM,          /* 26 End of line - multiline */
+  OP_CIRC,           /* 27 Start of line - not multiline */
+  OP_CIRCM,          /* 28 Start of line - multiline */
+
+  /* Single characters; caseful must precede the caseless ones, and these
+  must remain in this order, and adjacent. */
+
+  OP_CHAR,           /* 29 Match one character, casefully */
+  OP_CHARI,          /* 30 Match one character, caselessly */
+  OP_NOT,            /* 31 Match one character, not the given one, casefully */
+  OP_NOTI,           /* 32 Match one character, not the given one, caselessly */
+
+  /* The following sets of 13 opcodes must always be kept in step because
+  the offset from the first one is used to generate the others. */
+
+  /* Repeated characters; caseful must precede the caseless ones */
+
+  OP_STAR,           /* 33 The maximizing and minimizing versions of */
+  OP_MINSTAR,        /* 34 these six opcodes must come in pairs, with */
+  OP_PLUS,           /* 35 the minimizing one second. */
+  OP_MINPLUS,        /* 36 */
+  OP_QUERY,          /* 37 */
+  OP_MINQUERY,       /* 38 */
+
+  OP_UPTO,           /* 39 From 0 to n matches of one character, caseful*/
+  OP_MINUPTO,        /* 40 */
+  OP_EXACT,          /* 41 Exactly n matches */
+
+  OP_POSSTAR,        /* 42 Possessified star, caseful */
+  OP_POSPLUS,        /* 43 Possessified plus, caseful */
+  OP_POSQUERY,       /* 44 Posesssified query, caseful */
+  OP_POSUPTO,        /* 45 Possessified upto, caseful */
+
+  /* Repeated characters; caseless must follow the caseful ones */
+
+  OP_STARI,          /* 46 */
+  OP_MINSTARI,       /* 47 */
+  OP_PLUSI,          /* 48 */
+  OP_MINPLUSI,       /* 49 */
+  OP_QUERYI,         /* 50 */
+  OP_MINQUERYI,      /* 51 */
+
+  OP_UPTOI,          /* 52 From 0 to n matches of one character, caseless */
+  OP_MINUPTOI,       /* 53 */
+  OP_EXACTI,         /* 54 */
+
+  OP_POSSTARI,       /* 55 Possessified star, caseless */
+  OP_POSPLUSI,       /* 56 Possessified plus, caseless */
+  OP_POSQUERYI,      /* 57 Posesssified query, caseless */
+  OP_POSUPTOI,       /* 58 Possessified upto, caseless */
+
+  /* The negated ones must follow the non-negated ones, and match them */
+  /* Negated repeated character, caseful; must precede the caseless ones */
+
+  OP_NOTSTAR,        /* 59 The maximizing and minimizing versions of */
+  OP_NOTMINSTAR,     /* 60 these six opcodes must come in pairs, with */
+  OP_NOTPLUS,        /* 61 the minimizing one second. They must be in */
+  OP_NOTMINPLUS,     /* 62 exactly the same order as those above. */
+  OP_NOTQUERY,       /* 63 */
+  OP_NOTMINQUERY,    /* 64 */
+
+  OP_NOTUPTO,        /* 65 From 0 to n matches, caseful */
+  OP_NOTMINUPTO,     /* 66 */
+  OP_NOTEXACT,       /* 67 Exactly n matches */
+
+  OP_NOTPOSSTAR,     /* 68 Possessified versions, caseful */
+  OP_NOTPOSPLUS,     /* 69 */
+  OP_NOTPOSQUERY,    /* 70 */
+  OP_NOTPOSUPTO,     /* 71 */
+
+  /* Negated repeated character, caseless; must follow the caseful ones */
+
+  OP_NOTSTARI,       /* 72 */
+  OP_NOTMINSTARI,    /* 73 */
+  OP_NOTPLUSI,       /* 74 */
+  OP_NOTMINPLUSI,    /* 75 */
+  OP_NOTQUERYI,      /* 76 */
+  OP_NOTMINQUERYI,   /* 77 */
+
+  OP_NOTUPTOI,       /* 78 From 0 to n matches, caseless */
+  OP_NOTMINUPTOI,    /* 79 */
+  OP_NOTEXACTI,      /* 80 Exactly n matches */
+
+  OP_NOTPOSSTARI,    /* 81 Possessified versions, caseless */
+  OP_NOTPOSPLUSI,    /* 82 */
+  OP_NOTPOSQUERYI,   /* 83 */
+  OP_NOTPOSUPTOI,    /* 84 */
+
+  /* Character types */
+
+  OP_TYPESTAR,       /* 85 The maximizing and minimizing versions of */
+  OP_TYPEMINSTAR,    /* 86 these six opcodes must come in pairs, with */
+  OP_TYPEPLUS,       /* 87 the minimizing one second. These codes must */
+  OP_TYPEMINPLUS,    /* 88 be in exactly the same order as those above. */
+  OP_TYPEQUERY,      /* 89 */
+  OP_TYPEMINQUERY,   /* 90 */
+
+  OP_TYPEUPTO,       /* 91 From 0 to n matches */
+  OP_TYPEMINUPTO,    /* 92 */
+  OP_TYPEEXACT,      /* 93 Exactly n matches */
+
+  OP_TYPEPOSSTAR,    /* 94 Possessified versions */
+  OP_TYPEPOSPLUS,    /* 95 */
+  OP_TYPEPOSQUERY,   /* 96 */
+  OP_TYPEPOSUPTO,    /* 97 */
+
+  /* These are used for character classes and back references; only the
+  first six are the same as the sets above. */
+
+  OP_CRSTAR,         /* 98 The maximizing and minimizing versions of */
+  OP_CRMINSTAR,      /* 99 all these opcodes must come in pairs, with */
+  OP_CRPLUS,         /* 100 the minimizing one second. These codes must */
+  OP_CRMINPLUS,      /* 101 be in exactly the same order as those above. */
+  OP_CRQUERY,        /* 102 */
+  OP_CRMINQUERY,     /* 103 */
+
+  OP_CRRANGE,        /* 104 These are different to the three sets above. */
+  OP_CRMINRANGE,     /* 105 */
+
+  OP_CRPOSSTAR,      /* 106 Possessified versions */
+  OP_CRPOSPLUS,      /* 107 */
+  OP_CRPOSQUERY,     /* 108 */
+  OP_CRPOSRANGE,     /* 109 */
+
+  /* End of quantifier opcodes */
+
+  OP_CLASS,          /* 110 Match a character class, chars < 256 only */
+  OP_NCLASS,         /* 111 Same, but the bitmap was created from a negative
+                              class - the difference is relevant only when a
+                              character > 255 is encountered. */
+  OP_XCLASS,         /* 112 Extended class for handling > 255 chars within the
+                              class. This does both positive and negative. */
+  OP_REF,            /* 113 Match a back reference, casefully */
+  OP_REFI,           /* 114 Match a back reference, caselessly */
+  OP_DNREF,          /* 115 Match a duplicate name backref, casefully */
+  OP_DNREFI,         /* 116 Match a duplicate name backref, caselessly */
+  OP_RECURSE,        /* 117 Match a numbered subpattern (possibly recursive) */
+  OP_CALLOUT,        /* 118 Call out to external function if provided */
+  OP_CALLOUT_STR,    /* 119 Call out with string argument */
+
+  OP_ALT,            /* 120 Start of alternation */
+  OP_KET,            /* 121 End of group that doesn't have an unbounded repeat */
+  OP_KETRMAX,        /* 122 These two must remain together and in this */
+  OP_KETRMIN,        /* 123 order. They are for groups the repeat for ever. */
+  OP_KETRPOS,        /* 124 Possessive unlimited repeat. */
+
+  /* The assertions must come before BRA, CBRA, ONCE, and COND. */
+
+  OP_REVERSE,        /* 125 Move pointer back - used in lookbehind assertions */
+  OP_ASSERT,         /* 126 Positive lookahead */
+  OP_ASSERT_NOT,     /* 127 Negative lookahead */
+  OP_ASSERTBACK,     /* 128 Positive lookbehind */
+  OP_ASSERTBACK_NOT, /* 129 Negative lookbehind */
+  OP_ASSERT_NA,      /* 130 Positive non-atomic lookahead */
+  OP_ASSERTBACK_NA,  /* 131 Positive non-atomic lookbehind */
+
+  /* ONCE, SCRIPT_RUN, BRA, BRAPOS, CBRA, CBRAPOS, and COND must come
+  immediately after the assertions, with ONCE first, as there's a test for >=
+  ONCE for a subpattern that isn't an assertion. The POS versions must
+  immediately follow the non-POS versions in each case. */
+
+  OP_ONCE,           /* 132 Atomic group, contains captures */
+  OP_SCRIPT_RUN,     /* 133 Non-capture, but check characters' scripts */
+  OP_BRA,            /* 134 Start of non-capturing bracket */
+  OP_BRAPOS,         /* 135 Ditto, with unlimited, possessive repeat */
+  OP_CBRA,           /* 136 Start of capturing bracket */
+  OP_CBRAPOS,        /* 137 Ditto, with unlimited, possessive repeat */
+  OP_COND,           /* 138 Conditional group */
+
+  /* These five must follow the previous five, in the same order. There's a
+  check for >= SBRA to distinguish the two sets. */
+
+  OP_SBRA,           /* 139 Start of non-capturing bracket, check empty  */
+  OP_SBRAPOS,        /* 149 Ditto, with unlimited, possessive repeat */
+  OP_SCBRA,          /* 141 Start of capturing bracket, check empty */
+  OP_SCBRAPOS,       /* 142 Ditto, with unlimited, possessive repeat */
+  OP_SCOND,          /* 143 Conditional group, check empty */
+
+  /* The next two pairs must (respectively) be kept together. */
+
+  OP_CREF,           /* 144 Used to hold a capture number as condition */
+  OP_DNCREF,         /* 145 Used to point to duplicate names as a condition */
+  OP_RREF,           /* 146 Used to hold a recursion number as condition */
+  OP_DNRREF,         /* 147 Used to point to duplicate names as a condition */
+  OP_FALSE,          /* 148 Always false (used by DEFINE and VERSION) */
+  OP_TRUE,           /* 149 Always true (used by VERSION) */
+
+  OP_BRAZERO,        /* 150 These two must remain together and in this */
+  OP_BRAMINZERO,     /* 151 order. */
+  OP_BRAPOSZERO,     /* 152 */
+
+  /* These are backtracking control verbs */
+
+  OP_MARK,           /* 153 always has an argument */
+  OP_PRUNE,          /* 154 */
+  OP_PRUNE_ARG,      /* 155 same, but with argument */
+  OP_SKIP,           /* 156 */
+  OP_SKIP_ARG,       /* 157 same, but with argument */
+  OP_THEN,           /* 158 */
+  OP_THEN_ARG,       /* 159 same, but with argument */
+  OP_COMMIT,         /* 160 */
+  OP_COMMIT_ARG,     /* 161 same, but with argument */
+
+  /* These are forced failure and success verbs. FAIL and ACCEPT do accept an
+  argument, but these cases can be compiled as, for example, (*MARK:X)(*FAIL)
+  without the need for a special opcode. */
+
+  OP_FAIL,           /* 162 */
+  OP_ACCEPT,         /* 163 */
+  OP_ASSERT_ACCEPT,  /* 164 Used inside assertions */
+  OP_CLOSE,          /* 165 Used before OP_ACCEPT to close open captures */
+
+  /* This is used to skip a subpattern with a {0} quantifier */
+
+  OP_SKIPZERO,       /* 166 */
+
+  /* This is used to identify a DEFINE group during compilation so that it can
+  be checked for having only one branch. It is changed to OP_FALSE before
+  compilation finishes. */
+
+  OP_DEFINE,         /* 167 */
+
+  /* This is not an opcode, but is used to check that tables indexed by opcode
+  are the correct length, in order to catch updating errors - there have been
+  some in the past. */
+
+  OP_TABLE_LENGTH
+
+};
+
+/* *** NOTE NOTE NOTE *** Whenever the list above is updated, the two macro
+definitions that follow must also be updated to match. There are also tables
+called "opcode_possessify" in pcre2_compile.c and "coptable" and "poptable" in
+pcre2_dfa_match.c that must be updated. */
+
+
+/* This macro defines textual names for all the opcodes. These are used only
+for debugging, and some of them are only partial names. The macro is referenced
+only in pcre2_printint.c, which fills out the full names in many cases (and in
+some cases doesn't actually use these names at all). */
+
+#define OP_NAME_LIST \
+  "End", "\\A", "\\G", "\\K", "\\B", "\\b", "\\D", "\\d",         \
+  "\\S", "\\s", "\\W", "\\w", "Any", "AllAny", "Anybyte",         \
+  "notprop", "prop", "\\R", "\\H", "\\h", "\\V", "\\v",           \
+  "extuni",  "\\Z", "\\z",                                        \
+  "$", "$", "^", "^", "char", "chari", "not", "noti",             \
+  "*", "*?", "+", "+?", "?", "??",                                \
+  "{", "{", "{",                                                  \
+  "*+","++", "?+", "{",                                           \
+  "*", "*?", "+", "+?", "?", "??",                                \
+  "{", "{", "{",                                                  \
+  "*+","++", "?+", "{",                                           \
+  "*", "*?", "+", "+?", "?", "??",                                \
+  "{", "{", "{",                                                  \
+  "*+","++", "?+", "{",                                           \
+  "*", "*?", "+", "+?", "?", "??",                                \
+  "{", "{", "{",                                                  \
+  "*+","++", "?+", "{",                                           \
+  "*", "*?", "+", "+?", "?", "??", "{", "{", "{",                 \
+  "*+","++", "?+", "{",                                           \
+  "*", "*?", "+", "+?", "?", "??", "{", "{",                      \
+  "*+","++", "?+", "{",                                           \
+  "class", "nclass", "xclass", "Ref", "Refi", "DnRef", "DnRefi",  \
+  "Recurse", "Callout", "CalloutStr",                             \
+  "Alt", "Ket", "KetRmax", "KetRmin", "KetRpos",                  \
+  "Reverse", "Assert", "Assert not",                              \
+  "Assert back", "Assert back not",                               \
+  "Non-atomic assert", "Non-atomic assert back",                  \
+  "Once",                                                         \
+  "Script run",                                                   \
+  "Bra", "BraPos", "CBra", "CBraPos",                             \
+  "Cond",                                                         \
+  "SBra", "SBraPos", "SCBra", "SCBraPos",                         \
+  "SCond",                                                        \
+  "Cond ref", "Cond dnref", "Cond rec", "Cond dnrec",             \
+  "Cond false", "Cond true",                                      \
+  "Brazero", "Braminzero", "Braposzero",                          \
+  "*MARK", "*PRUNE", "*PRUNE", "*SKIP", "*SKIP",                  \
+  "*THEN", "*THEN", "*COMMIT", "*COMMIT", "*FAIL",                \
+  "*ACCEPT", "*ASSERT_ACCEPT",                                    \
+  "Close", "Skip zero", "Define"
+
+
+/* This macro defines the length of fixed length operations in the compiled
+regex. The lengths are used when searching for specific things, and also in the
+debugging printing of a compiled regex. We use a macro so that it can be
+defined close to the definitions of the opcodes themselves.
+
+As things have been extended, some of these are no longer fixed lenths, but are
+minima instead. For example, the length of a single-character repeat may vary
+in UTF-8 mode. The code that uses this table must know about such things. */
+
+#define OP_LENGTHS \
+  1,                             /* End                                    */ \
+  1, 1, 1, 1, 1,                 /* \A, \G, \K, \B, \b                     */ \
+  1, 1, 1, 1, 1, 1,              /* \D, \d, \S, \s, \W, \w                 */ \
+  1, 1, 1,                       /* Any, AllAny, Anybyte                   */ \
+  3, 3,                          /* \P, \p                                 */ \
+  1, 1, 1, 1, 1,                 /* \R, \H, \h, \V, \v                     */ \
+  1,                             /* \X                                     */ \
+  1, 1, 1, 1, 1, 1,              /* \Z, \z, $, $M ^, ^M                    */ \
+  2,                             /* Char  - the minimum length             */ \
+  2,                             /* Chari  - the minimum length            */ \
+  2,                             /* not                                    */ \
+  2,                             /* noti                                   */ \
+  /* Positive single-char repeats                             ** These are */ \
+  2, 2, 2, 2, 2, 2,              /* *, *?, +, +?, ?, ??       ** minima in */ \
+  2+IMM2_SIZE, 2+IMM2_SIZE,      /* upto, minupto             ** mode      */ \
+  2+IMM2_SIZE,                   /* exact                                  */ \
+  2, 2, 2, 2+IMM2_SIZE,          /* *+, ++, ?+, upto+                      */ \
+  2, 2, 2, 2, 2, 2,              /* *I, *?I, +I, +?I, ?I, ??I ** UTF-8     */ \
+  2+IMM2_SIZE, 2+IMM2_SIZE,      /* upto I, minupto I                      */ \
+  2+IMM2_SIZE,                   /* exact I                                */ \
+  2, 2, 2, 2+IMM2_SIZE,          /* *+I, ++I, ?+I, upto+I                  */ \
+  /* Negative single-char repeats - only for chars < 256                   */ \
+  2, 2, 2, 2, 2, 2,              /* NOT *, *?, +, +?, ?, ??                */ \
+  2+IMM2_SIZE, 2+IMM2_SIZE,      /* NOT upto, minupto                      */ \
+  2+IMM2_SIZE,                   /* NOT exact                              */ \
+  2, 2, 2, 2+IMM2_SIZE,          /* Possessive NOT *, +, ?, upto           */ \
+  2, 2, 2, 2, 2, 2,              /* NOT *I, *?I, +I, +?I, ?I, ??I          */ \
+  2+IMM2_SIZE, 2+IMM2_SIZE,      /* NOT upto I, minupto I                  */ \
+  2+IMM2_SIZE,                   /* NOT exact I                            */ \
+  2, 2, 2, 2+IMM2_SIZE,          /* Possessive NOT *I, +I, ?I, upto I      */ \
+  /* Positive type repeats                                                 */ \
+  2, 2, 2, 2, 2, 2,              /* Type *, *?, +, +?, ?, ??               */ \
+  2+IMM2_SIZE, 2+IMM2_SIZE,      /* Type upto, minupto                     */ \
+  2+IMM2_SIZE,                   /* Type exact                             */ \
+  2, 2, 2, 2+IMM2_SIZE,          /* Possessive *+, ++, ?+, upto+           */ \
+  /* Character class & ref repeats                                         */ \
+  1, 1, 1, 1, 1, 1,              /* *, *?, +, +?, ?, ??                    */ \
+  1+2*IMM2_SIZE, 1+2*IMM2_SIZE,  /* CRRANGE, CRMINRANGE                    */ \
+  1, 1, 1, 1+2*IMM2_SIZE,        /* Possessive *+, ++, ?+, CRPOSRANGE      */ \
+  1+(32/sizeof(PCRE2_UCHAR)),    /* CLASS                                  */ \
+  1+(32/sizeof(PCRE2_UCHAR)),    /* NCLASS                                 */ \
+  0,                             /* XCLASS - variable length               */ \
+  1+IMM2_SIZE,                   /* REF                                    */ \
+  1+IMM2_SIZE,                   /* REFI                                   */ \
+  1+2*IMM2_SIZE,                 /* DNREF                                  */ \
+  1+2*IMM2_SIZE,                 /* DNREFI                                 */ \
+  1+LINK_SIZE,                   /* RECURSE                                */ \
+  1+2*LINK_SIZE+1,               /* CALLOUT                                */ \
+  0,                             /* CALLOUT_STR - variable length          */ \
+  1+LINK_SIZE,                   /* Alt                                    */ \
+  1+LINK_SIZE,                   /* Ket                                    */ \
+  1+LINK_SIZE,                   /* KetRmax                                */ \
+  1+LINK_SIZE,                   /* KetRmin                                */ \
+  1+LINK_SIZE,                   /* KetRpos                                */ \
+  1+LINK_SIZE,                   /* Reverse                                */ \
+  1+LINK_SIZE,                   /* Assert                                 */ \
+  1+LINK_SIZE,                   /* Assert not                             */ \
+  1+LINK_SIZE,                   /* Assert behind                          */ \
+  1+LINK_SIZE,                   /* Assert behind not                      */ \
+  1+LINK_SIZE,                   /* NA Assert                              */ \
+  1+LINK_SIZE,                   /* NA Assert behind                       */ \
+  1+LINK_SIZE,                   /* ONCE                                   */ \
+  1+LINK_SIZE,                   /* SCRIPT_RUN                             */ \
+  1+LINK_SIZE,                   /* BRA                                    */ \
+  1+LINK_SIZE,                   /* BRAPOS                                 */ \
+  1+LINK_SIZE+IMM2_SIZE,         /* CBRA                                   */ \
+  1+LINK_SIZE+IMM2_SIZE,         /* CBRAPOS                                */ \
+  1+LINK_SIZE,                   /* COND                                   */ \
+  1+LINK_SIZE,                   /* SBRA                                   */ \
+  1+LINK_SIZE,                   /* SBRAPOS                                */ \
+  1+LINK_SIZE+IMM2_SIZE,         /* SCBRA                                  */ \
+  1+LINK_SIZE+IMM2_SIZE,         /* SCBRAPOS                               */ \
+  1+LINK_SIZE,                   /* SCOND                                  */ \
+  1+IMM2_SIZE, 1+2*IMM2_SIZE,    /* CREF, DNCREF                           */ \
+  1+IMM2_SIZE, 1+2*IMM2_SIZE,    /* RREF, DNRREF                           */ \
+  1, 1,                          /* FALSE, TRUE                            */ \
+  1, 1, 1,                       /* BRAZERO, BRAMINZERO, BRAPOSZERO        */ \
+  3, 1, 3,                       /* MARK, PRUNE, PRUNE_ARG                 */ \
+  1, 3,                          /* SKIP, SKIP_ARG                         */ \
+  1, 3,                          /* THEN, THEN_ARG                         */ \
+  1, 3,                          /* COMMIT, COMMIT_ARG                     */ \
+  1, 1, 1,                       /* FAIL, ACCEPT, ASSERT_ACCEPT            */ \
+  1+IMM2_SIZE, 1,                /* CLOSE, SKIPZERO                        */ \
+  1                              /* DEFINE                                 */
+
+/* A magic value for OP_RREF to indicate the "any recursion" condition. */
+
+#define RREF_ANY  0xffff
+
+
+/* ---------- Private structures that are mode-independent. ---------- */
+
+/* Structure to hold data for custom memory management. */
+
+typedef struct pcre2_memctl {
+  void *    (*malloc)(size_t, void *);
+  void      (*free)(void *, void *);
+  void      *memory_data;
+} pcre2_memctl;
+
+/* Structure for building a chain of open capturing subpatterns during
+compiling, so that instructions to close them can be compiled when (*ACCEPT) is
+encountered. */
+
+typedef struct open_capitem {
+  struct open_capitem *next;    /* Chain link */
+  uint16_t number;              /* Capture number */
+  uint16_t assert_depth;        /* Assertion depth when opened */
+} open_capitem;
+
+/* Layout of the UCP type table that translates property names into types and
+codes. Each entry used to point directly to a name, but to reduce the number of
+relocations in shared libraries, it now has an offset into a single string
+instead. */
+
+typedef struct {
+  uint16_t name_offset;
+  uint16_t type;
+  uint16_t value;
+} ucp_type_table;
+
+/* Unicode character database (UCD) record format */
+
+typedef struct {
+  uint8_t script;     /* ucp_Arabic, etc. */
+  uint8_t chartype;   /* ucp_Cc, etc. (general categories) */
+  uint8_t gbprop;     /* ucp_gbControl, etc. (grapheme break property) */
+  uint8_t caseset;    /* offset to multichar other cases or zero */
+  int32_t other_case; /* offset to other case, or zero if none */
+  int16_t scriptx;    /* script extension value */
+  int16_t dummy;      /* spare - to round to multiple of 4 bytes */
+} ucd_record;
+
+/* UCD access macros */
+
+#define UCD_BLOCK_SIZE 128
+#define REAL_GET_UCD(ch) (PRIV(ucd_records) + \
+        PRIV(ucd_stage2)[PRIV(ucd_stage1)[(int)(ch) / UCD_BLOCK_SIZE] * \
+        UCD_BLOCK_SIZE + (int)(ch) % UCD_BLOCK_SIZE])
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+#define GET_UCD(ch) ((ch > MAX_UTF_CODE_POINT)? \
+  PRIV(dummy_ucd_record) : REAL_GET_UCD(ch))
+#else
+#define GET_UCD(ch) REAL_GET_UCD(ch)
+#endif
+
+#define UCD_CHARTYPE(ch)    GET_UCD(ch)->chartype
+#define UCD_SCRIPT(ch)      GET_UCD(ch)->script
+#define UCD_CATEGORY(ch)    PRIV(ucp_gentype)[UCD_CHARTYPE(ch)]
+#define UCD_GRAPHBREAK(ch)  GET_UCD(ch)->gbprop
+#define UCD_CASESET(ch)     GET_UCD(ch)->caseset
+#define UCD_OTHERCASE(ch)   ((uint32_t)((int)ch + (int)(GET_UCD(ch)->other_case)))
+#define UCD_SCRIPTX(ch)     GET_UCD(ch)->scriptx
+
+/* Header for serialized pcre2 codes. */
+
+typedef struct pcre2_serialized_data {
+  uint32_t magic;
+  uint32_t version;
+  uint32_t config;
+  int32_t  number_of_codes;
+} pcre2_serialized_data;
+
+
+
+/* ----------------- Items that need PCRE2_CODE_UNIT_WIDTH ----------------- */
+
+/* When this file is included by pcre2test, PCRE2_CODE_UNIT_WIDTH is defined as
+0, so the following items are omitted. */
+
+#if defined PCRE2_CODE_UNIT_WIDTH && PCRE2_CODE_UNIT_WIDTH != 0
+
+/* EBCDIC is supported only for the 8-bit library. */
+
+#if defined EBCDIC && PCRE2_CODE_UNIT_WIDTH != 8
+#error EBCDIC is not supported for the 16-bit or 32-bit libraries
+#endif
+
+/* This is the largest non-UTF code point. */
+
+#define MAX_NON_UTF_CHAR (0xffffffffU >> (32 - PCRE2_CODE_UNIT_WIDTH))
+
+/* Internal shared data tables and variables. These are used by more than one
+of the exported public functions. They have to be "external" in the C sense,
+but are not part of the PCRE2 public API. Although the data for some of them is
+identical in all libraries, they must have different names so that multiple
+libraries can be simultaneously linked to a single application. However, UTF-8
+tables are needed only when compiling the 8-bit library. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+extern const int              PRIV(utf8_table1)[];
+extern const int              PRIV(utf8_table1_size);
+extern const int              PRIV(utf8_table2)[];
+extern const int              PRIV(utf8_table3)[];
+extern const uint8_t          PRIV(utf8_table4)[];
+#endif
+
+#define _pcre2_OP_lengths              PCRE2_SUFFIX(_pcre2_OP_lengths_)
+#define _pcre2_callout_end_delims      PCRE2_SUFFIX(_pcre2_callout_end_delims_)
+#define _pcre2_callout_start_delims    PCRE2_SUFFIX(_pcre2_callout_start_delims_)
+#define _pcre2_default_compile_context PCRE2_SUFFIX(_pcre2_default_compile_context_)
+#define _pcre2_default_convert_context PCRE2_SUFFIX(_pcre2_default_convert_context_)
+#define _pcre2_default_match_context   PCRE2_SUFFIX(_pcre2_default_match_context_)
+#define _pcre2_default_tables          PCRE2_SUFFIX(_pcre2_default_tables_)
+#if PCRE2_CODE_UNIT_WIDTH == 32
+#define _pcre2_dummy_ucd_record        PCRE2_SUFFIX(_pcre2_dummy_ucd_record_)
+#endif
+#define _pcre2_hspace_list             PCRE2_SUFFIX(_pcre2_hspace_list_)
+#define _pcre2_vspace_list             PCRE2_SUFFIX(_pcre2_vspace_list_)
+#define _pcre2_ucd_caseless_sets       PCRE2_SUFFIX(_pcre2_ucd_caseless_sets_)
+#define _pcre2_ucd_digit_sets          PCRE2_SUFFIX(_pcre2_ucd_digit_sets_)
+#define _pcre2_ucd_script_sets         PCRE2_SUFFIX(_pcre2_ucd_script_sets_)
+#define _pcre2_ucd_records             PCRE2_SUFFIX(_pcre2_ucd_records_)
+#define _pcre2_ucd_stage1              PCRE2_SUFFIX(_pcre2_ucd_stage1_)
+#define _pcre2_ucd_stage2              PCRE2_SUFFIX(_pcre2_ucd_stage2_)
+#define _pcre2_ucp_gbtable             PCRE2_SUFFIX(_pcre2_ucp_gbtable_)
+#define _pcre2_ucp_gentype             PCRE2_SUFFIX(_pcre2_ucp_gentype_)
+#define _pcre2_ucp_typerange           PCRE2_SUFFIX(_pcre2_ucp_typerange_)
+#define _pcre2_unicode_version         PCRE2_SUFFIX(_pcre2_unicode_version_)
+#define _pcre2_utt                     PCRE2_SUFFIX(_pcre2_utt_)
+#define _pcre2_utt_names               PCRE2_SUFFIX(_pcre2_utt_names_)
+#define _pcre2_utt_size                PCRE2_SUFFIX(_pcre2_utt_size_)
+
+extern const uint8_t                   PRIV(OP_lengths)[];
+extern const uint32_t                  PRIV(callout_end_delims)[];
+extern const uint32_t                  PRIV(callout_start_delims)[];
+extern const pcre2_compile_context     PRIV(default_compile_context);
+extern const pcre2_convert_context     PRIV(default_convert_context);
+extern const pcre2_match_context       PRIV(default_match_context);
+extern const uint8_t                   PRIV(default_tables)[];
+extern const uint32_t                  PRIV(hspace_list)[];
+extern const uint32_t                  PRIV(vspace_list)[];
+extern const uint32_t                  PRIV(ucd_caseless_sets)[];
+extern const uint32_t                  PRIV(ucd_digit_sets)[];
+extern const uint8_t                   PRIV(ucd_script_sets)[];
+extern const ucd_record                PRIV(ucd_records)[];
+#if PCRE2_CODE_UNIT_WIDTH == 32
+extern const ucd_record                PRIV(dummy_ucd_record)[];
+#endif
+extern const uint16_t                  PRIV(ucd_stage1)[];
+extern const uint16_t                  PRIV(ucd_stage2)[];
+extern const uint32_t                  PRIV(ucp_gbtable)[];
+extern const uint32_t                  PRIV(ucp_gentype)[];
+#ifdef SUPPORT_JIT
+extern const int                       PRIV(ucp_typerange)[];
+#endif
+extern const char                     *PRIV(unicode_version);
+extern const ucp_type_table            PRIV(utt)[];
+extern const char                      PRIV(utt_names)[];
+extern const size_t                    PRIV(utt_size);
+
+/* Mode-dependent macros and hidden and private structures are defined in a
+separate file so that pcre2test can include them at all supported widths. When
+compiling the library, PCRE2_CODE_UNIT_WIDTH will be defined, and we can
+include them at the appropriate width, after setting up suffix macros for the
+private structures. */
+
+#define branch_chain                 PCRE2_SUFFIX(branch_chain_)
+#define compile_block                PCRE2_SUFFIX(compile_block_)
+#define dfa_match_block              PCRE2_SUFFIX(dfa_match_block_)
+#define match_block                  PCRE2_SUFFIX(match_block_)
+#define named_group                  PCRE2_SUFFIX(named_group_)
+
+#include "pcre2_intmodedep.h"
+
+/* Private "external" functions. These are internal functions that are called
+from modules other than the one in which they are defined. They have to be
+"external" in the C sense, but are not part of the PCRE2 public API. They are
+not referenced from pcre2test, and must not be defined when no code unit width
+is available. */
+
+#define _pcre2_auto_possessify       PCRE2_SUFFIX(_pcre2_auto_possessify_)
+#define _pcre2_check_escape          PCRE2_SUFFIX(_pcre2_check_escape_)
+#define _pcre2_extuni                PCRE2_SUFFIX(_pcre2_extuni_)
+#define _pcre2_find_bracket          PCRE2_SUFFIX(_pcre2_find_bracket_)
+#define _pcre2_is_newline            PCRE2_SUFFIX(_pcre2_is_newline_)
+#define _pcre2_jit_free_rodata       PCRE2_SUFFIX(_pcre2_jit_free_rodata_)
+#define _pcre2_jit_free              PCRE2_SUFFIX(_pcre2_jit_free_)
+#define _pcre2_jit_get_size          PCRE2_SUFFIX(_pcre2_jit_get_size_)
+#define _pcre2_jit_get_target        PCRE2_SUFFIX(_pcre2_jit_get_target_)
+#define _pcre2_memctl_malloc         PCRE2_SUFFIX(_pcre2_memctl_malloc_)
+#define _pcre2_ord2utf               PCRE2_SUFFIX(_pcre2_ord2utf_)
+#define _pcre2_script_run            PCRE2_SUFFIX(_pcre2_script_run_)
+#define _pcre2_strcmp                PCRE2_SUFFIX(_pcre2_strcmp_)
+#define _pcre2_strcmp_c8             PCRE2_SUFFIX(_pcre2_strcmp_c8_)
+#define _pcre2_strcpy_c8             PCRE2_SUFFIX(_pcre2_strcpy_c8_)
+#define _pcre2_strlen                PCRE2_SUFFIX(_pcre2_strlen_)
+#define _pcre2_strncmp               PCRE2_SUFFIX(_pcre2_strncmp_)
+#define _pcre2_strncmp_c8            PCRE2_SUFFIX(_pcre2_strncmp_c8_)
+#define _pcre2_study                 PCRE2_SUFFIX(_pcre2_study_)
+#define _pcre2_valid_utf             PCRE2_SUFFIX(_pcre2_valid_utf_)
+#define _pcre2_was_newline           PCRE2_SUFFIX(_pcre2_was_newline_)
+#define _pcre2_xclass                PCRE2_SUFFIX(_pcre2_xclass_)
+
+extern int          _pcre2_auto_possessify(PCRE2_UCHAR *,
+                      const compile_block *);
+extern int          _pcre2_check_escape(PCRE2_SPTR *, PCRE2_SPTR, uint32_t *,
+                      int *, uint32_t, uint32_t, BOOL, compile_block *);
+extern PCRE2_SPTR   _pcre2_extuni(uint32_t, PCRE2_SPTR, PCRE2_SPTR, PCRE2_SPTR,
+                      BOOL, int *);
+extern PCRE2_SPTR   _pcre2_find_bracket(PCRE2_SPTR, BOOL, int);
+extern BOOL         _pcre2_is_newline(PCRE2_SPTR, uint32_t, PCRE2_SPTR,
+                      uint32_t *, BOOL);
+extern void         _pcre2_jit_free_rodata(void *, void *);
+extern void         _pcre2_jit_free(void *, pcre2_memctl *);
+extern size_t       _pcre2_jit_get_size(void *);
+const char *        _pcre2_jit_get_target(void);
+extern void *       _pcre2_memctl_malloc(size_t, pcre2_memctl *);
+extern unsigned int _pcre2_ord2utf(uint32_t, PCRE2_UCHAR *);
+extern BOOL         _pcre2_script_run(PCRE2_SPTR, PCRE2_SPTR, BOOL);
+extern int          _pcre2_strcmp(PCRE2_SPTR, PCRE2_SPTR);
+extern int          _pcre2_strcmp_c8(PCRE2_SPTR, const char *);
+extern PCRE2_SIZE   _pcre2_strcpy_c8(PCRE2_UCHAR *, const char *);
+extern PCRE2_SIZE   _pcre2_strlen(PCRE2_SPTR);
+extern int          _pcre2_strncmp(PCRE2_SPTR, PCRE2_SPTR, size_t);
+extern int          _pcre2_strncmp_c8(PCRE2_SPTR, const char *, size_t);
+extern int          _pcre2_study(pcre2_real_code *);
+extern int          _pcre2_valid_utf(PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE *);
+extern BOOL         _pcre2_was_newline(PCRE2_SPTR, uint32_t, PCRE2_SPTR,
+                      uint32_t *, BOOL);
+extern BOOL         _pcre2_xclass(uint32_t, PCRE2_SPTR, BOOL);
+
+/* This function is needed only when memmove() is not available. */
+
+#if !defined(VPCOMPAT) && !defined(HAVE_MEMMOVE)
+#define _pcre2_memmove               PCRE2_SUFFIX(_pcre2_memmove)
+extern void *       _pcre2_memmove(void *, const void *, size_t);
+#endif
+
+#endif  /* PCRE2_CODE_UNIT_WIDTH */
+#endif  /* PCRE2_INTERNAL_H_IDEMPOTENT_GUARD */
+
+/* End of pcre2_internal.h */
diff --git a/src/c/pcre2/src/pcre2_intmodedep.h b/src/c/pcre2/src/pcre2_intmodedep.h
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_intmodedep.h
@@ -0,0 +1,923 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains mode-dependent macro and structure definitions. The
+file is #included by pcre2_internal.h if PCRE2_CODE_UNIT_WIDTH is defined.
+These mode-dependent items are kept in a separate file so that they can also be
+#included multiple times for different code unit widths by pcre2test in order
+to have access to the hidden structures at all supported widths.
+
+Some of the mode-dependent macros are required at different widths for
+different parts of the pcre2test code (in particular, the included
+pcre_printint.c file). We undefine them here so that they can be re-defined for
+multiple inclusions. Not all of these are used in pcre2test, but it's easier
+just to undefine them all. */
+
+#undef ACROSSCHAR
+#undef BACKCHAR
+#undef BYTES2CU
+#undef CHMAX_255
+#undef CU2BYTES
+#undef FORWARDCHAR
+#undef FORWARDCHARTEST
+#undef GET
+#undef GET2
+#undef GETCHAR
+#undef GETCHARINC
+#undef GETCHARINCTEST
+#undef GETCHARLEN
+#undef GETCHARLENTEST
+#undef GETCHARTEST
+#undef GET_EXTRALEN
+#undef HAS_EXTRALEN
+#undef IMM2_SIZE
+#undef MAX_255
+#undef MAX_MARK
+#undef MAX_PATTERN_SIZE
+#undef MAX_UTF_SINGLE_CU
+#undef NOT_FIRSTCU
+#undef PUT
+#undef PUT2
+#undef PUT2INC
+#undef PUTCHAR
+#undef PUTINC
+#undef TABLE_GET
+
+
+
+/* -------------------------- MACROS ----------------------------- */
+
+/* PCRE keeps offsets in its compiled code as at least 16-bit quantities
+(always stored in big-endian order in 8-bit mode) by default. These are used,
+for example, to link from the start of a subpattern to its alternatives and its
+end. The use of 16 bits per offset limits the size of an 8-bit compiled regex
+to around 64K, which is big enough for almost everybody. However, I received a
+request for an even bigger limit. For this reason, and also to make the code
+easier to maintain, the storing and loading of offsets from the compiled code
+unit string is now handled by the macros that are defined here.
+
+The macros are controlled by the value of LINK_SIZE. This defaults to 2, but
+values of 3 or 4 are also supported. */
+
+/* ------------------- 8-bit support  ------------------ */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+
+#if LINK_SIZE == 2
+#define PUT(a,n,d)   \
+  (a[n] = (PCRE2_UCHAR)((d) >> 8)), \
+  (a[(n)+1] = (PCRE2_UCHAR)((d) & 255))
+#define GET(a,n) \
+  (unsigned int)(((a)[n] << 8) | (a)[(n)+1])
+#define MAX_PATTERN_SIZE (1 << 16)
+
+#elif LINK_SIZE == 3
+#define PUT(a,n,d)       \
+  (a[n] = (PCRE2_UCHAR)((d) >> 16)),    \
+  (a[(n)+1] = (PCRE2_UCHAR)((d) >> 8)), \
+  (a[(n)+2] = (PCRE2_UCHAR)((d) & 255))
+#define GET(a,n) \
+  (unsigned int)(((a)[n] << 16) | ((a)[(n)+1] << 8) | (a)[(n)+2])
+#define MAX_PATTERN_SIZE (1 << 24)
+
+#elif LINK_SIZE == 4
+#define PUT(a,n,d)        \
+  (a[n] = (PCRE2_UCHAR)((d) >> 24)),     \
+  (a[(n)+1] = (PCRE2_UCHAR)((d) >> 16)), \
+  (a[(n)+2] = (PCRE2_UCHAR)((d) >> 8)),  \
+  (a[(n)+3] = (PCRE2_UCHAR)((d) & 255))
+#define GET(a,n) \
+  (unsigned int)(((a)[n] << 24) | ((a)[(n)+1] << 16) | ((a)[(n)+2] << 8) | (a)[(n)+3])
+#define MAX_PATTERN_SIZE (1 << 30)   /* Keep it positive */
+
+#else
+#error LINK_SIZE must be 2, 3, or 4
+#endif
+
+
+/* ------------------- 16-bit support  ------------------ */
+
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+
+#if LINK_SIZE == 2
+#undef LINK_SIZE
+#define LINK_SIZE 1
+#define PUT(a,n,d)   \
+  (a[n] = (PCRE2_UCHAR)(d))
+#define GET(a,n) \
+  (a[n])
+#define MAX_PATTERN_SIZE (1 << 16)
+
+#elif LINK_SIZE == 3 || LINK_SIZE == 4
+#undef LINK_SIZE
+#define LINK_SIZE 2
+#define PUT(a,n,d)   \
+  (a[n] = (PCRE2_UCHAR)((d) >> 16)), \
+  (a[(n)+1] = (PCRE2_UCHAR)((d) & 65535))
+#define GET(a,n) \
+  (unsigned int)(((a)[n] << 16) | (a)[(n)+1])
+#define MAX_PATTERN_SIZE (1 << 30)  /* Keep it positive */
+
+#else
+#error LINK_SIZE must be 2, 3, or 4
+#endif
+
+
+/* ------------------- 32-bit support  ------------------ */
+
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+#undef LINK_SIZE
+#define LINK_SIZE 1
+#define PUT(a,n,d)   \
+  (a[n] = (d))
+#define GET(a,n) \
+  (a[n])
+#define MAX_PATTERN_SIZE (1 << 30)  /* Keep it positive */
+
+#else
+#error Unsupported compiling mode
+#endif
+
+
+/* --------------- Other mode-specific macros ----------------- */
+
+/* PCRE uses some other (at least) 16-bit quantities that do not change when
+the size of offsets changes. There are used for repeat counts and for other
+things such as capturing parenthesis numbers in back references.
+
+Define the number of code units required to hold a 16-bit count/offset, and
+macros to load and store such a value. For reasons that I do not understand,
+the expression in the 8-bit GET2 macro is treated by gcc as a signed
+expression, even when a is declared as unsigned. It seems that any kind of
+arithmetic results in a signed value. Hence the cast. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define IMM2_SIZE 2
+#define GET2(a,n) (unsigned int)(((a)[n] << 8) | (a)[(n)+1])
+#define PUT2(a,n,d) a[n] = (d) >> 8, a[(n)+1] = (d) & 255
+
+#else  /* Code units are 16 or 32 bits */
+#define IMM2_SIZE 1
+#define GET2(a,n) a[n]
+#define PUT2(a,n,d) a[n] = d
+#endif
+
+/* Other macros that are different for 8-bit mode. The MAX_255 macro checks
+whether its argument, which is assumed to be one code unit, is less than 256.
+The CHMAX_255 macro does not assume one code unit. The maximum length of a MARK
+name must fit in one code unit; currently it is set to 255 or 65535. The
+TABLE_GET macro is used to access elements of tables containing exactly 256
+items. Its argument is a code unit. When code points can be greater than 255, a
+check is needed before accessing these tables. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define MAX_255(c) TRUE
+#define MAX_MARK ((1u << 8) - 1)
+#define TABLE_GET(c, table, default) ((table)[c])
+#ifdef SUPPORT_UNICODE
+#define SUPPORT_WIDE_CHARS
+#define CHMAX_255(c) ((c) <= 255u)
+#else
+#define CHMAX_255(c) TRUE
+#endif  /* SUPPORT_UNICODE */
+
+#else  /* Code units are 16 or 32 bits */
+#define CHMAX_255(c) ((c) <= 255u)
+#define MAX_255(c) ((c) <= 255u)
+#define MAX_MARK ((1u << 16) - 1)
+#define SUPPORT_WIDE_CHARS
+#define TABLE_GET(c, table, default) (MAX_255(c)? ((table)[c]):(default))
+#endif
+
+
+/* ----------------- Character-handling macros ----------------- */
+
+/* There is a proposed future special "UTF-21" mode, in which only the lowest
+21 bits of a 32-bit character are interpreted as UTF, with the remaining 11
+high-order bits available to the application for other uses. In preparation for
+the future implementation of this mode, there are macros that load a data item
+and, if in this special mode, mask it to 21 bits. These macros all have names
+starting with UCHAR21. In all other modes, including the normal 32-bit
+library, the macros all have the same simple definitions. When the new mode is
+implemented, it is expected that these definitions will be varied appropriately
+using #ifdef when compiling the library that supports the special mode. */
+
+#define UCHAR21(eptr)        (*(eptr))
+#define UCHAR21TEST(eptr)    (*(eptr))
+#define UCHAR21INC(eptr)     (*(eptr)++)
+#define UCHAR21INCTEST(eptr) (*(eptr)++)
+
+/* When UTF encoding is being used, a character is no longer just a single
+byte in 8-bit mode or a single short in 16-bit mode. The macros for character
+handling generate simple sequences when used in the basic mode, and more
+complicated ones for UTF characters. GETCHARLENTEST and other macros are not
+used when UTF is not supported. To make sure they can never even appear when
+UTF support is omitted, we don't even define them. */
+
+#ifndef SUPPORT_UNICODE
+
+/* #define MAX_UTF_SINGLE_CU */
+/* #define HAS_EXTRALEN(c) */
+/* #define GET_EXTRALEN(c) */
+/* #define NOT_FIRSTCU(c) */
+#define GETCHAR(c, eptr) c = *eptr;
+#define GETCHARTEST(c, eptr) c = *eptr;
+#define GETCHARINC(c, eptr) c = *eptr++;
+#define GETCHARINCTEST(c, eptr) c = *eptr++;
+#define GETCHARLEN(c, eptr, len) c = *eptr;
+#define PUTCHAR(c, p) (*p = c, 1)
+/* #define GETCHARLENTEST(c, eptr, len) */
+/* #define BACKCHAR(eptr) */
+/* #define FORWARDCHAR(eptr) */
+/* #define FORWARCCHARTEST(eptr,end) */
+/* #define ACROSSCHAR(condition, eptr, action) */
+
+#else   /* SUPPORT_UNICODE */
+
+/* ------------------- 8-bit support  ------------------ */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define MAYBE_UTF_MULTI          /* UTF chars may use multiple code units */
+
+/* The largest UTF code point that can be encoded as a single code unit. */
+
+#define MAX_UTF_SINGLE_CU 127
+
+/* Tests whether the code point needs extra characters to decode. */
+
+#define HAS_EXTRALEN(c) HASUTF8EXTRALEN(c)
+
+/* Returns with the additional number of characters if IS_MULTICHAR(c) is TRUE.
+Otherwise it has an undefined behaviour. */
+
+#define GET_EXTRALEN(c) (PRIV(utf8_table4)[(c) & 0x3fu])
+
+/* Returns TRUE, if the given value is not the first code unit of a UTF
+sequence. */
+
+#define NOT_FIRSTCU(c) (((c) & 0xc0u) == 0x80u)
+
+/* Get the next UTF-8 character, not advancing the pointer. This is called when
+we know we are in UTF-8 mode. */
+
+#define GETCHAR(c, eptr) \
+  c = *eptr; \
+  if (c >= 0xc0u) GETUTF8(c, eptr);
+
+/* Get the next UTF-8 character, testing for UTF-8 mode, and not advancing the
+pointer. */
+
+#define GETCHARTEST(c, eptr) \
+  c = *eptr; \
+  if (utf && c >= 0xc0u) GETUTF8(c, eptr);
+
+/* Get the next UTF-8 character, advancing the pointer. This is called when we
+know we are in UTF-8 mode. */
+
+#define GETCHARINC(c, eptr) \
+  c = *eptr++; \
+  if (c >= 0xc0u) GETUTF8INC(c, eptr);
+
+/* Get the next character, testing for UTF-8 mode, and advancing the pointer.
+This is called when we don't know if we are in UTF-8 mode. */
+
+#define GETCHARINCTEST(c, eptr) \
+  c = *eptr++; \
+  if (utf && c >= 0xc0u) GETUTF8INC(c, eptr);
+
+/* Get the next UTF-8 character, not advancing the pointer, incrementing length
+if there are extra bytes. This is called when we know we are in UTF-8 mode. */
+
+#define GETCHARLEN(c, eptr, len) \
+  c = *eptr; \
+  if (c >= 0xc0u) GETUTF8LEN(c, eptr, len);
+
+/* Get the next UTF-8 character, testing for UTF-8 mode, not advancing the
+pointer, incrementing length if there are extra bytes. This is called when we
+do not know if we are in UTF-8 mode. */
+
+#define GETCHARLENTEST(c, eptr, len) \
+  c = *eptr; \
+  if (utf && c >= 0xc0u) GETUTF8LEN(c, eptr, len);
+
+/* If the pointer is not at the start of a character, move it back until
+it is. This is called only in UTF-8 mode - we don't put a test within the macro
+because almost all calls are already within a block of UTF-8 only code. */
+
+#define BACKCHAR(eptr) while((*eptr & 0xc0u) == 0x80u) eptr--
+
+/* Same as above, just in the other direction. */
+#define FORWARDCHAR(eptr) while((*eptr & 0xc0u) == 0x80u) eptr++
+#define FORWARDCHARTEST(eptr,end) while(eptr < end && (*eptr & 0xc0u) == 0x80u) eptr++
+
+/* Same as above, but it allows a fully customizable form. */
+#define ACROSSCHAR(condition, eptr, action) \
+  while((condition) && ((*eptr) & 0xc0u) == 0x80u) action
+
+/* Deposit a character into memory, returning the number of code units. */
+
+#define PUTCHAR(c, p) ((utf && c > MAX_UTF_SINGLE_CU)? \
+  PRIV(ord2utf)(c,p) : (*p = c, 1))
+
+
+/* ------------------- 16-bit support  ------------------ */
+
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+#define MAYBE_UTF_MULTI          /* UTF chars may use multiple code units */
+
+/* The largest UTF code point that can be encoded as a single code unit. */
+
+#define MAX_UTF_SINGLE_CU 65535
+
+/* Tests whether the code point needs extra characters to decode. */
+
+#define HAS_EXTRALEN(c) (((c) & 0xfc00u) == 0xd800u)
+
+/* Returns with the additional number of characters if IS_MULTICHAR(c) is TRUE.
+Otherwise it has an undefined behaviour. */
+
+#define GET_EXTRALEN(c) 1
+
+/* Returns TRUE, if the given value is not the first code unit of a UTF
+sequence. */
+
+#define NOT_FIRSTCU(c) (((c) & 0xfc00u) == 0xdc00u)
+
+/* Base macro to pick up the low surrogate of a UTF-16 character, not
+advancing the pointer. */
+
+#define GETUTF16(c, eptr) \
+   { c = (((c & 0x3ffu) << 10) | (eptr[1] & 0x3ffu)) + 0x10000u; }
+
+/* Get the next UTF-16 character, not advancing the pointer. This is called when
+we know we are in UTF-16 mode. */
+
+#define GETCHAR(c, eptr) \
+  c = *eptr; \
+  if ((c & 0xfc00u) == 0xd800u) GETUTF16(c, eptr);
+
+/* Get the next UTF-16 character, testing for UTF-16 mode, and not advancing the
+pointer. */
+
+#define GETCHARTEST(c, eptr) \
+  c = *eptr; \
+  if (utf && (c & 0xfc00u) == 0xd800u) GETUTF16(c, eptr);
+
+/* Base macro to pick up the low surrogate of a UTF-16 character, advancing
+the pointer. */
+
+#define GETUTF16INC(c, eptr) \
+   { c = (((c & 0x3ffu) << 10) | (*eptr++ & 0x3ffu)) + 0x10000u; }
+
+/* Get the next UTF-16 character, advancing the pointer. This is called when we
+know we are in UTF-16 mode. */
+
+#define GETCHARINC(c, eptr) \
+  c = *eptr++; \
+  if ((c & 0xfc00u) == 0xd800u) GETUTF16INC(c, eptr);
+
+/* Get the next character, testing for UTF-16 mode, and advancing the pointer.
+This is called when we don't know if we are in UTF-16 mode. */
+
+#define GETCHARINCTEST(c, eptr) \
+  c = *eptr++; \
+  if (utf && (c & 0xfc00u) == 0xd800u) GETUTF16INC(c, eptr);
+
+/* Base macro to pick up the low surrogate of a UTF-16 character, not
+advancing the pointer, incrementing the length. */
+
+#define GETUTF16LEN(c, eptr, len) \
+   { c = (((c & 0x3ffu) << 10) | (eptr[1] & 0x3ffu)) + 0x10000u; len++; }
+
+/* Get the next UTF-16 character, not advancing the pointer, incrementing
+length if there is a low surrogate. This is called when we know we are in
+UTF-16 mode. */
+
+#define GETCHARLEN(c, eptr, len) \
+  c = *eptr; \
+  if ((c & 0xfc00u) == 0xd800u) GETUTF16LEN(c, eptr, len);
+
+/* Get the next UTF-816character, testing for UTF-16 mode, not advancing the
+pointer, incrementing length if there is a low surrogate. This is called when
+we do not know if we are in UTF-16 mode. */
+
+#define GETCHARLENTEST(c, eptr, len) \
+  c = *eptr; \
+  if (utf && (c & 0xfc00u) == 0xd800u) GETUTF16LEN(c, eptr, len);
+
+/* If the pointer is not at the start of a character, move it back until
+it is. This is called only in UTF-16 mode - we don't put a test within the
+macro because almost all calls are already within a block of UTF-16 only
+code. */
+
+#define BACKCHAR(eptr) if ((*eptr & 0xfc00u) == 0xdc00u) eptr--
+
+/* Same as above, just in the other direction. */
+#define FORWARDCHAR(eptr) if ((*eptr & 0xfc00u) == 0xdc00u) eptr++
+#define FORWARDCHARTEST(eptr,end) if (eptr < end && (*eptr & 0xfc00u) == 0xdc00u) eptr++
+
+/* Same as above, but it allows a fully customizable form. */
+#define ACROSSCHAR(condition, eptr, action) \
+  if ((condition) && ((*eptr) & 0xfc00u) == 0xdc00u) action
+
+/* Deposit a character into memory, returning the number of code units. */
+
+#define PUTCHAR(c, p) ((utf && c > MAX_UTF_SINGLE_CU)? \
+  PRIV(ord2utf)(c,p) : (*p = c, 1))
+
+
+/* ------------------- 32-bit support  ------------------ */
+
+#else
+
+/* These are trivial for the 32-bit library, since all UTF-32 characters fit
+into one PCRE2_UCHAR unit. */
+
+#define MAX_UTF_SINGLE_CU (0x10ffffu)
+#define HAS_EXTRALEN(c) (0)
+#define GET_EXTRALEN(c) (0)
+#define NOT_FIRSTCU(c) (0)
+
+/* Get the next UTF-32 character, not advancing the pointer. This is called when
+we know we are in UTF-32 mode. */
+
+#define GETCHAR(c, eptr) \
+  c = *(eptr);
+
+/* Get the next UTF-32 character, testing for UTF-32 mode, and not advancing the
+pointer. */
+
+#define GETCHARTEST(c, eptr) \
+  c = *(eptr);
+
+/* Get the next UTF-32 character, advancing the pointer. This is called when we
+know we are in UTF-32 mode. */
+
+#define GETCHARINC(c, eptr) \
+  c = *((eptr)++);
+
+/* Get the next character, testing for UTF-32 mode, and advancing the pointer.
+This is called when we don't know if we are in UTF-32 mode. */
+
+#define GETCHARINCTEST(c, eptr) \
+  c = *((eptr)++);
+
+/* Get the next UTF-32 character, not advancing the pointer, not incrementing
+length (since all UTF-32 is of length 1). This is called when we know we are in
+UTF-32 mode. */
+
+#define GETCHARLEN(c, eptr, len) \
+  GETCHAR(c, eptr)
+
+/* Get the next UTF-32character, testing for UTF-32 mode, not advancing the
+pointer, not incrementing the length (since all UTF-32 is of length 1).
+This is called when we do not know if we are in UTF-32 mode. */
+
+#define GETCHARLENTEST(c, eptr, len) \
+  GETCHARTEST(c, eptr)
+
+/* If the pointer is not at the start of a character, move it back until
+it is. This is called only in UTF-32 mode - we don't put a test within the
+macro because almost all calls are already within a block of UTF-32 only
+code.
+
+These are all no-ops since all UTF-32 characters fit into one pcre_uchar. */
+
+#define BACKCHAR(eptr) do { } while (0)
+
+/* Same as above, just in the other direction. */
+
+#define FORWARDCHAR(eptr) do { } while (0)
+#define FORWARDCHARTEST(eptr,end) do { } while (0)
+
+/* Same as above, but it allows a fully customizable form. */
+
+#define ACROSSCHAR(condition, eptr, action) do { } while (0)
+
+/* Deposit a character into memory, returning the number of code units. */
+
+#define PUTCHAR(c, p) (*p = c, 1)
+
+#endif  /* UTF-32 character handling */
+#endif  /* SUPPORT_UNICODE */
+
+
+/* Mode-dependent macros that have the same definition in all modes. */
+
+#define CU2BYTES(x)     ((x)*((PCRE2_CODE_UNIT_WIDTH/8)))
+#define BYTES2CU(x)     ((x)/((PCRE2_CODE_UNIT_WIDTH/8)))
+#define PUTINC(a,n,d)   PUT(a,n,d), a += LINK_SIZE
+#define PUT2INC(a,n,d)  PUT2(a,n,d), a += IMM2_SIZE
+
+
+/* ----------------------- HIDDEN STRUCTURES ----------------------------- */
+
+/* NOTE: All these structures *must* start with a pcre2_memctl structure. The
+code that uses them is simpler because it assumes this. */
+
+/* The real general context structure. At present it holds only data for custom
+memory control. */
+
+typedef struct pcre2_real_general_context {
+  pcre2_memctl memctl;
+} pcre2_real_general_context;
+
+/* The real compile context structure */
+
+typedef struct pcre2_real_compile_context {
+  pcre2_memctl memctl;
+  int (*stack_guard)(uint32_t, void *);
+  void *stack_guard_data;
+  const uint8_t *tables;
+  PCRE2_SIZE max_pattern_length;
+  uint16_t bsr_convention;
+  uint16_t newline_convention;
+  uint32_t parens_nest_limit;
+  uint32_t extra_options;
+} pcre2_real_compile_context;
+
+/* The real match context structure. */
+
+typedef struct pcre2_real_match_context {
+  pcre2_memctl memctl;
+#ifdef SUPPORT_JIT
+  pcre2_jit_callback jit_callback;
+  void *jit_callback_data;
+#endif
+  int    (*callout)(pcre2_callout_block *, void *);
+  void    *callout_data;
+  int    (*substitute_callout)(pcre2_substitute_callout_block *, void *);
+  void    *substitute_callout_data;
+  PCRE2_SIZE offset_limit;
+  uint32_t heap_limit;
+  uint32_t match_limit;
+  uint32_t depth_limit;
+} pcre2_real_match_context;
+
+/* The real convert context structure. */
+
+typedef struct pcre2_real_convert_context {
+  pcre2_memctl memctl;
+  uint32_t glob_separator;
+  uint32_t glob_escape;
+} pcre2_real_convert_context;
+
+/* The real compiled code structure. The type for the blocksize field is
+defined specially because it is required in pcre2_serialize_decode() when
+copying the size from possibly unaligned memory into a variable of the same
+type. Use a macro rather than a typedef to avoid compiler warnings when this
+file is included multiple times by pcre2test. LOOKBEHIND_MAX specifies the
+largest lookbehind that is supported. (OP_REVERSE in a pattern has a 16-bit
+argument in 8-bit and 16-bit modes, so we need no more than a 16-bit field
+here.) */
+
+#undef  CODE_BLOCKSIZE_TYPE
+#define CODE_BLOCKSIZE_TYPE size_t
+
+#undef  LOOKBEHIND_MAX
+#define LOOKBEHIND_MAX UINT16_MAX
+
+typedef struct pcre2_real_code {
+  pcre2_memctl memctl;            /* Memory control fields */
+  const uint8_t *tables;          /* The character tables */
+  void    *executable_jit;        /* Pointer to JIT code */
+  uint8_t  start_bitmap[32];      /* Bitmap for starting code unit < 256 */
+  CODE_BLOCKSIZE_TYPE blocksize;  /* Total (bytes) that was malloc-ed */
+  uint32_t magic_number;          /* Paranoid and endianness check */
+  uint32_t compile_options;       /* Options passed to pcre2_compile() */
+  uint32_t overall_options;       /* Options after processing the pattern */
+  uint32_t extra_options;         /* Taken from compile_context */
+  uint32_t flags;                 /* Various state flags */
+  uint32_t limit_heap;            /* Limit set in the pattern */
+  uint32_t limit_match;           /* Limit set in the pattern */
+  uint32_t limit_depth;           /* Limit set in the pattern */
+  uint32_t first_codeunit;        /* Starting code unit */
+  uint32_t last_codeunit;         /* This codeunit must be seen */
+  uint16_t bsr_convention;        /* What \R matches */
+  uint16_t newline_convention;    /* What is a newline? */
+  uint16_t max_lookbehind;        /* Longest lookbehind (characters) */
+  uint16_t minlength;             /* Minimum length of match */
+  uint16_t top_bracket;           /* Highest numbered group */
+  uint16_t top_backref;           /* Highest numbered back reference */
+  uint16_t name_entry_size;       /* Size (code units) of table entries */
+  uint16_t name_count;            /* Number of name entries in the table */
+} pcre2_real_code;
+
+/* The real match data structure. Define ovector as large as it can ever
+actually be so that array bound checkers don't grumble. Memory for this
+structure is obtained by calling pcre2_match_data_create(), which sets the size
+as the offset of ovector plus a pair of elements for each capturable string, so
+the size varies from call to call. As the maximum number of capturing
+subpatterns is 65535 we must allow for 65536 strings to include the overall
+match. (See also the heapframe structure below.) */
+
+typedef struct pcre2_real_match_data {
+  pcre2_memctl     memctl;
+  const pcre2_real_code *code;    /* The pattern used for the match */
+  PCRE2_SPTR       subject;       /* The subject that was matched */
+  PCRE2_SPTR       mark;          /* Pointer to last mark */
+  PCRE2_SIZE       leftchar;      /* Offset to leftmost code unit */
+  PCRE2_SIZE       rightchar;     /* Offset to rightmost code unit */
+  PCRE2_SIZE       startchar;     /* Offset to starting code unit */
+  uint8_t          matchedby;     /* Type of match (normal, JIT, DFA) */
+  uint8_t          flags;         /* Various flags */
+  uint16_t         oveccount;     /* Number of pairs */
+  int              rc;            /* The return code from the match */
+  PCRE2_SIZE       ovector[131072]; /* Must be last in the structure */
+} pcre2_real_match_data;
+
+
+/* ----------------------- PRIVATE STRUCTURES ----------------------------- */
+
+/* These structures are not needed for pcre2test. */
+
+#ifndef PCRE2_PCRE2TEST
+
+/* Structures for checking for mutual recursion when scanning compiled or
+parsed code. */
+
+typedef struct recurse_check {
+  struct recurse_check *prev;
+  PCRE2_SPTR group;
+} recurse_check;
+
+typedef struct parsed_recurse_check {
+  struct parsed_recurse_check *prev;
+  uint32_t *groupptr;
+} parsed_recurse_check;
+
+/* Structure for building a cache when filling in recursion offsets. */
+
+typedef struct recurse_cache {
+  PCRE2_SPTR group;
+  int groupnumber;
+} recurse_cache;
+
+/* Structure for maintaining a chain of pointers to the currently incomplete
+branches, for testing for left recursion while compiling. */
+
+typedef struct branch_chain {
+  struct branch_chain *outer;
+  PCRE2_UCHAR *current_branch;
+} branch_chain;
+
+/* Structure for building a list of named groups during the first pass of
+compiling. */
+
+typedef struct named_group {
+  PCRE2_SPTR   name;          /* Points to the name in the pattern */
+  uint32_t     number;        /* Group number */
+  uint16_t     length;        /* Length of the name */
+  uint16_t     isdup;         /* TRUE if a duplicate */
+} named_group;
+
+/* Structure for passing "static" information around between the functions
+doing the compiling, so that they are thread-safe. */
+
+typedef struct compile_block {
+  pcre2_real_compile_context *cx;  /* Points to the compile context */
+  const uint8_t *lcc;              /* Points to lower casing table */
+  const uint8_t *fcc;              /* Points to case-flipping table */
+  const uint8_t *cbits;            /* Points to character type table */
+  const uint8_t *ctypes;           /* Points to table of type maps */
+  PCRE2_SPTR start_workspace;      /* The start of working space */
+  PCRE2_SPTR start_code;           /* The start of the compiled code */
+  PCRE2_SPTR start_pattern;        /* The start of the pattern */
+  PCRE2_SPTR end_pattern;          /* The end of the pattern */
+  PCRE2_UCHAR *name_table;         /* The name/number table */
+  PCRE2_SIZE workspace_size;       /* Size of workspace */
+  PCRE2_SIZE small_ref_offset[10]; /* Offsets for \1 to \9 */
+  PCRE2_SIZE erroroffset;          /* Offset of error in pattern */
+  uint16_t names_found;            /* Number of entries so far */
+  uint16_t name_entry_size;        /* Size of each entry */
+  uint16_t parens_depth;           /* Depth of nested parentheses */
+  uint16_t assert_depth;           /* Depth of nested assertions */
+  open_capitem *open_caps;         /* Chain of open capture items */
+  named_group *named_groups;       /* Points to vector in pre-compile */
+  uint32_t named_group_list_size;  /* Number of entries in the list */
+  uint32_t external_options;       /* External (initial) options */
+  uint32_t external_flags;         /* External flag bits to be set */
+  uint32_t bracount;               /* Count of capturing parentheses */
+  uint32_t lastcapture;            /* Last capture encountered */
+  uint32_t *parsed_pattern;        /* Parsed pattern buffer */
+  uint32_t *parsed_pattern_end;    /* Parsed pattern should not get here */
+  uint32_t *groupinfo;             /* Group info vector */
+  uint32_t top_backref;            /* Maximum back reference */
+  uint32_t backref_map;            /* Bitmap of low back refs */
+  uint32_t nltype;                 /* Newline type */
+  uint32_t nllen;                  /* Newline string length */
+  uint32_t class_range_start;      /* Overall class range start */
+  uint32_t class_range_end;        /* Overall class range end */
+  PCRE2_UCHAR nl[4];               /* Newline string when fixed length */
+  int  max_lookbehind;             /* Maximum lookbehind (characters) */
+  int  req_varyopt;                /* "After variable item" flag for reqbyte */
+  BOOL had_accept;                 /* (*ACCEPT) encountered */
+  BOOL had_pruneorskip;            /* (*PRUNE) or (*SKIP) encountered */
+  BOOL had_recurse;                /* Had a recursion or subroutine call */
+  BOOL dupnames;                   /* Duplicate names exist */
+} compile_block;
+
+/* Structure for keeping the properties of the in-memory stack used
+by the JIT matcher. */
+
+typedef struct pcre2_real_jit_stack {
+  pcre2_memctl memctl;
+  void* stack;
+} pcre2_real_jit_stack;
+
+/* Structure for items in a linked list that represents an explicit recursive
+call within the pattern when running pcre_dfa_match(). */
+
+typedef struct dfa_recursion_info {
+  struct dfa_recursion_info *prevrec;
+  PCRE2_SPTR subject_position;
+  uint32_t group_num;
+} dfa_recursion_info;
+
+/* Structure for "stack" frames that are used for remembering backtracking
+positions during matching. As these are used in a vector, with the ovector item
+being extended, the size of the structure must be a multiple of PCRE2_SIZE. The
+only way to check this at compile time is to force an error by generating an
+array with a negative size. By putting this in a typedef (which is never used),
+we don't generate any code when all is well. */
+
+typedef struct heapframe {
+
+  /* The first set of fields are variables that have to be preserved over calls
+  to RRMATCH(), but which do not need to be copied to new frames. */
+
+  PCRE2_SPTR ecode;          /* The current position in the pattern */
+  PCRE2_SPTR temp_sptr[2];   /* Used for short-term PCRE_SPTR values */
+  PCRE2_SIZE length;         /* Used for character, string, or code lengths */
+  PCRE2_SIZE back_frame;     /* Amount to subtract on RRETURN */
+  PCRE2_SIZE temp_size;      /* Used for short-term PCRE2_SIZE values */
+  uint32_t rdepth;           /* "Recursion" depth */
+  uint32_t group_frame_type; /* Type information for group frames */
+  uint32_t temp_32[4];       /* Used for short-term 32-bit or BOOL values */
+  uint8_t return_id;         /* Where to go on in internal "return" */
+  uint8_t op;                /* Processing opcode */
+
+  /* At this point, the structure is 16-bit aligned. On most architectures
+  the alignment requirement for a pointer will ensure that the eptr field below
+  is 32-bit or 64-bit aligned. However, on m68k it is fine to have a pointer
+  that is 16-bit aligned. We must therefore ensure that what comes between here
+  and eptr is an odd multiple of 16 bits so as to get back into 32-bit
+  alignment. This happens naturally when PCRE2_UCHAR is 8 bits wide, but needs
+  fudges in the other cases. In the 32-bit case the padding comes first so that
+  the occu field itself is 32-bit aligned. Without the padding, this structure
+  is no longer a multiple of PCRE2_SIZE on m68k, and the check below fails. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+  PCRE2_UCHAR occu[6];       /* Used for other case code units */
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+  PCRE2_UCHAR occu[2];       /* Used for other case code units */
+  uint8_t unused[2];         /* Ensure 32-bit alignment (see above) */
+#else
+  uint8_t unused[2];         /* Ensure 32-bit alignment (see above) */
+  PCRE2_UCHAR occu[1];       /* Used for other case code units */
+#endif
+
+  /* The rest have to be copied from the previous frame whenever a new frame
+  becomes current. The final field is specified as a large vector so that
+  runtime array bound checks don't catch references to it. However, for any
+  specific call to pcre2_match() the memory allocated for each frame structure
+  allows for exactly the right size ovector for the number of capturing
+  parentheses. (See also the comment for pcre2_real_match_data above.) */
+
+  PCRE2_SPTR eptr;           /* MUST BE FIRST */
+  PCRE2_SPTR start_match;    /* Can be adjusted by \K */
+  PCRE2_SPTR mark;           /* Most recent mark on the success path */
+  uint32_t current_recurse;  /* Current (deepest) recursion number */
+  uint32_t capture_last;     /* Most recent capture */
+  PCRE2_SIZE last_group_offset;  /* Saved offset to most recent group frame */
+  PCRE2_SIZE offset_top;     /* Offset after highest capture */
+  PCRE2_SIZE ovector[131072]; /* Must be last in the structure */
+} heapframe;
+
+/* This typedef is a check that the size of the heapframe structure is a
+multiple of PCRE2_SIZE. See various comments above. */
+
+typedef char check_heapframe_size[
+  ((sizeof(heapframe) % sizeof(PCRE2_SIZE)) == 0)? (+1):(-1)];
+
+/* Structure for passing "static" information around between the functions
+doing traditional NFA matching (pcre2_match() and friends). */
+
+typedef struct match_block {
+  pcre2_memctl memctl;            /* For general use */
+  PCRE2_SIZE frame_vector_size;   /* Size of a backtracking frame */
+  heapframe *match_frames;        /* Points to vector of frames */
+  heapframe *match_frames_top;    /* Points after the end of the vector */
+  heapframe *stack_frames;        /* The original vector on the stack */
+  PCRE2_SIZE heap_limit;          /* As it says */
+  uint32_t match_limit;           /* As it says */
+  uint32_t match_limit_depth;     /* As it says */
+  uint32_t match_call_count;      /* Number of times a new frame is created */
+  BOOL hitend;                    /* Hit the end of the subject at some point */
+  BOOL hasthen;                   /* Pattern contains (*THEN) */
+  BOOL allowemptypartial;         /* Allow empty hard partial */
+  const uint8_t *lcc;             /* Points to lower casing table */
+  const uint8_t *fcc;             /* Points to case-flipping table */
+  const uint8_t *ctypes;          /* Points to table of type maps */
+  PCRE2_SIZE start_offset;        /* The start offset value */
+  PCRE2_SIZE end_offset_top;      /* Highwater mark at end of match */
+  uint16_t partial;               /* PARTIAL options */
+  uint16_t bsr_convention;        /* \R interpretation */
+  uint16_t name_count;            /* Number of names in name table */
+  uint16_t name_entry_size;       /* Size of entry in names table */
+  PCRE2_SPTR name_table;          /* Table of group names */
+  PCRE2_SPTR start_code;          /* For use when recursing */
+  PCRE2_SPTR start_subject;       /* Start of the subject string */
+  PCRE2_SPTR check_subject;       /* Where UTF-checked from */
+  PCRE2_SPTR end_subject;         /* End of the subject string */
+  PCRE2_SPTR end_match_ptr;       /* Subject position at end match */
+  PCRE2_SPTR start_used_ptr;      /* Earliest consulted character */
+  PCRE2_SPTR last_used_ptr;       /* Latest consulted character */
+  PCRE2_SPTR mark;                /* Mark pointer to pass back on success */
+  PCRE2_SPTR nomatch_mark;        /* Mark pointer to pass back on failure */
+  PCRE2_SPTR verb_ecode_ptr;      /* For passing back info */
+  PCRE2_SPTR verb_skip_ptr;       /* For passing back a (*SKIP) name */
+  uint32_t verb_current_recurse;  /* Current recurse when (*VERB) happens */
+  uint32_t moptions;              /* Match options */
+  uint32_t poptions;              /* Pattern options */
+  uint32_t skip_arg_count;        /* For counting SKIP_ARGs */
+  uint32_t ignore_skip_arg;       /* For re-run when SKIP arg name not found */
+  uint32_t nltype;                /* Newline type */
+  uint32_t nllen;                 /* Newline string length */
+  PCRE2_UCHAR nl[4];              /* Newline string when fixed */
+  pcre2_callout_block *cb;        /* Points to a callout block */
+  void  *callout_data;            /* To pass back to callouts */
+  int (*callout)(pcre2_callout_block *,void *);  /* Callout function or NULL */
+} match_block;
+
+/* A similar structure is used for the same purpose by the DFA matching
+functions. */
+
+typedef struct dfa_match_block {
+  pcre2_memctl memctl;            /* For general use */
+  PCRE2_SPTR start_code;          /* Start of the compiled pattern */
+  PCRE2_SPTR start_subject ;      /* Start of the subject string */
+  PCRE2_SPTR end_subject;         /* End of subject string */
+  PCRE2_SPTR start_used_ptr;      /* Earliest consulted character */
+  PCRE2_SPTR last_used_ptr;       /* Latest consulted character */
+  const uint8_t *tables;          /* Character tables */
+  PCRE2_SIZE start_offset;        /* The start offset value */
+  PCRE2_SIZE heap_limit;          /* As it says */
+  PCRE2_SIZE heap_used;           /* As it says */
+  uint32_t match_limit;           /* As it says */
+  uint32_t match_limit_depth;     /* As it says */
+  uint32_t match_call_count;      /* Number of calls of internal function */
+  uint32_t moptions;              /* Match options */
+  uint32_t poptions;              /* Pattern options */
+  uint32_t nltype;                /* Newline type */
+  uint32_t nllen;                 /* Newline string length */
+  BOOL allowemptypartial;         /* Allow empty hard partial */
+  PCRE2_UCHAR nl[4];              /* Newline string when fixed */
+  uint16_t bsr_convention;        /* \R interpretation */
+  pcre2_callout_block *cb;        /* Points to a callout block */
+  void *callout_data;             /* To pass back to callouts */
+  int (*callout)(pcre2_callout_block *,void *);  /* Callout function or NULL */
+  dfa_recursion_info *recursive;  /* Linked list of recursion data */
+} dfa_match_block;
+
+#endif  /* PCRE2_PCRE2TEST */
+
+/* End of pcre2_intmodedep.h */
diff --git a/src/c/pcre2/src/pcre2_jit_compile.c b/src/c/pcre2/src/pcre2_jit_compile.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_jit_compile.c
@@ -0,0 +1,14252 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+                    This module by Zoltan Herczeg
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2019 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+#ifdef SUPPORT_JIT
+
+/* All-in-one: Since we use the JIT compiler only from here,
+we just include it. This way we don't need to touch the build
+system files. */
+
+#define SLJIT_CONFIG_AUTO 1
+#define SLJIT_CONFIG_STATIC 1
+#define SLJIT_VERBOSE 0
+
+#ifdef PCRE2_DEBUG
+#define SLJIT_DEBUG 1
+#else
+#define SLJIT_DEBUG 0
+#endif
+
+#define SLJIT_MALLOC(size, allocator_data) pcre2_jit_malloc(size, allocator_data)
+#define SLJIT_FREE(ptr, allocator_data) pcre2_jit_free(ptr, allocator_data)
+
+static void * pcre2_jit_malloc(size_t size, void *allocator_data)
+{
+pcre2_memctl *allocator = ((pcre2_memctl*)allocator_data);
+return allocator->malloc(size, allocator->memory_data);
+}
+
+static void pcre2_jit_free(void *ptr, void *allocator_data)
+{
+pcre2_memctl *allocator = ((pcre2_memctl*)allocator_data);
+allocator->free(ptr, allocator->memory_data);
+}
+
+#include "sljit/sljitLir.c"
+
+#if defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED
+#error Unsupported architecture
+#endif
+
+/* Defines for debugging purposes. */
+
+/* 1 - Use unoptimized capturing brackets.
+   2 - Enable capture_last_ptr (includes option 1). */
+/* #define DEBUG_FORCE_UNOPTIMIZED_CBRAS 2 */
+
+/* 1 - Always have a control head. */
+/* #define DEBUG_FORCE_CONTROL_HEAD 1 */
+
+/* Allocate memory for the regex stack on the real machine stack.
+Fast, but limited size. */
+#define MACHINE_STACK_SIZE 32768
+
+/* Growth rate for stack allocated by the OS. Should be the multiply
+of page size. */
+#define STACK_GROWTH_RATE 8192
+
+/* Enable to check that the allocation could destroy temporaries. */
+#if defined SLJIT_DEBUG && SLJIT_DEBUG
+#define DESTROY_REGISTERS 1
+#endif
+
+/*
+Short summary about the backtracking mechanism empolyed by the jit code generator:
+
+The code generator follows the recursive nature of the PERL compatible regular
+expressions. The basic blocks of regular expressions are condition checkers
+whose execute different commands depending on the result of the condition check.
+The relationship between the operators can be horizontal (concatenation) and
+vertical (sub-expression) (See struct backtrack_common for more details).
+
+  'ab' - 'a' and 'b' regexps are concatenated
+  'a+' - 'a' is the sub-expression of the '+' operator
+
+The condition checkers are boolean (true/false) checkers. Machine code is generated
+for the checker itself and for the actions depending on the result of the checker.
+The 'true' case is called as the matching path (expected path), and the other is called as
+the 'backtrack' path. Branch instructions are expesive for all CPUs, so we avoid taken
+branches on the matching path.
+
+ Greedy star operator (*) :
+   Matching path: match happens.
+   Backtrack path: match failed.
+ Non-greedy star operator (*?) :
+   Matching path: no need to perform a match.
+   Backtrack path: match is required.
+
+The following example shows how the code generated for a capturing bracket
+with two alternatives. Let A, B, C, D are arbirary regular expressions, and
+we have the following regular expression:
+
+   A(B|C)D
+
+The generated code will be the following:
+
+ A matching path
+ '(' matching path (pushing arguments to the stack)
+ B matching path
+ ')' matching path (pushing arguments to the stack)
+ D matching path
+ return with successful match
+
+ D backtrack path
+ ')' backtrack path (If we arrived from "C" jump to the backtrack of "C")
+ B backtrack path
+ C expected path
+ jump to D matching path
+ C backtrack path
+ A backtrack path
+
+ Notice, that the order of backtrack code paths are the opposite of the fast
+ code paths. In this way the topmost value on the stack is always belong
+ to the current backtrack code path. The backtrack path must check
+ whether there is a next alternative. If so, it needs to jump back to
+ the matching path eventually. Otherwise it needs to clear out its own stack
+ frame and continue the execution on the backtrack code paths.
+*/
+
+/*
+Saved stack frames:
+
+Atomic blocks and asserts require reloading the values of private data
+when the backtrack mechanism performed. Because of OP_RECURSE, the data
+are not necessarly known in compile time, thus we need a dynamic restore
+mechanism.
+
+The stack frames are stored in a chain list, and have the following format:
+([ capturing bracket offset ][ start value ][ end value ])+ ... [ 0 ] [ previous head ]
+
+Thus we can restore the private data to a particular point in the stack.
+*/
+
+typedef struct jit_arguments {
+  /* Pointers first. */
+  struct sljit_stack *stack;
+  PCRE2_SPTR str;
+  PCRE2_SPTR begin;
+  PCRE2_SPTR end;
+  pcre2_match_data *match_data;
+  PCRE2_SPTR startchar_ptr;
+  PCRE2_UCHAR *mark_ptr;
+  int (*callout)(pcre2_callout_block *, void *);
+  void *callout_data;
+  /* Everything else after. */
+  sljit_uw offset_limit;
+  sljit_u32 limit_match;
+  sljit_u32 oveccount;
+  sljit_u32 options;
+} jit_arguments;
+
+#define JIT_NUMBER_OF_COMPILE_MODES 3
+
+typedef struct executable_functions {
+  void *executable_funcs[JIT_NUMBER_OF_COMPILE_MODES];
+  void *read_only_data_heads[JIT_NUMBER_OF_COMPILE_MODES];
+  sljit_uw executable_sizes[JIT_NUMBER_OF_COMPILE_MODES];
+  sljit_u32 top_bracket;
+  sljit_u32 limit_match;
+} executable_functions;
+
+typedef struct jump_list {
+  struct sljit_jump *jump;
+  struct jump_list *next;
+} jump_list;
+
+typedef struct stub_list {
+  struct sljit_jump *start;
+  struct sljit_label *quit;
+  struct stub_list *next;
+} stub_list;
+
+enum frame_types {
+  no_frame = -1,
+  no_stack = -2
+};
+
+enum control_types {
+  type_mark = 0,
+  type_then_trap = 1
+};
+
+enum  early_fail_types {
+  type_skip = 0,
+  type_fail = 1,
+  type_fail_range = 2
+};
+
+typedef int (SLJIT_FUNC *jit_function)(jit_arguments *args);
+
+/* The following structure is the key data type for the recursive
+code generator. It is allocated by compile_matchingpath, and contains
+the arguments for compile_backtrackingpath. Must be the first member
+of its descendants. */
+typedef struct backtrack_common {
+  /* Concatenation stack. */
+  struct backtrack_common *prev;
+  jump_list *nextbacktracks;
+  /* Internal stack (for component operators). */
+  struct backtrack_common *top;
+  jump_list *topbacktracks;
+  /* Opcode pointer. */
+  PCRE2_SPTR cc;
+} backtrack_common;
+
+typedef struct assert_backtrack {
+  backtrack_common common;
+  jump_list *condfailed;
+  /* Less than 0 if a frame is not needed. */
+  int framesize;
+  /* Points to our private memory word on the stack. */
+  int private_data_ptr;
+  /* For iterators. */
+  struct sljit_label *matchingpath;
+} assert_backtrack;
+
+typedef struct bracket_backtrack {
+  backtrack_common common;
+  /* Where to coninue if an alternative is successfully matched. */
+  struct sljit_label *alternative_matchingpath;
+  /* For rmin and rmax iterators. */
+  struct sljit_label *recursive_matchingpath;
+  /* For greedy ? operator. */
+  struct sljit_label *zero_matchingpath;
+  /* Contains the branches of a failed condition. */
+  union {
+    /* Both for OP_COND, OP_SCOND. */
+    jump_list *condfailed;
+    assert_backtrack *assert;
+    /* For OP_ONCE. Less than 0 if not needed. */
+    int framesize;
+    /* For brackets with >3 alternatives. */
+    struct sljit_put_label *matching_put_label;
+  } u;
+  /* Points to our private memory word on the stack. */
+  int private_data_ptr;
+} bracket_backtrack;
+
+typedef struct bracketpos_backtrack {
+  backtrack_common common;
+  /* Points to our private memory word on the stack. */
+  int private_data_ptr;
+  /* Reverting stack is needed. */
+  int framesize;
+  /* Allocated stack size. */
+  int stacksize;
+} bracketpos_backtrack;
+
+typedef struct braminzero_backtrack {
+  backtrack_common common;
+  struct sljit_label *matchingpath;
+} braminzero_backtrack;
+
+typedef struct char_iterator_backtrack {
+  backtrack_common common;
+  /* Next iteration. */
+  struct sljit_label *matchingpath;
+  union {
+    jump_list *backtracks;
+    struct {
+      unsigned int othercasebit;
+      PCRE2_UCHAR chr;
+      BOOL enabled;
+    } charpos;
+  } u;
+} char_iterator_backtrack;
+
+typedef struct ref_iterator_backtrack {
+  backtrack_common common;
+  /* Next iteration. */
+  struct sljit_label *matchingpath;
+} ref_iterator_backtrack;
+
+typedef struct recurse_entry {
+  struct recurse_entry *next;
+  /* Contains the function entry label. */
+  struct sljit_label *entry_label;
+  /* Contains the function entry label. */
+  struct sljit_label *backtrack_label;
+  /* Collects the entry calls until the function is not created. */
+  jump_list *entry_calls;
+  /* Collects the backtrack calls until the function is not created. */
+  jump_list *backtrack_calls;
+  /* Points to the starting opcode. */
+  sljit_sw start;
+} recurse_entry;
+
+typedef struct recurse_backtrack {
+  backtrack_common common;
+  /* Return to the matching path. */
+  struct sljit_label *matchingpath;
+  /* Recursive pattern. */
+  recurse_entry *entry;
+  /* Pattern is inlined. */
+  BOOL inlined_pattern;
+} recurse_backtrack;
+
+#define OP_THEN_TRAP OP_TABLE_LENGTH
+
+typedef struct then_trap_backtrack {
+  backtrack_common common;
+  /* If then_trap is not NULL, this structure contains the real
+  then_trap for the backtracking path. */
+  struct then_trap_backtrack *then_trap;
+  /* Points to the starting opcode. */
+  sljit_sw start;
+  /* Exit point for the then opcodes of this alternative. */
+  jump_list *quit;
+  /* Frame size of the current alternative. */
+  int framesize;
+} then_trap_backtrack;
+
+#define MAX_N_CHARS 12
+#define MAX_DIFF_CHARS 5
+
+typedef struct fast_forward_char_data {
+  /* Number of characters in the chars array, 255 for any character. */
+  sljit_u8 count;
+  /* Number of last UTF-8 characters in the chars array. */
+  sljit_u8 last_count;
+  /* Available characters in the current position. */
+  PCRE2_UCHAR chars[MAX_DIFF_CHARS];
+} fast_forward_char_data;
+
+#define MAX_CLASS_RANGE_SIZE 4
+#define MAX_CLASS_CHARS_SIZE 3
+
+typedef struct compiler_common {
+  /* The sljit ceneric compiler. */
+  struct sljit_compiler *compiler;
+  /* Compiled regular expression. */
+  pcre2_real_code *re;
+  /* First byte code. */
+  PCRE2_SPTR start;
+  /* Maps private data offset to each opcode. */
+  sljit_s32 *private_data_ptrs;
+  /* Chain list of read-only data ptrs. */
+  void *read_only_data_head;
+  /* Tells whether the capturing bracket is optimized. */
+  sljit_u8 *optimized_cbracket;
+  /* Tells whether the starting offset is a target of then. */
+  sljit_u8 *then_offsets;
+  /* Current position where a THEN must jump. */
+  then_trap_backtrack *then_trap;
+  /* Starting offset of private data for capturing brackets. */
+  sljit_s32 cbra_ptr;
+  /* Output vector starting point. Must be divisible by 2. */
+  sljit_s32 ovector_start;
+  /* Points to the starting character of the current match. */
+  sljit_s32 start_ptr;
+  /* Last known position of the requested byte. */
+  sljit_s32 req_char_ptr;
+  /* Head of the last recursion. */
+  sljit_s32 recursive_head_ptr;
+  /* First inspected character for partial matching.
+     (Needed for avoiding zero length partial matches.) */
+  sljit_s32 start_used_ptr;
+  /* Starting pointer for partial soft matches. */
+  sljit_s32 hit_start;
+  /* Pointer of the match end position. */
+  sljit_s32 match_end_ptr;
+  /* Points to the marked string. */
+  sljit_s32 mark_ptr;
+  /* Recursive control verb management chain. */
+  sljit_s32 control_head_ptr;
+  /* Points to the last matched capture block index. */
+  sljit_s32 capture_last_ptr;
+  /* Fast forward skipping byte code pointer. */
+  PCRE2_SPTR fast_forward_bc_ptr;
+  /* Locals used by fast fail optimization. */
+  sljit_s32 early_fail_start_ptr;
+  sljit_s32 early_fail_end_ptr;
+
+  /* Flipped and lower case tables. */
+  const sljit_u8 *fcc;
+  sljit_sw lcc;
+  /* Mode can be PCRE2_JIT_COMPLETE and others. */
+  int mode;
+  /* TRUE, when empty match is accepted for partial matching. */
+  BOOL allow_empty_partial;
+  /* TRUE, when minlength is greater than 0. */
+  BOOL might_be_empty;
+  /* \K is found in the pattern. */
+  BOOL has_set_som;
+  /* (*SKIP:arg) is found in the pattern. */
+  BOOL has_skip_arg;
+  /* (*THEN) is found in the pattern. */
+  BOOL has_then;
+  /* (*SKIP) or (*SKIP:arg) is found in lookbehind assertion. */
+  BOOL has_skip_in_assert_back;
+  /* Quit is redirected by recurse, negative assertion, or positive assertion in conditional block. */
+  BOOL local_quit_available;
+  /* Currently in a positive assertion. */
+  BOOL in_positive_assertion;
+  /* Newline control. */
+  int nltype;
+  sljit_u32 nlmax;
+  sljit_u32 nlmin;
+  int newline;
+  int bsr_nltype;
+  sljit_u32 bsr_nlmax;
+  sljit_u32 bsr_nlmin;
+  /* Dollar endonly. */
+  int endonly;
+  /* Tables. */
+  sljit_sw ctypes;
+  /* Named capturing brackets. */
+  PCRE2_SPTR name_table;
+  sljit_sw name_count;
+  sljit_sw name_entry_size;
+
+  /* Labels and jump lists. */
+  struct sljit_label *partialmatchlabel;
+  struct sljit_label *quit_label;
+  struct sljit_label *abort_label;
+  struct sljit_label *accept_label;
+  struct sljit_label *ff_newline_shortcut;
+  stub_list *stubs;
+  recurse_entry *entries;
+  recurse_entry *currententry;
+  jump_list *partialmatch;
+  jump_list *quit;
+  jump_list *positive_assertion_quit;
+  jump_list *abort;
+  jump_list *failed_match;
+  jump_list *accept;
+  jump_list *calllimit;
+  jump_list *stackalloc;
+  jump_list *revertframes;
+  jump_list *wordboundary;
+  jump_list *anynewline;
+  jump_list *hspace;
+  jump_list *vspace;
+  jump_list *casefulcmp;
+  jump_list *caselesscmp;
+  jump_list *reset_match;
+  BOOL unset_backref;
+  BOOL alt_circumflex;
+#ifdef SUPPORT_UNICODE
+  BOOL utf;
+  BOOL invalid_utf;
+  BOOL ucp;
+  /* Points to saving area for iref. */
+  sljit_s32 iref_ptr;
+  jump_list *getucd;
+  jump_list *getucdtype;
+#if PCRE2_CODE_UNIT_WIDTH == 8
+  jump_list *utfreadchar;
+  jump_list *utfreadtype8;
+  jump_list *utfpeakcharback;
+#endif
+#if PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16
+  jump_list *utfreadchar_invalid;
+  jump_list *utfreadnewline_invalid;
+  jump_list *utfmoveback_invalid;
+  jump_list *utfpeakcharback_invalid;
+#endif
+#endif /* SUPPORT_UNICODE */
+} compiler_common;
+
+/* For byte_sequence_compare. */
+
+typedef struct compare_context {
+  int length;
+  int sourcereg;
+#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
+  int ucharptr;
+  union {
+    sljit_s32 asint;
+    sljit_u16 asushort;
+#if PCRE2_CODE_UNIT_WIDTH == 8
+    sljit_u8 asbyte;
+    sljit_u8 asuchars[4];
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+    sljit_u16 asuchars[2];
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+    sljit_u32 asuchars[1];
+#endif
+  } c;
+  union {
+    sljit_s32 asint;
+    sljit_u16 asushort;
+#if PCRE2_CODE_UNIT_WIDTH == 8
+    sljit_u8 asbyte;
+    sljit_u8 asuchars[4];
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+    sljit_u16 asuchars[2];
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+    sljit_u32 asuchars[1];
+#endif
+  } oc;
+#endif
+} compare_context;
+
+/* Undefine sljit macros. */
+#undef CMP
+
+/* Used for accessing the elements of the stack. */
+#define STACK(i)      ((i) * (int)sizeof(sljit_sw))
+
+#ifdef SLJIT_PREF_SHIFT_REG
+#if SLJIT_PREF_SHIFT_REG == SLJIT_R2
+/* Nothing. */
+#elif SLJIT_PREF_SHIFT_REG == SLJIT_R3
+#define SHIFT_REG_IS_R3
+#else
+#error "Unsupported shift register"
+#endif
+#endif
+
+#define TMP1          SLJIT_R0
+#ifdef SHIFT_REG_IS_R3
+#define TMP2          SLJIT_R3
+#define TMP3          SLJIT_R2
+#else
+#define TMP2          SLJIT_R2
+#define TMP3          SLJIT_R3
+#endif
+#define STR_PTR       SLJIT_R1
+#define STR_END       SLJIT_S0
+#define STACK_TOP     SLJIT_S1
+#define STACK_LIMIT   SLJIT_S2
+#define COUNT_MATCH   SLJIT_S3
+#define ARGUMENTS     SLJIT_S4
+#define RETURN_ADDR   SLJIT_R4
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+#define HAS_VIRTUAL_REGISTERS 1
+#else
+#define HAS_VIRTUAL_REGISTERS 0
+#endif
+
+/* Local space layout. */
+/* These two locals can be used by the current opcode. */
+#define LOCALS0          (0 * sizeof(sljit_sw))
+#define LOCALS1          (1 * sizeof(sljit_sw))
+/* Two local variables for possessive quantifiers (char1 cannot use them). */
+#define POSSESSIVE0      (2 * sizeof(sljit_sw))
+#define POSSESSIVE1      (3 * sizeof(sljit_sw))
+/* Max limit of recursions. */
+#define LIMIT_MATCH      (4 * sizeof(sljit_sw))
+/* The output vector is stored on the stack, and contains pointers
+to characters. The vector data is divided into two groups: the first
+group contains the start / end character pointers, and the second is
+the start pointers when the end of the capturing group has not yet reached. */
+#define OVECTOR_START    (common->ovector_start)
+#define OVECTOR(i)       (OVECTOR_START + (i) * (sljit_sw)sizeof(sljit_sw))
+#define OVECTOR_PRIV(i)  (common->cbra_ptr + (i) * (sljit_sw)sizeof(sljit_sw))
+#define PRIVATE_DATA(cc) (common->private_data_ptrs[(cc) - common->start])
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define MOV_UCHAR  SLJIT_MOV_U8
+#define IN_UCHARS(x) (x)
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+#define MOV_UCHAR  SLJIT_MOV_U16
+#define UCHAR_SHIFT (1)
+#define IN_UCHARS(x) ((x) * 2)
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+#define MOV_UCHAR  SLJIT_MOV_U32
+#define UCHAR_SHIFT (2)
+#define IN_UCHARS(x) ((x) * 4)
+#else
+#error Unsupported compiling mode
+#endif
+
+/* Shortcuts. */
+#define DEFINE_COMPILER \
+  struct sljit_compiler *compiler = common->compiler
+#define OP1(op, dst, dstw, src, srcw) \
+  sljit_emit_op1(compiler, (op), (dst), (dstw), (src), (srcw))
+#define OP2(op, dst, dstw, src1, src1w, src2, src2w) \
+  sljit_emit_op2(compiler, (op), (dst), (dstw), (src1), (src1w), (src2), (src2w))
+#define OP_SRC(op, src, srcw) \
+  sljit_emit_op_src(compiler, (op), (src), (srcw))
+#define LABEL() \
+  sljit_emit_label(compiler)
+#define JUMP(type) \
+  sljit_emit_jump(compiler, (type))
+#define JUMPTO(type, label) \
+  sljit_set_label(sljit_emit_jump(compiler, (type)), (label))
+#define JUMPHERE(jump) \
+  sljit_set_label((jump), sljit_emit_label(compiler))
+#define SET_LABEL(jump, label) \
+  sljit_set_label((jump), (label))
+#define CMP(type, src1, src1w, src2, src2w) \
+  sljit_emit_cmp(compiler, (type), (src1), (src1w), (src2), (src2w))
+#define CMPTO(type, src1, src1w, src2, src2w, label) \
+  sljit_set_label(sljit_emit_cmp(compiler, (type), (src1), (src1w), (src2), (src2w)), (label))
+#define OP_FLAGS(op, dst, dstw, type) \
+  sljit_emit_op_flags(compiler, (op), (dst), (dstw), (type))
+#define CMOV(type, dst_reg, src, srcw) \
+  sljit_emit_cmov(compiler, (type), (dst_reg), (src), (srcw))
+#define GET_LOCAL_BASE(dst, dstw, offset) \
+  sljit_get_local_base(compiler, (dst), (dstw), (offset))
+
+#define READ_CHAR_MAX 0x7fffffff
+
+#define INVALID_UTF_CHAR -1
+#define UNASSIGNED_UTF_CHAR 888
+
+#if defined SUPPORT_UNICODE
+#if PCRE2_CODE_UNIT_WIDTH == 8
+
+#define GETCHARINC_INVALID(c, ptr, end, invalid_action) \
+  { \
+  if (ptr[0] <= 0x7f) \
+    c = *ptr++; \
+  else if (ptr + 1 < end && ptr[1] >= 0x80 && ptr[1] < 0xc0) \
+    { \
+    c = ptr[1] - 0x80; \
+    \
+    if (ptr[0] >= 0xc2 && ptr[0] <= 0xdf) \
+      { \
+      c |= (ptr[0] - 0xc0) << 6; \
+      ptr += 2; \
+      } \
+    else if (ptr + 2 < end && ptr[2] >= 0x80 && ptr[2] < 0xc0) \
+      { \
+      c = c << 6 | (ptr[2] - 0x80); \
+      \
+      if (ptr[0] >= 0xe0 && ptr[0] <= 0xef) \
+        { \
+        c |= (ptr[0] - 0xe0) << 12; \
+        ptr += 3; \
+        \
+        if (c < 0x800 || (c >= 0xd800 && c < 0xe000)) \
+          { \
+          invalid_action; \
+          } \
+        } \
+      else if (ptr + 3 < end && ptr[3] >= 0x80 && ptr[3] < 0xc0) \
+        { \
+        c = c << 6 | (ptr[3] - 0x80); \
+        \
+        if (ptr[0] >= 0xf0 && ptr[0] <= 0xf4) \
+          { \
+          c |= (ptr[0] - 0xf0) << 18; \
+          ptr += 4; \
+          \
+          if (c >= 0x110000 || c < 0x10000) \
+            { \
+            invalid_action; \
+            } \
+          } \
+        else \
+          { \
+          invalid_action; \
+          } \
+        } \
+      else \
+        { \
+        invalid_action; \
+        } \
+      } \
+    else \
+      { \
+      invalid_action; \
+      } \
+    } \
+  else \
+    { \
+    invalid_action; \
+    } \
+  }
+
+#define GETCHARBACK_INVALID(c, ptr, start, invalid_action) \
+  { \
+  c = ptr[-1]; \
+  if (c <= 0x7f) \
+    ptr--; \
+  else if (ptr - 1 > start && ptr[-1] >= 0x80 && ptr[-1] < 0xc0) \
+    { \
+    c -= 0x80; \
+    \
+    if (ptr[-2] >= 0xc2 && ptr[-2] <= 0xdf) \
+      { \
+      c |= (ptr[-2] - 0xc0) << 6; \
+      ptr -= 2; \
+      } \
+    else if (ptr - 2 > start && ptr[-2] >= 0x80 && ptr[-2] < 0xc0) \
+      { \
+      c = c << 6 | (ptr[-2] - 0x80); \
+      \
+      if (ptr[-3] >= 0xe0 && ptr[-3] <= 0xef) \
+        { \
+        c |= (ptr[-3] - 0xe0) << 12; \
+        ptr -= 3; \
+        \
+        if (c < 0x800 || (c >= 0xd800 && c < 0xe000)) \
+          { \
+          invalid_action; \
+          } \
+        } \
+      else if (ptr - 3 > start && ptr[-3] >= 0x80 && ptr[-3] < 0xc0) \
+        { \
+        c = c << 6 | (ptr[-3] - 0x80); \
+        \
+        if (ptr[-4] >= 0xf0 && ptr[-4] <= 0xf4) \
+          { \
+          c |= (ptr[-4] - 0xf0) << 18; \
+          ptr -= 4; \
+          \
+          if (c >= 0x110000 || c < 0x10000) \
+            { \
+            invalid_action; \
+            } \
+          } \
+        else \
+          { \
+          invalid_action; \
+          } \
+        } \
+      else \
+        { \
+        invalid_action; \
+        } \
+      } \
+    else \
+      { \
+      invalid_action; \
+      } \
+    } \
+  else \
+    { \
+    invalid_action; \
+    } \
+  }
+
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+
+#define GETCHARINC_INVALID(c, ptr, end, invalid_action) \
+  { \
+  if (ptr[0] < 0xd800 || ptr[0] >= 0xe000) \
+    c = *ptr++; \
+  else if (ptr[0] < 0xdc00 && ptr + 1 < end && ptr[1] >= 0xdc00 && ptr[1] < 0xe000) \
+    { \
+    c = (((ptr[0] - 0xd800) << 10) | (ptr[1] - 0xdc00)) + 0x10000; \
+    ptr += 2; \
+    } \
+  else \
+    { \
+    invalid_action; \
+    } \
+  }
+
+#define GETCHARBACK_INVALID(c, ptr, start, invalid_action) \
+  { \
+  c = ptr[-1]; \
+  if (c < 0xd800 || c >= 0xe000) \
+    ptr--; \
+  else if (c >= 0xdc00 && ptr - 1 > start && ptr[-2] >= 0xd800 && ptr[-2] < 0xdc00) \
+    { \
+    c = (((ptr[-2] - 0xd800) << 10) | (c - 0xdc00)) + 0x10000; \
+    ptr -= 2; \
+    } \
+  else \
+    { \
+    invalid_action; \
+    } \
+  }
+
+
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+
+#define GETCHARINC_INVALID(c, ptr, end, invalid_action) \
+  { \
+  if (ptr[0] < 0xd800 || (ptr[0] >= 0xe000 && ptr[0] < 0x110000)) \
+    c = *ptr++; \
+  else \
+    { \
+    invalid_action; \
+    } \
+  }
+
+#define GETCHARBACK_INVALID(c, ptr, start, invalid_action) \
+  { \
+  c = ptr[-1]; \
+  if (ptr[-1] < 0xd800 || (ptr[-1] >= 0xe000 && ptr[-1] < 0x110000)) \
+    ptr--; \
+  else \
+    { \
+    invalid_action; \
+    } \
+  }
+
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
+#endif /* SUPPORT_UNICODE */
+
+static PCRE2_SPTR bracketend(PCRE2_SPTR cc)
+{
+SLJIT_ASSERT((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NA) || (*cc >= OP_ONCE && *cc <= OP_SCOND));
+do cc += GET(cc, 1); while (*cc == OP_ALT);
+SLJIT_ASSERT(*cc >= OP_KET && *cc <= OP_KETRPOS);
+cc += 1 + LINK_SIZE;
+return cc;
+}
+
+static int no_alternatives(PCRE2_SPTR cc)
+{
+int count = 0;
+SLJIT_ASSERT((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NA) || (*cc >= OP_ONCE && *cc <= OP_SCOND));
+do
+  {
+  cc += GET(cc, 1);
+  count++;
+  }
+while (*cc == OP_ALT);
+SLJIT_ASSERT(*cc >= OP_KET && *cc <= OP_KETRPOS);
+return count;
+}
+
+/* Functions whose might need modification for all new supported opcodes:
+ next_opcode
+ check_opcode_types
+ set_private_data_ptrs
+ get_framesize
+ init_frame
+ get_recurse_data_length
+ copy_recurse_data
+ compile_matchingpath
+ compile_backtrackingpath
+*/
+
+static PCRE2_SPTR next_opcode(compiler_common *common, PCRE2_SPTR cc)
+{
+SLJIT_UNUSED_ARG(common);
+switch(*cc)
+  {
+  case OP_SOD:
+  case OP_SOM:
+  case OP_SET_SOM:
+  case OP_NOT_WORD_BOUNDARY:
+  case OP_WORD_BOUNDARY:
+  case OP_NOT_DIGIT:
+  case OP_DIGIT:
+  case OP_NOT_WHITESPACE:
+  case OP_WHITESPACE:
+  case OP_NOT_WORDCHAR:
+  case OP_WORDCHAR:
+  case OP_ANY:
+  case OP_ALLANY:
+  case OP_NOTPROP:
+  case OP_PROP:
+  case OP_ANYNL:
+  case OP_NOT_HSPACE:
+  case OP_HSPACE:
+  case OP_NOT_VSPACE:
+  case OP_VSPACE:
+  case OP_EXTUNI:
+  case OP_EODN:
+  case OP_EOD:
+  case OP_CIRC:
+  case OP_CIRCM:
+  case OP_DOLL:
+  case OP_DOLLM:
+  case OP_CRSTAR:
+  case OP_CRMINSTAR:
+  case OP_CRPLUS:
+  case OP_CRMINPLUS:
+  case OP_CRQUERY:
+  case OP_CRMINQUERY:
+  case OP_CRRANGE:
+  case OP_CRMINRANGE:
+  case OP_CRPOSSTAR:
+  case OP_CRPOSPLUS:
+  case OP_CRPOSQUERY:
+  case OP_CRPOSRANGE:
+  case OP_CLASS:
+  case OP_NCLASS:
+  case OP_REF:
+  case OP_REFI:
+  case OP_DNREF:
+  case OP_DNREFI:
+  case OP_RECURSE:
+  case OP_CALLOUT:
+  case OP_ALT:
+  case OP_KET:
+  case OP_KETRMAX:
+  case OP_KETRMIN:
+  case OP_KETRPOS:
+  case OP_REVERSE:
+  case OP_ASSERT:
+  case OP_ASSERT_NOT:
+  case OP_ASSERTBACK:
+  case OP_ASSERTBACK_NOT:
+  case OP_ASSERT_NA:
+  case OP_ASSERTBACK_NA:
+  case OP_ONCE:
+  case OP_SCRIPT_RUN:
+  case OP_BRA:
+  case OP_BRAPOS:
+  case OP_CBRA:
+  case OP_CBRAPOS:
+  case OP_COND:
+  case OP_SBRA:
+  case OP_SBRAPOS:
+  case OP_SCBRA:
+  case OP_SCBRAPOS:
+  case OP_SCOND:
+  case OP_CREF:
+  case OP_DNCREF:
+  case OP_RREF:
+  case OP_DNRREF:
+  case OP_FALSE:
+  case OP_TRUE:
+  case OP_BRAZERO:
+  case OP_BRAMINZERO:
+  case OP_BRAPOSZERO:
+  case OP_PRUNE:
+  case OP_SKIP:
+  case OP_THEN:
+  case OP_COMMIT:
+  case OP_FAIL:
+  case OP_ACCEPT:
+  case OP_ASSERT_ACCEPT:
+  case OP_CLOSE:
+  case OP_SKIPZERO:
+  return cc + PRIV(OP_lengths)[*cc];
+
+  case OP_CHAR:
+  case OP_CHARI:
+  case OP_NOT:
+  case OP_NOTI:
+  case OP_STAR:
+  case OP_MINSTAR:
+  case OP_PLUS:
+  case OP_MINPLUS:
+  case OP_QUERY:
+  case OP_MINQUERY:
+  case OP_UPTO:
+  case OP_MINUPTO:
+  case OP_EXACT:
+  case OP_POSSTAR:
+  case OP_POSPLUS:
+  case OP_POSQUERY:
+  case OP_POSUPTO:
+  case OP_STARI:
+  case OP_MINSTARI:
+  case OP_PLUSI:
+  case OP_MINPLUSI:
+  case OP_QUERYI:
+  case OP_MINQUERYI:
+  case OP_UPTOI:
+  case OP_MINUPTOI:
+  case OP_EXACTI:
+  case OP_POSSTARI:
+  case OP_POSPLUSI:
+  case OP_POSQUERYI:
+  case OP_POSUPTOI:
+  case OP_NOTSTAR:
+  case OP_NOTMINSTAR:
+  case OP_NOTPLUS:
+  case OP_NOTMINPLUS:
+  case OP_NOTQUERY:
+  case OP_NOTMINQUERY:
+  case OP_NOTUPTO:
+  case OP_NOTMINUPTO:
+  case OP_NOTEXACT:
+  case OP_NOTPOSSTAR:
+  case OP_NOTPOSPLUS:
+  case OP_NOTPOSQUERY:
+  case OP_NOTPOSUPTO:
+  case OP_NOTSTARI:
+  case OP_NOTMINSTARI:
+  case OP_NOTPLUSI:
+  case OP_NOTMINPLUSI:
+  case OP_NOTQUERYI:
+  case OP_NOTMINQUERYI:
+  case OP_NOTUPTOI:
+  case OP_NOTMINUPTOI:
+  case OP_NOTEXACTI:
+  case OP_NOTPOSSTARI:
+  case OP_NOTPOSPLUSI:
+  case OP_NOTPOSQUERYI:
+  case OP_NOTPOSUPTOI:
+  cc += PRIV(OP_lengths)[*cc];
+#ifdef SUPPORT_UNICODE
+  if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+  return cc;
+
+  /* Special cases. */
+  case OP_TYPESTAR:
+  case OP_TYPEMINSTAR:
+  case OP_TYPEPLUS:
+  case OP_TYPEMINPLUS:
+  case OP_TYPEQUERY:
+  case OP_TYPEMINQUERY:
+  case OP_TYPEUPTO:
+  case OP_TYPEMINUPTO:
+  case OP_TYPEEXACT:
+  case OP_TYPEPOSSTAR:
+  case OP_TYPEPOSPLUS:
+  case OP_TYPEPOSQUERY:
+  case OP_TYPEPOSUPTO:
+  return cc + PRIV(OP_lengths)[*cc] - 1;
+
+  case OP_ANYBYTE:
+#ifdef SUPPORT_UNICODE
+  if (common->utf) return NULL;
+#endif
+  return cc + 1;
+
+  case OP_CALLOUT_STR:
+  return cc + GET(cc, 1 + 2*LINK_SIZE);
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+  case OP_XCLASS:
+  return cc + GET(cc, 1);
+#endif
+
+  case OP_MARK:
+  case OP_COMMIT_ARG:
+  case OP_PRUNE_ARG:
+  case OP_SKIP_ARG:
+  case OP_THEN_ARG:
+  return cc + 1 + 2 + cc[1];
+
+  default:
+  SLJIT_UNREACHABLE();
+  return NULL;
+  }
+}
+
+static BOOL check_opcode_types(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend)
+{
+int count;
+PCRE2_SPTR slot;
+PCRE2_SPTR assert_back_end = cc - 1;
+PCRE2_SPTR assert_na_end = cc - 1;
+
+/* Calculate important variables (like stack size) and checks whether all opcodes are supported. */
+while (cc < ccend)
+  {
+  switch(*cc)
+    {
+    case OP_SET_SOM:
+    common->has_set_som = TRUE;
+    common->might_be_empty = TRUE;
+    cc += 1;
+    break;
+
+    case OP_REFI:
+#ifdef SUPPORT_UNICODE
+    if (common->iref_ptr == 0)
+      {
+      common->iref_ptr = common->ovector_start;
+      common->ovector_start += 3 * sizeof(sljit_sw);
+      }
+#endif /* SUPPORT_UNICODE */
+    /* Fall through. */
+    case OP_REF:
+    common->optimized_cbracket[GET2(cc, 1)] = 0;
+    cc += 1 + IMM2_SIZE;
+    break;
+
+    case OP_ASSERT_NA:
+    case OP_ASSERTBACK_NA:
+    slot = bracketend(cc);
+    if (slot > assert_na_end)
+      assert_na_end = slot;
+    cc += 1 + LINK_SIZE;
+    break;
+
+    case OP_CBRAPOS:
+    case OP_SCBRAPOS:
+    common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] = 0;
+    cc += 1 + LINK_SIZE + IMM2_SIZE;
+    break;
+
+    case OP_COND:
+    case OP_SCOND:
+    /* Only AUTO_CALLOUT can insert this opcode. We do
+       not intend to support this case. */
+    if (cc[1 + LINK_SIZE] == OP_CALLOUT || cc[1 + LINK_SIZE] == OP_CALLOUT_STR)
+      return FALSE;
+    cc += 1 + LINK_SIZE;
+    break;
+
+    case OP_CREF:
+    common->optimized_cbracket[GET2(cc, 1)] = 0;
+    cc += 1 + IMM2_SIZE;
+    break;
+
+    case OP_DNREF:
+    case OP_DNREFI:
+    case OP_DNCREF:
+    count = GET2(cc, 1 + IMM2_SIZE);
+    slot = common->name_table + GET2(cc, 1) * common->name_entry_size;
+    while (count-- > 0)
+      {
+      common->optimized_cbracket[GET2(slot, 0)] = 0;
+      slot += common->name_entry_size;
+      }
+    cc += 1 + 2 * IMM2_SIZE;
+    break;
+
+    case OP_RECURSE:
+    /* Set its value only once. */
+    if (common->recursive_head_ptr == 0)
+      {
+      common->recursive_head_ptr = common->ovector_start;
+      common->ovector_start += sizeof(sljit_sw);
+      }
+    cc += 1 + LINK_SIZE;
+    break;
+
+    case OP_CALLOUT:
+    case OP_CALLOUT_STR:
+    if (common->capture_last_ptr == 0)
+      {
+      common->capture_last_ptr = common->ovector_start;
+      common->ovector_start += sizeof(sljit_sw);
+      }
+    cc += (*cc == OP_CALLOUT) ? PRIV(OP_lengths)[OP_CALLOUT] : GET(cc, 1 + 2*LINK_SIZE);
+    break;
+
+    case OP_ASSERTBACK:
+    slot = bracketend(cc);
+    if (slot > assert_back_end)
+      assert_back_end = slot;
+    cc += 1 + LINK_SIZE;
+    break;
+
+    case OP_THEN_ARG:
+    common->has_then = TRUE;
+    common->control_head_ptr = 1;
+    /* Fall through. */
+
+    case OP_COMMIT_ARG:
+    case OP_PRUNE_ARG:
+    if (cc < assert_na_end)
+      return FALSE;
+    /* Fall through */
+    case OP_MARK:
+    if (common->mark_ptr == 0)
+      {
+      common->mark_ptr = common->ovector_start;
+      common->ovector_start += sizeof(sljit_sw);
+      }
+    cc += 1 + 2 + cc[1];
+    break;
+
+    case OP_THEN:
+    common->has_then = TRUE;
+    common->control_head_ptr = 1;
+    cc += 1;
+    break;
+
+    case OP_SKIP:
+    if (cc < assert_back_end)
+      common->has_skip_in_assert_back = TRUE;
+    if (cc < assert_na_end)
+      return FALSE;
+    cc += 1;
+    break;
+
+    case OP_SKIP_ARG:
+    common->control_head_ptr = 1;
+    common->has_skip_arg = TRUE;
+    if (cc < assert_back_end)
+      common->has_skip_in_assert_back = TRUE;
+    if (cc < assert_na_end)
+      return FALSE;
+    cc += 1 + 2 + cc[1];
+    break;
+
+    case OP_PRUNE:
+    case OP_COMMIT:
+    case OP_ASSERT_ACCEPT:
+    if (cc < assert_na_end)
+      return FALSE;
+    cc++;
+    break;
+
+    default:
+    cc = next_opcode(common, cc);
+    if (cc == NULL)
+      return FALSE;
+    break;
+    }
+  }
+return TRUE;
+}
+
+#define EARLY_FAIL_ENHANCE_MAX (1 + 1)
+
+/*
+start:
+  0 - skip / early fail allowed
+  1 - only early fail with range allowed
+  >1 - (start - 1) early fail is processed
+
+return: current number of iterators enhanced with fast fail
+*/
+static int detect_early_fail(compiler_common *common, PCRE2_SPTR cc, int *private_data_start, sljit_s32 depth, int start)
+{
+PCRE2_SPTR next_alt;
+PCRE2_SPTR end;
+PCRE2_SPTR accelerated_start;
+int result = 0;
+int count;
+BOOL fast_forward_allowed = TRUE;
+
+SLJIT_ASSERT(*cc == OP_ONCE || *cc == OP_BRA || *cc == OP_CBRA);
+SLJIT_ASSERT(*cc != OP_CBRA || common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] != 0);
+SLJIT_ASSERT(start < EARLY_FAIL_ENHANCE_MAX);
+
+do
+  {
+  count = start;
+  next_alt = cc + GET(cc, 1);
+  cc += 1 + LINK_SIZE + ((*cc == OP_CBRA) ? IMM2_SIZE : 0);
+
+  while (TRUE)
+    {
+    accelerated_start = NULL;
+
+    switch(*cc)
+      {
+      case OP_SOD:
+      case OP_SOM:
+      case OP_SET_SOM:
+      case OP_NOT_WORD_BOUNDARY:
+      case OP_WORD_BOUNDARY:
+      case OP_EODN:
+      case OP_EOD:
+      case OP_CIRC:
+      case OP_CIRCM:
+      case OP_DOLL:
+      case OP_DOLLM:
+      /* Zero width assertions. */
+      cc++;
+      continue;
+
+      case OP_NOT_DIGIT:
+      case OP_DIGIT:
+      case OP_NOT_WHITESPACE:
+      case OP_WHITESPACE:
+      case OP_NOT_WORDCHAR:
+      case OP_WORDCHAR:
+      case OP_ANY:
+      case OP_ALLANY:
+      case OP_ANYBYTE:
+      case OP_NOT_HSPACE:
+      case OP_HSPACE:
+      case OP_NOT_VSPACE:
+      case OP_VSPACE:
+      fast_forward_allowed = FALSE;
+      cc++;
+      continue;
+
+      case OP_ANYNL:
+      case OP_EXTUNI:
+      fast_forward_allowed = FALSE;
+      if (count == 0)
+        count = 1;
+      cc++;
+      continue;
+
+      case OP_NOTPROP:
+      case OP_PROP:
+      fast_forward_allowed = FALSE;
+      cc += 1 + 2;
+      continue;
+
+      case OP_CHAR:
+      case OP_CHARI:
+      case OP_NOT:
+      case OP_NOTI:
+      fast_forward_allowed = FALSE;
+      cc += 2;
+#ifdef SUPPORT_UNICODE
+      if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+      continue;
+
+      case OP_TYPESTAR:
+      case OP_TYPEMINSTAR:
+      case OP_TYPEPLUS:
+      case OP_TYPEMINPLUS:
+      case OP_TYPEPOSSTAR:
+      case OP_TYPEPOSPLUS:
+      /* The type or prop opcode is skipped in the next iteration. */
+      cc += 1;
+
+      if (cc[0] != OP_ANYNL && cc[0] != OP_EXTUNI)
+        {
+        accelerated_start = cc - 1;
+        break;
+        }
+
+      if (count == 0)
+        count = 1;
+      fast_forward_allowed = FALSE;
+      continue;
+
+      case OP_TYPEUPTO:
+      case OP_TYPEMINUPTO:
+      case OP_TYPEEXACT:
+      case OP_TYPEPOSUPTO:
+      cc += IMM2_SIZE;
+      /* Fall through */
+
+      case OP_TYPEQUERY:
+      case OP_TYPEMINQUERY:
+      case OP_TYPEPOSQUERY:
+      /* The type or prop opcode is skipped in the next iteration. */
+      fast_forward_allowed = FALSE;
+      if (count == 0)
+        count = 1;
+      cc += 1;
+      continue;
+
+      case OP_STAR:
+      case OP_MINSTAR:
+      case OP_PLUS:
+      case OP_MINPLUS:
+      case OP_POSSTAR:
+      case OP_POSPLUS:
+
+      case OP_STARI:
+      case OP_MINSTARI:
+      case OP_PLUSI:
+      case OP_MINPLUSI:
+      case OP_POSSTARI:
+      case OP_POSPLUSI:
+
+      case OP_NOTSTAR:
+      case OP_NOTMINSTAR:
+      case OP_NOTPLUS:
+      case OP_NOTMINPLUS:
+      case OP_NOTPOSSTAR:
+      case OP_NOTPOSPLUS:
+
+      case OP_NOTSTARI:
+      case OP_NOTMINSTARI:
+      case OP_NOTPLUSI:
+      case OP_NOTMINPLUSI:
+      case OP_NOTPOSSTARI:
+      case OP_NOTPOSPLUSI:
+      accelerated_start = cc;
+      cc += 2;
+#ifdef SUPPORT_UNICODE
+      if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+      break;
+
+      case OP_UPTO:
+      case OP_MINUPTO:
+      case OP_EXACT:
+      case OP_POSUPTO:
+      case OP_UPTOI:
+      case OP_MINUPTOI:
+      case OP_EXACTI:
+      case OP_POSUPTOI:
+      case OP_NOTUPTO:
+      case OP_NOTMINUPTO:
+      case OP_NOTEXACT:
+      case OP_NOTPOSUPTO:
+      case OP_NOTUPTOI:
+      case OP_NOTMINUPTOI:
+      case OP_NOTEXACTI:
+      case OP_NOTPOSUPTOI:
+      cc += IMM2_SIZE;
+      /* Fall through */
+
+      case OP_QUERY:
+      case OP_MINQUERY:
+      case OP_POSQUERY:
+      case OP_QUERYI:
+      case OP_MINQUERYI:
+      case OP_POSQUERYI:
+      case OP_NOTQUERY:
+      case OP_NOTMINQUERY:
+      case OP_NOTPOSQUERY:
+      case OP_NOTQUERYI:
+      case OP_NOTMINQUERYI:
+      case OP_NOTPOSQUERYI:
+      fast_forward_allowed = FALSE;
+      if (count == 0)
+        count = 1;
+      cc += 2;
+#ifdef SUPPORT_UNICODE
+      if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+      continue;
+
+      case OP_CLASS:
+      case OP_NCLASS:
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+      case OP_XCLASS:
+      accelerated_start = cc;
+      cc += ((*cc == OP_XCLASS) ? GET(cc, 1) : (unsigned int)(1 + (32 / sizeof(PCRE2_UCHAR))));
+#else
+      accelerated_start = cc;
+      cc += (1 + (32 / sizeof(PCRE2_UCHAR)));
+#endif
+
+      switch (*cc)
+        {
+        case OP_CRSTAR:
+        case OP_CRMINSTAR:
+        case OP_CRPLUS:
+        case OP_CRMINPLUS:
+        case OP_CRPOSSTAR:
+        case OP_CRPOSPLUS:
+        cc++;
+        break;
+
+        case OP_CRRANGE:
+        case OP_CRMINRANGE:
+        case OP_CRPOSRANGE:
+        cc += 2 * IMM2_SIZE;
+        /* Fall through */
+        case OP_CRQUERY:
+        case OP_CRMINQUERY:
+        case OP_CRPOSQUERY:
+        cc++;
+        if (count == 0)
+          count = 1;
+        /* Fall through */
+        default:
+        accelerated_start = NULL;
+        fast_forward_allowed = FALSE;
+        continue;
+        }
+      break;
+
+      case OP_ONCE:
+      case OP_BRA:
+      case OP_CBRA:
+      end = cc + GET(cc, 1);
+
+      if (*end == OP_KET && PRIVATE_DATA(end) == 0)
+        {
+        if (*cc == OP_CBRA)
+          {
+          if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0)
+            break;
+          cc += IMM2_SIZE;
+          }
+
+        cc += 1 + LINK_SIZE;
+        continue;
+        }
+
+      fast_forward_allowed = FALSE;
+      if (depth >= 4)
+        break;
+
+      end = bracketend(cc) - (1 + LINK_SIZE);
+      if (*end != OP_KET || PRIVATE_DATA(end) != 0)
+        break;
+
+      if (*cc == OP_CBRA && common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0)
+        break;
+
+      count = detect_early_fail(common, cc, private_data_start, depth + 1, count);
+      if (count < EARLY_FAIL_ENHANCE_MAX)
+        {
+        cc = end + (1 + LINK_SIZE);
+        continue;
+        }
+      break;
+
+      case OP_KET:
+      SLJIT_ASSERT(PRIVATE_DATA(cc) == 0);
+      if (cc >= next_alt)
+        break;
+      cc += 1 + LINK_SIZE;
+      continue;
+      }
+
+    if (accelerated_start != NULL)
+      {
+      if (count == 0)
+        {
+        count++;
+
+        if (fast_forward_allowed && *next_alt == OP_KET)
+          {
+          common->fast_forward_bc_ptr = accelerated_start;
+          common->private_data_ptrs[(accelerated_start + 1) - common->start] = ((*private_data_start) << 3) | type_skip;
+          *private_data_start += sizeof(sljit_sw);
+          }
+        else
+          {
+          common->private_data_ptrs[(accelerated_start + 1) - common->start] = ((*private_data_start) << 3) | type_fail;
+
+          if (common->early_fail_start_ptr == 0)
+            common->early_fail_start_ptr = *private_data_start;
+
+          *private_data_start += sizeof(sljit_sw);
+          common->early_fail_end_ptr = *private_data_start;
+
+          if (*private_data_start > SLJIT_MAX_LOCAL_SIZE)
+            return EARLY_FAIL_ENHANCE_MAX;
+          }
+        }
+      else
+        {
+        common->private_data_ptrs[(accelerated_start + 1) - common->start] = ((*private_data_start) << 3) | type_fail_range;
+
+        if (common->early_fail_start_ptr == 0)
+          common->early_fail_start_ptr = *private_data_start;
+
+        *private_data_start += 2 * sizeof(sljit_sw);
+        common->early_fail_end_ptr = *private_data_start;
+
+        if (*private_data_start > SLJIT_MAX_LOCAL_SIZE)
+          return EARLY_FAIL_ENHANCE_MAX;
+        }
+
+      count++;
+
+      if (count < EARLY_FAIL_ENHANCE_MAX)
+        continue;
+      }
+
+    break;
+    }
+
+  if (*cc != OP_ALT && *cc != OP_KET)
+    result = EARLY_FAIL_ENHANCE_MAX;
+  else if (result < count)
+    result = count;
+
+  fast_forward_allowed = FALSE;
+  cc = next_alt;
+  }
+while (*cc == OP_ALT);
+
+return result;
+}
+
+static int get_class_iterator_size(PCRE2_SPTR cc)
+{
+sljit_u32 min;
+sljit_u32 max;
+switch(*cc)
+  {
+  case OP_CRSTAR:
+  case OP_CRPLUS:
+  return 2;
+
+  case OP_CRMINSTAR:
+  case OP_CRMINPLUS:
+  case OP_CRQUERY:
+  case OP_CRMINQUERY:
+  return 1;
+
+  case OP_CRRANGE:
+  case OP_CRMINRANGE:
+  min = GET2(cc, 1);
+  max = GET2(cc, 1 + IMM2_SIZE);
+  if (max == 0)
+    return (*cc == OP_CRRANGE) ? 2 : 1;
+  max -= min;
+  if (max > 2)
+    max = 2;
+  return max;
+
+  default:
+  return 0;
+  }
+}
+
+static BOOL detect_repeat(compiler_common *common, PCRE2_SPTR begin)
+{
+PCRE2_SPTR end = bracketend(begin);
+PCRE2_SPTR next;
+PCRE2_SPTR next_end;
+PCRE2_SPTR max_end;
+PCRE2_UCHAR type;
+sljit_sw length = end - begin;
+sljit_s32 min, max, i;
+
+/* Detect fixed iterations first. */
+if (end[-(1 + LINK_SIZE)] != OP_KET)
+  return FALSE;
+
+/* Already detected repeat. */
+if (common->private_data_ptrs[end - common->start - LINK_SIZE] != 0)
+  return TRUE;
+
+next = end;
+min = 1;
+while (1)
+  {
+  if (*next != *begin)
+    break;
+  next_end = bracketend(next);
+  if (next_end - next != length || memcmp(begin, next, IN_UCHARS(length)) != 0)
+    break;
+  next = next_end;
+  min++;
+  }
+
+if (min == 2)
+  return FALSE;
+
+max = 0;
+max_end = next;
+if (*next == OP_BRAZERO || *next == OP_BRAMINZERO)
+  {
+  type = *next;
+  while (1)
+    {
+    if (next[0] != type || next[1] != OP_BRA || next[2 + LINK_SIZE] != *begin)
+      break;
+    next_end = bracketend(next + 2 + LINK_SIZE);
+    if (next_end - next != (length + 2 + LINK_SIZE) || memcmp(begin, next + 2 + LINK_SIZE, IN_UCHARS(length)) != 0)
+      break;
+    next = next_end;
+    max++;
+    }
+
+  if (next[0] == type && next[1] == *begin && max >= 1)
+    {
+    next_end = bracketend(next + 1);
+    if (next_end - next == (length + 1) && memcmp(begin, next + 1, IN_UCHARS(length)) == 0)
+      {
+      for (i = 0; i < max; i++, next_end += 1 + LINK_SIZE)
+        if (*next_end != OP_KET)
+          break;
+
+      if (i == max)
+        {
+        common->private_data_ptrs[max_end - common->start - LINK_SIZE] = next_end - max_end;
+        common->private_data_ptrs[max_end - common->start - LINK_SIZE + 1] = (type == OP_BRAZERO) ? OP_UPTO : OP_MINUPTO;
+        /* +2 the original and the last. */
+        common->private_data_ptrs[max_end - common->start - LINK_SIZE + 2] = max + 2;
+        if (min == 1)
+          return TRUE;
+        min--;
+        max_end -= (1 + LINK_SIZE) + GET(max_end, -LINK_SIZE);
+        }
+      }
+    }
+  }
+
+if (min >= 3)
+  {
+  common->private_data_ptrs[end - common->start - LINK_SIZE] = max_end - end;
+  common->private_data_ptrs[end - common->start - LINK_SIZE + 1] = OP_EXACT;
+  common->private_data_ptrs[end - common->start - LINK_SIZE + 2] = min;
+  return TRUE;
+  }
+
+return FALSE;
+}
+
+#define CASE_ITERATOR_PRIVATE_DATA_1 \
+    case OP_MINSTAR: \
+    case OP_MINPLUS: \
+    case OP_QUERY: \
+    case OP_MINQUERY: \
+    case OP_MINSTARI: \
+    case OP_MINPLUSI: \
+    case OP_QUERYI: \
+    case OP_MINQUERYI: \
+    case OP_NOTMINSTAR: \
+    case OP_NOTMINPLUS: \
+    case OP_NOTQUERY: \
+    case OP_NOTMINQUERY: \
+    case OP_NOTMINSTARI: \
+    case OP_NOTMINPLUSI: \
+    case OP_NOTQUERYI: \
+    case OP_NOTMINQUERYI:
+
+#define CASE_ITERATOR_PRIVATE_DATA_2A \
+    case OP_STAR: \
+    case OP_PLUS: \
+    case OP_STARI: \
+    case OP_PLUSI: \
+    case OP_NOTSTAR: \
+    case OP_NOTPLUS: \
+    case OP_NOTSTARI: \
+    case OP_NOTPLUSI:
+
+#define CASE_ITERATOR_PRIVATE_DATA_2B \
+    case OP_UPTO: \
+    case OP_MINUPTO: \
+    case OP_UPTOI: \
+    case OP_MINUPTOI: \
+    case OP_NOTUPTO: \
+    case OP_NOTMINUPTO: \
+    case OP_NOTUPTOI: \
+    case OP_NOTMINUPTOI:
+
+#define CASE_ITERATOR_TYPE_PRIVATE_DATA_1 \
+    case OP_TYPEMINSTAR: \
+    case OP_TYPEMINPLUS: \
+    case OP_TYPEQUERY: \
+    case OP_TYPEMINQUERY:
+
+#define CASE_ITERATOR_TYPE_PRIVATE_DATA_2A \
+    case OP_TYPESTAR: \
+    case OP_TYPEPLUS:
+
+#define CASE_ITERATOR_TYPE_PRIVATE_DATA_2B \
+    case OP_TYPEUPTO: \
+    case OP_TYPEMINUPTO:
+
+static void set_private_data_ptrs(compiler_common *common, int *private_data_start, PCRE2_SPTR ccend)
+{
+PCRE2_SPTR cc = common->start;
+PCRE2_SPTR alternative;
+PCRE2_SPTR end = NULL;
+int private_data_ptr = *private_data_start;
+int space, size, bracketlen;
+BOOL repeat_check = TRUE;
+
+while (cc < ccend)
+  {
+  space = 0;
+  size = 0;
+  bracketlen = 0;
+  if (private_data_ptr > SLJIT_MAX_LOCAL_SIZE)
+    break;
+
+  if (repeat_check && (*cc == OP_ONCE || *cc == OP_BRA || *cc == OP_CBRA || *cc == OP_COND))
+    {
+    if (detect_repeat(common, cc))
+      {
+      /* These brackets are converted to repeats, so no global
+      based single character repeat is allowed. */
+      if (cc >= end)
+        end = bracketend(cc);
+      }
+    }
+  repeat_check = TRUE;
+
+  switch(*cc)
+    {
+    case OP_KET:
+    if (common->private_data_ptrs[cc + 1 - common->start] != 0)
+      {
+      common->private_data_ptrs[cc - common->start] = private_data_ptr;
+      private_data_ptr += sizeof(sljit_sw);
+      cc += common->private_data_ptrs[cc + 1 - common->start];
+      }
+    cc += 1 + LINK_SIZE;
+    break;
+
+    case OP_ASSERT:
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK:
+    case OP_ASSERTBACK_NOT:
+    case OP_ASSERT_NA:
+    case OP_ASSERTBACK_NA:
+    case OP_ONCE:
+    case OP_SCRIPT_RUN:
+    case OP_BRAPOS:
+    case OP_SBRA:
+    case OP_SBRAPOS:
+    case OP_SCOND:
+    common->private_data_ptrs[cc - common->start] = private_data_ptr;
+    private_data_ptr += sizeof(sljit_sw);
+    bracketlen = 1 + LINK_SIZE;
+    break;
+
+    case OP_CBRAPOS:
+    case OP_SCBRAPOS:
+    common->private_data_ptrs[cc - common->start] = private_data_ptr;
+    private_data_ptr += sizeof(sljit_sw);
+    bracketlen = 1 + LINK_SIZE + IMM2_SIZE;
+    break;
+
+    case OP_COND:
+    /* Might be a hidden SCOND. */
+    alternative = cc + GET(cc, 1);
+    if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN)
+      {
+      common->private_data_ptrs[cc - common->start] = private_data_ptr;
+      private_data_ptr += sizeof(sljit_sw);
+      }
+    bracketlen = 1 + LINK_SIZE;
+    break;
+
+    case OP_BRA:
+    bracketlen = 1 + LINK_SIZE;
+    break;
+
+    case OP_CBRA:
+    case OP_SCBRA:
+    bracketlen = 1 + LINK_SIZE + IMM2_SIZE;
+    break;
+
+    case OP_BRAZERO:
+    case OP_BRAMINZERO:
+    case OP_BRAPOSZERO:
+    size = 1;
+    repeat_check = FALSE;
+    break;
+
+    CASE_ITERATOR_PRIVATE_DATA_1
+    size = -2;
+    space = 1;
+    break;
+
+    CASE_ITERATOR_PRIVATE_DATA_2A
+    size = -2;
+    space = 2;
+    break;
+
+    CASE_ITERATOR_PRIVATE_DATA_2B
+    size = -(2 + IMM2_SIZE);
+    space = 2;
+    break;
+
+    CASE_ITERATOR_TYPE_PRIVATE_DATA_1
+    size = 1;
+    space = 1;
+    break;
+
+    CASE_ITERATOR_TYPE_PRIVATE_DATA_2A
+    size = 1;
+    if (cc[1] != OP_ANYNL && cc[1] != OP_EXTUNI)
+      space = 2;
+    break;
+
+    case OP_TYPEUPTO:
+    size = 1 + IMM2_SIZE;
+    if (cc[1 + IMM2_SIZE] != OP_ANYNL && cc[1 + IMM2_SIZE] != OP_EXTUNI)
+      space = 2;
+    break;
+
+    case OP_TYPEMINUPTO:
+    size = 1 + IMM2_SIZE;
+    space = 2;
+    break;
+
+    case OP_CLASS:
+    case OP_NCLASS:
+    size = 1 + 32 / sizeof(PCRE2_UCHAR);
+    space = get_class_iterator_size(cc + size);
+    break;
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+    case OP_XCLASS:
+    size = GET(cc, 1);
+    space = get_class_iterator_size(cc + size);
+    break;
+#endif
+
+    default:
+    cc = next_opcode(common, cc);
+    SLJIT_ASSERT(cc != NULL);
+    break;
+    }
+
+  /* Character iterators, which are not inside a repeated bracket,
+     gets a private slot instead of allocating it on the stack. */
+  if (space > 0 && cc >= end)
+    {
+    common->private_data_ptrs[cc - common->start] = private_data_ptr;
+    private_data_ptr += sizeof(sljit_sw) * space;
+    }
+
+  if (size != 0)
+    {
+    if (size < 0)
+      {
+      cc += -size;
+#ifdef SUPPORT_UNICODE
+      if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+      }
+    else
+      cc += size;
+    }
+
+  if (bracketlen > 0)
+    {
+    if (cc >= end)
+      {
+      end = bracketend(cc);
+      if (end[-1 - LINK_SIZE] == OP_KET)
+        end = NULL;
+      }
+    cc += bracketlen;
+    }
+  }
+*private_data_start = private_data_ptr;
+}
+
+/* Returns with a frame_types (always < 0) if no need for frame. */
+static int get_framesize(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, BOOL recursive, BOOL *needs_control_head)
+{
+int length = 0;
+int possessive = 0;
+BOOL stack_restore = FALSE;
+BOOL setsom_found = recursive;
+BOOL setmark_found = recursive;
+/* The last capture is a local variable even for recursions. */
+BOOL capture_last_found = FALSE;
+
+#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD
+SLJIT_ASSERT(common->control_head_ptr != 0);
+*needs_control_head = TRUE;
+#else
+*needs_control_head = FALSE;
+#endif
+
+if (ccend == NULL)
+  {
+  ccend = bracketend(cc) - (1 + LINK_SIZE);
+  if (!recursive && (*cc == OP_CBRAPOS || *cc == OP_SCBRAPOS))
+    {
+    possessive = length = (common->capture_last_ptr != 0) ? 5 : 3;
+    /* This is correct regardless of common->capture_last_ptr. */
+    capture_last_found = TRUE;
+    }
+  cc = next_opcode(common, cc);
+  }
+
+SLJIT_ASSERT(cc != NULL);
+while (cc < ccend)
+  switch(*cc)
+    {
+    case OP_SET_SOM:
+    SLJIT_ASSERT(common->has_set_som);
+    stack_restore = TRUE;
+    if (!setsom_found)
+      {
+      length += 2;
+      setsom_found = TRUE;
+      }
+    cc += 1;
+    break;
+
+    case OP_MARK:
+    case OP_COMMIT_ARG:
+    case OP_PRUNE_ARG:
+    case OP_THEN_ARG:
+    SLJIT_ASSERT(common->mark_ptr != 0);
+    stack_restore = TRUE;
+    if (!setmark_found)
+      {
+      length += 2;
+      setmark_found = TRUE;
+      }
+    if (common->control_head_ptr != 0)
+      *needs_control_head = TRUE;
+    cc += 1 + 2 + cc[1];
+    break;
+
+    case OP_RECURSE:
+    stack_restore = TRUE;
+    if (common->has_set_som && !setsom_found)
+      {
+      length += 2;
+      setsom_found = TRUE;
+      }
+    if (common->mark_ptr != 0 && !setmark_found)
+      {
+      length += 2;
+      setmark_found = TRUE;
+      }
+    if (common->capture_last_ptr != 0 && !capture_last_found)
+      {
+      length += 2;
+      capture_last_found = TRUE;
+      }
+    cc += 1 + LINK_SIZE;
+    break;
+
+    case OP_CBRA:
+    case OP_CBRAPOS:
+    case OP_SCBRA:
+    case OP_SCBRAPOS:
+    stack_restore = TRUE;
+    if (common->capture_last_ptr != 0 && !capture_last_found)
+      {
+      length += 2;
+      capture_last_found = TRUE;
+      }
+    length += 3;
+    cc += 1 + LINK_SIZE + IMM2_SIZE;
+    break;
+
+    case OP_THEN:
+    stack_restore = TRUE;
+    if (common->control_head_ptr != 0)
+      *needs_control_head = TRUE;
+    cc ++;
+    break;
+
+    default:
+    stack_restore = TRUE;
+    /* Fall through. */
+
+    case OP_NOT_WORD_BOUNDARY:
+    case OP_WORD_BOUNDARY:
+    case OP_NOT_DIGIT:
+    case OP_DIGIT:
+    case OP_NOT_WHITESPACE:
+    case OP_WHITESPACE:
+    case OP_NOT_WORDCHAR:
+    case OP_WORDCHAR:
+    case OP_ANY:
+    case OP_ALLANY:
+    case OP_ANYBYTE:
+    case OP_NOTPROP:
+    case OP_PROP:
+    case OP_ANYNL:
+    case OP_NOT_HSPACE:
+    case OP_HSPACE:
+    case OP_NOT_VSPACE:
+    case OP_VSPACE:
+    case OP_EXTUNI:
+    case OP_EODN:
+    case OP_EOD:
+    case OP_CIRC:
+    case OP_CIRCM:
+    case OP_DOLL:
+    case OP_DOLLM:
+    case OP_CHAR:
+    case OP_CHARI:
+    case OP_NOT:
+    case OP_NOTI:
+
+    case OP_EXACT:
+    case OP_POSSTAR:
+    case OP_POSPLUS:
+    case OP_POSQUERY:
+    case OP_POSUPTO:
+
+    case OP_EXACTI:
+    case OP_POSSTARI:
+    case OP_POSPLUSI:
+    case OP_POSQUERYI:
+    case OP_POSUPTOI:
+
+    case OP_NOTEXACT:
+    case OP_NOTPOSSTAR:
+    case OP_NOTPOSPLUS:
+    case OP_NOTPOSQUERY:
+    case OP_NOTPOSUPTO:
+
+    case OP_NOTEXACTI:
+    case OP_NOTPOSSTARI:
+    case OP_NOTPOSPLUSI:
+    case OP_NOTPOSQUERYI:
+    case OP_NOTPOSUPTOI:
+
+    case OP_TYPEEXACT:
+    case OP_TYPEPOSSTAR:
+    case OP_TYPEPOSPLUS:
+    case OP_TYPEPOSQUERY:
+    case OP_TYPEPOSUPTO:
+
+    case OP_CLASS:
+    case OP_NCLASS:
+    case OP_XCLASS:
+
+    case OP_CALLOUT:
+    case OP_CALLOUT_STR:
+
+    cc = next_opcode(common, cc);
+    SLJIT_ASSERT(cc != NULL);
+    break;
+    }
+
+/* Possessive quantifiers can use a special case. */
+if (SLJIT_UNLIKELY(possessive == length))
+  return stack_restore ? no_frame : no_stack;
+
+if (length > 0)
+  return length + 1;
+return stack_restore ? no_frame : no_stack;
+}
+
+static void init_frame(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, int stackpos, int stacktop)
+{
+DEFINE_COMPILER;
+BOOL setsom_found = FALSE;
+BOOL setmark_found = FALSE;
+/* The last capture is a local variable even for recursions. */
+BOOL capture_last_found = FALSE;
+int offset;
+
+/* >= 1 + shortest item size (2) */
+SLJIT_UNUSED_ARG(stacktop);
+SLJIT_ASSERT(stackpos >= stacktop + 2);
+
+stackpos = STACK(stackpos);
+if (ccend == NULL)
+  {
+  ccend = bracketend(cc) - (1 + LINK_SIZE);
+  if (*cc != OP_CBRAPOS && *cc != OP_SCBRAPOS)
+    cc = next_opcode(common, cc);
+  }
+
+SLJIT_ASSERT(cc != NULL);
+while (cc < ccend)
+  switch(*cc)
+    {
+    case OP_SET_SOM:
+    SLJIT_ASSERT(common->has_set_som);
+    if (!setsom_found)
+      {
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0));
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -OVECTOR(0));
+      stackpos -= (int)sizeof(sljit_sw);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
+      stackpos -= (int)sizeof(sljit_sw);
+      setsom_found = TRUE;
+      }
+    cc += 1;
+    break;
+
+    case OP_MARK:
+    case OP_COMMIT_ARG:
+    case OP_PRUNE_ARG:
+    case OP_THEN_ARG:
+    SLJIT_ASSERT(common->mark_ptr != 0);
+    if (!setmark_found)
+      {
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->mark_ptr);
+      stackpos -= (int)sizeof(sljit_sw);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
+      stackpos -= (int)sizeof(sljit_sw);
+      setmark_found = TRUE;
+      }
+    cc += 1 + 2 + cc[1];
+    break;
+
+    case OP_RECURSE:
+    if (common->has_set_som && !setsom_found)
+      {
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0));
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -OVECTOR(0));
+      stackpos -= (int)sizeof(sljit_sw);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
+      stackpos -= (int)sizeof(sljit_sw);
+      setsom_found = TRUE;
+      }
+    if (common->mark_ptr != 0 && !setmark_found)
+      {
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->mark_ptr);
+      stackpos -= (int)sizeof(sljit_sw);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
+      stackpos -= (int)sizeof(sljit_sw);
+      setmark_found = TRUE;
+      }
+    if (common->capture_last_ptr != 0 && !capture_last_found)
+      {
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->capture_last_ptr);
+      stackpos -= (int)sizeof(sljit_sw);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
+      stackpos -= (int)sizeof(sljit_sw);
+      capture_last_found = TRUE;
+      }
+    cc += 1 + LINK_SIZE;
+    break;
+
+    case OP_CBRA:
+    case OP_CBRAPOS:
+    case OP_SCBRA:
+    case OP_SCBRAPOS:
+    if (common->capture_last_ptr != 0 && !capture_last_found)
+      {
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->capture_last_ptr);
+      stackpos -= (int)sizeof(sljit_sw);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
+      stackpos -= (int)sizeof(sljit_sw);
+      capture_last_found = TRUE;
+      }
+    offset = (GET2(cc, 1 + LINK_SIZE)) << 1;
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, OVECTOR(offset));
+    stackpos -= (int)sizeof(sljit_sw);
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
+    stackpos -= (int)sizeof(sljit_sw);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP2, 0);
+    stackpos -= (int)sizeof(sljit_sw);
+
+    cc += 1 + LINK_SIZE + IMM2_SIZE;
+    break;
+
+    default:
+    cc = next_opcode(common, cc);
+    SLJIT_ASSERT(cc != NULL);
+    break;
+    }
+
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, 0);
+SLJIT_ASSERT(stackpos == STACK(stacktop));
+}
+
+#define RECURSE_TMP_REG_COUNT 3
+
+typedef struct delayed_mem_copy_status {
+  struct sljit_compiler *compiler;
+  int store_bases[RECURSE_TMP_REG_COUNT];
+  int store_offsets[RECURSE_TMP_REG_COUNT];
+  int tmp_regs[RECURSE_TMP_REG_COUNT];
+  int saved_tmp_regs[RECURSE_TMP_REG_COUNT];
+  int next_tmp_reg;
+} delayed_mem_copy_status;
+
+static void delayed_mem_copy_init(delayed_mem_copy_status *status, compiler_common *common)
+{
+int i;
+
+for (i = 0; i < RECURSE_TMP_REG_COUNT; i++)
+  {
+  SLJIT_ASSERT(status->tmp_regs[i] >= 0);
+  SLJIT_ASSERT(sljit_get_register_index(status->saved_tmp_regs[i]) < 0 || status->tmp_regs[i] == status->saved_tmp_regs[i]);
+
+  status->store_bases[i] = -1;
+  }
+status->next_tmp_reg = 0;
+status->compiler = common->compiler;
+}
+
+static void delayed_mem_copy_move(delayed_mem_copy_status *status, int load_base, sljit_sw load_offset,
+  int store_base, sljit_sw store_offset)
+{
+struct sljit_compiler *compiler = status->compiler;
+int next_tmp_reg = status->next_tmp_reg;
+int tmp_reg = status->tmp_regs[next_tmp_reg];
+
+SLJIT_ASSERT(load_base > 0 && store_base > 0);
+
+if (status->store_bases[next_tmp_reg] == -1)
+  {
+  /* Preserve virtual registers. */
+  if (sljit_get_register_index(status->saved_tmp_regs[next_tmp_reg]) < 0)
+    OP1(SLJIT_MOV, status->saved_tmp_regs[next_tmp_reg], 0, tmp_reg, 0);
+  }
+else
+  OP1(SLJIT_MOV, SLJIT_MEM1(status->store_bases[next_tmp_reg]), status->store_offsets[next_tmp_reg], tmp_reg, 0);
+
+OP1(SLJIT_MOV, tmp_reg, 0, SLJIT_MEM1(load_base), load_offset);
+status->store_bases[next_tmp_reg] = store_base;
+status->store_offsets[next_tmp_reg] = store_offset;
+
+status->next_tmp_reg = (next_tmp_reg + 1) % RECURSE_TMP_REG_COUNT;
+}
+
+static void delayed_mem_copy_finish(delayed_mem_copy_status *status)
+{
+struct sljit_compiler *compiler = status->compiler;
+int next_tmp_reg = status->next_tmp_reg;
+int tmp_reg, saved_tmp_reg, i;
+
+for (i = 0; i < RECURSE_TMP_REG_COUNT; i++)
+  {
+  if (status->store_bases[next_tmp_reg] != -1)
+    {
+    tmp_reg = status->tmp_regs[next_tmp_reg];
+    saved_tmp_reg = status->saved_tmp_regs[next_tmp_reg];
+
+    OP1(SLJIT_MOV, SLJIT_MEM1(status->store_bases[next_tmp_reg]), status->store_offsets[next_tmp_reg], tmp_reg, 0);
+
+    /* Restore virtual registers. */
+    if (sljit_get_register_index(saved_tmp_reg) < 0)
+      OP1(SLJIT_MOV, tmp_reg, 0, saved_tmp_reg, 0);
+    }
+
+  next_tmp_reg = (next_tmp_reg + 1) % RECURSE_TMP_REG_COUNT;
+  }
+}
+
+#undef RECURSE_TMP_REG_COUNT
+
+static int get_recurse_data_length(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend,
+  BOOL *needs_control_head, BOOL *has_quit, BOOL *has_accept)
+{
+int length = 1;
+int size;
+PCRE2_SPTR alternative;
+BOOL quit_found = FALSE;
+BOOL accept_found = FALSE;
+BOOL setsom_found = FALSE;
+BOOL setmark_found = FALSE;
+BOOL capture_last_found = FALSE;
+BOOL control_head_found = FALSE;
+
+#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD
+SLJIT_ASSERT(common->control_head_ptr != 0);
+control_head_found = TRUE;
+#endif
+
+/* Calculate the sum of the private machine words. */
+while (cc < ccend)
+  {
+  size = 0;
+  switch(*cc)
+    {
+    case OP_SET_SOM:
+    SLJIT_ASSERT(common->has_set_som);
+    setsom_found = TRUE;
+    cc += 1;
+    break;
+
+    case OP_RECURSE:
+    if (common->has_set_som)
+      setsom_found = TRUE;
+    if (common->mark_ptr != 0)
+      setmark_found = TRUE;
+    if (common->capture_last_ptr != 0)
+      capture_last_found = TRUE;
+    cc += 1 + LINK_SIZE;
+    break;
+
+    case OP_KET:
+    if (PRIVATE_DATA(cc) != 0)
+      {
+      length++;
+      SLJIT_ASSERT(PRIVATE_DATA(cc + 1) != 0);
+      cc += PRIVATE_DATA(cc + 1);
+      }
+    cc += 1 + LINK_SIZE;
+    break;
+
+    case OP_ASSERT:
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK:
+    case OP_ASSERTBACK_NOT:
+    case OP_ASSERT_NA:
+    case OP_ASSERTBACK_NA:
+    case OP_ONCE:
+    case OP_SCRIPT_RUN:
+    case OP_BRAPOS:
+    case OP_SBRA:
+    case OP_SBRAPOS:
+    case OP_SCOND:
+    length++;
+    SLJIT_ASSERT(PRIVATE_DATA(cc) != 0);
+    cc += 1 + LINK_SIZE;
+    break;
+
+    case OP_CBRA:
+    case OP_SCBRA:
+    length += 2;
+    if (common->capture_last_ptr != 0)
+      capture_last_found = TRUE;
+    if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0)
+      length++;
+    cc += 1 + LINK_SIZE + IMM2_SIZE;
+    break;
+
+    case OP_CBRAPOS:
+    case OP_SCBRAPOS:
+    length += 2 + 2;
+    if (common->capture_last_ptr != 0)
+      capture_last_found = TRUE;
+    cc += 1 + LINK_SIZE + IMM2_SIZE;
+    break;
+
+    case OP_COND:
+    /* Might be a hidden SCOND. */
+    alternative = cc + GET(cc, 1);
+    if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN)
+      length++;
+    cc += 1 + LINK_SIZE;
+    break;
+
+    CASE_ITERATOR_PRIVATE_DATA_1
+    if (PRIVATE_DATA(cc) != 0)
+      length++;
+    cc += 2;
+#ifdef SUPPORT_UNICODE
+    if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+    break;
+
+    CASE_ITERATOR_PRIVATE_DATA_2A
+    if (PRIVATE_DATA(cc) != 0)
+      length += 2;
+    cc += 2;
+#ifdef SUPPORT_UNICODE
+    if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+    break;
+
+    CASE_ITERATOR_PRIVATE_DATA_2B
+    if (PRIVATE_DATA(cc) != 0)
+      length += 2;
+    cc += 2 + IMM2_SIZE;
+#ifdef SUPPORT_UNICODE
+    if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+    break;
+
+    CASE_ITERATOR_TYPE_PRIVATE_DATA_1
+    if (PRIVATE_DATA(cc) != 0)
+      length++;
+    cc += 1;
+    break;
+
+    CASE_ITERATOR_TYPE_PRIVATE_DATA_2A
+    if (PRIVATE_DATA(cc) != 0)
+      length += 2;
+    cc += 1;
+    break;
+
+    CASE_ITERATOR_TYPE_PRIVATE_DATA_2B
+    if (PRIVATE_DATA(cc) != 0)
+      length += 2;
+    cc += 1 + IMM2_SIZE;
+    break;
+
+    case OP_CLASS:
+    case OP_NCLASS:
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+    case OP_XCLASS:
+    size = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(PCRE2_UCHAR);
+#else
+    size = 1 + 32 / (int)sizeof(PCRE2_UCHAR);
+#endif
+    if (PRIVATE_DATA(cc) != 0)
+      length += get_class_iterator_size(cc + size);
+    cc += size;
+    break;
+
+    case OP_MARK:
+    case OP_COMMIT_ARG:
+    case OP_PRUNE_ARG:
+    case OP_THEN_ARG:
+    SLJIT_ASSERT(common->mark_ptr != 0);
+    if (!setmark_found)
+      setmark_found = TRUE;
+    if (common->control_head_ptr != 0)
+      control_head_found = TRUE;
+    if (*cc != OP_MARK)
+      quit_found = TRUE;
+
+    cc += 1 + 2 + cc[1];
+    break;
+
+    case OP_PRUNE:
+    case OP_SKIP:
+    case OP_COMMIT:
+    quit_found = TRUE;
+    cc++;
+    break;
+
+    case OP_SKIP_ARG:
+    quit_found = TRUE;
+    cc += 1 + 2 + cc[1];
+    break;
+
+    case OP_THEN:
+    SLJIT_ASSERT(common->control_head_ptr != 0);
+    quit_found = TRUE;
+    if (!control_head_found)
+      control_head_found = TRUE;
+    cc++;
+    break;
+
+    case OP_ACCEPT:
+    case OP_ASSERT_ACCEPT:
+    accept_found = TRUE;
+    cc++;
+    break;
+
+    default:
+    cc = next_opcode(common, cc);
+    SLJIT_ASSERT(cc != NULL);
+    break;
+    }
+  }
+SLJIT_ASSERT(cc == ccend);
+
+if (control_head_found)
+  length++;
+if (capture_last_found)
+  length++;
+if (quit_found)
+  {
+  if (setsom_found)
+    length++;
+  if (setmark_found)
+    length++;
+  }
+
+*needs_control_head = control_head_found;
+*has_quit = quit_found;
+*has_accept = accept_found;
+return length;
+}
+
+enum copy_recurse_data_types {
+  recurse_copy_from_global,
+  recurse_copy_private_to_global,
+  recurse_copy_shared_to_global,
+  recurse_copy_kept_shared_to_global,
+  recurse_swap_global
+};
+
+static void copy_recurse_data(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend,
+  int type, int stackptr, int stacktop, BOOL has_quit)
+{
+delayed_mem_copy_status status;
+PCRE2_SPTR alternative;
+sljit_sw private_srcw[2];
+sljit_sw shared_srcw[3];
+sljit_sw kept_shared_srcw[2];
+int private_count, shared_count, kept_shared_count;
+int from_sp, base_reg, offset, i;
+BOOL setsom_found = FALSE;
+BOOL setmark_found = FALSE;
+BOOL capture_last_found = FALSE;
+BOOL control_head_found = FALSE;
+
+#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD
+SLJIT_ASSERT(common->control_head_ptr != 0);
+control_head_found = TRUE;
+#endif
+
+switch (type)
+  {
+  case recurse_copy_from_global:
+  from_sp = TRUE;
+  base_reg = STACK_TOP;
+  break;
+
+  case recurse_copy_private_to_global:
+  case recurse_copy_shared_to_global:
+  case recurse_copy_kept_shared_to_global:
+  from_sp = FALSE;
+  base_reg = STACK_TOP;
+  break;
+
+  default:
+  SLJIT_ASSERT(type == recurse_swap_global);
+  from_sp = FALSE;
+  base_reg = TMP2;
+  break;
+  }
+
+stackptr = STACK(stackptr);
+stacktop = STACK(stacktop);
+
+status.tmp_regs[0] = TMP1;
+status.saved_tmp_regs[0] = TMP1;
+
+if (base_reg != TMP2)
+  {
+  status.tmp_regs[1] = TMP2;
+  status.saved_tmp_regs[1] = TMP2;
+  }
+else
+  {
+  status.saved_tmp_regs[1] = RETURN_ADDR;
+  if (HAS_VIRTUAL_REGISTERS)
+    status.tmp_regs[1] = STR_PTR;
+  else
+    status.tmp_regs[1] = RETURN_ADDR;
+  }
+
+status.saved_tmp_regs[2] = TMP3;
+if (HAS_VIRTUAL_REGISTERS)
+  status.tmp_regs[2] = STR_END;
+else
+  status.tmp_regs[2] = TMP3;
+
+delayed_mem_copy_init(&status, common);
+
+if (type != recurse_copy_shared_to_global && type != recurse_copy_kept_shared_to_global)
+  {
+  SLJIT_ASSERT(type == recurse_copy_from_global || type == recurse_copy_private_to_global || type == recurse_swap_global);
+
+  if (!from_sp)
+    delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, common->recursive_head_ptr);
+
+  if (from_sp || type == recurse_swap_global)
+    delayed_mem_copy_move(&status, SLJIT_SP, common->recursive_head_ptr, base_reg, stackptr);
+  }
+
+stackptr += sizeof(sljit_sw);
+
+#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD
+if (type != recurse_copy_shared_to_global)
+  {
+  if (!from_sp)
+    delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, common->control_head_ptr);
+
+  if (from_sp || type == recurse_swap_global)
+    delayed_mem_copy_move(&status, SLJIT_SP, common->control_head_ptr, base_reg, stackptr);
+  }
+
+stackptr += sizeof(sljit_sw);
+#endif
+
+while (cc < ccend)
+  {
+  private_count = 0;
+  shared_count = 0;
+  kept_shared_count = 0;
+
+  switch(*cc)
+    {
+    case OP_SET_SOM:
+    SLJIT_ASSERT(common->has_set_som);
+    if (has_quit && !setsom_found)
+      {
+      kept_shared_srcw[0] = OVECTOR(0);
+      kept_shared_count = 1;
+      setsom_found = TRUE;
+      }
+    cc += 1;
+    break;
+
+    case OP_RECURSE:
+    if (has_quit)
+      {
+      if (common->has_set_som && !setsom_found)
+        {
+        kept_shared_srcw[0] = OVECTOR(0);
+        kept_shared_count = 1;
+        setsom_found = TRUE;
+        }
+      if (common->mark_ptr != 0 && !setmark_found)
+        {
+        kept_shared_srcw[kept_shared_count] = common->mark_ptr;
+        kept_shared_count++;
+        setmark_found = TRUE;
+        }
+      }
+    if (common->capture_last_ptr != 0 && !capture_last_found)
+      {
+      shared_srcw[0] = common->capture_last_ptr;
+      shared_count = 1;
+      capture_last_found = TRUE;
+      }
+    cc += 1 + LINK_SIZE;
+    break;
+
+    case OP_KET:
+    if (PRIVATE_DATA(cc) != 0)
+      {
+      private_count = 1;
+      private_srcw[0] = PRIVATE_DATA(cc);
+      SLJIT_ASSERT(PRIVATE_DATA(cc + 1) != 0);
+      cc += PRIVATE_DATA(cc + 1);
+      }
+    cc += 1 + LINK_SIZE;
+    break;
+
+    case OP_ASSERT:
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK:
+    case OP_ASSERTBACK_NOT:
+    case OP_ASSERT_NA:
+    case OP_ASSERTBACK_NA:
+    case OP_ONCE:
+    case OP_SCRIPT_RUN:
+    case OP_BRAPOS:
+    case OP_SBRA:
+    case OP_SBRAPOS:
+    case OP_SCOND:
+    private_count = 1;
+    private_srcw[0] = PRIVATE_DATA(cc);
+    cc += 1 + LINK_SIZE;
+    break;
+
+    case OP_CBRA:
+    case OP_SCBRA:
+    offset = (GET2(cc, 1 + LINK_SIZE)) << 1;
+    shared_srcw[0] = OVECTOR(offset);
+    shared_srcw[1] = OVECTOR(offset + 1);
+    shared_count = 2;
+
+    if (common->capture_last_ptr != 0 && !capture_last_found)
+      {
+      shared_srcw[2] = common->capture_last_ptr;
+      shared_count = 3;
+      capture_last_found = TRUE;
+      }
+
+    if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0)
+      {
+      private_count = 1;
+      private_srcw[0] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE));
+      }
+    cc += 1 + LINK_SIZE + IMM2_SIZE;
+    break;
+
+    case OP_CBRAPOS:
+    case OP_SCBRAPOS:
+    offset = (GET2(cc, 1 + LINK_SIZE)) << 1;
+    shared_srcw[0] = OVECTOR(offset);
+    shared_srcw[1] = OVECTOR(offset + 1);
+    shared_count = 2;
+
+    if (common->capture_last_ptr != 0 && !capture_last_found)
+      {
+      shared_srcw[2] = common->capture_last_ptr;
+      shared_count = 3;
+      capture_last_found = TRUE;
+      }
+
+    private_count = 2;
+    private_srcw[0] = PRIVATE_DATA(cc);
+    private_srcw[1] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE));
+    cc += 1 + LINK_SIZE + IMM2_SIZE;
+    break;
+
+    case OP_COND:
+    /* Might be a hidden SCOND. */
+    alternative = cc + GET(cc, 1);
+    if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN)
+      {
+      private_count = 1;
+      private_srcw[0] = PRIVATE_DATA(cc);
+      }
+    cc += 1 + LINK_SIZE;
+    break;
+
+    CASE_ITERATOR_PRIVATE_DATA_1
+    if (PRIVATE_DATA(cc))
+      {
+      private_count = 1;
+      private_srcw[0] = PRIVATE_DATA(cc);
+      }
+    cc += 2;
+#ifdef SUPPORT_UNICODE
+    if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+    break;
+
+    CASE_ITERATOR_PRIVATE_DATA_2A
+    if (PRIVATE_DATA(cc))
+      {
+      private_count = 2;
+      private_srcw[0] = PRIVATE_DATA(cc);
+      private_srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw);
+      }
+    cc += 2;
+#ifdef SUPPORT_UNICODE
+    if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+    break;
+
+    CASE_ITERATOR_PRIVATE_DATA_2B
+    if (PRIVATE_DATA(cc))
+      {
+      private_count = 2;
+      private_srcw[0] = PRIVATE_DATA(cc);
+      private_srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw);
+      }
+    cc += 2 + IMM2_SIZE;
+#ifdef SUPPORT_UNICODE
+    if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+    break;
+
+    CASE_ITERATOR_TYPE_PRIVATE_DATA_1
+    if (PRIVATE_DATA(cc))
+      {
+      private_count = 1;
+      private_srcw[0] = PRIVATE_DATA(cc);
+      }
+    cc += 1;
+    break;
+
+    CASE_ITERATOR_TYPE_PRIVATE_DATA_2A
+    if (PRIVATE_DATA(cc))
+      {
+      private_count = 2;
+      private_srcw[0] = PRIVATE_DATA(cc);
+      private_srcw[1] = private_srcw[0] + sizeof(sljit_sw);
+      }
+    cc += 1;
+    break;
+
+    CASE_ITERATOR_TYPE_PRIVATE_DATA_2B
+    if (PRIVATE_DATA(cc))
+      {
+      private_count = 2;
+      private_srcw[0] = PRIVATE_DATA(cc);
+      private_srcw[1] = private_srcw[0] + sizeof(sljit_sw);
+      }
+    cc += 1 + IMM2_SIZE;
+    break;
+
+    case OP_CLASS:
+    case OP_NCLASS:
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+    case OP_XCLASS:
+    i = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(PCRE2_UCHAR);
+#else
+    i = 1 + 32 / (int)sizeof(PCRE2_UCHAR);
+#endif
+    if (PRIVATE_DATA(cc) != 0)
+      switch(get_class_iterator_size(cc + i))
+        {
+        case 1:
+        private_count = 1;
+        private_srcw[0] = PRIVATE_DATA(cc);
+        break;
+
+        case 2:
+        private_count = 2;
+        private_srcw[0] = PRIVATE_DATA(cc);
+        private_srcw[1] = private_srcw[0] + sizeof(sljit_sw);
+        break;
+
+        default:
+        SLJIT_UNREACHABLE();
+        break;
+        }
+    cc += i;
+    break;
+
+    case OP_MARK:
+    case OP_COMMIT_ARG:
+    case OP_PRUNE_ARG:
+    case OP_THEN_ARG:
+    SLJIT_ASSERT(common->mark_ptr != 0);
+    if (has_quit && !setmark_found)
+      {
+      kept_shared_srcw[0] = common->mark_ptr;
+      kept_shared_count = 1;
+      setmark_found = TRUE;
+      }
+    if (common->control_head_ptr != 0 && !control_head_found)
+      {
+      private_srcw[0] = common->control_head_ptr;
+      private_count = 1;
+      control_head_found = TRUE;
+      }
+    cc += 1 + 2 + cc[1];
+    break;
+
+    case OP_THEN:
+    SLJIT_ASSERT(common->control_head_ptr != 0);
+    if (!control_head_found)
+      {
+      private_srcw[0] = common->control_head_ptr;
+      private_count = 1;
+      control_head_found = TRUE;
+      }
+    cc++;
+    break;
+
+    default:
+    cc = next_opcode(common, cc);
+    SLJIT_ASSERT(cc != NULL);
+    break;
+    }
+
+  if (type != recurse_copy_shared_to_global && type != recurse_copy_kept_shared_to_global)
+    {
+    SLJIT_ASSERT(type == recurse_copy_from_global || type == recurse_copy_private_to_global || type == recurse_swap_global);
+
+    for (i = 0; i < private_count; i++)
+      {
+      SLJIT_ASSERT(private_srcw[i] != 0);
+
+      if (!from_sp)
+        delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, private_srcw[i]);
+
+      if (from_sp || type == recurse_swap_global)
+        delayed_mem_copy_move(&status, SLJIT_SP, private_srcw[i], base_reg, stackptr);
+
+      stackptr += sizeof(sljit_sw);
+      }
+    }
+  else
+    stackptr += sizeof(sljit_sw) * private_count;
+
+  if (type != recurse_copy_private_to_global && type != recurse_copy_kept_shared_to_global)
+    {
+    SLJIT_ASSERT(type == recurse_copy_from_global || type == recurse_copy_shared_to_global || type == recurse_swap_global);
+
+    for (i = 0; i < shared_count; i++)
+      {
+      SLJIT_ASSERT(shared_srcw[i] != 0);
+
+      if (!from_sp)
+        delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, shared_srcw[i]);
+
+      if (from_sp || type == recurse_swap_global)
+        delayed_mem_copy_move(&status, SLJIT_SP, shared_srcw[i], base_reg, stackptr);
+
+      stackptr += sizeof(sljit_sw);
+      }
+    }
+  else
+    stackptr += sizeof(sljit_sw) * shared_count;
+
+  if (type != recurse_copy_private_to_global && type != recurse_swap_global)
+    {
+    SLJIT_ASSERT(type == recurse_copy_from_global || type == recurse_copy_shared_to_global || type == recurse_copy_kept_shared_to_global);
+
+    for (i = 0; i < kept_shared_count; i++)
+      {
+      SLJIT_ASSERT(kept_shared_srcw[i] != 0);
+
+      if (!from_sp)
+        delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, kept_shared_srcw[i]);
+
+      if (from_sp || type == recurse_swap_global)
+        delayed_mem_copy_move(&status, SLJIT_SP, kept_shared_srcw[i], base_reg, stackptr);
+
+      stackptr += sizeof(sljit_sw);
+      }
+    }
+  else
+    stackptr += sizeof(sljit_sw) * kept_shared_count;
+  }
+
+SLJIT_ASSERT(cc == ccend && stackptr == stacktop);
+
+delayed_mem_copy_finish(&status);
+}
+
+static SLJIT_INLINE PCRE2_SPTR set_then_offsets(compiler_common *common, PCRE2_SPTR cc, sljit_u8 *current_offset)
+{
+PCRE2_SPTR end = bracketend(cc);
+BOOL has_alternatives = cc[GET(cc, 1)] == OP_ALT;
+
+/* Assert captures then. */
+if (*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NA)
+  current_offset = NULL;
+/* Conditional block does not. */
+if (*cc == OP_COND || *cc == OP_SCOND)
+  has_alternatives = FALSE;
+
+cc = next_opcode(common, cc);
+if (has_alternatives)
+  current_offset = common->then_offsets + (cc - common->start);
+
+while (cc < end)
+  {
+  if ((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NA) || (*cc >= OP_ONCE && *cc <= OP_SCOND))
+    cc = set_then_offsets(common, cc, current_offset);
+  else
+    {
+    if (*cc == OP_ALT && has_alternatives)
+      current_offset = common->then_offsets + (cc + 1 + LINK_SIZE - common->start);
+    if (*cc >= OP_THEN && *cc <= OP_THEN_ARG && current_offset != NULL)
+      *current_offset = 1;
+    cc = next_opcode(common, cc);
+    }
+  }
+
+return end;
+}
+
+#undef CASE_ITERATOR_PRIVATE_DATA_1
+#undef CASE_ITERATOR_PRIVATE_DATA_2A
+#undef CASE_ITERATOR_PRIVATE_DATA_2B
+#undef CASE_ITERATOR_TYPE_PRIVATE_DATA_1
+#undef CASE_ITERATOR_TYPE_PRIVATE_DATA_2A
+#undef CASE_ITERATOR_TYPE_PRIVATE_DATA_2B
+
+static SLJIT_INLINE BOOL is_powerof2(unsigned int value)
+{
+return (value & (value - 1)) == 0;
+}
+
+static SLJIT_INLINE void set_jumps(jump_list *list, struct sljit_label *label)
+{
+while (list)
+  {
+  /* sljit_set_label is clever enough to do nothing
+  if either the jump or the label is NULL. */
+  SET_LABEL(list->jump, label);
+  list = list->next;
+  }
+}
+
+static SLJIT_INLINE void add_jump(struct sljit_compiler *compiler, jump_list **list, struct sljit_jump *jump)
+{
+jump_list *list_item = sljit_alloc_memory(compiler, sizeof(jump_list));
+if (list_item)
+  {
+  list_item->next = *list;
+  list_item->jump = jump;
+  *list = list_item;
+  }
+}
+
+static void add_stub(compiler_common *common, struct sljit_jump *start)
+{
+DEFINE_COMPILER;
+stub_list *list_item = sljit_alloc_memory(compiler, sizeof(stub_list));
+
+if (list_item)
+  {
+  list_item->start = start;
+  list_item->quit = LABEL();
+  list_item->next = common->stubs;
+  common->stubs = list_item;
+  }
+}
+
+static void flush_stubs(compiler_common *common)
+{
+DEFINE_COMPILER;
+stub_list *list_item = common->stubs;
+
+while (list_item)
+  {
+  JUMPHERE(list_item->start);
+  add_jump(compiler, &common->stackalloc, JUMP(SLJIT_FAST_CALL));
+  JUMPTO(SLJIT_JUMP, list_item->quit);
+  list_item = list_item->next;
+  }
+common->stubs = NULL;
+}
+
+static SLJIT_INLINE void count_match(compiler_common *common)
+{
+DEFINE_COMPILER;
+
+OP2(SLJIT_SUB | SLJIT_SET_Z, COUNT_MATCH, 0, COUNT_MATCH, 0, SLJIT_IMM, 1);
+add_jump(compiler, &common->calllimit, JUMP(SLJIT_ZERO));
+}
+
+static SLJIT_INLINE void allocate_stack(compiler_common *common, int size)
+{
+/* May destroy all locals and registers except TMP2. */
+DEFINE_COMPILER;
+
+SLJIT_ASSERT(size > 0);
+OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw));
+#ifdef DESTROY_REGISTERS
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 12345);
+OP1(SLJIT_MOV, TMP3, 0, TMP1, 0);
+OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0);
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, TMP1, 0);
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP1, 0);
+#endif
+add_stub(common, CMP(SLJIT_LESS, STACK_TOP, 0, STACK_LIMIT, 0));
+}
+
+static SLJIT_INLINE void free_stack(compiler_common *common, int size)
+{
+DEFINE_COMPILER;
+
+SLJIT_ASSERT(size > 0);
+OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw));
+}
+
+static sljit_uw * allocate_read_only_data(compiler_common *common, sljit_uw size)
+{
+DEFINE_COMPILER;
+sljit_uw *result;
+
+if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+  return NULL;
+
+result = (sljit_uw *)SLJIT_MALLOC(size + sizeof(sljit_uw), compiler->allocator_data);
+if (SLJIT_UNLIKELY(result == NULL))
+  {
+  sljit_set_compiler_memory_error(compiler);
+  return NULL;
+  }
+
+*(void**)result = common->read_only_data_head;
+common->read_only_data_head = (void *)result;
+return result + 1;
+}
+
+static SLJIT_INLINE void reset_ovector(compiler_common *common, int length)
+{
+DEFINE_COMPILER;
+struct sljit_label *loop;
+sljit_s32 i;
+
+/* At this point we can freely use all temporary registers. */
+SLJIT_ASSERT(length > 1);
+/* TMP1 returns with begin - 1. */
+OP2(SLJIT_SUB, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_S0), SLJIT_OFFSETOF(jit_arguments, begin), SLJIT_IMM, IN_UCHARS(1));
+if (length < 8)
+  {
+  for (i = 1; i < length; i++)
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(i), SLJIT_R0, 0);
+  }
+else
+  {
+  if (sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_STORE | SLJIT_MEM_PRE, SLJIT_R0, SLJIT_MEM1(SLJIT_R1), sizeof(sljit_sw)) == SLJIT_SUCCESS)
+    {
+    GET_LOCAL_BASE(SLJIT_R1, 0, OVECTOR_START);
+    OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, length - 1);
+    loop = LABEL();
+    sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_STORE | SLJIT_MEM_PRE, SLJIT_R0, SLJIT_MEM1(SLJIT_R1), sizeof(sljit_sw));
+    OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1);
+    JUMPTO(SLJIT_NOT_ZERO, loop);
+    }
+  else
+    {
+    GET_LOCAL_BASE(SLJIT_R1, 0, OVECTOR_START + sizeof(sljit_sw));
+    OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, length - 1);
+    loop = LABEL();
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R1), 0, SLJIT_R0, 0);
+    OP2(SLJIT_ADD, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, sizeof(sljit_sw));
+    OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1);
+    JUMPTO(SLJIT_NOT_ZERO, loop);
+    }
+  }
+}
+
+static SLJIT_INLINE void reset_early_fail(compiler_common *common)
+{
+DEFINE_COMPILER;
+sljit_u32 size = (sljit_u32)(common->early_fail_end_ptr - common->early_fail_start_ptr);
+sljit_u32 uncleared_size;
+sljit_s32 src = SLJIT_IMM;
+sljit_s32 i;
+struct sljit_label *loop;
+
+SLJIT_ASSERT(common->early_fail_start_ptr < common->early_fail_end_ptr);
+
+if (size == sizeof(sljit_sw))
+  {
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->early_fail_start_ptr, SLJIT_IMM, 0);
+  return;
+  }
+
+if (sljit_get_register_index(TMP3) >= 0 && !sljit_has_cpu_feature(SLJIT_HAS_ZERO_REGISTER))
+  {
+  OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 0);
+  src = TMP3;
+  }
+
+if (size <= 6 * sizeof(sljit_sw))
+  {
+  for (i = common->early_fail_start_ptr; i < common->early_fail_end_ptr; i += sizeof(sljit_sw))
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), i, src, 0);
+  return;
+  }
+
+GET_LOCAL_BASE(TMP1, 0, common->early_fail_start_ptr);
+
+uncleared_size = ((size / sizeof(sljit_sw)) % 3) * sizeof(sljit_sw);
+
+OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, size - uncleared_size);
+
+loop = LABEL();
+OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), 0, src, 0);
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 3 * sizeof(sljit_sw));
+OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), -2 * (sljit_sw)sizeof(sljit_sw), src, 0);
+OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), -1 * (sljit_sw)sizeof(sljit_sw), src, 0);
+CMPTO(SLJIT_LESS, TMP1, 0, TMP2, 0, loop);
+
+if (uncleared_size >= sizeof(sljit_sw))
+  OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), 0, src, 0);
+
+if (uncleared_size >= 2 * sizeof(sljit_sw))
+  OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), sizeof(sljit_sw), src, 0);
+}
+
+static SLJIT_INLINE void do_reset_match(compiler_common *common, int length)
+{
+DEFINE_COMPILER;
+struct sljit_label *loop;
+int i;
+
+SLJIT_ASSERT(length > 1);
+/* OVECTOR(1) contains the "string begin - 1" constant. */
+if (length > 2)
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1));
+if (length < 8)
+  {
+  for (i = 2; i < length; i++)
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(i), TMP1, 0);
+  }
+else
+  {
+  if (sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_STORE | SLJIT_MEM_PRE, TMP1, SLJIT_MEM1(TMP2), sizeof(sljit_sw)) == SLJIT_SUCCESS)
+    {
+    GET_LOCAL_BASE(TMP2, 0, OVECTOR_START + sizeof(sljit_sw));
+    OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, length - 2);
+    loop = LABEL();
+    sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_STORE | SLJIT_MEM_PRE, TMP1, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
+    OP2(SLJIT_SUB | SLJIT_SET_Z, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1);
+    JUMPTO(SLJIT_NOT_ZERO, loop);
+    }
+  else
+    {
+    GET_LOCAL_BASE(TMP2, 0, OVECTOR_START + 2 * sizeof(sljit_sw));
+    OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, length - 2);
+    loop = LABEL();
+    OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, TMP1, 0);
+    OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, sizeof(sljit_sw));
+    OP2(SLJIT_SUB | SLJIT_SET_Z, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1);
+    JUMPTO(SLJIT_NOT_ZERO, loop);
+    }
+  }
+
+if (!HAS_VIRTUAL_REGISTERS)
+  OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, stack));
+else
+  OP1(SLJIT_MOV, STACK_TOP, 0, ARGUMENTS, 0);
+
+if (common->mark_ptr != 0)
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, SLJIT_IMM, 0);
+if (common->control_head_ptr != 0)
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0);
+if (HAS_VIRTUAL_REGISTERS)
+  OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), SLJIT_OFFSETOF(jit_arguments, stack));
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr);
+OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), SLJIT_OFFSETOF(struct sljit_stack, end));
+}
+
+static sljit_sw SLJIT_FUNC do_search_mark(sljit_sw *current, PCRE2_SPTR skip_arg)
+{
+while (current != NULL)
+  {
+  switch (current[1])
+    {
+    case type_then_trap:
+    break;
+
+    case type_mark:
+    if (PRIV(strcmp)(skip_arg, (PCRE2_SPTR)current[2]) == 0)
+      return current[3];
+    break;
+
+    default:
+    SLJIT_UNREACHABLE();
+    break;
+    }
+  SLJIT_ASSERT(current[0] == 0 || current < (sljit_sw*)current[0]);
+  current = (sljit_sw*)current[0];
+  }
+return 0;
+}
+
+static SLJIT_INLINE void copy_ovector(compiler_common *common, int topbracket)
+{
+DEFINE_COMPILER;
+struct sljit_label *loop;
+BOOL has_pre;
+
+/* At this point we can freely use all registers. */
+OP1(SLJIT_MOV, SLJIT_S2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1));
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(1), STR_PTR, 0);
+
+if (HAS_VIRTUAL_REGISTERS)
+  {
+  OP1(SLJIT_MOV, SLJIT_R0, 0, ARGUMENTS, 0);
+  OP1(SLJIT_MOV, SLJIT_S0, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr);
+  if (common->mark_ptr != 0)
+    OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr);
+  OP1(SLJIT_MOV_U32, SLJIT_R1, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, oveccount));
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, startchar_ptr), SLJIT_S0, 0);
+  if (common->mark_ptr != 0)
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, mark_ptr), SLJIT_R2, 0);
+  OP2(SLJIT_ADD, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, match_data),
+    SLJIT_IMM, SLJIT_OFFSETOF(pcre2_match_data, ovector) - sizeof(PCRE2_SIZE));
+  }
+else
+  {
+  OP1(SLJIT_MOV, SLJIT_S0, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr);
+  OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, match_data));
+  if (common->mark_ptr != 0)
+    OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr);
+  OP1(SLJIT_MOV_U32, SLJIT_R1, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, oveccount));
+  OP1(SLJIT_MOV, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, startchar_ptr), SLJIT_S0, 0);
+  if (common->mark_ptr != 0)
+    OP1(SLJIT_MOV, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, mark_ptr), SLJIT_R0, 0);
+  OP2(SLJIT_ADD, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, SLJIT_OFFSETOF(pcre2_match_data, ovector) - sizeof(PCRE2_SIZE));
+  }
+
+has_pre = sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, SLJIT_S1, SLJIT_MEM1(SLJIT_S0), sizeof(sljit_sw)) == SLJIT_SUCCESS;
+
+GET_LOCAL_BASE(SLJIT_S0, 0, OVECTOR_START - (has_pre ? sizeof(sljit_sw) : 0));
+OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(HAS_VIRTUAL_REGISTERS ? SLJIT_R0 : ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin));
+
+loop = LABEL();
+
+if (has_pre)
+  sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_PRE, SLJIT_S1, SLJIT_MEM1(SLJIT_S0), sizeof(sljit_sw));
+else
+  {
+  OP1(SLJIT_MOV, SLJIT_S1, 0, SLJIT_MEM1(SLJIT_S0), 0);
+  OP2(SLJIT_ADD, SLJIT_S0, 0, SLJIT_S0, 0, SLJIT_IMM, sizeof(sljit_sw));
+  }
+
+OP2(SLJIT_ADD, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, sizeof(PCRE2_SIZE));
+OP2(SLJIT_SUB, SLJIT_S1, 0, SLJIT_S1, 0, SLJIT_R0, 0);
+/* Copy the integer value to the output buffer */
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+OP2(SLJIT_ASHR, SLJIT_S1, 0, SLJIT_S1, 0, SLJIT_IMM, UCHAR_SHIFT);
+#endif
+
+SLJIT_ASSERT(sizeof(PCRE2_SIZE) == 4 || sizeof(PCRE2_SIZE) == 8);
+OP1(((sizeof(PCRE2_SIZE) == 4) ? SLJIT_MOV_U32 : SLJIT_MOV), SLJIT_MEM1(SLJIT_R2), 0, SLJIT_S1, 0);
+
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1);
+JUMPTO(SLJIT_NOT_ZERO, loop);
+
+/* Calculate the return value, which is the maximum ovector value. */
+if (topbracket > 1)
+  {
+  if (sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, SLJIT_R2, SLJIT_MEM1(SLJIT_R0), -(2 * (sljit_sw)sizeof(sljit_sw))) == SLJIT_SUCCESS)
+    {
+    GET_LOCAL_BASE(SLJIT_R0, 0, OVECTOR_START + topbracket * 2 * sizeof(sljit_sw));
+    OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, topbracket + 1);
+
+    /* OVECTOR(0) is never equal to SLJIT_S2. */
+    loop = LABEL();
+    sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_PRE, SLJIT_R2, SLJIT_MEM1(SLJIT_R0), -(2 * (sljit_sw)sizeof(sljit_sw)));
+    OP2(SLJIT_SUB, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1);
+    CMPTO(SLJIT_EQUAL, SLJIT_R2, 0, SLJIT_S2, 0, loop);
+    OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_R1, 0);
+    }
+  else
+    {
+    GET_LOCAL_BASE(SLJIT_R0, 0, OVECTOR_START + (topbracket - 1) * 2 * sizeof(sljit_sw));
+    OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, topbracket + 1);
+
+    /* OVECTOR(0) is never equal to SLJIT_S2. */
+    loop = LABEL();
+    OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R0), 0);
+    OP2(SLJIT_SUB, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_IMM, 2 * (sljit_sw)sizeof(sljit_sw));
+    OP2(SLJIT_SUB, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1);
+    CMPTO(SLJIT_EQUAL, SLJIT_R2, 0, SLJIT_S2, 0, loop);
+    OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_R1, 0);
+    }
+  }
+else
+  OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1);
+}
+
+static SLJIT_INLINE void return_with_partial_match(compiler_common *common, struct sljit_label *quit)
+{
+DEFINE_COMPILER;
+sljit_s32 mov_opcode;
+sljit_s32 arguments_reg = !HAS_VIRTUAL_REGISTERS ? ARGUMENTS : SLJIT_R1;
+
+SLJIT_COMPILE_ASSERT(STR_END == SLJIT_S0, str_end_must_be_saved_reg0);
+SLJIT_ASSERT(common->start_used_ptr != 0 && common->start_ptr != 0
+  && (common->mode == PCRE2_JIT_PARTIAL_SOFT ? common->hit_start != 0 : common->hit_start == 0));
+
+if (arguments_reg != ARGUMENTS)
+  OP1(SLJIT_MOV, arguments_reg, 0, ARGUMENTS, 0);
+OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP),
+  common->mode == PCRE2_JIT_PARTIAL_SOFT ? common->hit_start : common->start_ptr);
+OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_PARTIAL);
+
+/* Store match begin and end. */
+OP1(SLJIT_MOV, SLJIT_S1, 0, SLJIT_MEM1(arguments_reg), SLJIT_OFFSETOF(jit_arguments, begin));
+OP1(SLJIT_MOV, SLJIT_MEM1(arguments_reg), SLJIT_OFFSETOF(jit_arguments, startchar_ptr), SLJIT_R2, 0);
+OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_MEM1(arguments_reg), SLJIT_OFFSETOF(jit_arguments, match_data));
+
+mov_opcode = (sizeof(PCRE2_SIZE) == 4) ? SLJIT_MOV_U32 : SLJIT_MOV;
+
+OP2(SLJIT_SUB, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_S1, 0);
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+OP2(SLJIT_ASHR, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, UCHAR_SHIFT);
+#endif
+OP1(mov_opcode, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(pcre2_match_data, ovector), SLJIT_R2, 0);
+
+OP2(SLJIT_SUB, STR_END, 0, STR_END, 0, SLJIT_S1, 0);
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+OP2(SLJIT_ASHR, STR_END, 0, STR_END, 0, SLJIT_IMM, UCHAR_SHIFT);
+#endif
+OP1(mov_opcode, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(pcre2_match_data, ovector) + sizeof(PCRE2_SIZE), STR_END, 0);
+
+JUMPTO(SLJIT_JUMP, quit);
+}
+
+static SLJIT_INLINE void check_start_used_ptr(compiler_common *common)
+{
+/* May destroy TMP1. */
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+
+if (common->mode == PCRE2_JIT_PARTIAL_SOFT)
+  {
+  /* The value of -1 must be kept for start_used_ptr! */
+  OP2(SLJIT_ADD, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, 1);
+  /* Jumps if start_used_ptr < STR_PTR, or start_used_ptr == -1. Although overwriting
+  is not necessary if start_used_ptr == STR_PTR, it does not hurt as well. */
+  jump = CMP(SLJIT_LESS_EQUAL, TMP1, 0, STR_PTR, 0);
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
+  JUMPHERE(jump);
+  }
+else if (common->mode == PCRE2_JIT_PARTIAL_HARD)
+  {
+  jump = CMP(SLJIT_LESS_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
+  JUMPHERE(jump);
+  }
+}
+
+static SLJIT_INLINE BOOL char_has_othercase(compiler_common *common, PCRE2_SPTR cc)
+{
+/* Detects if the character has an othercase. */
+unsigned int c;
+
+#ifdef SUPPORT_UNICODE
+if (common->utf || common->ucp)
+  {
+  if (common->utf)
+    {
+    GETCHAR(c, cc);
+    }
+  else
+    c = *cc;
+
+  if (c > 127)
+    return c != UCD_OTHERCASE(c);
+
+  return common->fcc[c] != c;
+  }
+else
+#endif
+  c = *cc;
+return MAX_255(c) ? common->fcc[c] != c : FALSE;
+}
+
+static SLJIT_INLINE unsigned int char_othercase(compiler_common *common, unsigned int c)
+{
+/* Returns with the othercase. */
+#ifdef SUPPORT_UNICODE
+if ((common->utf || common->ucp) && c > 127)
+  return UCD_OTHERCASE(c);
+#endif
+return TABLE_GET(c, common->fcc, c);
+}
+
+static unsigned int char_get_othercase_bit(compiler_common *common, PCRE2_SPTR cc)
+{
+/* Detects if the character and its othercase has only 1 bit difference. */
+unsigned int c, oc, bit;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+int n;
+#endif
+
+#ifdef SUPPORT_UNICODE
+if (common->utf || common->ucp)
+  {
+  if (common->utf)
+    {
+    GETCHAR(c, cc);
+    }
+  else
+    c = *cc;
+
+  if (c <= 127)
+    oc = common->fcc[c];
+  else
+    oc = UCD_OTHERCASE(c);
+  }
+else
+  {
+  c = *cc;
+  oc = TABLE_GET(c, common->fcc, c);
+  }
+#else
+c = *cc;
+oc = TABLE_GET(c, common->fcc, c);
+#endif
+
+SLJIT_ASSERT(c != oc);
+
+bit = c ^ oc;
+/* Optimized for English alphabet. */
+if (c <= 127 && bit == 0x20)
+  return (0 << 8) | 0x20;
+
+/* Since c != oc, they must have at least 1 bit difference. */
+if (!is_powerof2(bit))
+  return 0;
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+
+#ifdef SUPPORT_UNICODE
+if (common->utf && c > 127)
+  {
+  n = GET_EXTRALEN(*cc);
+  while ((bit & 0x3f) == 0)
+    {
+    n--;
+    bit >>= 6;
+    }
+  return (n << 8) | bit;
+  }
+#endif /* SUPPORT_UNICODE */
+return (0 << 8) | bit;
+
+#elif PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+
+#ifdef SUPPORT_UNICODE
+if (common->utf && c > 65535)
+  {
+  if (bit >= (1u << 10))
+    bit >>= 10;
+  else
+    return (bit < 256) ? ((2 << 8) | bit) : ((3 << 8) | (bit >> 8));
+  }
+#endif /* SUPPORT_UNICODE */
+return (bit < 256) ? ((0u << 8) | bit) : ((1u << 8) | (bit >> 8));
+
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
+}
+
+static void check_partial(compiler_common *common, BOOL force)
+{
+/* Checks whether a partial matching is occurred. Does not modify registers. */
+DEFINE_COMPILER;
+struct sljit_jump *jump = NULL;
+
+SLJIT_ASSERT(!force || common->mode != PCRE2_JIT_COMPLETE);
+
+if (common->mode == PCRE2_JIT_COMPLETE)
+  return;
+
+if (!force && !common->allow_empty_partial)
+  jump = CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
+else if (common->mode == PCRE2_JIT_PARTIAL_SOFT)
+  jump = CMP(SLJIT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, -1);
+
+if (common->mode == PCRE2_JIT_PARTIAL_SOFT)
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0);
+else
+  {
+  if (common->partialmatchlabel != NULL)
+    JUMPTO(SLJIT_JUMP, common->partialmatchlabel);
+  else
+    add_jump(compiler, &common->partialmatch, JUMP(SLJIT_JUMP));
+  }
+
+if (jump != NULL)
+  JUMPHERE(jump);
+}
+
+static void check_str_end(compiler_common *common, jump_list **end_reached)
+{
+/* Does not affect registers. Usually used in a tight spot. */
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+
+if (common->mode == PCRE2_JIT_COMPLETE)
+  {
+  add_jump(compiler, end_reached, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+  return;
+  }
+
+jump = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0);
+if (common->mode == PCRE2_JIT_PARTIAL_SOFT)
+  {
+  add_jump(compiler, end_reached, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0));
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0);
+  add_jump(compiler, end_reached, JUMP(SLJIT_JUMP));
+  }
+else
+  {
+  add_jump(compiler, end_reached, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0));
+  if (common->partialmatchlabel != NULL)
+    JUMPTO(SLJIT_JUMP, common->partialmatchlabel);
+  else
+    add_jump(compiler, &common->partialmatch, JUMP(SLJIT_JUMP));
+  }
+JUMPHERE(jump);
+}
+
+static void detect_partial_match(compiler_common *common, jump_list **backtracks)
+{
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+
+if (common->mode == PCRE2_JIT_COMPLETE)
+  {
+  add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+  return;
+  }
+
+/* Partial matching mode. */
+jump = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0);
+if (!common->allow_empty_partial)
+  add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0));
+else if (common->mode == PCRE2_JIT_PARTIAL_SOFT)
+  add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, -1));
+
+if (common->mode == PCRE2_JIT_PARTIAL_SOFT)
+  {
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0);
+  add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+  }
+else
+  {
+  if (common->partialmatchlabel != NULL)
+    JUMPTO(SLJIT_JUMP, common->partialmatchlabel);
+  else
+    add_jump(compiler, &common->partialmatch, JUMP(SLJIT_JUMP));
+  }
+JUMPHERE(jump);
+}
+
+static void process_partial_match(compiler_common *common)
+{
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+
+/* Partial matching mode. */
+if (common->mode == PCRE2_JIT_PARTIAL_SOFT)
+  {
+  jump = CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0);
+  JUMPHERE(jump);
+  }
+else if (common->mode == PCRE2_JIT_PARTIAL_HARD)
+  {
+  if (common->partialmatchlabel != NULL)
+    CMPTO(SLJIT_LESS, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0, common->partialmatchlabel);
+  else
+    add_jump(compiler, &common->partialmatch, CMP(SLJIT_LESS, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0));
+  }
+}
+
+static void detect_partial_match_to(compiler_common *common, struct sljit_label *label)
+{
+DEFINE_COMPILER;
+
+CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, label);
+process_partial_match(common);
+}
+
+static void peek_char(compiler_common *common, sljit_u32 max, sljit_s32 dst, sljit_sw dstw, jump_list **backtracks)
+{
+/* Reads the character into TMP1, keeps STR_PTR.
+Does not check STR_END. TMP2, dst, RETURN_ADDR Destroyed. */
+DEFINE_COMPILER;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+struct sljit_jump *jump;
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */
+
+SLJIT_UNUSED_ARG(max);
+SLJIT_UNUSED_ARG(dst);
+SLJIT_UNUSED_ARG(dstw);
+SLJIT_UNUSED_ARG(backtracks);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+
+#ifdef SUPPORT_UNICODE
+#if PCRE2_CODE_UNIT_WIDTH == 8
+if (common->utf)
+  {
+  if (max < 128) return;
+
+  jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x80);
+  OP1(SLJIT_MOV, dst, dstw, STR_PTR, 0);
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  add_jump(compiler, common->invalid_utf ? &common->utfreadchar_invalid : &common->utfreadchar, JUMP(SLJIT_FAST_CALL));
+  OP1(SLJIT_MOV, STR_PTR, 0, dst, dstw);
+  if (backtracks && common->invalid_utf)
+    add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR));
+  JUMPHERE(jump);
+  }
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+if (common->utf)
+  {
+  if (max < 0xd800) return;
+
+  OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+
+  if (common->invalid_utf)
+    {
+    jump = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800);
+    OP1(SLJIT_MOV, dst, dstw, STR_PTR, 0);
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    add_jump(compiler, &common->utfreadchar_invalid, JUMP(SLJIT_FAST_CALL));
+    OP1(SLJIT_MOV, STR_PTR, 0, dst, dstw);
+    if (backtracks && common->invalid_utf)
+      add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR));
+    }
+  else
+    {
+    /* TMP2 contains the high surrogate. */
+    jump = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0xdc00 - 0xd800);
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+    OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 10);
+    OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x10000 - 0xdc00);
+    OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+    }
+
+  JUMPHERE(jump);
+  }
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+if (common->invalid_utf)
+  {
+  if (max < 0xd800) return;
+
+  if (backtracks != NULL)
+    {
+    OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+    add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x110000));
+    add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800));
+    }
+  else
+    {
+    OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+    OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x110000);
+    CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR);
+    OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800);
+    CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR);
+    }
+  }
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
+#endif /* SUPPORT_UNICODE */
+}
+
+static void peek_char_back(compiler_common *common, sljit_u32 max, jump_list **backtracks)
+{
+/* Reads one character back without moving STR_PTR. TMP2 must
+contain the start of the subject buffer. Affects TMP1, TMP2, and RETURN_ADDR. */
+DEFINE_COMPILER;
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+struct sljit_jump *jump;
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */
+
+SLJIT_UNUSED_ARG(max);
+SLJIT_UNUSED_ARG(backtracks);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+
+#ifdef SUPPORT_UNICODE
+#if PCRE2_CODE_UNIT_WIDTH == 8
+if (common->utf)
+  {
+  if (max < 128) return;
+
+  jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x80);
+  if (common->invalid_utf)
+    {
+    add_jump(compiler, &common->utfpeakcharback_invalid, JUMP(SLJIT_FAST_CALL));
+    if (backtracks != NULL)
+      add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR));
+    }
+  else
+    add_jump(compiler, &common->utfpeakcharback, JUMP(SLJIT_FAST_CALL));
+  JUMPHERE(jump);
+  }
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+if (common->utf)
+  {
+  if (max < 0xd800) return;
+
+  if (common->invalid_utf)
+    {
+    jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800);
+    add_jump(compiler, &common->utfpeakcharback_invalid, JUMP(SLJIT_FAST_CALL));
+    if (backtracks != NULL)
+      add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR));
+    }
+  else
+    {
+    OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xdc00);
+    jump = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0xe000 - 0xdc00);
+    /* TMP2 contains the low surrogate. */
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2));
+    OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x10000);
+    OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+    OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 10);
+    OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+    }
+    JUMPHERE(jump);
+  }
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+if (common->invalid_utf)
+  {
+  OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+  add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x110000));
+  add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800));
+  }
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
+#endif /* SUPPORT_UNICODE */
+}
+
+#define READ_CHAR_UPDATE_STR_PTR 0x1
+#define READ_CHAR_UTF8_NEWLINE 0x2
+#define READ_CHAR_NEWLINE (READ_CHAR_UPDATE_STR_PTR | READ_CHAR_UTF8_NEWLINE)
+#define READ_CHAR_VALID_UTF 0x4
+
+static void read_char(compiler_common *common, sljit_u32 min, sljit_u32 max,
+  jump_list **backtracks, sljit_u32 options)
+{
+/* Reads the precise value of a character into TMP1, if the character is
+between min and max (c >= min && c <= max). Otherwise it returns with a value
+outside the range. Does not check STR_END. */
+DEFINE_COMPILER;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+struct sljit_jump *jump;
+#endif
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+struct sljit_jump *jump2;
+#endif
+
+SLJIT_UNUSED_ARG(min);
+SLJIT_UNUSED_ARG(max);
+SLJIT_UNUSED_ARG(backtracks);
+SLJIT_UNUSED_ARG(options);
+SLJIT_ASSERT(min <= max);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+#ifdef SUPPORT_UNICODE
+#if PCRE2_CODE_UNIT_WIDTH == 8
+if (common->utf)
+  {
+  if (max < 128 && !(options & READ_CHAR_UPDATE_STR_PTR)) return;
+
+  if (common->invalid_utf && !(options & READ_CHAR_VALID_UTF))
+    {
+    jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x80);
+
+    if (options & READ_CHAR_UTF8_NEWLINE)
+      add_jump(compiler, &common->utfreadnewline_invalid, JUMP(SLJIT_FAST_CALL));
+    else
+      add_jump(compiler, &common->utfreadchar_invalid, JUMP(SLJIT_FAST_CALL));
+
+    if (backtracks != NULL)
+      add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR));
+    JUMPHERE(jump);
+    return;
+    }
+
+  jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
+  if (min >= 0x10000)
+    {
+    OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xf0);
+    if (options & READ_CHAR_UPDATE_STR_PTR)
+      OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+    jump2 = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0x7);
+    OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
+    OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f);
+    OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+    OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+    OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+    OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
+    OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+    OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(2));
+    if (!(options & READ_CHAR_UPDATE_STR_PTR))
+      OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(3));
+    OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+    OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
+    OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+    JUMPHERE(jump2);
+    if (options & READ_CHAR_UPDATE_STR_PTR)
+      OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, RETURN_ADDR, 0);
+    }
+  else if (min >= 0x800 && max <= 0xffff)
+    {
+    OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xe0);
+    if (options & READ_CHAR_UPDATE_STR_PTR)
+      OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+    jump2 = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0xf);
+    OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
+    OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f);
+    OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+    OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+    if (!(options & READ_CHAR_UPDATE_STR_PTR))
+      OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+    OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+    OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
+    OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+    JUMPHERE(jump2);
+    if (options & READ_CHAR_UPDATE_STR_PTR)
+      OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, RETURN_ADDR, 0);
+    }
+  else if (max >= 0x800)
+    {
+    add_jump(compiler, &common->utfreadchar, JUMP(SLJIT_FAST_CALL));
+    }
+  else if (max < 128)
+    {
+    OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+    }
+  else
+    {
+    OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+    if (!(options & READ_CHAR_UPDATE_STR_PTR))
+      OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    else
+      OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+    OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f);
+    OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+    OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
+    OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+    if (options & READ_CHAR_UPDATE_STR_PTR)
+      OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, RETURN_ADDR, 0);
+    }
+  JUMPHERE(jump);
+  }
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+if (common->utf)
+  {
+  if (max < 0xd800 && !(options & READ_CHAR_UPDATE_STR_PTR)) return;
+
+  if (common->invalid_utf && !(options & READ_CHAR_VALID_UTF))
+    {
+    OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+    jump = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800);
+
+    if (options & READ_CHAR_UTF8_NEWLINE)
+      add_jump(compiler, &common->utfreadnewline_invalid, JUMP(SLJIT_FAST_CALL));
+    else
+      add_jump(compiler, &common->utfreadchar_invalid, JUMP(SLJIT_FAST_CALL));
+
+    if (backtracks != NULL)
+      add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR));
+    JUMPHERE(jump);
+    return;
+    }
+
+  if (max >= 0x10000)
+    {
+    OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+    jump = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0xdc00 - 0xd800);
+    /* TMP2 contains the high surrogate. */
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+    OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 10);
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x10000 - 0xdc00);
+    OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+    JUMPHERE(jump);
+    return;
+    }
+
+  /* Skip low surrogate if necessary. */
+  OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+
+  if (sljit_has_cpu_feature(SLJIT_HAS_CMOV) && !HAS_VIRTUAL_REGISTERS)
+    {
+    if (options & READ_CHAR_UPDATE_STR_PTR)
+      OP2(SLJIT_ADD, RETURN_ADDR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0x400);
+    if (options & READ_CHAR_UPDATE_STR_PTR)
+      CMOV(SLJIT_LESS, STR_PTR, RETURN_ADDR, 0);
+    if (max >= 0xd800)
+      CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, 0x10000);
+    }
+  else
+    {
+    jump = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x400);
+    if (options & READ_CHAR_UPDATE_STR_PTR)
+      OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    if (max >= 0xd800)
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0x10000);
+    JUMPHERE(jump);
+    }
+  }
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+if (common->invalid_utf)
+  {
+  if (backtracks != NULL)
+    {
+    OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+    add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x110000));
+    add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800));
+    }
+  else
+    {
+    OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+    OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x110000);
+    CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR);
+    OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800);
+    CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR);
+    }
+  }
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
+#endif /* SUPPORT_UNICODE */
+}
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+
+static BOOL is_char7_bitset(const sljit_u8 *bitset, BOOL nclass)
+{
+/* Tells whether the character codes below 128 are enough
+to determine a match. */
+const sljit_u8 value = nclass ? 0xff : 0;
+const sljit_u8 *end = bitset + 32;
+
+bitset += 16;
+do
+  {
+  if (*bitset++ != value)
+    return FALSE;
+  }
+while (bitset < end);
+return TRUE;
+}
+
+static void read_char7_type(compiler_common *common, jump_list **backtracks, BOOL negated)
+{
+/* Reads the precise character type of a character into TMP1, if the character
+is less than 128. Otherwise it returns with zero. Does not check STR_END. The
+full_read argument tells whether characters above max are accepted or not. */
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+
+SLJIT_ASSERT(common->utf);
+
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), 0);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+/* All values > 127 are zero in ctypes. */
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
+
+if (negated)
+  {
+  jump = CMP(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0x80);
+
+  if (common->invalid_utf)
+    {
+    add_jump(compiler, &common->utfreadchar_invalid, JUMP(SLJIT_FAST_CALL));
+    add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR));
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
+    }
+  else
+    {
+    OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+    }
+  JUMPHERE(jump);
+  }
+}
+
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 */
+
+static void read_char8_type(compiler_common *common, jump_list **backtracks, BOOL negated)
+{
+/* Reads the character type into TMP1, updates STR_PTR. Does not check STR_END. */
+DEFINE_COMPILER;
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+struct sljit_jump *jump;
+#endif
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+struct sljit_jump *jump2;
+#endif
+
+SLJIT_UNUSED_ARG(backtracks);
+SLJIT_UNUSED_ARG(negated);
+
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), 0);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+if (common->utf)
+  {
+  /* The result of this read may be unused, but saves an "else" part. */
+  OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
+  jump = CMP(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0x80);
+
+  if (!negated)
+    {
+    if (common->invalid_utf)
+      add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc2);
+    if (common->invalid_utf)
+      add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0xe0 - 0xc2));
+
+    OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
+    OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0);
+    OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x80);
+    if (common->invalid_utf)
+      add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40));
+
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
+    jump2 = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 255);
+    OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
+    JUMPHERE(jump2);
+    }
+  else if (common->invalid_utf)
+    {
+    add_jump(compiler, &common->utfreadchar_invalid, JUMP(SLJIT_FAST_CALL));
+    OP1(SLJIT_MOV, TMP2, 0, TMP1, 0);
+    add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR));
+
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
+    jump2 = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 255);
+    OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
+    JUMPHERE(jump2);
+    }
+  else
+    add_jump(compiler, &common->utfreadtype8, JUMP(SLJIT_FAST_CALL));
+
+  JUMPHERE(jump);
+  return;
+  }
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 */
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 32
+if (common->invalid_utf && negated)
+  add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x110000));
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 32 */
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+/* The ctypes array contains only 256 values. */
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
+jump = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 255);
+#endif /* PCRE2_CODE_UNIT_WIDTH != 8 */
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+JUMPHERE(jump);
+#endif /* PCRE2_CODE_UNIT_WIDTH != 8 */
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 16
+if (common->utf && negated)
+  {
+  /* Skip low surrogate if necessary. */
+  if (!common->invalid_utf)
+    {
+    OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xd800);
+
+    if (sljit_has_cpu_feature(SLJIT_HAS_CMOV) && !HAS_VIRTUAL_REGISTERS)
+      {
+      OP2(SLJIT_ADD, RETURN_ADDR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+      OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0x400);
+      CMOV(SLJIT_LESS, STR_PTR, RETURN_ADDR, 0);
+      }
+    else
+      {
+      jump = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x400);
+      OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+      JUMPHERE(jump);
+      }
+    return;
+    }
+
+  OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xd800);
+  jump = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800);
+  add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x400));
+  add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+  OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xdc00);
+  add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x400));
+
+  JUMPHERE(jump);
+  return;
+  }
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 16 */
+}
+
+static void move_back(compiler_common *common, jump_list **backtracks, BOOL must_be_valid)
+{
+/* Goes one character back. Affects STR_PTR and TMP1. If must_be_valid is TRUE,
+TMP2 is not used. Otherwise TMP2 must contain the start of the subject buffer,
+and it is destroyed. Does not modify STR_PTR for invalid character sequences. */
+DEFINE_COMPILER;
+
+SLJIT_UNUSED_ARG(backtracks);
+SLJIT_UNUSED_ARG(must_be_valid);
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+struct sljit_jump *jump;
+#endif
+
+#ifdef SUPPORT_UNICODE
+#if PCRE2_CODE_UNIT_WIDTH == 8
+struct sljit_label *label;
+
+if (common->utf)
+  {
+  if (!must_be_valid && common->invalid_utf)
+    {
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -IN_UCHARS(1));
+    OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x80);
+    add_jump(compiler, &common->utfmoveback_invalid, JUMP(SLJIT_FAST_CALL));
+    if (backtracks != NULL)
+      add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0));
+    JUMPHERE(jump);
+    return;
+    }
+
+  label = LABEL();
+  OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -IN_UCHARS(1));
+  OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0);
+  CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, label);
+  return;
+  }
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+if (common->utf)
+  {
+  OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -IN_UCHARS(1));
+  OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+  if (!must_be_valid && common->invalid_utf)
+    {
+    OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+    jump = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xe000 - 0xd800);
+    add_jump(compiler, &common->utfmoveback_invalid, JUMP(SLJIT_FAST_CALL));
+    if (backtracks != NULL)
+      add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0));
+    JUMPHERE(jump);
+    return;
+    }
+
+  /* Skip low surrogate if necessary. */
+  OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00);
+  OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xdc00);
+  OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL);
+  OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT);
+  OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+  return;
+  }
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+if (common->invalid_utf && !must_be_valid)
+  {
+  OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -IN_UCHARS(1));
+  if (backtracks != NULL)
+    {
+    add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x110000));
+    OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    return;
+    }
+
+  OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x110000);
+  OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_LESS);
+  OP2(SLJIT_SHL,  TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT);
+  OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+  return;
+  }
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
+#endif /* SUPPORT_UNICODE */
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+}
+
+static void check_newlinechar(compiler_common *common, int nltype, jump_list **backtracks, BOOL jumpifmatch)
+{
+/* Character comes in TMP1. Checks if it is a newline. TMP2 may be destroyed. */
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+
+if (nltype == NLTYPE_ANY)
+  {
+  add_jump(compiler, &common->anynewline, JUMP(SLJIT_FAST_CALL));
+  sljit_set_current_flags(compiler, SLJIT_SET_Z);
+  add_jump(compiler, backtracks, JUMP(jumpifmatch ? SLJIT_NOT_ZERO : SLJIT_ZERO));
+  }
+else if (nltype == NLTYPE_ANYCRLF)
+  {
+  if (jumpifmatch)
+    {
+    add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR));
+    add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL));
+    }
+  else
+    {
+    jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
+    add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL));
+    JUMPHERE(jump);
+    }
+  }
+else
+  {
+  SLJIT_ASSERT(nltype == NLTYPE_FIXED && common->newline < 256);
+  add_jump(compiler, backtracks, CMP(jumpifmatch ? SLJIT_EQUAL : SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, common->newline));
+  }
+}
+
+#ifdef SUPPORT_UNICODE
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+static void do_utfreadchar(compiler_common *common)
+{
+/* Fast decoding a UTF-8 character. TMP1 contains the first byte
+of the character (>= 0xc0). Return char value in TMP1. */
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+/* Searching for the first zero. */
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800);
+jump = JUMP(SLJIT_NOT_ZERO);
+/* Two byte sequence. */
+OP2(SLJIT_XOR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3000);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+JUMPHERE(jump);
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x10000);
+jump = JUMP(SLJIT_NOT_ZERO);
+/* Three byte sequence. */
+OP2(SLJIT_XOR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xe0000);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+/* Four byte sequence. */
+JUMPHERE(jump);
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(2));
+OP2(SLJIT_XOR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xf0000);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(3));
+OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+}
+
+static void do_utfreadtype8(compiler_common *common)
+{
+/* Fast decoding a UTF-8 character type. TMP2 contains the first byte
+of the character (>= 0xc0). Return value in TMP1. */
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+struct sljit_jump *compare;
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0x20);
+jump = JUMP(SLJIT_NOT_ZERO);
+/* Two byte sequence. */
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x1f);
+/* The upper 5 bits are known at this point. */
+compare = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0x3);
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
+OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f);
+OP2(SLJIT_OR, TMP2, 0, TMP2, 0, TMP1, 0);
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+JUMPHERE(compare);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+/* We only have types for characters less than 256. */
+JUMPHERE(jump);
+OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+}
+
+static void do_utfreadchar_invalid(compiler_common *common)
+{
+/* Slow decoding a UTF-8 character. TMP1 contains the first byte
+of the character (>= 0xc0). Return char value in TMP1. STR_PTR is
+undefined for invalid characters. */
+DEFINE_COMPILER;
+sljit_s32 i;
+sljit_s32 has_cmov = sljit_has_cpu_feature(SLJIT_HAS_CMOV);
+struct sljit_jump *jump;
+struct sljit_jump *buffer_end_close;
+struct sljit_label *three_byte_entry;
+struct sljit_label *exit_invalid_label;
+struct sljit_jump *exit_invalid[11];
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc2);
+
+/* Usually more than 3 characters remained in the subject buffer. */
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(3));
+
+/* Not a valid start of a multi-byte sequence, no more bytes read. */
+exit_invalid[0] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xf5 - 0xc2);
+
+buffer_end_close = CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0);
+
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-3));
+OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+/* If TMP2 is in 0x80-0xbf range, TMP1 is also increased by (0x2 << 6). */
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x80);
+exit_invalid[1] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40);
+
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800);
+jump = JUMP(SLJIT_NOT_ZERO);
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+JUMPHERE(jump);
+
+/* Three-byte sequence. */
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2));
+OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x80);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+if (has_cmov)
+  {
+  OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0x40);
+  CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, 0x20000);
+  exit_invalid[2] = NULL;
+  }
+else
+  exit_invalid[2] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40);
+
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x10000);
+jump = JUMP(SLJIT_NOT_ZERO);
+
+three_byte_entry = LABEL();
+
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x2d800);
+if (has_cmov)
+  {
+  OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800);
+  CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR - 0xd800);
+  exit_invalid[3] = NULL;
+  }
+else
+  exit_invalid[3] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x800);
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+if (has_cmov)
+  {
+  OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800);
+  CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR);
+  exit_invalid[4] = NULL;
+  }
+else
+  exit_invalid[4] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x800);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+JUMPHERE(jump);
+
+/* Four-byte sequence. */
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x80);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+if (has_cmov)
+  {
+  OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0x40);
+  CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, 0);
+  exit_invalid[5] = NULL;
+  }
+else
+  exit_invalid[5] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40);
+
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc10000);
+if (has_cmov)
+  {
+  OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x100000);
+  CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR - 0x10000);
+  exit_invalid[6] = NULL;
+  }
+else
+  exit_invalid[6] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x100000);
+
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x10000);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+JUMPHERE(buffer_end_close);
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+exit_invalid[7] = CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0);
+
+/* Two-byte sequence. */
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+/* If TMP2 is in 0x80-0xbf range, TMP1 is also increased by (0x2 << 6). */
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x80);
+exit_invalid[8] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40);
+
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800);
+jump = JUMP(SLJIT_NOT_ZERO);
+
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+/* Three-byte sequence. */
+JUMPHERE(jump);
+exit_invalid[9] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x80);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+if (has_cmov)
+  {
+  OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0x40);
+  CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR);
+  exit_invalid[10] = NULL;
+  }
+else
+  exit_invalid[10] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40);
+
+/* One will be substracted from STR_PTR later. */
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+
+/* Four byte sequences are not possible. */
+CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x30000, three_byte_entry);
+
+exit_invalid_label = LABEL();
+for (i = 0; i < 11; i++)
+  sljit_set_label(exit_invalid[i], exit_invalid_label);
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+}
+
+static void do_utfreadnewline_invalid(compiler_common *common)
+{
+/* Slow decoding a UTF-8 character, specialized for newlines.
+TMP1 contains the first byte of the character (>= 0xc0). Return
+char value in TMP1. */
+DEFINE_COMPILER;
+struct sljit_label *loop;
+struct sljit_label *skip_start;
+struct sljit_label *three_byte_exit;
+struct sljit_jump *jump[5];
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+if (common->nltype != NLTYPE_ANY)
+  {
+  SLJIT_ASSERT(common->nltype != NLTYPE_FIXED || common->newline < 128);
+
+  /* All newlines are ascii, just skip intermediate octets. */
+  jump[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+  loop = LABEL();
+  if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_POST, TMP2, SLJIT_MEM1(STR_PTR), IN_UCHARS(1)) == SLJIT_SUCCESS)
+    sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, TMP2, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+  else
+    {
+    OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    }
+
+  OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc0);
+  CMPTO(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0x80, loop);
+  OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+  JUMPHERE(jump[0]);
+
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR);
+  OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+  return;
+  }
+
+jump[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+jump[1] = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0xc2);
+jump[2] = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0xe2);
+
+skip_start = LABEL();
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc0);
+jump[3] = CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0x80);
+
+/* Skip intermediate octets. */
+loop = LABEL();
+jump[4] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc0);
+CMPTO(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0x80, loop);
+
+JUMPHERE(jump[3]);
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+three_byte_exit = LABEL();
+JUMPHERE(jump[0]);
+JUMPHERE(jump[4]);
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+/* Two byte long newline: 0x85. */
+JUMPHERE(jump[1]);
+CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0x85, skip_start);
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0x85);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+/* Three byte long newlines: 0x2028 and 0x2029. */
+JUMPHERE(jump[2]);
+CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0x80, skip_start);
+CMPTO(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0, three_byte_exit);
+
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+OP2(SLJIT_SUB, TMP1, 0, TMP2, 0, SLJIT_IMM, 0x80);
+CMPTO(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x40, skip_start);
+
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0x2000);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+}
+
+static void do_utfmoveback_invalid(compiler_common *common)
+{
+/* Goes one character back. */
+DEFINE_COMPILER;
+sljit_s32 i;
+struct sljit_jump *jump;
+struct sljit_jump *buffer_start_close;
+struct sljit_label *exit_ok_label;
+struct sljit_label *exit_invalid_label;
+struct sljit_jump *exit_invalid[7];
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(3));
+exit_invalid[0] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xc0);
+
+/* Two-byte sequence. */
+buffer_start_close = CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(2));
+
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0);
+jump = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x20);
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 1);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+/* Three-byte sequence. */
+JUMPHERE(jump);
+exit_invalid[1] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, -0x40);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xe0);
+jump = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x10);
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 1);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+/* Four-byte sequence. */
+JUMPHERE(jump);
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xe0 - 0x80);
+exit_invalid[2] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x40);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xf0);
+exit_invalid[3] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x05);
+
+exit_ok_label = LABEL();
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 1);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+/* Two-byte sequence. */
+JUMPHERE(buffer_start_close);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+
+exit_invalid[4] = CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0);
+CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x20, exit_ok_label);
+
+/* Three-byte sequence. */
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+exit_invalid[5] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, -0x40);
+exit_invalid[6] = CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xe0);
+CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x10, exit_ok_label);
+
+/* Four-byte sequences are not possible. */
+
+exit_invalid_label = LABEL();
+sljit_set_label(exit_invalid[5], exit_invalid_label);
+sljit_set_label(exit_invalid[6], exit_invalid_label);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(3));
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+JUMPHERE(exit_invalid[4]);
+/* -2 + 4 = 2 */
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+
+exit_invalid_label = LABEL();
+for (i = 0; i < 4; i++)
+  sljit_set_label(exit_invalid[i], exit_invalid_label);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(4));
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+}
+
+static void do_utfpeakcharback(compiler_common *common)
+{
+/* Peak a character back. Does not modify STR_PTR. */
+DEFINE_COMPILER;
+struct sljit_jump *jump[2];
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2));
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0);
+jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x20);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-3));
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xe0);
+jump[1] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x10);
+
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-4));
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xe0 - 0x80);
+OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf0);
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+JUMPHERE(jump[1]);
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2));
+OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x80);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+JUMPHERE(jump[0]);
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x80);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+}
+
+static void do_utfpeakcharback_invalid(compiler_common *common)
+{
+/* Peak a character back. Does not modify STR_PTR. */
+DEFINE_COMPILER;
+sljit_s32 i;
+sljit_s32 has_cmov = sljit_has_cpu_feature(SLJIT_HAS_CMOV);
+struct sljit_jump *jump[2];
+struct sljit_label *two_byte_entry;
+struct sljit_label *three_byte_entry;
+struct sljit_label *exit_invalid_label;
+struct sljit_jump *exit_invalid[8];
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(3));
+exit_invalid[0] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xc0);
+jump[0] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, STR_PTR, 0);
+
+/* Two-byte sequence. */
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2));
+OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc2);
+jump[1] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x1e);
+
+two_byte_entry = LABEL();
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
+/* If TMP1 is in 0x80-0xbf range, TMP1 is also increased by (0x2 << 6). */
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+JUMPHERE(jump[1]);
+OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc2 - 0x80);
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x80);
+exit_invalid[1] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40);
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+/* Three-byte sequence. */
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-3));
+OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xe0);
+jump[1] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x10);
+
+three_byte_entry = LABEL();
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 12);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+if (has_cmov)
+  {
+  OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800);
+  CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, -0xd800);
+  exit_invalid[2] = NULL;
+  }
+else
+  exit_invalid[2] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x800);
+
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+if (has_cmov)
+  {
+  OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800);
+  CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR);
+  exit_invalid[3] = NULL;
+  }
+else
+  exit_invalid[3] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x800);
+
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+JUMPHERE(jump[1]);
+OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xe0 - 0x80);
+exit_invalid[4] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40);
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 12);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+/* Four-byte sequence. */
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-4));
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x10000);
+OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf0);
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 18);
+/* ADD is used instead of OR because of the SUB 0x10000 above. */
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+
+if (has_cmov)
+  {
+  OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x100000);
+  CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR - 0x10000);
+  exit_invalid[5] = NULL;
+  }
+else
+  exit_invalid[5] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x100000);
+
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x10000);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+JUMPHERE(jump[0]);
+OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
+jump[0] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, STR_PTR, 0);
+
+/* Two-byte sequence. */
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2));
+OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc2);
+CMPTO(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0x1e, two_byte_entry);
+
+OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc2 - 0x80);
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x80);
+exit_invalid[6] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40);
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+/* Three-byte sequence. */
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-3));
+OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xe0);
+CMPTO(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0x10, three_byte_entry);
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+JUMPHERE(jump[0]);
+exit_invalid[7] = CMP(SLJIT_GREATER, TMP2, 0, STR_PTR, 0);
+
+/* Two-byte sequence. */
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2));
+OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xc2);
+CMPTO(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0x1e, two_byte_entry);
+
+exit_invalid_label = LABEL();
+for (i = 0; i < 8; i++)
+  sljit_set_label(exit_invalid[i], exit_invalid_label);
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+}
+
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+
+#if PCRE2_CODE_UNIT_WIDTH == 16
+
+static void do_utfreadchar_invalid(compiler_common *common)
+{
+/* Slow decoding a UTF-16 character. TMP1 contains the first half
+of the character (>= 0xd800). Return char value in TMP1. STR_PTR is
+undefined for invalid characters. */
+DEFINE_COMPILER;
+struct sljit_jump *exit_invalid[3];
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+/* TMP2 contains the high surrogate. */
+exit_invalid[0] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xdc00);
+exit_invalid[1] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 10);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xdc00);
+OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x10000);
+exit_invalid[2] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x400);
+
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+JUMPHERE(exit_invalid[0]);
+JUMPHERE(exit_invalid[1]);
+JUMPHERE(exit_invalid[2]);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+}
+
+static void do_utfreadnewline_invalid(compiler_common *common)
+{
+/* Slow decoding a UTF-16 character, specialized for newlines.
+TMP1 contains the first half of the character (>= 0xd800). Return
+char value in TMP1. */
+
+DEFINE_COMPILER;
+struct sljit_jump *exit_invalid[2];
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+/* TMP2 contains the high surrogate. */
+exit_invalid[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+exit_invalid[1] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xdc00);
+
+OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xdc00);
+OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0x400);
+OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0x10000);
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCHAR_SHIFT);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+JUMPHERE(exit_invalid[0]);
+JUMPHERE(exit_invalid[1]);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+}
+
+static void do_utfmoveback_invalid(compiler_common *common)
+{
+/* Goes one character back. */
+DEFINE_COMPILER;
+struct sljit_jump *exit_invalid[3];
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+exit_invalid[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x400);
+exit_invalid[1] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, STR_PTR, 0);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+exit_invalid[2] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x400);
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 1);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+JUMPHERE(exit_invalid[0]);
+JUMPHERE(exit_invalid[1]);
+JUMPHERE(exit_invalid[2]);
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+}
+
+static void do_utfpeakcharback_invalid(compiler_common *common)
+{
+/* Peak a character back. Does not modify STR_PTR. */
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+struct sljit_jump *exit_invalid[3];
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+jump = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xe000);
+OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
+exit_invalid[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xdc00);
+exit_invalid[1] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, STR_PTR, 0);
+
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2));
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x10000 - 0xdc00);
+OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xd800);
+exit_invalid[2] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x400);
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 10);
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+
+JUMPHERE(jump);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+JUMPHERE(exit_invalid[0]);
+JUMPHERE(exit_invalid[1]);
+JUMPHERE(exit_invalid[2]);
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+}
+
+#endif /* PCRE2_CODE_UNIT_WIDTH == 16 */
+
+/* UCD_BLOCK_SIZE must be 128 (see the assert below). */
+#define UCD_BLOCK_MASK 127
+#define UCD_BLOCK_SHIFT 7
+
+static void do_getucd(compiler_common *common)
+{
+/* Search the UCD record for the character comes in TMP1.
+Returns chartype in TMP1 and UCD offset in TMP2. */
+DEFINE_COMPILER;
+#if PCRE2_CODE_UNIT_WIDTH == 32
+struct sljit_jump *jump;
+#endif
+
+#if defined SLJIT_DEBUG && SLJIT_DEBUG
+/* dummy_ucd_record */
+const ucd_record *record = GET_UCD(UNASSIGNED_UTF_CHAR);
+SLJIT_ASSERT(record->script == ucp_Unknown && record->chartype == ucp_Cn && record->gbprop == ucp_gbOther);
+SLJIT_ASSERT(record->caseset == 0 && record->other_case == 0);
+#endif
+
+SLJIT_ASSERT(UCD_BLOCK_SIZE == 128 && sizeof(ucd_record) == 12);
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+if (!common->utf)
+  {
+  jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, MAX_UTF_CODE_POINT + 1);
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, UNASSIGNED_UTF_CHAR);
+  JUMPHERE(jump);
+  }
+#endif
+
+OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT);
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 1);
+OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1));
+OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK);
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCD_BLOCK_SHIFT);
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_stage2));
+OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM2(TMP2, TMP1), 1);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+}
+
+static void do_getucdtype(compiler_common *common)
+{
+/* Search the UCD record for the character comes in TMP1.
+Returns chartype in TMP1 and UCD offset in TMP2. */
+DEFINE_COMPILER;
+#if PCRE2_CODE_UNIT_WIDTH == 32
+struct sljit_jump *jump;
+#endif
+
+#if defined SLJIT_DEBUG && SLJIT_DEBUG
+/* dummy_ucd_record */
+const ucd_record *record = GET_UCD(UNASSIGNED_UTF_CHAR);
+SLJIT_ASSERT(record->script == ucp_Unknown && record->chartype == ucp_Cn && record->gbprop == ucp_gbOther);
+SLJIT_ASSERT(record->caseset == 0 && record->other_case == 0);
+#endif
+
+SLJIT_ASSERT(UCD_BLOCK_SIZE == 128 && sizeof(ucd_record) == 12);
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+if (!common->utf)
+  {
+  jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, MAX_UTF_CODE_POINT + 1);
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, UNASSIGNED_UTF_CHAR);
+  JUMPHERE(jump);
+  }
+#endif
+
+OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT);
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 1);
+OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1));
+OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK);
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCD_BLOCK_SHIFT);
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_stage2));
+OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM2(TMP2, TMP1), 1);
+
+/* TMP2 is multiplied by 12. Same as (TMP2 << 2) + ((TMP2 << 2) << 1). */
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype));
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 2);
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM2(TMP1, TMP2), 1);
+
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+}
+
+#endif /* SUPPORT_UNICODE */
+
+static SLJIT_INLINE struct sljit_label *mainloop_entry(compiler_common *common)
+{
+DEFINE_COMPILER;
+struct sljit_label *mainloop;
+struct sljit_label *newlinelabel = NULL;
+struct sljit_jump *start;
+struct sljit_jump *end = NULL;
+struct sljit_jump *end2 = NULL;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+struct sljit_label *loop;
+struct sljit_jump *jump;
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */
+jump_list *newline = NULL;
+sljit_u32 overall_options = common->re->overall_options;
+BOOL hascrorlf = (common->re->flags & PCRE2_HASCRORLF) != 0;
+BOOL newlinecheck = FALSE;
+BOOL readuchar = FALSE;
+
+if (!(hascrorlf || (overall_options & PCRE2_FIRSTLINE) != 0)
+    && (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF || common->newline > 255))
+  newlinecheck = TRUE;
+
+SLJIT_ASSERT(common->abort_label == NULL);
+
+if ((overall_options & PCRE2_FIRSTLINE) != 0)
+  {
+  /* Search for the end of the first line. */
+  SLJIT_ASSERT(common->match_end_ptr != 0);
+  OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0);
+
+  if (common->nltype == NLTYPE_FIXED && common->newline > 255)
+    {
+    mainloop = LABEL();
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    end = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+    OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+    CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, mainloop);
+    CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff, mainloop);
+    JUMPHERE(end);
+    OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    }
+  else
+    {
+    end = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+    mainloop = LABEL();
+    /* Continual stores does not cause data dependency. */
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, STR_PTR, 0);
+    read_char(common, common->nlmin, common->nlmax, NULL, READ_CHAR_NEWLINE);
+    check_newlinechar(common, common->nltype, &newline, TRUE);
+    CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, mainloop);
+    JUMPHERE(end);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, STR_PTR, 0);
+    set_jumps(newline, LABEL());
+    }
+
+  OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0);
+  }
+else if ((overall_options & PCRE2_USE_OFFSET_LIMIT) != 0)
+  {
+  /* Check whether offset limit is set and valid. */
+  SLJIT_ASSERT(common->match_end_ptr != 0);
+
+  if (HAS_VIRTUAL_REGISTERS)
+    {
+    OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, offset_limit));
+    }
+  else
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, offset_limit));
+
+  OP1(SLJIT_MOV, TMP2, 0, STR_END, 0);
+  end = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, (sljit_sw) PCRE2_UNSET);
+  if (HAS_VIRTUAL_REGISTERS)
+    OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
+  else
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin));
+
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+  OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT);
+#endif /* PCRE2_CODE_UNIT_WIDTH == [16|32] */
+  if (HAS_VIRTUAL_REGISTERS)
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin));
+
+  OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0);
+  end2 = CMP(SLJIT_LESS_EQUAL, TMP2, 0, STR_END, 0);
+  OP1(SLJIT_MOV, TMP2, 0, STR_END, 0);
+  JUMPHERE(end2);
+  OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH);
+  add_jump(compiler, &common->abort, CMP(SLJIT_LESS, TMP2, 0, STR_PTR, 0));
+  JUMPHERE(end);
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, TMP2, 0);
+  }
+
+start = JUMP(SLJIT_JUMP);
+
+if (newlinecheck)
+  {
+  newlinelabel = LABEL();
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  end = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+  OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+  OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, common->newline & 0xff);
+  OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL);
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+  OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT);
+#endif /* PCRE2_CODE_UNIT_WIDTH == [16|32] */
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+  end2 = JUMP(SLJIT_JUMP);
+  }
+
+mainloop = LABEL();
+
+/* Increasing the STR_PTR here requires one less jump in the most common case. */
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+if (common->utf && !common->invalid_utf) readuchar = TRUE;
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */
+if (newlinecheck) readuchar = TRUE;
+
+if (readuchar)
+  OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+
+if (newlinecheck)
+  CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, newlinelabel);
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+#if PCRE2_CODE_UNIT_WIDTH == 8
+if (common->invalid_utf)
+  {
+  /* Skip continuation code units. */
+  loop = LABEL();
+  jump = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+  OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x80);
+  CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x40, loop);
+  OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  JUMPHERE(jump);
+  }
+else if (common->utf)
+  {
+  jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
+  OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+  JUMPHERE(jump);
+  }
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+if (common->invalid_utf)
+  {
+  /* Skip continuation code units. */
+  loop = LABEL();
+  jump = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+  OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xdc00);
+  CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x400, loop);
+  OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  JUMPHERE(jump);
+  }
+else if (common->utf)
+  {
+  OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+
+  if (sljit_has_cpu_feature(SLJIT_HAS_CMOV))
+    {
+    OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x400);
+    CMOV(SLJIT_LESS, STR_PTR, TMP2, 0);
+    }
+  else
+    {
+    OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x400);
+    OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_LESS);
+    OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT);
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+    }
+  }
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16] */
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */
+JUMPHERE(start);
+
+if (newlinecheck)
+  {
+  JUMPHERE(end);
+  JUMPHERE(end2);
+  }
+
+return mainloop;
+}
+
+
+static SLJIT_INLINE void add_prefix_char(PCRE2_UCHAR chr, fast_forward_char_data *chars, BOOL last)
+{
+sljit_u32 i, count = chars->count;
+
+if (count == 255)
+  return;
+
+if (count == 0)
+  {
+  chars->count = 1;
+  chars->chars[0] = chr;
+
+  if (last)
+    chars->last_count = 1;
+  return;
+  }
+
+for (i = 0; i < count; i++)
+  if (chars->chars[i] == chr)
+    return;
+
+if (count >= MAX_DIFF_CHARS)
+  {
+  chars->count = 255;
+  return;
+  }
+
+chars->chars[count] = chr;
+chars->count = count + 1;
+
+if (last)
+  chars->last_count++;
+}
+
+static int scan_prefix(compiler_common *common, PCRE2_SPTR cc, fast_forward_char_data *chars, int max_chars, sljit_u32 *rec_count)
+{
+/* Recursive function, which scans prefix literals. */
+BOOL last, any, class, caseless;
+int len, repeat, len_save, consumed = 0;
+sljit_u32 chr; /* Any unicode character. */
+sljit_u8 *bytes, *bytes_end, byte;
+PCRE2_SPTR alternative, cc_save, oc;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+PCRE2_UCHAR othercase[4];
+#elif defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 16
+PCRE2_UCHAR othercase[2];
+#else
+PCRE2_UCHAR othercase[1];
+#endif
+
+repeat = 1;
+while (TRUE)
+  {
+  if (*rec_count == 0)
+    return 0;
+  (*rec_count)--;
+
+  last = TRUE;
+  any = FALSE;
+  class = FALSE;
+  caseless = FALSE;
+
+  switch (*cc)
+    {
+    case OP_CHARI:
+    caseless = TRUE;
+    /* Fall through */
+    case OP_CHAR:
+    last = FALSE;
+    cc++;
+    break;
+
+    case OP_SOD:
+    case OP_SOM:
+    case OP_SET_SOM:
+    case OP_NOT_WORD_BOUNDARY:
+    case OP_WORD_BOUNDARY:
+    case OP_EODN:
+    case OP_EOD:
+    case OP_CIRC:
+    case OP_CIRCM:
+    case OP_DOLL:
+    case OP_DOLLM:
+    /* Zero width assertions. */
+    cc++;
+    continue;
+
+    case OP_ASSERT:
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK:
+    case OP_ASSERTBACK_NOT:
+    case OP_ASSERT_NA:
+    case OP_ASSERTBACK_NA:
+    cc = bracketend(cc);
+    continue;
+
+    case OP_PLUSI:
+    case OP_MINPLUSI:
+    case OP_POSPLUSI:
+    caseless = TRUE;
+    /* Fall through */
+    case OP_PLUS:
+    case OP_MINPLUS:
+    case OP_POSPLUS:
+    cc++;
+    break;
+
+    case OP_EXACTI:
+    caseless = TRUE;
+    /* Fall through */
+    case OP_EXACT:
+    repeat = GET2(cc, 1);
+    last = FALSE;
+    cc += 1 + IMM2_SIZE;
+    break;
+
+    case OP_QUERYI:
+    case OP_MINQUERYI:
+    case OP_POSQUERYI:
+    caseless = TRUE;
+    /* Fall through */
+    case OP_QUERY:
+    case OP_MINQUERY:
+    case OP_POSQUERY:
+    len = 1;
+    cc++;
+#ifdef SUPPORT_UNICODE
+    if (common->utf && HAS_EXTRALEN(*cc)) len += GET_EXTRALEN(*cc);
+#endif
+    max_chars = scan_prefix(common, cc + len, chars, max_chars, rec_count);
+    if (max_chars == 0)
+      return consumed;
+    last = FALSE;
+    break;
+
+    case OP_KET:
+    cc += 1 + LINK_SIZE;
+    continue;
+
+    case OP_ALT:
+    cc += GET(cc, 1);
+    continue;
+
+    case OP_ONCE:
+    case OP_BRA:
+    case OP_BRAPOS:
+    case OP_CBRA:
+    case OP_CBRAPOS:
+    alternative = cc + GET(cc, 1);
+    while (*alternative == OP_ALT)
+      {
+      max_chars = scan_prefix(common, alternative + 1 + LINK_SIZE, chars, max_chars, rec_count);
+      if (max_chars == 0)
+        return consumed;
+      alternative += GET(alternative, 1);
+      }
+
+    if (*cc == OP_CBRA || *cc == OP_CBRAPOS)
+      cc += IMM2_SIZE;
+    cc += 1 + LINK_SIZE;
+    continue;
+
+    case OP_CLASS:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+    if (common->utf && !is_char7_bitset((const sljit_u8 *)(cc + 1), FALSE))
+      return consumed;
+#endif
+    class = TRUE;
+    break;
+
+    case OP_NCLASS:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+    if (common->utf) return consumed;
+#endif
+    class = TRUE;
+    break;
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+    case OP_XCLASS:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+    if (common->utf) return consumed;
+#endif
+    any = TRUE;
+    cc += GET(cc, 1);
+    break;
+#endif
+
+    case OP_DIGIT:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+    if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_digit, FALSE))
+      return consumed;
+#endif
+    any = TRUE;
+    cc++;
+    break;
+
+    case OP_WHITESPACE:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+    if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_space, FALSE))
+      return consumed;
+#endif
+    any = TRUE;
+    cc++;
+    break;
+
+    case OP_WORDCHAR:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+    if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_word, FALSE))
+      return consumed;
+#endif
+    any = TRUE;
+    cc++;
+    break;
+
+    case OP_NOT:
+    case OP_NOTI:
+    cc++;
+    /* Fall through. */
+    case OP_NOT_DIGIT:
+    case OP_NOT_WHITESPACE:
+    case OP_NOT_WORDCHAR:
+    case OP_ANY:
+    case OP_ALLANY:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+    if (common->utf) return consumed;
+#endif
+    any = TRUE;
+    cc++;
+    break;
+
+#ifdef SUPPORT_UNICODE
+    case OP_NOTPROP:
+    case OP_PROP:
+#if PCRE2_CODE_UNIT_WIDTH != 32
+    if (common->utf) return consumed;
+#endif
+    any = TRUE;
+    cc += 1 + 2;
+    break;
+#endif
+
+    case OP_TYPEEXACT:
+    repeat = GET2(cc, 1);
+    cc += 1 + IMM2_SIZE;
+    continue;
+
+    case OP_NOTEXACT:
+    case OP_NOTEXACTI:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+    if (common->utf) return consumed;
+#endif
+    any = TRUE;
+    repeat = GET2(cc, 1);
+    cc += 1 + IMM2_SIZE + 1;
+    break;
+
+    default:
+    return consumed;
+    }
+
+  if (any)
+    {
+    do
+      {
+      chars->count = 255;
+
+      consumed++;
+      if (--max_chars == 0)
+        return consumed;
+      chars++;
+      }
+    while (--repeat > 0);
+
+    repeat = 1;
+    continue;
+    }
+
+  if (class)
+    {
+    bytes = (sljit_u8*) (cc + 1);
+    cc += 1 + 32 / sizeof(PCRE2_UCHAR);
+
+    switch (*cc)
+      {
+      case OP_CRSTAR:
+      case OP_CRMINSTAR:
+      case OP_CRPOSSTAR:
+      case OP_CRQUERY:
+      case OP_CRMINQUERY:
+      case OP_CRPOSQUERY:
+      max_chars = scan_prefix(common, cc + 1, chars, max_chars, rec_count);
+      if (max_chars == 0)
+        return consumed;
+      break;
+
+      default:
+      case OP_CRPLUS:
+      case OP_CRMINPLUS:
+      case OP_CRPOSPLUS:
+      break;
+
+      case OP_CRRANGE:
+      case OP_CRMINRANGE:
+      case OP_CRPOSRANGE:
+      repeat = GET2(cc, 1);
+      if (repeat <= 0)
+        return consumed;
+      break;
+      }
+
+    do
+      {
+      if (bytes[31] & 0x80)
+        chars->count = 255;
+      else if (chars->count != 255)
+        {
+        bytes_end = bytes + 32;
+        chr = 0;
+        do
+          {
+          byte = *bytes++;
+          SLJIT_ASSERT((chr & 0x7) == 0);
+          if (byte == 0)
+            chr += 8;
+          else
+            {
+            do
+              {
+              if ((byte & 0x1) != 0)
+                add_prefix_char(chr, chars, TRUE);
+              byte >>= 1;
+              chr++;
+              }
+            while (byte != 0);
+            chr = (chr + 7) & ~7;
+            }
+          }
+        while (chars->count != 255 && bytes < bytes_end);
+        bytes = bytes_end - 32;
+        }
+
+      consumed++;
+      if (--max_chars == 0)
+        return consumed;
+      chars++;
+      }
+    while (--repeat > 0);
+
+    switch (*cc)
+      {
+      case OP_CRSTAR:
+      case OP_CRMINSTAR:
+      case OP_CRPOSSTAR:
+      return consumed;
+
+      case OP_CRQUERY:
+      case OP_CRMINQUERY:
+      case OP_CRPOSQUERY:
+      cc++;
+      break;
+
+      case OP_CRRANGE:
+      case OP_CRMINRANGE:
+      case OP_CRPOSRANGE:
+      if (GET2(cc, 1) != GET2(cc, 1 + IMM2_SIZE))
+        return consumed;
+      cc += 1 + 2 * IMM2_SIZE;
+      break;
+      }
+
+    repeat = 1;
+    continue;
+    }
+
+  len = 1;
+#ifdef SUPPORT_UNICODE
+  if (common->utf && HAS_EXTRALEN(*cc)) len += GET_EXTRALEN(*cc);
+#endif
+
+  if (caseless && char_has_othercase(common, cc))
+    {
+#ifdef SUPPORT_UNICODE
+    if (common->utf)
+      {
+      GETCHAR(chr, cc);
+      if ((int)PRIV(ord2utf)(char_othercase(common, chr), othercase) != len)
+        return consumed;
+      }
+    else
+#endif
+      {
+      chr = *cc;
+#ifdef SUPPORT_UNICODE
+      if (common->ucp && chr > 127)
+        othercase[0] = UCD_OTHERCASE(chr);
+      else
+#endif
+        othercase[0] = TABLE_GET(chr, common->fcc, chr);
+      }
+    }
+  else
+    {
+    caseless = FALSE;
+    othercase[0] = 0; /* Stops compiler warning - PH */
+    }
+
+  len_save = len;
+  cc_save = cc;
+  while (TRUE)
+    {
+    oc = othercase;
+    do
+      {
+      len--;
+      consumed++;
+
+      chr = *cc;
+      add_prefix_char(*cc, chars, len == 0);
+
+      if (caseless)
+        add_prefix_char(*oc, chars, len == 0);
+
+      if (--max_chars == 0)
+        return consumed;
+      chars++;
+      cc++;
+      oc++;
+      }
+    while (len > 0);
+
+    if (--repeat == 0)
+      break;
+
+    len = len_save;
+    cc = cc_save;
+    }
+
+  repeat = 1;
+  if (last)
+    return consumed;
+  }
+}
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+static void jumpto_if_not_utf_char_start(struct sljit_compiler *compiler, sljit_s32 reg, struct sljit_label *label)
+{
+#if PCRE2_CODE_UNIT_WIDTH == 8
+OP2(SLJIT_AND, reg, 0, reg, 0, SLJIT_IMM, 0xc0);
+CMPTO(SLJIT_EQUAL, reg, 0, SLJIT_IMM, 0x80, label);
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+OP2(SLJIT_AND, reg, 0, reg, 0, SLJIT_IMM, 0xfc00);
+CMPTO(SLJIT_EQUAL, reg, 0, SLJIT_IMM, 0xdc00, label);
+#else
+#error "Unknown code width"
+#endif
+}
+#endif
+
+#include "pcre2_jit_simd_inc.h"
+
+#ifdef JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD
+
+static BOOL check_fast_forward_char_pair_simd(compiler_common *common, fast_forward_char_data *chars, int max)
+{
+  sljit_s32 i, j, max_i = 0, max_j = 0;
+  sljit_u32 max_pri = 0;
+  PCRE2_UCHAR a1, a2, a_pri, b1, b2, b_pri;
+
+  for (i = max - 1; i >= 1; i--)
+    {
+    if (chars[i].last_count > 2)
+      {
+      a1 = chars[i].chars[0];
+      a2 = chars[i].chars[1];
+      a_pri = chars[i].last_count;
+
+      j = i - max_fast_forward_char_pair_offset();
+      if (j < 0)
+        j = 0;
+
+      while (j < i)
+        {
+        b_pri = chars[j].last_count;
+        if (b_pri > 2 && a_pri + b_pri >= max_pri)
+          {
+          b1 = chars[j].chars[0];
+          b2 = chars[j].chars[1];
+
+          if (a1 != b1 && a1 != b2 && a2 != b1 && a2 != b2)
+            {
+            max_pri = a_pri + b_pri;
+            max_i = i;
+            max_j = j;
+            }
+          }
+        j++;
+        }
+      }
+    }
+
+if (max_pri == 0)
+  return FALSE;
+
+fast_forward_char_pair_simd(common, max_i, chars[max_i].chars[0], chars[max_i].chars[1], max_j, chars[max_j].chars[0], chars[max_j].chars[1]);
+return TRUE;
+}
+
+#endif /* JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD */
+
+static void fast_forward_first_char2(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset)
+{
+DEFINE_COMPILER;
+struct sljit_label *start;
+struct sljit_jump *match;
+struct sljit_jump *partial_quit;
+PCRE2_UCHAR mask;
+BOOL has_match_end = (common->match_end_ptr != 0);
+
+SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE || offset == 0);
+
+if (has_match_end)
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+
+if (offset > 0)
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset));
+
+if (has_match_end)
+  {
+  OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
+
+  OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offset + 1));
+  OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_END, 0, TMP1, 0);
+  CMOV(SLJIT_GREATER, STR_END, TMP1, 0);
+  }
+
+#ifdef JIT_HAS_FAST_FORWARD_CHAR_SIMD
+
+if (JIT_HAS_FAST_FORWARD_CHAR_SIMD)
+  {
+  fast_forward_char_simd(common, char1, char2, offset);
+
+  if (offset > 0)
+    OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset));
+
+  if (has_match_end)
+    OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+  return;
+  }
+
+#endif
+
+start = LABEL();
+
+partial_quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+if (common->mode == PCRE2_JIT_COMPLETE)
+  add_jump(compiler, &common->failed_match, partial_quit);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+if (char1 == char2)
+  CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, char1, start);
+else
+  {
+  mask = char1 ^ char2;
+  if (is_powerof2(mask))
+    {
+    OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, mask);
+    CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, char1 | mask, start);
+    }
+  else
+    {
+    match = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, char1);
+    CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, char2, start);
+    JUMPHERE(match);
+    }
+  }
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+if (common->utf && offset > 0)
+  {
+  OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-(offset + 1)));
+  jumpto_if_not_utf_char_start(compiler, TMP1, start);
+  }
+#endif
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset + 1));
+
+if (common->mode != PCRE2_JIT_COMPLETE)
+  JUMPHERE(partial_quit);
+
+if (has_match_end)
+  OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+}
+
+static SLJIT_INLINE BOOL fast_forward_first_n_chars(compiler_common *common)
+{
+DEFINE_COMPILER;
+struct sljit_label *start;
+struct sljit_jump *match;
+fast_forward_char_data chars[MAX_N_CHARS];
+sljit_s32 offset;
+PCRE2_UCHAR mask;
+PCRE2_UCHAR *char_set, *char_set_end;
+int i, max, from;
+int range_right = -1, range_len;
+sljit_u8 *update_table = NULL;
+BOOL in_range;
+sljit_u32 rec_count;
+
+for (i = 0; i < MAX_N_CHARS; i++)
+  {
+  chars[i].count = 0;
+  chars[i].last_count = 0;
+  }
+
+rec_count = 10000;
+max = scan_prefix(common, common->start, chars, MAX_N_CHARS, &rec_count);
+
+if (max < 1)
+  return FALSE;
+
+/* Convert last_count to priority. */
+for (i = 0; i < max; i++)
+  {
+  SLJIT_ASSERT(chars[i].count > 0 && chars[i].last_count <= chars[i].count);
+
+  if (chars[i].count == 1)
+    {
+    chars[i].last_count = (chars[i].last_count == 1) ? 7 : 5;
+    /* Simplifies algorithms later. */
+    chars[i].chars[1] = chars[i].chars[0];
+    }
+  else if (chars[i].count == 2)
+    {
+    SLJIT_ASSERT(chars[i].chars[0] != chars[i].chars[1]);
+
+    if (is_powerof2(chars[i].chars[0] ^ chars[i].chars[1]))
+      chars[i].last_count = (chars[i].last_count == 2) ? 6 : 4;
+    else
+      chars[i].last_count = (chars[i].last_count == 2) ? 3 : 2;
+    }
+  else
+    chars[i].last_count = (chars[i].count == 255) ? 0 : 1;
+  }
+
+#ifdef JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD
+if (JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD && check_fast_forward_char_pair_simd(common, chars, max))
+  return TRUE;
+#endif
+
+in_range = FALSE;
+/* Prevent compiler "uninitialized" warning */
+from = 0;
+range_len = 4 /* minimum length */ - 1;
+for (i = 0; i <= max; i++)
+  {
+  if (in_range && (i - from) > range_len && (chars[i - 1].count < 255))
+    {
+    range_len = i - from;
+    range_right = i - 1;
+    }
+
+  if (i < max && chars[i].count < 255)
+    {
+    SLJIT_ASSERT(chars[i].count > 0);
+    if (!in_range)
+      {
+      in_range = TRUE;
+      from = i;
+      }
+    }
+  else
+    in_range = FALSE;
+  }
+
+if (range_right >= 0)
+  {
+  update_table = (sljit_u8 *)allocate_read_only_data(common, 256);
+  if (update_table == NULL)
+    return TRUE;
+  memset(update_table, IN_UCHARS(range_len), 256);
+
+  for (i = 0; i < range_len; i++)
+    {
+    SLJIT_ASSERT(chars[range_right - i].count > 0 && chars[range_right - i].count < 255);
+
+    char_set = chars[range_right - i].chars;
+    char_set_end = char_set + chars[range_right - i].count;
+    do
+      {
+      if (update_table[(*char_set) & 0xff] > IN_UCHARS(i))
+        update_table[(*char_set) & 0xff] = IN_UCHARS(i);
+      char_set++;
+      }
+    while (char_set < char_set_end);
+    }
+  }
+
+offset = -1;
+/* Scan forward. */
+for (i = 0; i < max; i++)
+  {
+  if (range_right == i)
+    continue;
+
+  if (offset == -1)
+    {
+    if (chars[i].last_count >= 2)
+      offset = i;
+    }
+  else if (chars[offset].last_count < chars[i].last_count)
+    offset = i;
+  }
+
+SLJIT_ASSERT(offset == -1 || (chars[offset].count >= 1 && chars[offset].count <= 2));
+
+if (range_right < 0)
+  {
+  if (offset < 0)
+    return FALSE;
+  /* Works regardless the value is 1 or 2. */
+  fast_forward_first_char2(common, chars[offset].chars[0], chars[offset].chars[1], offset);
+  return TRUE;
+  }
+
+SLJIT_ASSERT(range_right != offset);
+
+if (common->match_end_ptr != 0)
+  {
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+  OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
+  OP2(SLJIT_SUB | SLJIT_SET_LESS, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max));
+  add_jump(compiler, &common->failed_match, JUMP(SLJIT_LESS));
+  OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_END, 0, TMP1, 0);
+  CMOV(SLJIT_GREATER, STR_END, TMP1, 0);
+  }
+else
+  {
+  OP2(SLJIT_SUB | SLJIT_SET_LESS, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max));
+  add_jump(compiler, &common->failed_match, JUMP(SLJIT_LESS));
+  }
+
+SLJIT_ASSERT(range_right >= 0);
+
+if (!HAS_VIRTUAL_REGISTERS)
+  OP1(SLJIT_MOV, RETURN_ADDR, 0, SLJIT_IMM, (sljit_sw)update_table);
+
+start = LABEL();
+add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0));
+
+#if PCRE2_CODE_UNIT_WIDTH == 8 || (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(range_right));
+#else
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(range_right + 1) - 1);
+#endif
+
+if (!HAS_VIRTUAL_REGISTERS)
+  OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM2(RETURN_ADDR, TMP1), 0);
+else
+  OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)update_table);
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, start);
+
+if (offset >= 0)
+  {
+  OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(offset));
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+  if (chars[offset].count == 1)
+    CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset].chars[0], start);
+  else
+    {
+    mask = chars[offset].chars[0] ^ chars[offset].chars[1];
+    if (is_powerof2(mask))
+      {
+      OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, mask);
+      CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset].chars[0] | mask, start);
+      }
+    else
+      {
+      match = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset].chars[0]);
+      CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset].chars[1], start);
+      JUMPHERE(match);
+      }
+    }
+  }
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+if (common->utf && offset != 0)
+  {
+  if (offset < 0)
+    {
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    }
+  else
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+
+  jumpto_if_not_utf_char_start(compiler, TMP1, start);
+
+  if (offset < 0)
+    OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  }
+#endif
+
+if (offset >= 0)
+  OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+if (common->match_end_ptr != 0)
+  OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+else
+  OP2(SLJIT_ADD, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max));
+return TRUE;
+}
+
+static SLJIT_INLINE void fast_forward_first_char(compiler_common *common)
+{
+PCRE2_UCHAR first_char = (PCRE2_UCHAR)(common->re->first_codeunit);
+PCRE2_UCHAR oc;
+
+oc = first_char;
+if ((common->re->flags & PCRE2_FIRSTCASELESS) != 0)
+  {
+  oc = TABLE_GET(first_char, common->fcc, first_char);
+#if defined SUPPORT_UNICODE
+  if (first_char > 127 && (common->utf || common->ucp))
+    oc = UCD_OTHERCASE(first_char);
+#endif
+  }
+
+fast_forward_first_char2(common, first_char, oc, 0);
+}
+
+static SLJIT_INLINE void fast_forward_newline(compiler_common *common)
+{
+DEFINE_COMPILER;
+struct sljit_label *loop;
+struct sljit_jump *lastchar = NULL;
+struct sljit_jump *firstchar;
+struct sljit_jump *quit = NULL;
+struct sljit_jump *foundcr = NULL;
+struct sljit_jump *notfoundnl;
+jump_list *newline = NULL;
+
+if (common->match_end_ptr != 0)
+  {
+  OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
+  OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+  }
+
+if (common->nltype == NLTYPE_FIXED && common->newline > 255)
+  {
+#ifdef JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD
+  if (JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD && common->mode == PCRE2_JIT_COMPLETE)
+    {
+    if (HAS_VIRTUAL_REGISTERS)
+      {
+      OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+      OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
+      }
+    else
+      {
+      OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, str));
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin));
+      }
+    firstchar = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0);
+
+    OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, STR_PTR, 0, TMP1, 0);
+    OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_NOT_EQUAL);
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+    OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT);
+#endif
+    OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+
+    fast_forward_char_pair_simd(common, 1, common->newline & 0xff, common->newline & 0xff, 0, (common->newline >> 8) & 0xff, (common->newline >> 8) & 0xff);
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+    }
+  else
+#endif /* JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD */
+    {
+    lastchar = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+    if (HAS_VIRTUAL_REGISTERS)
+      {
+      OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+      OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
+      }
+    else
+      {
+      OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, str));
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin));
+      }
+    firstchar = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0);
+
+    OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(2));
+    OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, STR_PTR, 0, TMP1, 0);
+    OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER_EQUAL);
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+    OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCHAR_SHIFT);
+#endif
+    OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+    loop = LABEL();
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2));
+    OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+    CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, loop);
+    CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff, loop);
+
+    JUMPHERE(quit);
+    JUMPHERE(lastchar);
+    }
+
+  JUMPHERE(firstchar);
+
+  if (common->match_end_ptr != 0)
+    OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+  return;
+  }
+
+if (HAS_VIRTUAL_REGISTERS)
+  {
+  OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
+  }
+else
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, str));
+
+/* Example: match /^/ to \r\n from offset 1. */
+firstchar = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0);
+
+if (common->nltype == NLTYPE_ANY)
+  move_back(common, NULL, FALSE);
+else
+  OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+loop = LABEL();
+common->ff_newline_shortcut = loop;
+
+#ifdef JIT_HAS_FAST_FORWARD_CHAR_SIMD
+if (JIT_HAS_FAST_FORWARD_CHAR_SIMD && (common->nltype == NLTYPE_FIXED || common->nltype == NLTYPE_ANYCRLF))
+  {
+  if (common->nltype == NLTYPE_ANYCRLF)
+    {
+    fast_forward_char_simd(common, CHAR_CR, CHAR_LF, 0);
+    if (common->mode != PCRE2_JIT_COMPLETE)
+      lastchar = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    quit = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
+    }
+   else
+    {
+    fast_forward_char_simd(common, common->newline, common->newline, 0);
+
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    if (common->mode != PCRE2_JIT_COMPLETE)
+      {
+      OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_PTR, 0, STR_END, 0);
+      CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0);
+      }
+    }
+  }
+else
+#endif /* JIT_HAS_FAST_FORWARD_CHAR_SIMD */
+  {
+  read_char(common, common->nlmin, common->nlmax, NULL, READ_CHAR_NEWLINE);
+  lastchar = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+  if (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF)
+    foundcr = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
+  check_newlinechar(common, common->nltype, &newline, FALSE);
+  set_jumps(newline, loop);
+  }
+
+if (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF)
+  {
+  if (quit == NULL)
+    {
+    quit = JUMP(SLJIT_JUMP);
+    JUMPHERE(foundcr);
+    }
+
+  notfoundnl = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+  OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+  OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_NL);
+  OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL);
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+  OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT);
+#endif
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+  JUMPHERE(notfoundnl);
+  JUMPHERE(quit);
+  }
+
+if (lastchar)
+  JUMPHERE(lastchar);
+JUMPHERE(firstchar);
+
+if (common->match_end_ptr != 0)
+  OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+}
+
+static BOOL optimize_class(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks);
+
+static SLJIT_INLINE void fast_forward_start_bits(compiler_common *common)
+{
+DEFINE_COMPILER;
+const sljit_u8 *start_bits = common->re->start_bitmap;
+struct sljit_label *start;
+struct sljit_jump *partial_quit;
+#if PCRE2_CODE_UNIT_WIDTH != 8
+struct sljit_jump *found = NULL;
+#endif
+jump_list *matches = NULL;
+
+if (common->match_end_ptr != 0)
+  {
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+  OP1(SLJIT_MOV, RETURN_ADDR, 0, STR_END, 0);
+  OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
+  OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_END, 0, TMP1, 0);
+  CMOV(SLJIT_GREATER, STR_END, TMP1, 0);
+  }
+
+start = LABEL();
+
+partial_quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+if (common->mode == PCRE2_JIT_COMPLETE)
+  add_jump(compiler, &common->failed_match, partial_quit);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+if (!optimize_class(common, start_bits, (start_bits[31] & 0x80) != 0, FALSE, &matches))
+  {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+  if ((start_bits[31] & 0x80) != 0)
+    found = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 255);
+  else
+    CMPTO(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 255, start);
+#elif defined SUPPORT_UNICODE
+  if (common->utf && is_char7_bitset(start_bits, FALSE))
+    CMPTO(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 127, start);
+#endif
+  OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7);
+  OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3);
+  OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)start_bits);
+  if (!HAS_VIRTUAL_REGISTERS)
+    {
+    OP2(SLJIT_SHL, TMP3, 0, SLJIT_IMM, 1, TMP2, 0);
+    OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP3, 0);
+    }
+  else
+    {
+    OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0);
+    OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
+    }
+  JUMPTO(SLJIT_ZERO, start);
+  }
+else
+  set_jumps(matches, start);
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+if (found != NULL)
+  JUMPHERE(found);
+#endif
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+if (common->mode != PCRE2_JIT_COMPLETE)
+  JUMPHERE(partial_quit);
+
+if (common->match_end_ptr != 0)
+  OP1(SLJIT_MOV, STR_END, 0, RETURN_ADDR, 0);
+}
+
+static SLJIT_INLINE jump_list *search_requested_char(compiler_common *common, PCRE2_UCHAR req_char, BOOL caseless, BOOL has_firstchar)
+{
+DEFINE_COMPILER;
+struct sljit_label *loop;
+struct sljit_jump *toolong;
+struct sljit_jump *already_found;
+struct sljit_jump *found;
+struct sljit_jump *found_oc = NULL;
+jump_list *not_found = NULL;
+sljit_u32 oc, bit;
+
+SLJIT_ASSERT(common->req_char_ptr != 0);
+OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(REQ_CU_MAX) * 100);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->req_char_ptr);
+toolong = CMP(SLJIT_LESS, TMP2, 0, STR_END, 0);
+already_found = CMP(SLJIT_LESS, STR_PTR, 0, TMP1, 0);
+
+if (has_firstchar)
+  OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+else
+  OP1(SLJIT_MOV, TMP1, 0, STR_PTR, 0);
+
+oc = req_char;
+if (caseless)
+  {
+  oc = TABLE_GET(req_char, common->fcc, req_char);
+#if defined SUPPORT_UNICODE
+  if (req_char > 127 && (common->utf || common->ucp))
+    oc = UCD_OTHERCASE(req_char);
+#endif
+  }
+
+#ifdef JIT_HAS_FAST_REQUESTED_CHAR_SIMD
+if (JIT_HAS_FAST_REQUESTED_CHAR_SIMD)
+  {
+  not_found = fast_requested_char_simd(common, req_char, oc);
+  }
+else
+#endif
+  {
+  loop = LABEL();
+  add_jump(compiler, &not_found, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0));
+
+  OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(TMP1), 0);
+
+  if (req_char == oc)
+    found = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, req_char);
+  else
+    {
+    bit = req_char ^ oc;
+    if (is_powerof2(bit))
+      {
+       OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, bit);
+      found = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, req_char | bit);
+      }
+    else
+      {
+      found = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, req_char);
+      found_oc = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, oc);
+      }
+    }
+  OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
+  JUMPTO(SLJIT_JUMP, loop);
+
+  JUMPHERE(found);
+  if (found_oc)
+    JUMPHERE(found_oc);
+  }
+
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->req_char_ptr, TMP1, 0);
+
+JUMPHERE(already_found);
+JUMPHERE(toolong);
+return not_found;
+}
+
+static void do_revertframes(compiler_common *common)
+{
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+struct sljit_label *mainloop;
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+GET_LOCAL_BASE(TMP1, 0, 0);
+
+/* Drop frames until we reach STACK_TOP. */
+mainloop = LABEL();
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), -sizeof(sljit_sw));
+jump = CMP(SLJIT_SIG_LESS_EQUAL, TMP2, 0, SLJIT_IMM, 0);
+
+OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0);
+if (HAS_VIRTUAL_REGISTERS)
+  {
+  OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(STACK_TOP), -(2 * sizeof(sljit_sw)));
+  OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), sizeof(sljit_sw), SLJIT_MEM1(STACK_TOP), -(3 * sizeof(sljit_sw)));
+  OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 3 * sizeof(sljit_sw));
+  }
+else
+  {
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), -(2 * sizeof(sljit_sw)));
+  OP1(SLJIT_MOV, TMP3, 0, SLJIT_MEM1(STACK_TOP), -(3 * sizeof(sljit_sw)));
+  OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 3 * sizeof(sljit_sw));
+  OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, TMP1, 0);
+  GET_LOCAL_BASE(TMP1, 0, 0);
+  OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP3, 0);
+  }
+JUMPTO(SLJIT_JUMP, mainloop);
+
+JUMPHERE(jump);
+jump = CMP(SLJIT_NOT_ZERO /* SIG_LESS */, TMP2, 0, SLJIT_IMM, 0);
+/* End of reverting values. */
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+
+JUMPHERE(jump);
+OP1(SLJIT_NEG, TMP2, 0, TMP2, 0);
+OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0);
+if (HAS_VIRTUAL_REGISTERS)
+  {
+  OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(STACK_TOP), -(2 * sizeof(sljit_sw)));
+  OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 2 * sizeof(sljit_sw));
+  }
+else
+  {
+  OP1(SLJIT_MOV, TMP3, 0, SLJIT_MEM1(STACK_TOP), -(2 * sizeof(sljit_sw)));
+  OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 2 * sizeof(sljit_sw));
+  OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, TMP3, 0);
+  }
+JUMPTO(SLJIT_JUMP, mainloop);
+}
+
+static void check_wordboundary(compiler_common *common)
+{
+DEFINE_COMPILER;
+struct sljit_jump *skipread;
+jump_list *skipread_list = NULL;
+#ifdef SUPPORT_UNICODE
+struct sljit_label *valid_utf;
+jump_list *invalid_utf1 = NULL;
+#endif /* SUPPORT_UNICODE */
+jump_list *invalid_utf2 = NULL;
+#if PCRE2_CODE_UNIT_WIDTH != 8 || defined SUPPORT_UNICODE
+struct sljit_jump *jump;
+#endif /* PCRE2_CODE_UNIT_WIDTH != 8 || SUPPORT_UNICODE */
+
+SLJIT_COMPILE_ASSERT(ctype_word == 0x10, ctype_word_must_be_16);
+
+sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+/* Get type of the previous char, and put it to TMP3. */
+OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
+OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 0);
+skipread = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0);
+
+#ifdef SUPPORT_UNICODE
+if (common->invalid_utf)
+  {
+  peek_char_back(common, READ_CHAR_MAX, &invalid_utf1);
+
+  if (common->mode != PCRE2_JIT_COMPLETE)
+    {
+    OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0);
+    move_back(common, NULL, TRUE);
+    check_start_used_ptr(common);
+    OP1(SLJIT_MOV, STR_PTR, 0, TMP2, 0);
+    }
+  }
+else
+#endif /* SUPPORT_UNICODE */
+  {
+  if (common->mode == PCRE2_JIT_COMPLETE)
+    peek_char_back(common, READ_CHAR_MAX, NULL);
+  else
+    {
+    move_back(common, NULL, TRUE);
+    check_start_used_ptr(common);
+    read_char(common, 0, READ_CHAR_MAX, NULL, READ_CHAR_UPDATE_STR_PTR);
+    }
+  }
+
+/* Testing char type. */
+#ifdef SUPPORT_UNICODE
+if (common->ucp)
+  {
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 1);
+  jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE);
+  add_jump(compiler, &common->getucdtype, JUMP(SLJIT_FAST_CALL));
+  OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll);
+  OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
+  OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+  OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll);
+  OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd);
+  OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
+  JUMPHERE(jump);
+  OP1(SLJIT_MOV, TMP3, 0, TMP2, 0);
+  }
+else
+#endif /* SUPPORT_UNICODE */
+  {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+  jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
+#elif defined SUPPORT_UNICODE
+  /* Here TMP3 has already been zeroed. */
+  jump = NULL;
+  if (common->utf)
+    jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+  OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), common->ctypes);
+  OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 4 /* ctype_word */);
+  OP2(SLJIT_AND, TMP3, 0, TMP1, 0, SLJIT_IMM, 1);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+  JUMPHERE(jump);
+#elif defined SUPPORT_UNICODE
+  if (jump != NULL)
+    JUMPHERE(jump);
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+  }
+JUMPHERE(skipread);
+
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0);
+check_str_end(common, &skipread_list);
+peek_char(common, READ_CHAR_MAX, SLJIT_MEM1(SLJIT_SP), LOCALS1, &invalid_utf2);
+
+/* Testing char type. This is a code duplication. */
+#ifdef SUPPORT_UNICODE
+
+valid_utf = LABEL();
+
+if (common->ucp)
+  {
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 1);
+  jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE);
+  add_jump(compiler, &common->getucdtype, JUMP(SLJIT_FAST_CALL));
+  OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll);
+  OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
+  OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+  OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll);
+  OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd);
+  OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
+  JUMPHERE(jump);
+  }
+else
+#endif /* SUPPORT_UNICODE */
+  {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+  /* TMP2 may be destroyed by peek_char. */
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0);
+  jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
+#elif defined SUPPORT_UNICODE
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0);
+  jump = NULL;
+  if (common->utf)
+    jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
+#endif
+  OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), common->ctypes);
+  OP2(SLJIT_LSHR, TMP2, 0, TMP2, 0, SLJIT_IMM, 4 /* ctype_word */);
+  OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 1);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+  JUMPHERE(jump);
+#elif defined SUPPORT_UNICODE
+  if (jump != NULL)
+    JUMPHERE(jump);
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+  }
+set_jumps(skipread_list, LABEL());
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+OP2(SLJIT_XOR | SLJIT_SET_Z, TMP2, 0, TMP2, 0, TMP3, 0);
+OP_SRC(SLJIT_FAST_RETURN, TMP1, 0);
+
+#ifdef SUPPORT_UNICODE
+if (common->invalid_utf)
+  {
+  set_jumps(invalid_utf1, LABEL());
+
+  peek_char(common, READ_CHAR_MAX, SLJIT_MEM1(SLJIT_SP), LOCALS1, NULL);
+  CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR, valid_utf);
+
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, -1);
+  OP_SRC(SLJIT_FAST_RETURN, TMP1, 0);
+
+  set_jumps(invalid_utf2, LABEL());
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+  OP1(SLJIT_MOV, TMP2, 0, TMP3, 0);
+  OP_SRC(SLJIT_FAST_RETURN, TMP1, 0);
+  }
+#endif /* SUPPORT_UNICODE */
+}
+
+static BOOL optimize_class_ranges(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks)
+{
+/* May destroy TMP1. */
+DEFINE_COMPILER;
+int ranges[MAX_CLASS_RANGE_SIZE];
+sljit_u8 bit, cbit, all;
+int i, byte, length = 0;
+
+bit = bits[0] & 0x1;
+/* All bits will be zero or one (since bit is zero or one). */
+all = -bit;
+
+for (i = 0; i < 256; )
+  {
+  byte = i >> 3;
+  if ((i & 0x7) == 0 && bits[byte] == all)
+    i += 8;
+  else
+    {
+    cbit = (bits[byte] >> (i & 0x7)) & 0x1;
+    if (cbit != bit)
+      {
+      if (length >= MAX_CLASS_RANGE_SIZE)
+        return FALSE;
+      ranges[length] = i;
+      length++;
+      bit = cbit;
+      all = -cbit;
+      }
+    i++;
+    }
+  }
+
+if (((bit == 0) && nclass) || ((bit == 1) && !nclass))
+  {
+  if (length >= MAX_CLASS_RANGE_SIZE)
+    return FALSE;
+  ranges[length] = 256;
+  length++;
+  }
+
+if (length < 0 || length > 4)
+  return FALSE;
+
+bit = bits[0] & 0x1;
+if (invert) bit ^= 0x1;
+
+/* No character is accepted. */
+if (length == 0 && bit == 0)
+  add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+
+switch(length)
+  {
+  case 0:
+  /* When bit != 0, all characters are accepted. */
+  return TRUE;
+
+  case 1:
+  add_jump(compiler, backtracks, CMP(bit == 0 ? SLJIT_LESS : SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[0]));
+  return TRUE;
+
+  case 2:
+  if (ranges[0] + 1 != ranges[1])
+    {
+    OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[0]);
+    add_jump(compiler, backtracks, CMP(bit != 0 ? SLJIT_LESS : SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0]));
+    }
+  else
+    add_jump(compiler, backtracks, CMP(bit != 0 ? SLJIT_EQUAL : SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[0]));
+  return TRUE;
+
+  case 3:
+  if (bit != 0)
+    {
+    add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[2]));
+    if (ranges[0] + 1 != ranges[1])
+      {
+      OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[0]);
+      add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0]));
+      }
+    else
+      add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[0]));
+    return TRUE;
+    }
+
+  add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[0]));
+  if (ranges[1] + 1 != ranges[2])
+    {
+    OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[1]);
+    add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[2] - ranges[1]));
+    }
+  else
+    add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[1]));
+  return TRUE;
+
+  case 4:
+  if ((ranges[1] - ranges[0]) == (ranges[3] - ranges[2])
+      && (ranges[0] | (ranges[2] - ranges[0])) == ranges[2]
+      && (ranges[1] & (ranges[2] - ranges[0])) == 0
+      && is_powerof2(ranges[2] - ranges[0]))
+    {
+    SLJIT_ASSERT((ranges[0] & (ranges[2] - ranges[0])) == 0 && (ranges[2] & ranges[3] & (ranges[2] - ranges[0])) != 0);
+    OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[2] - ranges[0]);
+    if (ranges[2] + 1 != ranges[3])
+      {
+      OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[2]);
+      add_jump(compiler, backtracks, CMP(bit != 0 ? SLJIT_LESS : SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[3] - ranges[2]));
+      }
+    else
+      add_jump(compiler, backtracks, CMP(bit != 0 ? SLJIT_EQUAL : SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[2]));
+    return TRUE;
+    }
+
+  if (bit != 0)
+    {
+    i = 0;
+    if (ranges[0] + 1 != ranges[1])
+      {
+      OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[0]);
+      add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0]));
+      i = ranges[0];
+      }
+    else
+      add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[0]));
+
+    if (ranges[2] + 1 != ranges[3])
+      {
+      OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[2] - i);
+      add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[3] - ranges[2]));
+      }
+    else
+      add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[2] - i));
+    return TRUE;
+    }
+
+  OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[0]);
+  add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[3] - ranges[0]));
+  if (ranges[1] + 1 != ranges[2])
+    {
+    OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0]);
+    add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[2] - ranges[1]));
+    }
+  else
+    add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0]));
+  return TRUE;
+
+  default:
+  SLJIT_UNREACHABLE();
+  return FALSE;
+  }
+}
+
+static BOOL optimize_class_chars(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks)
+{
+/* May destroy TMP1. */
+DEFINE_COMPILER;
+uint16_t char_list[MAX_CLASS_CHARS_SIZE];
+uint8_t byte;
+sljit_s32 type;
+int i, j, k, len, c;
+
+if (!sljit_has_cpu_feature(SLJIT_HAS_CMOV))
+  return FALSE;
+
+len = 0;
+
+for (i = 0; i < 32; i++)
+  {
+  byte = bits[i];
+
+  if (nclass)
+    byte = ~byte;
+
+  j = 0;
+  while (byte != 0)
+    {
+    if (byte & 0x1)
+      {
+      c = i * 8 + j;
+
+      k = len;
+
+      if ((c & 0x20) != 0)
+        {
+        for (k = 0; k < len; k++)
+          if (char_list[k] == c - 0x20)
+            {
+            char_list[k] |= 0x120;
+            break;
+            }
+        }
+
+      if (k == len)
+        {
+        if (len >= MAX_CLASS_CHARS_SIZE)
+          return FALSE;
+
+        char_list[len++] = (uint16_t) c;
+        }
+      }
+
+    byte >>= 1;
+    j++;
+    }
+  }
+
+if (len == 0) return FALSE;  /* Should never occur, but stops analyzers complaining. */
+
+i = 0;
+j = 0;
+
+if (char_list[0] == 0)
+  {
+  i++;
+  OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0);
+  OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_ZERO);
+  }
+else
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0);
+
+while (i < len)
+  {
+  if ((char_list[i] & 0x100) != 0)
+    j++;
+  else
+    {
+    OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, char_list[i]);
+    CMOV(SLJIT_ZERO, TMP2, TMP1, 0);
+    }
+  i++;
+  }
+
+if (j != 0)
+  {
+  OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x20);
+
+  for (i = 0; i < len; i++)
+    if ((char_list[i] & 0x100) != 0)
+      {
+      j--;
+      OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, char_list[i] & 0xff);
+      CMOV(SLJIT_ZERO, TMP2, TMP1, 0);
+      }
+  }
+
+if (invert)
+  nclass = !nclass;
+
+type = nclass ? SLJIT_NOT_EQUAL : SLJIT_EQUAL;
+add_jump(compiler, backtracks, CMP(type, TMP2, 0, SLJIT_IMM, 0));
+return TRUE;
+}
+
+static BOOL optimize_class(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks)
+{
+/* May destroy TMP1. */
+if (optimize_class_ranges(common, bits, nclass, invert, backtracks))
+  return TRUE;
+return optimize_class_chars(common, bits, nclass, invert, backtracks);
+}
+
+static void check_anynewline(compiler_common *common)
+{
+/* Check whether TMP1 contains a newline character. TMP2 destroyed. */
+DEFINE_COMPILER;
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a);
+OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a);
+OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a);
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+#if PCRE2_CODE_UNIT_WIDTH == 8
+if (common->utf)
+  {
+#endif
+  OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+  OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1);
+  OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a);
+#if PCRE2_CODE_UNIT_WIDTH == 8
+  }
+#endif
+#endif /* SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == [16|32] */
+OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+}
+
+static void check_hspace(compiler_common *common)
+{
+/* Check whether TMP1 contains a newline character. TMP2 destroyed. */
+DEFINE_COMPILER;
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x09);
+OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x20);
+OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xa0);
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+#if PCRE2_CODE_UNIT_WIDTH == 8
+if (common->utf)
+  {
+#endif
+  OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+  OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x1680);
+  OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+  OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e);
+  OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+  OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x2000);
+  OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x200A - 0x2000);
+  OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
+  OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x202f - 0x2000);
+  OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+  OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x205f - 0x2000);
+  OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+  OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x3000 - 0x2000);
+#if PCRE2_CODE_UNIT_WIDTH == 8
+  }
+#endif
+#endif /* SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == [16|32] */
+OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
+
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+}
+
+static void check_vspace(compiler_common *common)
+{
+/* Check whether TMP1 contains a newline character. TMP2 destroyed. */
+DEFINE_COMPILER;
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a);
+OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a);
+OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a);
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+#if PCRE2_CODE_UNIT_WIDTH == 8
+if (common->utf)
+  {
+#endif
+  OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+  OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1);
+  OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a);
+#if PCRE2_CODE_UNIT_WIDTH == 8
+  }
+#endif
+#endif /* SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == [16|32] */
+OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
+
+OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
+}
+
+static void do_casefulcmp(compiler_common *common)
+{
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+struct sljit_label *label;
+int char1_reg;
+int char2_reg;
+
+if (HAS_VIRTUAL_REGISTERS)
+  {
+  char1_reg = STR_END;
+  char2_reg = STACK_TOP;
+  }
+else
+  {
+  char1_reg = TMP3;
+  char2_reg = RETURN_ADDR;
+  }
+
+sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+if (char1_reg == STR_END)
+  {
+  OP1(SLJIT_MOV, TMP3, 0, char1_reg, 0);
+  OP1(SLJIT_MOV, RETURN_ADDR, 0, char2_reg, 0);
+  }
+
+if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS)
+  {
+  label = LABEL();
+  sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1));
+  sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+  jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0);
+  OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
+  JUMPTO(SLJIT_NOT_ZERO, label);
+
+  JUMPHERE(jump);
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+  }
+else if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS)
+  {
+  OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
+  OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+  label = LABEL();
+  sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1));
+  sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+  jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0);
+  OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
+  JUMPTO(SLJIT_NOT_ZERO, label);
+
+  JUMPHERE(jump);
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  }
+else
+  {
+  label = LABEL();
+  OP1(MOV_UCHAR, char1_reg, 0, SLJIT_MEM1(TMP1), 0);
+  OP1(MOV_UCHAR, char2_reg, 0, SLJIT_MEM1(STR_PTR), 0);
+  OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0);
+  OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
+  JUMPTO(SLJIT_NOT_ZERO, label);
+
+  JUMPHERE(jump);
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+  }
+
+if (char1_reg == STR_END)
+  {
+  OP1(SLJIT_MOV, char1_reg, 0, TMP3, 0);
+  OP1(SLJIT_MOV, char2_reg, 0, RETURN_ADDR, 0);
+  }
+
+OP_SRC(SLJIT_FAST_RETURN, TMP1, 0);
+}
+
+static void do_caselesscmp(compiler_common *common)
+{
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+struct sljit_label *label;
+int char1_reg = STR_END;
+int char2_reg;
+int lcc_table;
+int opt_type = 0;
+
+if (HAS_VIRTUAL_REGISTERS)
+  {
+  char2_reg = STACK_TOP;
+  lcc_table = STACK_LIMIT;
+  }
+else
+  {
+  char2_reg = RETURN_ADDR;
+  lcc_table = TMP3;
+  }
+
+if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS)
+  opt_type = 1;
+else if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS)
+  opt_type = 2;
+
+sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, char1_reg, 0);
+
+if (char2_reg == STACK_TOP)
+  {
+  OP1(SLJIT_MOV, TMP3, 0, char2_reg, 0);
+  OP1(SLJIT_MOV, RETURN_ADDR, 0, lcc_table, 0);
+  }
+
+OP1(SLJIT_MOV, lcc_table, 0, SLJIT_IMM, common->lcc);
+
+if (opt_type == 1)
+  {
+  label = LABEL();
+  sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1));
+  sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+  }
+else if (opt_type == 2)
+  {
+  OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
+  OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+  label = LABEL();
+  sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1));
+  sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+  }
+else
+  {
+  label = LABEL();
+  OP1(MOV_UCHAR, char1_reg, 0, SLJIT_MEM1(TMP1), 0);
+  OP1(MOV_UCHAR, char2_reg, 0, SLJIT_MEM1(STR_PTR), 0);
+  OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
+  }
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+jump = CMP(SLJIT_GREATER, char1_reg, 0, SLJIT_IMM, 255);
+#endif
+OP1(SLJIT_MOV_U8, char1_reg, 0, SLJIT_MEM2(lcc_table, char1_reg), 0);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+JUMPHERE(jump);
+jump = CMP(SLJIT_GREATER, char2_reg, 0, SLJIT_IMM, 255);
+#endif
+OP1(SLJIT_MOV_U8, char2_reg, 0, SLJIT_MEM2(lcc_table, char2_reg), 0);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+JUMPHERE(jump);
+#endif
+
+if (opt_type == 0)
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0);
+OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
+JUMPTO(SLJIT_NOT_ZERO, label);
+
+JUMPHERE(jump);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+
+if (opt_type == 2)
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+if (char2_reg == STACK_TOP)
+  {
+  OP1(SLJIT_MOV, char2_reg, 0, TMP3, 0);
+  OP1(SLJIT_MOV, lcc_table, 0, RETURN_ADDR, 0);
+  }
+
+OP1(SLJIT_MOV, char1_reg, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1);
+OP_SRC(SLJIT_FAST_RETURN, TMP1, 0);
+}
+
+static PCRE2_SPTR byte_sequence_compare(compiler_common *common, BOOL caseless, PCRE2_SPTR cc,
+    compare_context *context, jump_list **backtracks)
+{
+DEFINE_COMPILER;
+unsigned int othercasebit = 0;
+PCRE2_SPTR othercasechar = NULL;
+#ifdef SUPPORT_UNICODE
+int utflength;
+#endif
+
+if (caseless && char_has_othercase(common, cc))
+  {
+  othercasebit = char_get_othercase_bit(common, cc);
+  SLJIT_ASSERT(othercasebit);
+  /* Extracting bit difference info. */
+#if PCRE2_CODE_UNIT_WIDTH == 8
+  othercasechar = cc + (othercasebit >> 8);
+  othercasebit &= 0xff;
+#elif PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+  /* Note that this code only handles characters in the BMP. If there
+  ever are characters outside the BMP whose othercase differs in only one
+  bit from itself (there currently are none), this code will need to be
+  revised for PCRE2_CODE_UNIT_WIDTH == 32. */
+  othercasechar = cc + (othercasebit >> 9);
+  if ((othercasebit & 0x100) != 0)
+    othercasebit = (othercasebit & 0xff) << 8;
+  else
+    othercasebit &= 0xff;
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
+  }
+
+if (context->sourcereg == -1)
+  {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
+  if (context->length >= 4)
+    OP1(SLJIT_MOV_S32, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
+  else if (context->length >= 2)
+    OP1(SLJIT_MOV_U16, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
+  else
+#endif
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
+  if (context->length >= 4)
+    OP1(SLJIT_MOV_S32, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
+  else
+#endif
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+  OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
+  context->sourcereg = TMP2;
+  }
+
+#ifdef SUPPORT_UNICODE
+utflength = 1;
+if (common->utf && HAS_EXTRALEN(*cc))
+  utflength += GET_EXTRALEN(*cc);
+
+do
+  {
+#endif
+
+  context->length -= IN_UCHARS(1);
+#if (defined SLJIT_UNALIGNED && SLJIT_UNALIGNED) && (PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16)
+
+  /* Unaligned read is supported. */
+  if (othercasebit != 0 && othercasechar == cc)
+    {
+    context->c.asuchars[context->ucharptr] = *cc | othercasebit;
+    context->oc.asuchars[context->ucharptr] = othercasebit;
+    }
+  else
+    {
+    context->c.asuchars[context->ucharptr] = *cc;
+    context->oc.asuchars[context->ucharptr] = 0;
+    }
+  context->ucharptr++;
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+  if (context->ucharptr >= 4 || context->length == 0 || (context->ucharptr == 2 && context->length == 1))
+#else
+  if (context->ucharptr >= 2 || context->length == 0)
+#endif
+    {
+    if (context->length >= 4)
+      OP1(SLJIT_MOV_S32, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
+    else if (context->length >= 2)
+      OP1(SLJIT_MOV_U16, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
+#if PCRE2_CODE_UNIT_WIDTH == 8
+    else if (context->length >= 1)
+      OP1(SLJIT_MOV_U8, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+    context->sourcereg = context->sourcereg == TMP1 ? TMP2 : TMP1;
+
+    switch(context->ucharptr)
+      {
+      case 4 / sizeof(PCRE2_UCHAR):
+      if (context->oc.asint != 0)
+        OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asint);
+      add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, context->c.asint | context->oc.asint));
+      break;
+
+      case 2 / sizeof(PCRE2_UCHAR):
+      if (context->oc.asushort != 0)
+        OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asushort);
+      add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, context->c.asushort | context->oc.asushort));
+      break;
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+      case 1:
+      if (context->oc.asbyte != 0)
+        OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asbyte);
+      add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, context->c.asbyte | context->oc.asbyte));
+      break;
+#endif
+
+      default:
+      SLJIT_UNREACHABLE();
+      break;
+      }
+    context->ucharptr = 0;
+    }
+
+#else
+
+  /* Unaligned read is unsupported or in 32 bit mode. */
+  if (context->length >= 1)
+    OP1(MOV_UCHAR, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
+
+  context->sourcereg = context->sourcereg == TMP1 ? TMP2 : TMP1;
+
+  if (othercasebit != 0 && othercasechar == cc)
+    {
+    OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, othercasebit);
+    add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, *cc | othercasebit));
+    }
+  else
+    add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, *cc));
+
+#endif
+
+  cc++;
+#ifdef SUPPORT_UNICODE
+  utflength--;
+  }
+while (utflength > 0);
+#endif
+
+return cc;
+}
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+
+#define SET_TYPE_OFFSET(value) \
+  if ((value) != typeoffset) \
+    { \
+    if ((value) < typeoffset) \
+      OP2(SLJIT_ADD, typereg, 0, typereg, 0, SLJIT_IMM, typeoffset - (value)); \
+    else \
+      OP2(SLJIT_SUB, typereg, 0, typereg, 0, SLJIT_IMM, (value) - typeoffset); \
+    } \
+  typeoffset = (value);
+
+#define SET_CHAR_OFFSET(value) \
+  if ((value) != charoffset) \
+    { \
+    if ((value) < charoffset) \
+      OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(charoffset - (value))); \
+    else \
+      OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)((value) - charoffset)); \
+    } \
+  charoffset = (value);
+
+static PCRE2_SPTR compile_char1_matchingpath(compiler_common *common, PCRE2_UCHAR type, PCRE2_SPTR cc, jump_list **backtracks, BOOL check_str_ptr);
+
+static void compile_xclass_matchingpath(compiler_common *common, PCRE2_SPTR cc, jump_list **backtracks)
+{
+DEFINE_COMPILER;
+jump_list *found = NULL;
+jump_list **list = (cc[0] & XCL_NOT) == 0 ? &found : backtracks;
+sljit_uw c, charoffset, max = 256, min = READ_CHAR_MAX;
+struct sljit_jump *jump = NULL;
+PCRE2_SPTR ccbegin;
+int compares, invertcmp, numberofcmps;
+#if defined SUPPORT_UNICODE && (PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16)
+BOOL utf = common->utf;
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == [8|16] */
+
+#ifdef SUPPORT_UNICODE
+BOOL needstype = FALSE, needsscript = FALSE, needschar = FALSE;
+BOOL charsaved = FALSE;
+int typereg = TMP1;
+const sljit_u32 *other_cases;
+sljit_uw typeoffset;
+#endif /* SUPPORT_UNICODE */
+
+/* Scanning the necessary info. */
+cc++;
+ccbegin = cc;
+compares = 0;
+
+if (cc[-1] & XCL_MAP)
+  {
+  min = 0;
+  cc += 32 / sizeof(PCRE2_UCHAR);
+  }
+
+while (*cc != XCL_END)
+  {
+  compares++;
+  if (*cc == XCL_SINGLE)
+    {
+    cc ++;
+    GETCHARINCTEST(c, cc);
+    if (c > max) max = c;
+    if (c < min) min = c;
+#ifdef SUPPORT_UNICODE
+    needschar = TRUE;
+#endif /* SUPPORT_UNICODE */
+    }
+  else if (*cc == XCL_RANGE)
+    {
+    cc ++;
+    GETCHARINCTEST(c, cc);
+    if (c < min) min = c;
+    GETCHARINCTEST(c, cc);
+    if (c > max) max = c;
+#ifdef SUPPORT_UNICODE
+    needschar = TRUE;
+#endif /* SUPPORT_UNICODE */
+    }
+#ifdef SUPPORT_UNICODE
+  else
+    {
+    SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP);
+    cc++;
+    if (*cc == PT_CLIST)
+      {
+      other_cases = PRIV(ucd_caseless_sets) + cc[1];
+      while (*other_cases != NOTACHAR)
+        {
+        if (*other_cases > max) max = *other_cases;
+        if (*other_cases < min) min = *other_cases;
+        other_cases++;
+        }
+      }
+    else
+      {
+      max = READ_CHAR_MAX;
+      min = 0;
+      }
+
+    switch(*cc)
+      {
+      case PT_ANY:
+      /* Any either accepts everything or ignored. */
+      if (cc[-1] == XCL_PROP)
+        {
+        compile_char1_matchingpath(common, OP_ALLANY, cc, backtracks, FALSE);
+        if (list == backtracks)
+          add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+        return;
+        }
+      break;
+
+      case PT_LAMP:
+      case PT_GC:
+      case PT_PC:
+      case PT_ALNUM:
+      needstype = TRUE;
+      break;
+
+      case PT_SC:
+      needsscript = TRUE;
+      break;
+
+      case PT_SPACE:
+      case PT_PXSPACE:
+      case PT_WORD:
+      case PT_PXGRAPH:
+      case PT_PXPRINT:
+      case PT_PXPUNCT:
+      needstype = TRUE;
+      needschar = TRUE;
+      break;
+
+      case PT_CLIST:
+      case PT_UCNC:
+      needschar = TRUE;
+      break;
+
+      default:
+      SLJIT_UNREACHABLE();
+      break;
+      }
+    cc += 2;
+    }
+#endif /* SUPPORT_UNICODE */
+  }
+SLJIT_ASSERT(compares > 0);
+
+/* We are not necessary in utf mode even in 8 bit mode. */
+cc = ccbegin;
+if ((cc[-1] & XCL_NOT) != 0)
+  read_char(common, min, max, backtracks, READ_CHAR_UPDATE_STR_PTR);
+else
+  {
+#ifdef SUPPORT_UNICODE
+  read_char(common, min, max, (needstype || needsscript) ? backtracks : NULL, 0);
+#else /* !SUPPORT_UNICODE */
+  read_char(common, min, max, NULL, 0);
+#endif /* SUPPORT_UNICODE */
+  }
+
+if ((cc[-1] & XCL_HASPROP) == 0)
+  {
+  if ((cc[-1] & XCL_MAP) != 0)
+    {
+    jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
+    if (!optimize_class(common, (const sljit_u8 *)cc, (((const sljit_u8 *)cc)[31] & 0x80) != 0, TRUE, &found))
+      {
+      OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7);
+      OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3);
+      OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc);
+      OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0);
+      OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
+      add_jump(compiler, &found, JUMP(SLJIT_NOT_ZERO));
+      }
+
+    add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+    JUMPHERE(jump);
+
+    cc += 32 / sizeof(PCRE2_UCHAR);
+    }
+  else
+    {
+    OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, min);
+    add_jump(compiler, (cc[-1] & XCL_NOT) == 0 ? backtracks : &found, CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, max - min));
+    }
+  }
+else if ((cc[-1] & XCL_MAP) != 0)
+  {
+  OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0);
+#ifdef SUPPORT_UNICODE
+  charsaved = TRUE;
+#endif /* SUPPORT_UNICODE */
+  if (!optimize_class(common, (const sljit_u8 *)cc, FALSE, TRUE, list))
+    {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+    jump = NULL;
+    if (common->utf)
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+      jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
+
+    OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7);
+    OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3);
+    OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc);
+    OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0);
+    OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
+    add_jump(compiler, list, JUMP(SLJIT_NOT_ZERO));
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+    if (common->utf)
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+      JUMPHERE(jump);
+    }
+
+  OP1(SLJIT_MOV, TMP1, 0, RETURN_ADDR, 0);
+  cc += 32 / sizeof(PCRE2_UCHAR);
+  }
+
+#ifdef SUPPORT_UNICODE
+if (needstype || needsscript)
+  {
+  if (needschar && !charsaved)
+    OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0);
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+  if (!common->utf)
+    {
+    jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, MAX_UTF_CODE_POINT + 1);
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, UNASSIGNED_UTF_CHAR);
+    JUMPHERE(jump);
+    }
+#endif /* PCRE2_CODE_UNIT_WIDTH == 32 */
+
+  OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT);
+  OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 1);
+  OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1));
+  OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK);
+  OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCD_BLOCK_SHIFT);
+  OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_stage2));
+  OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM2(TMP2, TMP1), 1);
+
+  /* Before anything else, we deal with scripts. */
+  if (needsscript)
+    {
+    OP2(SLJIT_SHL, TMP1, 0, TMP2, 0, SLJIT_IMM, 3);
+    OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 2);
+    OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+
+    OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, script));
+
+    ccbegin = cc;
+
+    while (*cc != XCL_END)
+      {
+      if (*cc == XCL_SINGLE)
+        {
+        cc ++;
+        GETCHARINCTEST(c, cc);
+        }
+      else if (*cc == XCL_RANGE)
+        {
+        cc ++;
+        GETCHARINCTEST(c, cc);
+        GETCHARINCTEST(c, cc);
+        }
+      else
+        {
+        SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP);
+        cc++;
+        if (*cc == PT_SC)
+          {
+          compares--;
+          invertcmp = (compares == 0 && list != backtracks);
+          if (cc[-1] == XCL_NOTPROP)
+            invertcmp ^= 0x1;
+          jump = CMP(SLJIT_EQUAL ^ invertcmp, TMP1, 0, SLJIT_IMM, (int)cc[1]);
+          add_jump(compiler, compares > 0 ? list : backtracks, jump);
+          }
+        cc += 2;
+        }
+      }
+
+    cc = ccbegin;
+
+    if (needstype)
+      {
+      /* TMP2 has already been shifted by 2 */
+      if (!needschar)
+        {
+        OP2(SLJIT_ADD, TMP1, 0, TMP2, 0, TMP2, 0);
+        OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+
+        OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype));
+        }
+      else
+        {
+        OP2(SLJIT_ADD, TMP1, 0, TMP2, 0, TMP2, 0);
+        OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0);
+
+        OP1(SLJIT_MOV, TMP1, 0, RETURN_ADDR, 0);
+        OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype));
+        typereg = RETURN_ADDR;
+        }
+      }
+    else if (needschar)
+      OP1(SLJIT_MOV, TMP1, 0, RETURN_ADDR, 0);
+    }
+  else if (needstype)
+    {
+    OP2(SLJIT_SHL, TMP1, 0, TMP2, 0, SLJIT_IMM, 3);
+    OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 2);
+
+    if (!needschar)
+      {
+      OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+
+      OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype));
+      }
+    else
+      {
+      OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0);
+
+      OP1(SLJIT_MOV, TMP1, 0, RETURN_ADDR, 0);
+      OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype));
+      typereg = RETURN_ADDR;
+      }
+    }
+  else if (needschar)
+    OP1(SLJIT_MOV, TMP1, 0, RETURN_ADDR, 0);
+  }
+#endif /* SUPPORT_UNICODE */
+
+/* Generating code. */
+charoffset = 0;
+numberofcmps = 0;
+#ifdef SUPPORT_UNICODE
+typeoffset = 0;
+#endif /* SUPPORT_UNICODE */
+
+while (*cc != XCL_END)
+  {
+  compares--;
+  invertcmp = (compares == 0 && list != backtracks);
+  jump = NULL;
+
+  if (*cc == XCL_SINGLE)
+    {
+    cc ++;
+    GETCHARINCTEST(c, cc);
+
+    if (numberofcmps < 3 && (*cc == XCL_SINGLE || *cc == XCL_RANGE))
+      {
+      OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
+      OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+      numberofcmps++;
+      }
+    else if (numberofcmps > 0)
+      {
+      OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
+      OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
+      jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+      numberofcmps = 0;
+      }
+    else
+      {
+      jump = CMP(SLJIT_EQUAL ^ invertcmp, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
+      numberofcmps = 0;
+      }
+    }
+  else if (*cc == XCL_RANGE)
+    {
+    cc ++;
+    GETCHARINCTEST(c, cc);
+    SET_CHAR_OFFSET(c);
+    GETCHARINCTEST(c, cc);
+
+    if (numberofcmps < 3 && (*cc == XCL_SINGLE || *cc == XCL_RANGE))
+      {
+      OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
+      OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
+      numberofcmps++;
+      }
+    else if (numberofcmps > 0)
+      {
+      OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
+      OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL);
+      jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+      numberofcmps = 0;
+      }
+    else
+      {
+      jump = CMP(SLJIT_LESS_EQUAL ^ invertcmp, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
+      numberofcmps = 0;
+      }
+    }
+#ifdef SUPPORT_UNICODE
+  else
+    {
+    SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP);
+    if (*cc == XCL_NOTPROP)
+      invertcmp ^= 0x1;
+    cc++;
+    switch(*cc)
+      {
+      case PT_ANY:
+      if (!invertcmp)
+        jump = JUMP(SLJIT_JUMP);
+      break;
+
+      case PT_LAMP:
+      OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - typeoffset);
+      OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+      OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Ll - typeoffset);
+      OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+      OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lt - typeoffset);
+      OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
+      jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+      break;
+
+      case PT_GC:
+      c = PRIV(ucp_typerange)[(int)cc[1] * 2];
+      SET_TYPE_OFFSET(c);
+      jump = CMP(SLJIT_LESS_EQUAL ^ invertcmp, typereg, 0, SLJIT_IMM, PRIV(ucp_typerange)[(int)cc[1] * 2 + 1] - c);
+      break;
+
+      case PT_PC:
+      jump = CMP(SLJIT_EQUAL ^ invertcmp, typereg, 0, SLJIT_IMM, (int)cc[1] - typeoffset);
+      break;
+
+      case PT_SC:
+      compares++;
+      /* Do nothing. */
+      break;
+
+      case PT_SPACE:
+      case PT_PXSPACE:
+      SET_CHAR_OFFSET(9);
+      OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd - 0x9);
+      OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+
+      OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x9);
+      OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+
+      OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e - 0x9);
+      OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+
+      SET_TYPE_OFFSET(ucp_Zl);
+      OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Zl);
+      OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL);
+      jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+      break;
+
+      case PT_WORD:
+      OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_UNDERSCORE - charoffset));
+      OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+      /* Fall through. */
+
+      case PT_ALNUM:
+      SET_TYPE_OFFSET(ucp_Ll);
+      OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
+      OP_FLAGS((*cc == PT_ALNUM) ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
+      SET_TYPE_OFFSET(ucp_Nd);
+      OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_No - ucp_Nd);
+      OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL);
+      jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+      break;
+
+      case PT_CLIST:
+      other_cases = PRIV(ucd_caseless_sets) + cc[1];
+
+      /* At least three characters are required.
+         Otherwise this case would be handled by the normal code path. */
+      SLJIT_ASSERT(other_cases[0] != NOTACHAR && other_cases[1] != NOTACHAR && other_cases[2] != NOTACHAR);
+      SLJIT_ASSERT(other_cases[0] < other_cases[1] && other_cases[1] < other_cases[2]);
+
+      /* Optimizing character pairs, if their difference is power of 2. */
+      if (is_powerof2(other_cases[1] ^ other_cases[0]))
+        {
+        if (charoffset == 0)
+          OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]);
+        else
+          {
+          OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)charoffset);
+          OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]);
+          }
+        OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, other_cases[1]);
+        OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+        other_cases += 2;
+        }
+      else if (is_powerof2(other_cases[2] ^ other_cases[1]))
+        {
+        if (charoffset == 0)
+          OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, other_cases[2] ^ other_cases[1]);
+        else
+          {
+          OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)charoffset);
+          OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]);
+          }
+        OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, other_cases[2]);
+        OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+
+        OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(other_cases[0] - charoffset));
+        OP_FLAGS(SLJIT_OR | ((other_cases[3] == NOTACHAR) ? SLJIT_SET_Z : 0), TMP2, 0, SLJIT_EQUAL);
+
+        other_cases += 3;
+        }
+      else
+        {
+        OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(*other_cases++ - charoffset));
+        OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+        }
+
+      while (*other_cases != NOTACHAR)
+        {
+        OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(*other_cases++ - charoffset));
+        OP_FLAGS(SLJIT_OR | ((*other_cases == NOTACHAR) ? SLJIT_SET_Z : 0), TMP2, 0, SLJIT_EQUAL);
+        }
+      jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+      break;
+
+      case PT_UCNC:
+      OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_DOLLAR_SIGN - charoffset));
+      OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+      OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_COMMERCIAL_AT - charoffset));
+      OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+      OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_GRAVE_ACCENT - charoffset));
+      OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+
+      SET_CHAR_OFFSET(0xa0);
+      OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(0xd7ff - charoffset));
+      OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
+      SET_CHAR_OFFSET(0);
+      OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xe000 - 0);
+      OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_GREATER_EQUAL);
+      jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+      break;
+
+      case PT_PXGRAPH:
+      /* C and Z groups are the farthest two groups. */
+      SET_TYPE_OFFSET(ucp_Ll);
+      OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll);
+      OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER);
+
+      jump = CMP(SLJIT_NOT_EQUAL, typereg, 0, SLJIT_IMM, ucp_Cf - ucp_Ll);
+
+      /* In case of ucp_Cf, we overwrite the result. */
+      SET_CHAR_OFFSET(0x2066);
+      OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066);
+      OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+
+      OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066);
+      OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+
+      OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e - 0x2066);
+      OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+
+      JUMPHERE(jump);
+      jump = CMP(SLJIT_ZERO ^ invertcmp, TMP2, 0, SLJIT_IMM, 0);
+      break;
+
+      case PT_PXPRINT:
+      /* C and Z groups are the farthest two groups. */
+      SET_TYPE_OFFSET(ucp_Ll);
+      OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll);
+      OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER);
+
+      OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Ll);
+      OP_FLAGS(SLJIT_AND, TMP2, 0, SLJIT_NOT_EQUAL);
+
+      jump = CMP(SLJIT_NOT_EQUAL, typereg, 0, SLJIT_IMM, ucp_Cf - ucp_Ll);
+
+      /* In case of ucp_Cf, we overwrite the result. */
+      SET_CHAR_OFFSET(0x2066);
+      OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066);
+      OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+
+      OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066);
+      OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+
+      JUMPHERE(jump);
+      jump = CMP(SLJIT_ZERO ^ invertcmp, TMP2, 0, SLJIT_IMM, 0);
+      break;
+
+      case PT_PXPUNCT:
+      SET_TYPE_OFFSET(ucp_Sc);
+      OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Sc);
+      OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+
+      SET_CHAR_OFFSET(0);
+      OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x7f);
+      OP_FLAGS(SLJIT_AND, TMP2, 0, SLJIT_LESS_EQUAL);
+
+      SET_TYPE_OFFSET(ucp_Pc);
+      OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Ps - ucp_Pc);
+      OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL);
+      jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+      break;
+
+      default:
+      SLJIT_UNREACHABLE();
+      break;
+      }
+    cc += 2;
+    }
+#endif /* SUPPORT_UNICODE */
+
+  if (jump != NULL)
+    add_jump(compiler, compares > 0 ? list : backtracks, jump);
+  }
+
+if (found != NULL)
+  set_jumps(found, LABEL());
+}
+
+#undef SET_TYPE_OFFSET
+#undef SET_CHAR_OFFSET
+
+#endif
+
+static PCRE2_SPTR compile_simple_assertion_matchingpath(compiler_common *common, PCRE2_UCHAR type, PCRE2_SPTR cc, jump_list **backtracks)
+{
+DEFINE_COMPILER;
+int length;
+struct sljit_jump *jump[4];
+#ifdef SUPPORT_UNICODE
+struct sljit_label *label;
+#endif /* SUPPORT_UNICODE */
+
+switch(type)
+  {
+  case OP_SOD:
+  if (HAS_VIRTUAL_REGISTERS)
+    {
+    OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
+    }
+  else
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin));
+  add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, TMP1, 0));
+  return cc;
+
+  case OP_SOM:
+  if (HAS_VIRTUAL_REGISTERS)
+    {
+    OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
+    }
+  else
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, str));
+  add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, TMP1, 0));
+  return cc;
+
+  case OP_NOT_WORD_BOUNDARY:
+  case OP_WORD_BOUNDARY:
+  add_jump(compiler, &common->wordboundary, JUMP(SLJIT_FAST_CALL));
+#ifdef SUPPORT_UNICODE
+  if (common->invalid_utf)
+    {
+    add_jump(compiler, backtracks, CMP((type == OP_NOT_WORD_BOUNDARY) ? SLJIT_NOT_EQUAL : SLJIT_SIG_LESS_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+    return cc;
+    }
+#endif /* SUPPORT_UNICODE */
+  sljit_set_current_flags(compiler, SLJIT_SET_Z);
+  add_jump(compiler, backtracks, JUMP(type == OP_NOT_WORD_BOUNDARY ? SLJIT_NOT_ZERO : SLJIT_ZERO));
+  return cc;
+
+  case OP_EODN:
+  /* Requires rather complex checks. */
+  jump[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+  if (common->nltype == NLTYPE_FIXED && common->newline > 255)
+    {
+    OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+    if (common->mode == PCRE2_JIT_COMPLETE)
+      add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_END, 0));
+    else
+      {
+      jump[1] = CMP(SLJIT_EQUAL, TMP2, 0, STR_END, 0);
+      OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP2, 0, STR_END, 0);
+      OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS);
+      OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff);
+      OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_NOT_EQUAL);
+      add_jump(compiler, backtracks, JUMP(SLJIT_NOT_EQUAL));
+      check_partial(common, TRUE);
+      add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+      JUMPHERE(jump[1]);
+      }
+    OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+    add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
+    add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff));
+    }
+  else if (common->nltype == NLTYPE_FIXED)
+    {
+    OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+    add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_END, 0));
+    add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, common->newline));
+    }
+  else
+    {
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+    jump[1] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
+    OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+    OP2(SLJIT_SUB | SLJIT_SET_Z | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, TMP2, 0, STR_END, 0);
+    jump[2] = JUMP(SLJIT_GREATER);
+    add_jump(compiler, backtracks, JUMP(SLJIT_NOT_EQUAL) /* LESS */);
+    /* Equal. */
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+    jump[3] = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL);
+    add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+
+    JUMPHERE(jump[1]);
+    if (common->nltype == NLTYPE_ANYCRLF)
+      {
+      OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+      add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP2, 0, STR_END, 0));
+      add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL));
+      }
+    else
+      {
+      OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0);
+      read_char(common, common->nlmin, common->nlmax, backtracks, READ_CHAR_UPDATE_STR_PTR);
+      add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, STR_END, 0));
+      add_jump(compiler, &common->anynewline, JUMP(SLJIT_FAST_CALL));
+      sljit_set_current_flags(compiler, SLJIT_SET_Z);
+      add_jump(compiler, backtracks, JUMP(SLJIT_ZERO));
+      OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0);
+      }
+    JUMPHERE(jump[2]);
+    JUMPHERE(jump[3]);
+    }
+  JUMPHERE(jump[0]);
+  if (common->mode != PCRE2_JIT_COMPLETE)
+    check_partial(common, TRUE);
+  return cc;
+
+  case OP_EOD:
+  add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0));
+  if (common->mode != PCRE2_JIT_COMPLETE)
+    check_partial(common, TRUE);
+  return cc;
+
+  case OP_DOLL:
+  if (HAS_VIRTUAL_REGISTERS)
+    {
+    OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
+    OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL);
+    }
+  else
+    OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL);
+  add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32));
+
+  if (!common->endonly)
+    compile_simple_assertion_matchingpath(common, OP_EODN, cc, backtracks);
+  else
+    {
+    add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0));
+    check_partial(common, FALSE);
+    }
+  return cc;
+
+  case OP_DOLLM:
+  jump[1] = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0);
+  if (HAS_VIRTUAL_REGISTERS)
+    {
+    OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
+    OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL);
+    }
+  else
+    OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL);
+  add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32));
+  check_partial(common, FALSE);
+  jump[0] = JUMP(SLJIT_JUMP);
+  JUMPHERE(jump[1]);
+
+  if (common->nltype == NLTYPE_FIXED && common->newline > 255)
+    {
+    OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+    if (common->mode == PCRE2_JIT_COMPLETE)
+      add_jump(compiler, backtracks, CMP(SLJIT_GREATER, TMP2, 0, STR_END, 0));
+    else
+      {
+      jump[1] = CMP(SLJIT_LESS_EQUAL, TMP2, 0, STR_END, 0);
+      /* STR_PTR = STR_END - IN_UCHARS(1) */
+      add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
+      check_partial(common, TRUE);
+      add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+      JUMPHERE(jump[1]);
+      }
+
+    OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+    add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
+    add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff));
+    }
+  else
+    {
+    peek_char(common, common->nlmax, TMP3, 0, NULL);
+    check_newlinechar(common, common->nltype, backtracks, FALSE);
+    }
+  JUMPHERE(jump[0]);
+  return cc;
+
+  case OP_CIRC:
+  if (HAS_VIRTUAL_REGISTERS)
+    {
+    OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin));
+    add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0));
+    OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL);
+    add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32));
+    }
+  else
+    {
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin));
+    add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0));
+    OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL);
+    add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32));
+    }
+  return cc;
+
+  case OP_CIRCM:
+  /* TMP2 might be used by peek_char_back. */
+  if (HAS_VIRTUAL_REGISTERS)
+    {
+    OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
+    jump[1] = CMP(SLJIT_GREATER, STR_PTR, 0, TMP2, 0);
+    OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL);
+    }
+  else
+    {
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin));
+    jump[1] = CMP(SLJIT_GREATER, STR_PTR, 0, TMP2, 0);
+    OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL);
+    }
+  add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32));
+  jump[0] = JUMP(SLJIT_JUMP);
+  JUMPHERE(jump[1]);
+
+  if (!common->alt_circumflex)
+    add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+  if (common->nltype == NLTYPE_FIXED && common->newline > 255)
+    {
+    OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+    add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, TMP2, 0));
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2));
+    OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+    add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
+    add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff));
+    }
+  else
+    {
+    peek_char_back(common, common->nlmax, backtracks);
+    check_newlinechar(common, common->nltype, backtracks, FALSE);
+    }
+  JUMPHERE(jump[0]);
+  return cc;
+
+  case OP_REVERSE:
+  length = GET(cc, 0);
+  if (length == 0)
+    return cc + LINK_SIZE;
+  if (HAS_VIRTUAL_REGISTERS)
+    {
+    OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
+    }
+  else
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin));
+#ifdef SUPPORT_UNICODE
+  if (common->utf)
+    {
+    OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, length);
+    label = LABEL();
+    add_jump(compiler, backtracks, CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0));
+    move_back(common, backtracks, FALSE);
+    OP2(SLJIT_SUB | SLJIT_SET_Z, TMP3, 0, TMP3, 0, SLJIT_IMM, 1);
+    JUMPTO(SLJIT_NOT_ZERO, label);
+    }
+  else
+#endif
+    {
+    OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(length));
+    add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0));
+    }
+  check_start_used_ptr(common);
+  return cc + LINK_SIZE;
+  }
+SLJIT_UNREACHABLE();
+return cc;
+}
+
+#ifdef SUPPORT_UNICODE
+
+#if PCRE2_CODE_UNIT_WIDTH != 32
+
+static PCRE2_SPTR SLJIT_FUNC do_extuni_utf(jit_arguments *args, PCRE2_SPTR cc)
+{
+PCRE2_SPTR start_subject = args->begin;
+PCRE2_SPTR end_subject = args->end;
+int lgb, rgb, ricount;
+PCRE2_SPTR prevcc, endcc, bptr;
+BOOL first = TRUE;
+uint32_t c;
+
+prevcc = cc;
+endcc = NULL;
+do
+  {
+  GETCHARINC(c, cc);
+  rgb = UCD_GRAPHBREAK(c);
+
+  if (first)
+    {
+    lgb = rgb;
+    endcc = cc;
+    first = FALSE;
+    continue;
+    }
+
+  if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0)
+    break;
+
+  /* Not breaking between Regional Indicators is allowed only if there
+  are an even number of preceding RIs. */
+
+  if (lgb == ucp_gbRegionalIndicator && rgb == ucp_gbRegionalIndicator)
+    {
+    ricount = 0;
+    bptr = prevcc;
+
+    /* bptr is pointing to the left-hand character */
+    while (bptr > start_subject)
+      {
+      bptr--;
+      BACKCHAR(bptr);
+      GETCHAR(c, bptr);
+
+      if (UCD_GRAPHBREAK(c) != ucp_gbRegionalIndicator)
+        break;
+
+      ricount++;
+      }
+
+    if ((ricount & 1) != 0) break;  /* Grapheme break required */
+    }
+
+  /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this
+  allows any number of them before a following Extended_Pictographic. */
+
+  if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) ||
+       lgb != ucp_gbExtended_Pictographic)
+    lgb = rgb;
+
+  prevcc = endcc;
+  endcc = cc;
+  }
+while (cc < end_subject);
+
+return endcc;
+}
+
+#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */
+
+static PCRE2_SPTR SLJIT_FUNC do_extuni_utf_invalid(jit_arguments *args, PCRE2_SPTR cc)
+{
+PCRE2_SPTR start_subject = args->begin;
+PCRE2_SPTR end_subject = args->end;
+int lgb, rgb, ricount;
+PCRE2_SPTR prevcc, endcc, bptr;
+BOOL first = TRUE;
+uint32_t c;
+
+prevcc = cc;
+endcc = NULL;
+do
+  {
+  GETCHARINC_INVALID(c, cc, end_subject, break);
+  rgb = UCD_GRAPHBREAK(c);
+
+  if (first)
+    {
+    lgb = rgb;
+    endcc = cc;
+    first = FALSE;
+    continue;
+    }
+
+  if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0)
+    break;
+
+  /* Not breaking between Regional Indicators is allowed only if there
+  are an even number of preceding RIs. */
+
+  if (lgb == ucp_gbRegionalIndicator && rgb == ucp_gbRegionalIndicator)
+    {
+    ricount = 0;
+    bptr = prevcc;
+
+    /* bptr is pointing to the left-hand character */
+    while (bptr > start_subject)
+      {
+      GETCHARBACK_INVALID(c, bptr, start_subject, break);
+
+      if (UCD_GRAPHBREAK(c) != ucp_gbRegionalIndicator)
+        break;
+
+      ricount++;
+      }
+
+    if ((ricount & 1) != 0)
+      break;  /* Grapheme break required */
+    }
+
+  /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this
+  allows any number of them before a following Extended_Pictographic. */
+
+  if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) ||
+       lgb != ucp_gbExtended_Pictographic)
+    lgb = rgb;
+
+  prevcc = endcc;
+  endcc = cc;
+  }
+while (cc < end_subject);
+
+return endcc;
+}
+
+static PCRE2_SPTR SLJIT_FUNC do_extuni_no_utf(jit_arguments *args, PCRE2_SPTR cc)
+{
+PCRE2_SPTR start_subject = args->begin;
+PCRE2_SPTR end_subject = args->end;
+int lgb, rgb, ricount;
+PCRE2_SPTR bptr;
+uint32_t c;
+
+/* Patch by PH */
+/* GETCHARINC(c, cc); */
+c = *cc++;
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+if (c >= 0x110000)
+  return NULL;
+#endif /* PCRE2_CODE_UNIT_WIDTH == 32 */
+lgb = UCD_GRAPHBREAK(c);
+
+while (cc < end_subject)
+  {
+  c = *cc;
+#if PCRE2_CODE_UNIT_WIDTH == 32
+  if (c >= 0x110000)
+    break;
+#endif /* PCRE2_CODE_UNIT_WIDTH == 32 */
+  rgb = UCD_GRAPHBREAK(c);
+
+  if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0)
+    break;
+
+  /* Not breaking between Regional Indicators is allowed only if there
+  are an even number of preceding RIs. */
+
+  if (lgb == ucp_gbRegionalIndicator && rgb == ucp_gbRegionalIndicator)
+    {
+    ricount = 0;
+    bptr = cc - 1;
+
+    /* bptr is pointing to the left-hand character */
+    while (bptr > start_subject)
+      {
+      bptr--;
+      c = *bptr;
+#if PCRE2_CODE_UNIT_WIDTH == 32
+      if (c >= 0x110000)
+        break;
+#endif /* PCRE2_CODE_UNIT_WIDTH == 32 */
+
+      if (UCD_GRAPHBREAK(c) != ucp_gbRegionalIndicator) break;
+
+      ricount++;
+      }
+
+    if ((ricount & 1) != 0)
+      break;  /* Grapheme break required */
+    }
+
+  /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this
+  allows any number of them before a following Extended_Pictographic. */
+
+  if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) ||
+       lgb != ucp_gbExtended_Pictographic)
+    lgb = rgb;
+
+  cc++;
+  }
+
+return cc;
+}
+
+#endif /* SUPPORT_UNICODE */
+
+static PCRE2_SPTR compile_char1_matchingpath(compiler_common *common, PCRE2_UCHAR type, PCRE2_SPTR cc, jump_list **backtracks, BOOL check_str_ptr)
+{
+DEFINE_COMPILER;
+int length;
+unsigned int c, oc, bit;
+compare_context context;
+struct sljit_jump *jump[3];
+jump_list *end_list;
+#ifdef SUPPORT_UNICODE
+PCRE2_UCHAR propdata[5];
+#endif /* SUPPORT_UNICODE */
+
+switch(type)
+  {
+  case OP_NOT_DIGIT:
+  case OP_DIGIT:
+  /* Digits are usually 0-9, so it is worth to optimize them. */
+  if (check_str_ptr)
+    detect_partial_match(common, backtracks);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+  if (common->utf && is_char7_bitset((const sljit_u8*)common->ctypes - cbit_length + cbit_digit, FALSE))
+    read_char7_type(common, backtracks, type == OP_NOT_DIGIT);
+  else
+#endif
+    read_char8_type(common, backtracks, type == OP_NOT_DIGIT);
+    /* Flip the starting bit in the negative case. */
+  OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_digit);
+  add_jump(compiler, backtracks, JUMP(type == OP_DIGIT ? SLJIT_ZERO : SLJIT_NOT_ZERO));
+  return cc;
+
+  case OP_NOT_WHITESPACE:
+  case OP_WHITESPACE:
+  if (check_str_ptr)
+    detect_partial_match(common, backtracks);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+  if (common->utf && is_char7_bitset((const sljit_u8*)common->ctypes - cbit_length + cbit_space, FALSE))
+    read_char7_type(common, backtracks, type == OP_NOT_WHITESPACE);
+  else
+#endif
+    read_char8_type(common, backtracks, type == OP_NOT_WHITESPACE);
+  OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_space);
+  add_jump(compiler, backtracks, JUMP(type == OP_WHITESPACE ? SLJIT_ZERO : SLJIT_NOT_ZERO));
+  return cc;
+
+  case OP_NOT_WORDCHAR:
+  case OP_WORDCHAR:
+  if (check_str_ptr)
+    detect_partial_match(common, backtracks);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+  if (common->utf && is_char7_bitset((const sljit_u8*)common->ctypes - cbit_length + cbit_word, FALSE))
+    read_char7_type(common, backtracks, type == OP_NOT_WORDCHAR);
+  else
+#endif
+    read_char8_type(common, backtracks, type == OP_NOT_WORDCHAR);
+  OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_word);
+  add_jump(compiler, backtracks, JUMP(type == OP_WORDCHAR ? SLJIT_ZERO : SLJIT_NOT_ZERO));
+  return cc;
+
+  case OP_ANY:
+  if (check_str_ptr)
+    detect_partial_match(common, backtracks);
+  read_char(common, common->nlmin, common->nlmax, backtracks, READ_CHAR_UPDATE_STR_PTR);
+  if (common->nltype == NLTYPE_FIXED && common->newline > 255)
+    {
+    jump[0] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff);
+    end_list = NULL;
+    if (common->mode != PCRE2_JIT_PARTIAL_HARD)
+      add_jump(compiler, &end_list, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+    else
+      check_str_end(common, &end_list);
+
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+    add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, common->newline & 0xff));
+    set_jumps(end_list, LABEL());
+    JUMPHERE(jump[0]);
+    }
+  else
+    check_newlinechar(common, common->nltype, backtracks, TRUE);
+  return cc;
+
+  case OP_ALLANY:
+  if (check_str_ptr)
+    detect_partial_match(common, backtracks);
+#ifdef SUPPORT_UNICODE
+  if (common->utf)
+    {
+    if (common->invalid_utf)
+      {
+      read_char(common, 0, READ_CHAR_MAX, backtracks, READ_CHAR_UPDATE_STR_PTR);
+      return cc;
+      }
+
+#if PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+#if PCRE2_CODE_UNIT_WIDTH == 8
+    jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
+    OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+    jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800);
+    OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00);
+    OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+    OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL);
+    OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+    JUMPHERE(jump[0]);
+    return cc;
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16] */
+    }
+#endif /* SUPPORT_UNICODE */
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  return cc;
+
+  case OP_ANYBYTE:
+  if (check_str_ptr)
+    detect_partial_match(common, backtracks);
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  return cc;
+
+#ifdef SUPPORT_UNICODE
+  case OP_NOTPROP:
+  case OP_PROP:
+  propdata[0] = XCL_HASPROP;
+  propdata[1] = type == OP_NOTPROP ? XCL_NOTPROP : XCL_PROP;
+  propdata[2] = cc[0];
+  propdata[3] = cc[1];
+  propdata[4] = XCL_END;
+  if (check_str_ptr)
+    detect_partial_match(common, backtracks);
+  compile_xclass_matchingpath(common, propdata, backtracks);
+  return cc + 2;
+#endif
+
+  case OP_ANYNL:
+  if (check_str_ptr)
+    detect_partial_match(common, backtracks);
+  read_char(common, common->bsr_nlmin, common->bsr_nlmax, NULL, 0);
+  jump[0] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
+  /* We don't need to handle soft partial matching case. */
+  end_list = NULL;
+  if (common->mode != PCRE2_JIT_PARTIAL_HARD)
+    add_jump(compiler, &end_list, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+  else
+    check_str_end(common, &end_list);
+  OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+  jump[1] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL);
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  jump[2] = JUMP(SLJIT_JUMP);
+  JUMPHERE(jump[0]);
+  check_newlinechar(common, common->bsr_nltype, backtracks, FALSE);
+  set_jumps(end_list, LABEL());
+  JUMPHERE(jump[1]);
+  JUMPHERE(jump[2]);
+  return cc;
+
+  case OP_NOT_HSPACE:
+  case OP_HSPACE:
+  if (check_str_ptr)
+    detect_partial_match(common, backtracks);
+
+  if (type == OP_NOT_HSPACE)
+    read_char(common, 0x9, 0x3000, backtracks, READ_CHAR_UPDATE_STR_PTR);
+  else
+    read_char(common, 0x9, 0x3000, NULL, 0);
+
+  add_jump(compiler, &common->hspace, JUMP(SLJIT_FAST_CALL));
+  sljit_set_current_flags(compiler, SLJIT_SET_Z);
+  add_jump(compiler, backtracks, JUMP(type == OP_NOT_HSPACE ? SLJIT_NOT_ZERO : SLJIT_ZERO));
+  return cc;
+
+  case OP_NOT_VSPACE:
+  case OP_VSPACE:
+  if (check_str_ptr)
+    detect_partial_match(common, backtracks);
+
+  if (type == OP_NOT_VSPACE)
+    read_char(common, 0xa, 0x2029, backtracks, READ_CHAR_UPDATE_STR_PTR);
+  else
+    read_char(common, 0xa, 0x2029, NULL, 0);
+
+  add_jump(compiler, &common->vspace, JUMP(SLJIT_FAST_CALL));
+  sljit_set_current_flags(compiler, SLJIT_SET_Z);
+  add_jump(compiler, backtracks, JUMP(type == OP_NOT_VSPACE ? SLJIT_NOT_ZERO : SLJIT_ZERO));
+  return cc;
+
+#ifdef SUPPORT_UNICODE
+  case OP_EXTUNI:
+  if (check_str_ptr)
+    detect_partial_match(common, backtracks);
+
+  SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1);
+  OP1(SLJIT_MOV, SLJIT_R0, 0, ARGUMENTS, 0);
+
+#if PCRE2_CODE_UNIT_WIDTH != 32
+  sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM,
+    common->utf ? (common->invalid_utf ? SLJIT_FUNC_OFFSET(do_extuni_utf_invalid) : SLJIT_FUNC_OFFSET(do_extuni_utf)) : SLJIT_FUNC_OFFSET(do_extuni_no_utf));
+  if (common->invalid_utf)
+    add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0));
+#else
+  sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM,
+    common->invalid_utf ? SLJIT_FUNC_OFFSET(do_extuni_utf_invalid) : SLJIT_FUNC_OFFSET(do_extuni_no_utf));
+  if (!common->utf || common->invalid_utf)
+    add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0));
+#endif
+
+  OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0);
+
+  if (common->mode == PCRE2_JIT_PARTIAL_HARD)
+    {
+    jump[0] = CMP(SLJIT_LESS, SLJIT_RETURN_REG, 0, STR_END, 0);
+    /* Since we successfully read a char above, partial matching must occure. */
+    check_partial(common, TRUE);
+    JUMPHERE(jump[0]);
+    }
+  return cc;
+#endif
+
+  case OP_CHAR:
+  case OP_CHARI:
+  length = 1;
+#ifdef SUPPORT_UNICODE
+  if (common->utf && HAS_EXTRALEN(*cc)) length += GET_EXTRALEN(*cc);
+#endif
+
+  if (check_str_ptr && common->mode != PCRE2_JIT_COMPLETE)
+    detect_partial_match(common, backtracks);
+
+  if (type == OP_CHAR || !char_has_othercase(common, cc) || char_get_othercase_bit(common, cc) != 0)
+    {
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(length));
+    if (length > 1 || (check_str_ptr && common->mode == PCRE2_JIT_COMPLETE))
+      add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0));
+
+    context.length = IN_UCHARS(length);
+    context.sourcereg = -1;
+#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
+    context.ucharptr = 0;
+#endif
+    return byte_sequence_compare(common, type == OP_CHARI, cc, &context, backtracks);
+    }
+
+#ifdef SUPPORT_UNICODE
+  if (common->utf)
+    {
+    GETCHAR(c, cc);
+    }
+  else
+#endif
+    c = *cc;
+
+  SLJIT_ASSERT(type == OP_CHARI && char_has_othercase(common, cc));
+
+  if (check_str_ptr && common->mode == PCRE2_JIT_COMPLETE)
+    add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+  oc = char_othercase(common, c);
+  read_char(common, c < oc ? c : oc, c > oc ? c : oc, NULL, 0);
+
+  SLJIT_ASSERT(!is_powerof2(c ^ oc));
+
+  if (sljit_has_cpu_feature(SLJIT_HAS_CMOV))
+    {
+    OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, oc);
+    CMOV(SLJIT_EQUAL, TMP1, SLJIT_IMM, c);
+    add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, c));
+    }
+  else
+    {
+    jump[0] = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c);
+    add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, oc));
+    JUMPHERE(jump[0]);
+    }
+  return cc + length;
+
+  case OP_NOT:
+  case OP_NOTI:
+  if (check_str_ptr)
+    detect_partial_match(common, backtracks);
+
+  length = 1;
+#ifdef SUPPORT_UNICODE
+  if (common->utf)
+    {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+    c = *cc;
+    if (c < 128 && !common->invalid_utf)
+      {
+      OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+      if (type == OP_NOT || !char_has_othercase(common, cc))
+        add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c));
+      else
+        {
+        /* Since UTF8 code page is fixed, we know that c is in [a-z] or [A-Z] range. */
+        OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x20);
+        add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, c | 0x20));
+        }
+      /* Skip the variable-length character. */
+      OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+      jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
+      OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+      OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+      JUMPHERE(jump[0]);
+      return cc + 1;
+      }
+    else
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+      {
+      GETCHARLEN(c, cc, length);
+      }
+    }
+  else
+#endif /* SUPPORT_UNICODE */
+    c = *cc;
+
+  if (type == OP_NOT || !char_has_othercase(common, cc))
+    {
+    read_char(common, c, c, backtracks, READ_CHAR_UPDATE_STR_PTR);
+    add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c));
+    }
+  else
+    {
+    oc = char_othercase(common, c);
+    read_char(common, c < oc ? c : oc, c > oc ? c : oc, backtracks, READ_CHAR_UPDATE_STR_PTR);
+    bit = c ^ oc;
+    if (is_powerof2(bit))
+      {
+      OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, bit);
+      add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c | bit));
+      }
+    else
+      {
+      add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c));
+      add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, oc));
+      }
+    }
+  return cc + length;
+
+  case OP_CLASS:
+  case OP_NCLASS:
+  if (check_str_ptr)
+    detect_partial_match(common, backtracks);
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+  bit = (common->utf && is_char7_bitset((const sljit_u8 *)cc, type == OP_NCLASS)) ? 127 : 255;
+  if (type == OP_NCLASS)
+    read_char(common, 0, bit, backtracks, READ_CHAR_UPDATE_STR_PTR);
+  else
+    read_char(common, 0, bit, NULL, 0);
+#else
+  if (type == OP_NCLASS)
+    read_char(common, 0, 255, backtracks, READ_CHAR_UPDATE_STR_PTR);
+  else
+    read_char(common, 0, 255, NULL, 0);
+#endif
+
+  if (optimize_class(common, (const sljit_u8 *)cc, type == OP_NCLASS, FALSE, backtracks))
+    return cc + 32 / sizeof(PCRE2_UCHAR);
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+  jump[0] = NULL;
+  if (common->utf)
+    {
+    jump[0] = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, bit);
+    if (type == OP_CLASS)
+      {
+      add_jump(compiler, backtracks, jump[0]);
+      jump[0] = NULL;
+      }
+    }
+#elif PCRE2_CODE_UNIT_WIDTH != 8
+  jump[0] = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
+  if (type == OP_CLASS)
+    {
+    add_jump(compiler, backtracks, jump[0]);
+    jump[0] = NULL;
+    }
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 */
+
+  OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7);
+  OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3);
+  OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc);
+  OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0);
+  OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
+  add_jump(compiler, backtracks, JUMP(SLJIT_ZERO));
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+  if (jump[0] != NULL)
+    JUMPHERE(jump[0]);
+#endif
+  return cc + 32 / sizeof(PCRE2_UCHAR);
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+  case OP_XCLASS:
+  if (check_str_ptr)
+    detect_partial_match(common, backtracks);
+  compile_xclass_matchingpath(common, cc + LINK_SIZE, backtracks);
+  return cc + GET(cc, 0) - 1;
+#endif
+  }
+SLJIT_UNREACHABLE();
+return cc;
+}
+
+static SLJIT_INLINE PCRE2_SPTR compile_charn_matchingpath(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, jump_list **backtracks)
+{
+/* This function consumes at least one input character. */
+/* To decrease the number of length checks, we try to concatenate the fixed length character sequences. */
+DEFINE_COMPILER;
+PCRE2_SPTR ccbegin = cc;
+compare_context context;
+int size;
+
+context.length = 0;
+do
+  {
+  if (cc >= ccend)
+    break;
+
+  if (*cc == OP_CHAR)
+    {
+    size = 1;
+#ifdef SUPPORT_UNICODE
+    if (common->utf && HAS_EXTRALEN(cc[1]))
+      size += GET_EXTRALEN(cc[1]);
+#endif
+    }
+  else if (*cc == OP_CHARI)
+    {
+    size = 1;
+#ifdef SUPPORT_UNICODE
+    if (common->utf)
+      {
+      if (char_has_othercase(common, cc + 1) && char_get_othercase_bit(common, cc + 1) == 0)
+        size = 0;
+      else if (HAS_EXTRALEN(cc[1]))
+        size += GET_EXTRALEN(cc[1]);
+      }
+    else
+#endif
+    if (char_has_othercase(common, cc + 1) && char_get_othercase_bit(common, cc + 1) == 0)
+      size = 0;
+    }
+  else
+    size = 0;
+
+  cc += 1 + size;
+  context.length += IN_UCHARS(size);
+  }
+while (size > 0 && context.length <= 128);
+
+cc = ccbegin;
+if (context.length > 0)
+  {
+  /* We have a fixed-length byte sequence. */
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, context.length);
+  add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0));
+
+  context.sourcereg = -1;
+#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
+  context.ucharptr = 0;
+#endif
+  do cc = byte_sequence_compare(common, *cc == OP_CHARI, cc + 1, &context, backtracks); while (context.length > 0);
+  return cc;
+  }
+
+/* A non-fixed length character will be checked if length == 0. */
+return compile_char1_matchingpath(common, *cc, cc + 1, backtracks, TRUE);
+}
+
+/* Forward definitions. */
+static void compile_matchingpath(compiler_common *, PCRE2_SPTR, PCRE2_SPTR, backtrack_common *);
+static void compile_backtrackingpath(compiler_common *, struct backtrack_common *);
+
+#define PUSH_BACKTRACK(size, ccstart, error) \
+  do \
+    { \
+    backtrack = sljit_alloc_memory(compiler, (size)); \
+    if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) \
+      return error; \
+    memset(backtrack, 0, size); \
+    backtrack->prev = parent->top; \
+    backtrack->cc = (ccstart); \
+    parent->top = backtrack; \
+    } \
+  while (0)
+
+#define PUSH_BACKTRACK_NOVALUE(size, ccstart) \
+  do \
+    { \
+    backtrack = sljit_alloc_memory(compiler, (size)); \
+    if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) \
+      return; \
+    memset(backtrack, 0, size); \
+    backtrack->prev = parent->top; \
+    backtrack->cc = (ccstart); \
+    parent->top = backtrack; \
+    } \
+  while (0)
+
+#define BACKTRACK_AS(type) ((type *)backtrack)
+
+static void compile_dnref_search(compiler_common *common, PCRE2_SPTR cc, jump_list **backtracks)
+{
+/* The OVECTOR offset goes to TMP2. */
+DEFINE_COMPILER;
+int count = GET2(cc, 1 + IMM2_SIZE);
+PCRE2_SPTR slot = common->name_table + GET2(cc, 1) * common->name_entry_size;
+unsigned int offset;
+jump_list *found = NULL;
+
+SLJIT_ASSERT(*cc == OP_DNREF || *cc == OP_DNREFI);
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1));
+
+count--;
+while (count-- > 0)
+  {
+  offset = GET2(slot, 0) << 1;
+  GET_LOCAL_BASE(TMP2, 0, OVECTOR(offset));
+  add_jump(compiler, &found, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0));
+  slot += common->name_entry_size;
+  }
+
+offset = GET2(slot, 0) << 1;
+GET_LOCAL_BASE(TMP2, 0, OVECTOR(offset));
+if (backtracks != NULL && !common->unset_backref)
+  add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0));
+
+set_jumps(found, LABEL());
+}
+
+static void compile_ref_matchingpath(compiler_common *common, PCRE2_SPTR cc, jump_list **backtracks, BOOL withchecks, BOOL emptyfail)
+{
+DEFINE_COMPILER;
+BOOL ref = (*cc == OP_REF || *cc == OP_REFI);
+int offset = 0;
+struct sljit_jump *jump = NULL;
+struct sljit_jump *partial;
+struct sljit_jump *nopartial;
+#if defined SUPPORT_UNICODE
+struct sljit_label *loop;
+struct sljit_label *caseless_loop;
+jump_list *no_match = NULL;
+int source_reg = COUNT_MATCH;
+int source_end_reg = ARGUMENTS;
+int char1_reg = STACK_LIMIT;
+#endif /* SUPPORT_UNICODE */
+
+if (ref)
+  {
+  offset = GET2(cc, 1) << 1;
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
+  /* OVECTOR(1) contains the "string begin - 1" constant. */
+  if (withchecks && !common->unset_backref)
+    add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)));
+  }
+else
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0);
+
+#if defined SUPPORT_UNICODE
+if (common->utf && *cc == OP_REFI)
+  {
+  SLJIT_ASSERT(common->iref_ptr != 0);
+
+  if (ref)
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
+  else
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
+
+  if (withchecks && emptyfail)
+    add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, TMP2, 0));
+
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->iref_ptr, source_reg, 0);
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->iref_ptr + sizeof(sljit_sw), source_end_reg, 0);
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->iref_ptr + sizeof(sljit_sw) * 2, char1_reg, 0);
+
+  OP1(SLJIT_MOV, source_reg, 0, TMP1, 0);
+  OP1(SLJIT_MOV, source_end_reg, 0, TMP2, 0);
+
+  loop = LABEL();
+  jump = CMP(SLJIT_GREATER_EQUAL, source_reg, 0, source_end_reg, 0);
+  partial = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+
+  /* Read original character. It must be a valid UTF character. */
+  OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0);
+  OP1(SLJIT_MOV, STR_PTR, 0, source_reg, 0);
+
+  read_char(common, 0, READ_CHAR_MAX, NULL, READ_CHAR_UPDATE_STR_PTR | READ_CHAR_VALID_UTF);
+
+  OP1(SLJIT_MOV, source_reg, 0, STR_PTR, 0);
+  OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0);
+  OP1(SLJIT_MOV, char1_reg, 0, TMP1, 0);
+
+  /* Read second character. */
+  read_char(common, 0, READ_CHAR_MAX, &no_match, READ_CHAR_UPDATE_STR_PTR);
+
+  CMPTO(SLJIT_EQUAL, TMP1, 0, char1_reg, 0, loop);
+
+  OP1(SLJIT_MOV, TMP3, 0, TMP1, 0);
+
+  add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL));
+
+  OP2(SLJIT_SHL, TMP1, 0, TMP2, 0, SLJIT_IMM, 2);
+  OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 3);
+  OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0);
+
+  OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records));
+
+  OP1(SLJIT_MOV_S32, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(ucd_record, other_case));
+  OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(ucd_record, caseset));
+  OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP3, 0);
+  CMPTO(SLJIT_EQUAL, TMP1, 0, char1_reg, 0, loop);
+
+  add_jump(compiler, &no_match, CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+  OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 2);
+  OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_caseless_sets));
+
+  caseless_loop = LABEL();
+  OP1(SLJIT_MOV_U32, TMP1, 0, SLJIT_MEM1(TMP2), 0);
+  OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, sizeof(uint32_t));
+  OP2(SLJIT_SUB | SLJIT_SET_Z | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP1, 0, char1_reg, 0);
+  JUMPTO(SLJIT_EQUAL, loop);
+  JUMPTO(SLJIT_LESS, caseless_loop);
+
+  set_jumps(no_match, LABEL());
+  if (common->mode == PCRE2_JIT_COMPLETE)
+    JUMPHERE(partial);
+
+  OP1(SLJIT_MOV, source_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr);
+  OP1(SLJIT_MOV, source_end_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr + sizeof(sljit_sw));
+  OP1(SLJIT_MOV, char1_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr + sizeof(sljit_sw) * 2);
+  add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+
+  if (common->mode != PCRE2_JIT_COMPLETE)
+    {
+    JUMPHERE(partial);
+    OP1(SLJIT_MOV, source_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr);
+    OP1(SLJIT_MOV, source_end_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr + sizeof(sljit_sw));
+    OP1(SLJIT_MOV, char1_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr + sizeof(sljit_sw) * 2);
+
+    check_partial(common, FALSE);
+    add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+    }
+
+  JUMPHERE(jump);
+  OP1(SLJIT_MOV, source_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr);
+  OP1(SLJIT_MOV, source_end_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr + sizeof(sljit_sw));
+  OP1(SLJIT_MOV, char1_reg, 0, SLJIT_MEM1(SLJIT_SP), common->iref_ptr + sizeof(sljit_sw) * 2);
+  return;
+  }
+else
+#endif /* SUPPORT_UNICODE */
+  {
+  if (ref)
+    OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP1, 0);
+  else
+    OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP1, 0);
+
+  if (withchecks)
+    jump = JUMP(SLJIT_ZERO);
+
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+  partial = CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0);
+  if (common->mode == PCRE2_JIT_COMPLETE)
+    add_jump(compiler, backtracks, partial);
+
+  add_jump(compiler, *cc == OP_REF ? &common->casefulcmp : &common->caselesscmp, JUMP(SLJIT_FAST_CALL));
+  add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+
+  if (common->mode != PCRE2_JIT_COMPLETE)
+    {
+    nopartial = JUMP(SLJIT_JUMP);
+    JUMPHERE(partial);
+    /* TMP2 -= STR_END - STR_PTR */
+    OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, STR_PTR, 0);
+    OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, STR_END, 0);
+    partial = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0);
+    OP1(SLJIT_MOV, STR_PTR, 0, STR_END, 0);
+    add_jump(compiler, *cc == OP_REF ? &common->casefulcmp : &common->caselesscmp, JUMP(SLJIT_FAST_CALL));
+    add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+    JUMPHERE(partial);
+    check_partial(common, FALSE);
+    add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+    JUMPHERE(nopartial);
+    }
+  }
+
+if (jump != NULL)
+  {
+  if (emptyfail)
+    add_jump(compiler, backtracks, jump);
+  else
+    JUMPHERE(jump);
+  }
+}
+
+static SLJIT_INLINE PCRE2_SPTR compile_ref_iterator_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+BOOL ref = (*cc == OP_REF || *cc == OP_REFI);
+backtrack_common *backtrack;
+PCRE2_UCHAR type;
+int offset = 0;
+struct sljit_label *label;
+struct sljit_jump *zerolength;
+struct sljit_jump *jump = NULL;
+PCRE2_SPTR ccbegin = cc;
+int min = 0, max = 0;
+BOOL minimize;
+
+PUSH_BACKTRACK(sizeof(ref_iterator_backtrack), cc, NULL);
+
+if (ref)
+  offset = GET2(cc, 1) << 1;
+else
+  cc += IMM2_SIZE;
+type = cc[1 + IMM2_SIZE];
+
+SLJIT_COMPILE_ASSERT((OP_CRSTAR & 0x1) == 0, crstar_opcode_must_be_even);
+minimize = (type & 0x1) != 0;
+switch(type)
+  {
+  case OP_CRSTAR:
+  case OP_CRMINSTAR:
+  min = 0;
+  max = 0;
+  cc += 1 + IMM2_SIZE + 1;
+  break;
+  case OP_CRPLUS:
+  case OP_CRMINPLUS:
+  min = 1;
+  max = 0;
+  cc += 1 + IMM2_SIZE + 1;
+  break;
+  case OP_CRQUERY:
+  case OP_CRMINQUERY:
+  min = 0;
+  max = 1;
+  cc += 1 + IMM2_SIZE + 1;
+  break;
+  case OP_CRRANGE:
+  case OP_CRMINRANGE:
+  min = GET2(cc, 1 + IMM2_SIZE + 1);
+  max = GET2(cc, 1 + IMM2_SIZE + 1 + IMM2_SIZE);
+  cc += 1 + IMM2_SIZE + 1 + 2 * IMM2_SIZE;
+  break;
+  default:
+  SLJIT_UNREACHABLE();
+  break;
+  }
+
+if (!minimize)
+  {
+  if (min == 0)
+    {
+    allocate_stack(common, 2);
+    if (ref)
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0);
+    /* Temporary release of STR_PTR. */
+    OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+    /* Handles both invalid and empty cases. Since the minimum repeat,
+    is zero the invalid case is basically the same as an empty case. */
+    if (ref)
+      zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
+    else
+      {
+      compile_dnref_search(common, ccbegin, NULL);
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0);
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, TMP2, 0);
+      zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
+      }
+    /* Restore if not zero length. */
+    OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+    }
+  else
+    {
+    allocate_stack(common, 1);
+    if (ref)
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+    if (ref)
+      {
+      add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)));
+      zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
+      }
+    else
+      {
+      compile_dnref_search(common, ccbegin, &backtrack->topbacktracks);
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0);
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, TMP2, 0);
+      zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
+      }
+    }
+
+  if (min > 1 || max > 1)
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, SLJIT_IMM, 0);
+
+  label = LABEL();
+  if (!ref)
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1);
+  compile_ref_matchingpath(common, ccbegin, &backtrack->topbacktracks, FALSE, FALSE);
+
+  if (min > 1 || max > 1)
+    {
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0);
+    OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, TMP1, 0);
+    if (min > 1)
+      CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, min, label);
+    if (max > 1)
+      {
+      jump = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, max);
+      allocate_stack(common, 1);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+      JUMPTO(SLJIT_JUMP, label);
+      JUMPHERE(jump);
+      }
+    }
+
+  if (max == 0)
+    {
+    /* Includes min > 1 case as well. */
+    allocate_stack(common, 1);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+    JUMPTO(SLJIT_JUMP, label);
+    }
+
+  JUMPHERE(zerolength);
+  BACKTRACK_AS(ref_iterator_backtrack)->matchingpath = LABEL();
+
+  count_match(common);
+  return cc;
+  }
+
+allocate_stack(common, ref ? 2 : 3);
+if (ref)
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+if (type != OP_CRMINSTAR)
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0);
+
+if (min == 0)
+  {
+  /* Handles both invalid and empty cases. Since the minimum repeat,
+  is zero the invalid case is basically the same as an empty case. */
+  if (ref)
+    zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
+  else
+    {
+    compile_dnref_search(common, ccbegin, NULL);
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP2, 0);
+    zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
+    }
+  /* Length is non-zero, we can match real repeats. */
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+  jump = JUMP(SLJIT_JUMP);
+  }
+else
+  {
+  if (ref)
+    {
+    add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)));
+    zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
+    }
+  else
+    {
+    compile_dnref_search(common, ccbegin, &backtrack->topbacktracks);
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP2, 0);
+    zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
+    }
+  }
+
+BACKTRACK_AS(ref_iterator_backtrack)->matchingpath = LABEL();
+if (max > 0)
+  add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, max));
+
+if (!ref)
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(2));
+compile_ref_matchingpath(common, ccbegin, &backtrack->topbacktracks, TRUE, TRUE);
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+
+if (min > 1)
+  {
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+  OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
+  CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, min, BACKTRACK_AS(ref_iterator_backtrack)->matchingpath);
+  }
+else if (max > 0)
+  OP2(SLJIT_ADD, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 1);
+
+if (jump != NULL)
+  JUMPHERE(jump);
+JUMPHERE(zerolength);
+
+count_match(common);
+return cc;
+}
+
+static SLJIT_INLINE PCRE2_SPTR compile_recurse_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+recurse_entry *entry = common->entries;
+recurse_entry *prev = NULL;
+sljit_sw start = GET(cc, 1);
+PCRE2_SPTR start_cc;
+BOOL needs_control_head;
+
+PUSH_BACKTRACK(sizeof(recurse_backtrack), cc, NULL);
+
+/* Inlining simple patterns. */
+if (get_framesize(common, common->start + start, NULL, TRUE, &needs_control_head) == no_stack)
+  {
+  start_cc = common->start + start;
+  compile_matchingpath(common, next_opcode(common, start_cc), bracketend(start_cc) - (1 + LINK_SIZE), backtrack);
+  BACKTRACK_AS(recurse_backtrack)->inlined_pattern = TRUE;
+  return cc + 1 + LINK_SIZE;
+  }
+
+while (entry != NULL)
+  {
+  if (entry->start == start)
+    break;
+  prev = entry;
+  entry = entry->next;
+  }
+
+if (entry == NULL)
+  {
+  entry = sljit_alloc_memory(compiler, sizeof(recurse_entry));
+  if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+    return NULL;
+  entry->next = NULL;
+  entry->entry_label = NULL;
+  entry->backtrack_label = NULL;
+  entry->entry_calls = NULL;
+  entry->backtrack_calls = NULL;
+  entry->start = start;
+
+  if (prev != NULL)
+    prev->next = entry;
+  else
+    common->entries = entry;
+  }
+
+BACKTRACK_AS(recurse_backtrack)->entry = entry;
+
+if (entry->entry_label == NULL)
+  add_jump(compiler, &entry->entry_calls, JUMP(SLJIT_FAST_CALL));
+else
+  JUMPTO(SLJIT_FAST_CALL, entry->entry_label);
+/* Leave if the match is failed. */
+add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0));
+BACKTRACK_AS(recurse_backtrack)->matchingpath = LABEL();
+return cc + 1 + LINK_SIZE;
+}
+
+static sljit_s32 SLJIT_FUNC do_callout(struct jit_arguments *arguments, pcre2_callout_block *callout_block, PCRE2_SPTR *jit_ovector)
+{
+PCRE2_SPTR begin;
+PCRE2_SIZE *ovector;
+sljit_u32 oveccount, capture_top;
+
+if (arguments->callout == NULL)
+  return 0;
+
+SLJIT_COMPILE_ASSERT(sizeof (PCRE2_SIZE) <= sizeof (sljit_sw), pcre2_size_must_be_lower_than_sljit_sw_size);
+
+begin = arguments->begin;
+ovector = (PCRE2_SIZE*)(callout_block + 1);
+oveccount = callout_block->capture_top;
+
+SLJIT_ASSERT(oveccount >= 1);
+
+callout_block->version = 2;
+callout_block->callout_flags = 0;
+
+/* Offsets in subject. */
+callout_block->subject_length = arguments->end - arguments->begin;
+callout_block->start_match = jit_ovector[0] - begin;
+callout_block->current_position = (PCRE2_SPTR)callout_block->offset_vector - begin;
+callout_block->subject = begin;
+
+/* Convert and copy the JIT offset vector to the ovector array. */
+callout_block->capture_top = 1;
+callout_block->offset_vector = ovector;
+
+ovector[0] = PCRE2_UNSET;
+ovector[1] = PCRE2_UNSET;
+ovector += 2;
+jit_ovector += 2;
+capture_top = 1;
+
+/* Convert pointers to sizes. */
+while (--oveccount != 0)
+  {
+  capture_top++;
+
+  ovector[0] = (PCRE2_SIZE)(jit_ovector[0] - begin);
+  ovector[1] = (PCRE2_SIZE)(jit_ovector[1] - begin);
+
+  if (ovector[0] != PCRE2_UNSET)
+    callout_block->capture_top = capture_top;
+
+  ovector += 2;
+  jit_ovector += 2;
+  }
+
+return (arguments->callout)(callout_block, arguments->callout_data);
+}
+
+#define CALLOUT_ARG_OFFSET(arg) \
+    SLJIT_OFFSETOF(pcre2_callout_block, arg)
+
+static SLJIT_INLINE PCRE2_SPTR compile_callout_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+sljit_s32 mov_opcode;
+unsigned int callout_length = (*cc == OP_CALLOUT)
+    ? PRIV(OP_lengths)[OP_CALLOUT] : GET(cc, 1 + 2 * LINK_SIZE);
+sljit_sw value1;
+sljit_sw value2;
+sljit_sw value3;
+sljit_uw callout_arg_size = (common->re->top_bracket + 1) * 2 * sizeof(sljit_sw);
+
+PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL);
+
+callout_arg_size = (sizeof(pcre2_callout_block) + callout_arg_size + sizeof(sljit_sw) - 1) / sizeof(sljit_sw);
+
+allocate_stack(common, callout_arg_size);
+
+SLJIT_ASSERT(common->capture_last_ptr != 0);
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr);
+OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+value1 = (*cc == OP_CALLOUT) ? cc[1 + 2 * LINK_SIZE] : 0;
+OP1(SLJIT_MOV_U32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_number), SLJIT_IMM, value1);
+OP1(SLJIT_MOV_U32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(capture_last), TMP2, 0);
+OP1(SLJIT_MOV_U32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(capture_top), SLJIT_IMM, common->re->top_bracket + 1);
+
+/* These pointer sized fields temporarly stores internal variables. */
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(offset_vector), STR_PTR, 0);
+
+if (common->mark_ptr != 0)
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, mark_ptr));
+mov_opcode = (sizeof(PCRE2_SIZE) == 4) ? SLJIT_MOV_U32 : SLJIT_MOV;
+OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(pattern_position), SLJIT_IMM, GET(cc, 1));
+OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(next_item_length), SLJIT_IMM, GET(cc, 1 + LINK_SIZE));
+
+if (*cc == OP_CALLOUT)
+  {
+  value1 = 0;
+  value2 = 0;
+  value3 = 0;
+  }
+else
+  {
+  value1 = (sljit_sw) (cc + (1 + 4*LINK_SIZE) + 1);
+  value2 = (callout_length - (1 + 4*LINK_SIZE + 2));
+  value3 = (sljit_sw) (GET(cc, 1 + 3*LINK_SIZE));
+  }
+
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_string), SLJIT_IMM, value1);
+OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_string_length), SLJIT_IMM, value2);
+OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_string_offset), SLJIT_IMM, value3);
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(mark), (common->mark_ptr != 0) ? TMP2 : SLJIT_IMM, 0);
+
+SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1);
+
+/* Needed to save important temporary registers. */
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STR_PTR, 0);
+/* SLJIT_R0 = arguments */
+OP1(SLJIT_MOV, SLJIT_R1, 0, STACK_TOP, 0);
+GET_LOCAL_BASE(SLJIT_R2, 0, OVECTOR_START);
+sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(S32) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW) | SLJIT_ARG3(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(do_callout));
+OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+free_stack(common, callout_arg_size);
+
+/* Check return value. */
+OP2(SLJIT_SUB32 | SLJIT_SET_Z | SLJIT_SET_SIG_GREATER, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
+add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_SIG_GREATER32));
+if (common->abort_label == NULL)
+  add_jump(compiler, &common->abort, JUMP(SLJIT_NOT_EQUAL32) /* SIG_LESS */);
+else
+  JUMPTO(SLJIT_NOT_EQUAL32 /* SIG_LESS */, common->abort_label);
+return cc + callout_length;
+}
+
+#undef CALLOUT_ARG_SIZE
+#undef CALLOUT_ARG_OFFSET
+
+static SLJIT_INLINE BOOL assert_needs_str_ptr_saving(PCRE2_SPTR cc)
+{
+while (TRUE)
+  {
+  switch (*cc)
+    {
+    case OP_CALLOUT_STR:
+    cc += GET(cc, 1 + 2*LINK_SIZE);
+    break;
+
+    case OP_NOT_WORD_BOUNDARY:
+    case OP_WORD_BOUNDARY:
+    case OP_CIRC:
+    case OP_CIRCM:
+    case OP_DOLL:
+    case OP_DOLLM:
+    case OP_CALLOUT:
+    case OP_ALT:
+    cc += PRIV(OP_lengths)[*cc];
+    break;
+
+    case OP_KET:
+    return FALSE;
+
+    default:
+    return TRUE;
+    }
+  }
+}
+
+static PCRE2_SPTR compile_assert_matchingpath(compiler_common *common, PCRE2_SPTR cc, assert_backtrack *backtrack, BOOL conditional)
+{
+DEFINE_COMPILER;
+int framesize;
+int extrasize;
+BOOL local_quit_available = FALSE;
+BOOL needs_control_head;
+int private_data_ptr;
+backtrack_common altbacktrack;
+PCRE2_SPTR ccbegin;
+PCRE2_UCHAR opcode;
+PCRE2_UCHAR bra = OP_BRA;
+jump_list *tmp = NULL;
+jump_list **target = (conditional) ? &backtrack->condfailed : &backtrack->common.topbacktracks;
+jump_list **found;
+/* Saving previous accept variables. */
+BOOL save_local_quit_available = common->local_quit_available;
+BOOL save_in_positive_assertion = common->in_positive_assertion;
+then_trap_backtrack *save_then_trap = common->then_trap;
+struct sljit_label *save_quit_label = common->quit_label;
+struct sljit_label *save_accept_label = common->accept_label;
+jump_list *save_quit = common->quit;
+jump_list *save_positive_assertion_quit = common->positive_assertion_quit;
+jump_list *save_accept = common->accept;
+struct sljit_jump *jump;
+struct sljit_jump *brajump = NULL;
+
+/* Assert captures then. */
+common->then_trap = NULL;
+
+if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO)
+  {
+  SLJIT_ASSERT(!conditional);
+  bra = *cc;
+  cc++;
+  }
+private_data_ptr = PRIVATE_DATA(cc);
+SLJIT_ASSERT(private_data_ptr != 0);
+framesize = get_framesize(common, cc, NULL, FALSE, &needs_control_head);
+backtrack->framesize = framesize;
+backtrack->private_data_ptr = private_data_ptr;
+opcode = *cc;
+SLJIT_ASSERT(opcode >= OP_ASSERT && opcode <= OP_ASSERTBACK_NOT);
+found = (opcode == OP_ASSERT || opcode == OP_ASSERTBACK) ? &tmp : target;
+ccbegin = cc;
+cc += GET(cc, 1);
+
+if (bra == OP_BRAMINZERO)
+  {
+  /* This is a braminzero backtrack path. */
+  OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+  free_stack(common, 1);
+  brajump = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
+  }
+
+if (framesize < 0)
+  {
+  extrasize = 1;
+  if (bra == OP_BRA && !assert_needs_str_ptr_saving(ccbegin + 1 + LINK_SIZE))
+    extrasize = 0;
+
+  if (needs_control_head)
+    extrasize++;
+
+  if (framesize == no_frame)
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0);
+
+  if (extrasize > 0)
+    allocate_stack(common, extrasize);
+
+  if (needs_control_head)
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+
+  if (extrasize > 0)
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+
+  if (needs_control_head)
+    {
+    SLJIT_ASSERT(extrasize == 2);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
+    }
+  }
+else
+  {
+  extrasize = needs_control_head ? 3 : 2;
+  allocate_stack(common, framesize + extrasize);
+
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+  OP2(SLJIT_ADD, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + extrasize) * sizeof(sljit_sw));
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0);
+  if (needs_control_head)
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+
+  if (needs_control_head)
+    {
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0);
+    }
+  else
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
+
+  init_frame(common, ccbegin, NULL, framesize + extrasize - 1, extrasize);
+  }
+
+memset(&altbacktrack, 0, sizeof(backtrack_common));
+if (conditional || (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT))
+  {
+  /* Control verbs cannot escape from these asserts. */
+  local_quit_available = TRUE;
+  common->local_quit_available = TRUE;
+  common->quit_label = NULL;
+  common->quit = NULL;
+  }
+
+common->in_positive_assertion = (opcode == OP_ASSERT || opcode == OP_ASSERTBACK);
+common->positive_assertion_quit = NULL;
+
+while (1)
+  {
+  common->accept_label = NULL;
+  common->accept = NULL;
+  altbacktrack.top = NULL;
+  altbacktrack.topbacktracks = NULL;
+
+  if (*ccbegin == OP_ALT && extrasize > 0)
+    OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+
+  altbacktrack.cc = ccbegin;
+  compile_matchingpath(common, ccbegin + 1 + LINK_SIZE, cc, &altbacktrack);
+  if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+    {
+    if (local_quit_available)
+      {
+      common->local_quit_available = save_local_quit_available;
+      common->quit_label = save_quit_label;
+      common->quit = save_quit;
+      }
+    common->in_positive_assertion = save_in_positive_assertion;
+    common->then_trap = save_then_trap;
+    common->accept_label = save_accept_label;
+    common->positive_assertion_quit = save_positive_assertion_quit;
+    common->accept = save_accept;
+    return NULL;
+    }
+  common->accept_label = LABEL();
+  if (common->accept != NULL)
+    set_jumps(common->accept, common->accept_label);
+
+  /* Reset stack. */
+  if (framesize < 0)
+    {
+    if (framesize == no_frame)
+      OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+    else if (extrasize > 0)
+      free_stack(common, extrasize);
+
+    if (needs_control_head)
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1));
+    }
+  else
+    {
+    if ((opcode != OP_ASSERT_NOT && opcode != OP_ASSERTBACK_NOT) || conditional)
+      {
+      /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */
+      OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw));
+      if (needs_control_head)
+        OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1));
+      }
+    else
+      {
+      OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+      if (needs_control_head)
+        OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 2));
+      add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+      OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize - 1) * sizeof(sljit_sw));
+      }
+    }
+
+  if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT)
+    {
+    /* We know that STR_PTR was stored on the top of the stack. */
+    if (conditional)
+      {
+      if (extrasize > 0)
+        OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), needs_control_head ? STACK(-2) : STACK(-1));
+      }
+    else if (bra == OP_BRAZERO)
+      {
+      if (framesize < 0)
+        OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize));
+      else
+        {
+        OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 1));
+        OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-framesize - extrasize));
+        OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0);
+        }
+      OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+      }
+    else if (framesize >= 0)
+      {
+      /* For OP_BRA and OP_BRAMINZERO. */
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 1));
+      }
+    }
+  add_jump(compiler, found, JUMP(SLJIT_JUMP));
+
+  compile_backtrackingpath(common, altbacktrack.top);
+  if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+    {
+    if (local_quit_available)
+      {
+      common->local_quit_available = save_local_quit_available;
+      common->quit_label = save_quit_label;
+      common->quit = save_quit;
+      }
+    common->in_positive_assertion = save_in_positive_assertion;
+    common->then_trap = save_then_trap;
+    common->accept_label = save_accept_label;
+    common->positive_assertion_quit = save_positive_assertion_quit;
+    common->accept = save_accept;
+    return NULL;
+    }
+  set_jumps(altbacktrack.topbacktracks, LABEL());
+
+  if (*cc != OP_ALT)
+    break;
+
+  ccbegin = cc;
+  cc += GET(cc, 1);
+  }
+
+if (local_quit_available)
+  {
+  SLJIT_ASSERT(common->positive_assertion_quit == NULL);
+  /* Makes the check less complicated below. */
+  common->positive_assertion_quit = common->quit;
+  }
+
+/* None of them matched. */
+if (common->positive_assertion_quit != NULL)
+  {
+  jump = JUMP(SLJIT_JUMP);
+  set_jumps(common->positive_assertion_quit, LABEL());
+  SLJIT_ASSERT(framesize != no_stack);
+  if (framesize < 0)
+    OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, extrasize * sizeof(sljit_sw));
+  else
+    {
+    OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+    add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+    OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (extrasize + 1) * sizeof(sljit_sw));
+    }
+  JUMPHERE(jump);
+  }
+
+if (needs_control_head)
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(1));
+
+if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK)
+  {
+  /* Assert is failed. */
+  if ((conditional && extrasize > 0) || bra == OP_BRAZERO)
+    OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+
+  if (framesize < 0)
+    {
+    /* The topmost item should be 0. */
+    if (bra == OP_BRAZERO)
+      {
+      if (extrasize == 2)
+        free_stack(common, 1);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+      }
+    else if (extrasize > 0)
+      free_stack(common, extrasize);
+    }
+  else
+    {
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(extrasize - 1));
+    /* The topmost item should be 0. */
+    if (bra == OP_BRAZERO)
+      {
+      free_stack(common, framesize + extrasize - 1);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+      }
+    else
+      free_stack(common, framesize + extrasize);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0);
+    }
+  jump = JUMP(SLJIT_JUMP);
+  if (bra != OP_BRAZERO)
+    add_jump(compiler, target, jump);
+
+  /* Assert is successful. */
+  set_jumps(tmp, LABEL());
+  if (framesize < 0)
+    {
+    /* We know that STR_PTR was stored on the top of the stack. */
+    if (extrasize > 0)
+      OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize));
+
+    /* Keep the STR_PTR on the top of the stack. */
+    if (bra == OP_BRAZERO)
+      {
+      OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+      if (extrasize == 2)
+        OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+      }
+    else if (bra == OP_BRAMINZERO)
+      {
+      OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+      }
+    }
+  else
+    {
+    if (bra == OP_BRA)
+      {
+      /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */
+      OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw));
+      OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize + 1));
+      }
+    else
+      {
+      /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */
+      OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 2) * sizeof(sljit_sw));
+      if (extrasize == 2)
+        {
+        OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+        if (bra == OP_BRAMINZERO)
+          OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+        }
+      else
+        {
+        SLJIT_ASSERT(extrasize == 3);
+        OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-1));
+        OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), bra == OP_BRAZERO ? STR_PTR : SLJIT_IMM, 0);
+        }
+      }
+    }
+
+  if (bra == OP_BRAZERO)
+    {
+    backtrack->matchingpath = LABEL();
+    SET_LABEL(jump, backtrack->matchingpath);
+    }
+  else if (bra == OP_BRAMINZERO)
+    {
+    JUMPTO(SLJIT_JUMP, backtrack->matchingpath);
+    JUMPHERE(brajump);
+    if (framesize >= 0)
+      {
+      OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+      add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2));
+      OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize - 1) * sizeof(sljit_sw));
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0);
+      }
+    set_jumps(backtrack->common.topbacktracks, LABEL());
+    }
+  }
+else
+  {
+  /* AssertNot is successful. */
+  if (framesize < 0)
+    {
+    if (extrasize > 0)
+      OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+
+    if (bra != OP_BRA)
+      {
+      if (extrasize == 2)
+        free_stack(common, 1);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+      }
+    else if (extrasize > 0)
+      free_stack(common, extrasize);
+    }
+  else
+    {
+    OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(extrasize - 1));
+    /* The topmost item should be 0. */
+    if (bra != OP_BRA)
+      {
+      free_stack(common, framesize + extrasize - 1);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+      }
+    else
+      free_stack(common, framesize + extrasize);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0);
+    }
+
+  if (bra == OP_BRAZERO)
+    backtrack->matchingpath = LABEL();
+  else if (bra == OP_BRAMINZERO)
+    {
+    JUMPTO(SLJIT_JUMP, backtrack->matchingpath);
+    JUMPHERE(brajump);
+    }
+
+  if (bra != OP_BRA)
+    {
+    SLJIT_ASSERT(found == &backtrack->common.topbacktracks);
+    set_jumps(backtrack->common.topbacktracks, LABEL());
+    backtrack->common.topbacktracks = NULL;
+    }
+  }
+
+if (local_quit_available)
+  {
+  common->local_quit_available = save_local_quit_available;
+  common->quit_label = save_quit_label;
+  common->quit = save_quit;
+  }
+common->in_positive_assertion = save_in_positive_assertion;
+common->then_trap = save_then_trap;
+common->accept_label = save_accept_label;
+common->positive_assertion_quit = save_positive_assertion_quit;
+common->accept = save_accept;
+return cc + 1 + LINK_SIZE;
+}
+
+static SLJIT_INLINE void match_once_common(compiler_common *common, PCRE2_UCHAR ket, int framesize, int private_data_ptr, BOOL has_alternatives, BOOL needs_control_head)
+{
+DEFINE_COMPILER;
+int stacksize;
+
+if (framesize < 0)
+  {
+  if (framesize == no_frame)
+    OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+  else
+    {
+    stacksize = needs_control_head ? 1 : 0;
+    if (ket != OP_KET || has_alternatives)
+      stacksize++;
+
+    if (stacksize > 0)
+      free_stack(common, stacksize);
+    }
+
+  if (needs_control_head)
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), (ket != OP_KET || has_alternatives) ? STACK(-2) : STACK(-1));
+
+  /* TMP2 which is set here used by OP_KETRMAX below. */
+  if (ket == OP_KETRMAX)
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(-1));
+  else if (ket == OP_KETRMIN)
+    {
+    /* Move the STR_PTR to the private_data_ptr. */
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1));
+    }
+  }
+else
+  {
+  stacksize = (ket != OP_KET || has_alternatives) ? 2 : 1;
+  OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + stacksize) * sizeof(sljit_sw));
+  if (needs_control_head)
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-1));
+
+  if (ket == OP_KETRMAX)
+    {
+    /* TMP2 which is set here used by OP_KETRMAX below. */
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    }
+  }
+if (needs_control_head)
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, TMP1, 0);
+}
+
+static SLJIT_INLINE int match_capture_common(compiler_common *common, int stacksize, int offset, int private_data_ptr)
+{
+DEFINE_COMPILER;
+
+if (common->capture_last_ptr != 0)
+  {
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr);
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, offset >> 1);
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0);
+  stacksize++;
+  }
+if (common->optimized_cbracket[offset >> 1] == 0)
+  {
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0);
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize + 1), TMP2, 0);
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0);
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0);
+  stacksize += 2;
+  }
+return stacksize;
+}
+
+static PCRE2_SPTR SLJIT_FUNC do_script_run(PCRE2_SPTR ptr, PCRE2_SPTR endptr)
+{
+  if (PRIV(script_run)(ptr, endptr, FALSE))
+    return endptr;
+  return NULL;
+}
+
+#ifdef SUPPORT_UNICODE
+
+static PCRE2_SPTR SLJIT_FUNC do_script_run_utf(PCRE2_SPTR ptr, PCRE2_SPTR endptr)
+{
+  if (PRIV(script_run)(ptr, endptr, TRUE))
+    return endptr;
+  return NULL;
+}
+
+#endif /* SUPPORT_UNICODE */
+
+static SLJIT_INLINE void match_script_run_common(compiler_common *common, int private_data_ptr, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+
+SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1);
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+#ifdef SUPPORT_UNICODE
+sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM,
+  common->utf ? SLJIT_FUNC_OFFSET(do_script_run_utf) : SLJIT_FUNC_OFFSET(do_script_run));
+#else
+sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(do_script_run));
+#endif
+
+OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0);
+add_jump(compiler, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0));
+}
+
+/*
+  Handling bracketed expressions is probably the most complex part.
+
+  Stack layout naming characters:
+    S - Push the current STR_PTR
+    0 - Push a 0 (NULL)
+    A - Push the current STR_PTR. Needed for restoring the STR_PTR
+        before the next alternative. Not pushed if there are no alternatives.
+    M - Any values pushed by the current alternative. Can be empty, or anything.
+    C - Push the previous OVECTOR(i), OVECTOR(i+1) and OVECTOR_PRIV(i) to the stack.
+    L - Push the previous local (pointed by localptr) to the stack
+   () - opional values stored on the stack
+  ()* - optonal, can be stored multiple times
+
+  The following list shows the regular expression templates, their PCRE byte codes
+  and stack layout supported by pcre-sljit.
+
+  (?:)                     OP_BRA     | OP_KET                A M
+  ()                       OP_CBRA    | OP_KET                C M
+  (?:)+                    OP_BRA     | OP_KETRMAX        0   A M S   ( A M S )*
+                           OP_SBRA    | OP_KETRMAX        0   L M S   ( L M S )*
+  (?:)+?                   OP_BRA     | OP_KETRMIN        0   A M S   ( A M S )*
+                           OP_SBRA    | OP_KETRMIN        0   L M S   ( L M S )*
+  ()+                      OP_CBRA    | OP_KETRMAX        0   C M S   ( C M S )*
+                           OP_SCBRA   | OP_KETRMAX        0   C M S   ( C M S )*
+  ()+?                     OP_CBRA    | OP_KETRMIN        0   C M S   ( C M S )*
+                           OP_SCBRA   | OP_KETRMIN        0   C M S   ( C M S )*
+  (?:)?    OP_BRAZERO    | OP_BRA     | OP_KET            S ( A M 0 )
+  (?:)??   OP_BRAMINZERO | OP_BRA     | OP_KET            S ( A M 0 )
+  ()?      OP_BRAZERO    | OP_CBRA    | OP_KET            S ( C M 0 )
+  ()??     OP_BRAMINZERO | OP_CBRA    | OP_KET            S ( C M 0 )
+  (?:)*    OP_BRAZERO    | OP_BRA     | OP_KETRMAX      S 0 ( A M S )*
+           OP_BRAZERO    | OP_SBRA    | OP_KETRMAX      S 0 ( L M S )*
+  (?:)*?   OP_BRAMINZERO | OP_BRA     | OP_KETRMIN      S 0 ( A M S )*
+           OP_BRAMINZERO | OP_SBRA    | OP_KETRMIN      S 0 ( L M S )*
+  ()*      OP_BRAZERO    | OP_CBRA    | OP_KETRMAX      S 0 ( C M S )*
+           OP_BRAZERO    | OP_SCBRA   | OP_KETRMAX      S 0 ( C M S )*
+  ()*?     OP_BRAMINZERO | OP_CBRA    | OP_KETRMIN      S 0 ( C M S )*
+           OP_BRAMINZERO | OP_SCBRA   | OP_KETRMIN      S 0 ( C M S )*
+
+
+  Stack layout naming characters:
+    A - Push the alternative index (starting from 0) on the stack.
+        Not pushed if there is no alternatives.
+    M - Any values pushed by the current alternative. Can be empty, or anything.
+
+  The next list shows the possible content of a bracket:
+  (|)     OP_*BRA    | OP_ALT ...         M A
+  (?()|)  OP_*COND   | OP_ALT             M A
+  (?>|)   OP_ONCE    | OP_ALT ...         [stack trace] M A
+                                          Or nothing, if trace is unnecessary
+*/
+
+static PCRE2_SPTR compile_bracket_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+PCRE2_UCHAR opcode;
+int private_data_ptr = 0;
+int offset = 0;
+int i, stacksize;
+int repeat_ptr = 0, repeat_length = 0;
+int repeat_type = 0, repeat_count = 0;
+PCRE2_SPTR ccbegin;
+PCRE2_SPTR matchingpath;
+PCRE2_SPTR slot;
+PCRE2_UCHAR bra = OP_BRA;
+PCRE2_UCHAR ket;
+assert_backtrack *assert;
+BOOL has_alternatives;
+BOOL needs_control_head = FALSE;
+struct sljit_jump *jump;
+struct sljit_jump *skip;
+struct sljit_label *rmax_label = NULL;
+struct sljit_jump *braminzero = NULL;
+
+PUSH_BACKTRACK(sizeof(bracket_backtrack), cc, NULL);
+
+if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO)
+  {
+  bra = *cc;
+  cc++;
+  opcode = *cc;
+  }
+
+opcode = *cc;
+ccbegin = cc;
+matchingpath = bracketend(cc) - 1 - LINK_SIZE;
+ket = *matchingpath;
+if (ket == OP_KET && PRIVATE_DATA(matchingpath) != 0)
+  {
+  repeat_ptr = PRIVATE_DATA(matchingpath);
+  repeat_length = PRIVATE_DATA(matchingpath + 1);
+  repeat_type = PRIVATE_DATA(matchingpath + 2);
+  repeat_count = PRIVATE_DATA(matchingpath + 3);
+  SLJIT_ASSERT(repeat_length != 0 && repeat_type != 0 && repeat_count != 0);
+  if (repeat_type == OP_UPTO)
+    ket = OP_KETRMAX;
+  if (repeat_type == OP_MINUPTO)
+    ket = OP_KETRMIN;
+  }
+
+matchingpath = ccbegin + 1 + LINK_SIZE;
+SLJIT_ASSERT(ket == OP_KET || ket == OP_KETRMAX || ket == OP_KETRMIN);
+SLJIT_ASSERT(!((bra == OP_BRAZERO && ket == OP_KETRMIN) || (bra == OP_BRAMINZERO && ket == OP_KETRMAX)));
+cc += GET(cc, 1);
+
+has_alternatives = *cc == OP_ALT;
+if (SLJIT_UNLIKELY(opcode == OP_COND || opcode == OP_SCOND))
+  {
+  SLJIT_COMPILE_ASSERT(OP_DNRREF == OP_RREF + 1 && OP_FALSE == OP_RREF + 2 && OP_TRUE == OP_RREF + 3,
+    compile_time_checks_must_be_grouped_together);
+  has_alternatives = ((*matchingpath >= OP_RREF && *matchingpath <= OP_TRUE) || *matchingpath == OP_FAIL) ? FALSE : TRUE;
+  }
+
+if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN))
+  opcode = OP_SCOND;
+
+if (opcode == OP_CBRA || opcode == OP_SCBRA)
+  {
+  /* Capturing brackets has a pre-allocated space. */
+  offset = GET2(ccbegin, 1 + LINK_SIZE);
+  if (common->optimized_cbracket[offset] == 0)
+    {
+    private_data_ptr = OVECTOR_PRIV(offset);
+    offset <<= 1;
+    }
+  else
+    {
+    offset <<= 1;
+    private_data_ptr = OVECTOR(offset);
+    }
+  BACKTRACK_AS(bracket_backtrack)->private_data_ptr = private_data_ptr;
+  matchingpath += IMM2_SIZE;
+  }
+else if (opcode == OP_ASSERT_NA || opcode == OP_ASSERTBACK_NA || opcode == OP_ONCE || opcode == OP_SCRIPT_RUN || opcode == OP_SBRA || opcode == OP_SCOND)
+  {
+  /* Other brackets simply allocate the next entry. */
+  private_data_ptr = PRIVATE_DATA(ccbegin);
+  SLJIT_ASSERT(private_data_ptr != 0);
+  BACKTRACK_AS(bracket_backtrack)->private_data_ptr = private_data_ptr;
+  if (opcode == OP_ONCE)
+    BACKTRACK_AS(bracket_backtrack)->u.framesize = get_framesize(common, ccbegin, NULL, FALSE, &needs_control_head);
+  }
+
+/* Instructions before the first alternative. */
+stacksize = 0;
+if (ket == OP_KETRMAX || (ket == OP_KETRMIN && bra != OP_BRAMINZERO))
+  stacksize++;
+if (bra == OP_BRAZERO)
+  stacksize++;
+
+if (stacksize > 0)
+  allocate_stack(common, stacksize);
+
+stacksize = 0;
+if (ket == OP_KETRMAX || (ket == OP_KETRMIN && bra != OP_BRAMINZERO))
+  {
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0);
+  stacksize++;
+  }
+
+if (bra == OP_BRAZERO)
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0);
+
+if (bra == OP_BRAMINZERO)
+  {
+  /* This is a backtrack path! (Since the try-path of OP_BRAMINZERO matches to the empty string) */
+  OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+  if (ket != OP_KETRMIN)
+    {
+    free_stack(common, 1);
+    braminzero = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
+    }
+  else if (opcode == OP_ONCE || opcode >= OP_SBRA)
+    {
+    jump = CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
+    OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+    /* Nothing stored during the first run. */
+    skip = JUMP(SLJIT_JUMP);
+    JUMPHERE(jump);
+    /* Checking zero-length iteration. */
+    if (opcode != OP_ONCE || BACKTRACK_AS(bracket_backtrack)->u.framesize < 0)
+      {
+      /* When we come from outside, private_data_ptr contains the previous STR_PTR. */
+      braminzero = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+      }
+    else
+      {
+      /* Except when the whole stack frame must be saved. */
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+      braminzero = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), STACK(-BACKTRACK_AS(bracket_backtrack)->u.framesize - 2));
+      }
+    JUMPHERE(skip);
+    }
+  else
+    {
+    jump = CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
+    OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+    JUMPHERE(jump);
+    }
+  }
+
+if (repeat_type != 0)
+  {
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, repeat_count);
+  if (repeat_type == OP_EXACT)
+    rmax_label = LABEL();
+  }
+
+if (ket == OP_KETRMIN)
+  BACKTRACK_AS(bracket_backtrack)->recursive_matchingpath = LABEL();
+
+if (ket == OP_KETRMAX)
+  {
+  rmax_label = LABEL();
+  if (has_alternatives && opcode >= OP_BRA && opcode < OP_SBRA && repeat_type == 0)
+    BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = rmax_label;
+  }
+
+/* Handling capturing brackets and alternatives. */
+if (opcode == OP_ONCE)
+  {
+  stacksize = 0;
+  if (needs_control_head)
+    {
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+    stacksize++;
+    }
+
+  if (BACKTRACK_AS(bracket_backtrack)->u.framesize < 0)
+    {
+    /* Neither capturing brackets nor recursions are found in the block. */
+    if (ket == OP_KETRMIN)
+      {
+      stacksize += 2;
+      if (!needs_control_head)
+        OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+      }
+    else
+      {
+      if (BACKTRACK_AS(bracket_backtrack)->u.framesize == no_frame)
+        OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0);
+      if (ket == OP_KETRMAX || has_alternatives)
+        stacksize++;
+      }
+
+    if (stacksize > 0)
+      allocate_stack(common, stacksize);
+
+    stacksize = 0;
+    if (needs_control_head)
+      {
+      stacksize++;
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
+      }
+
+    if (ket == OP_KETRMIN)
+      {
+      if (needs_control_head)
+        OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0);
+      if (BACKTRACK_AS(bracket_backtrack)->u.framesize == no_frame)
+        OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, needs_control_head ? (2 * sizeof(sljit_sw)) : sizeof(sljit_sw));
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize + 1), TMP2, 0);
+      }
+    else if (ket == OP_KETRMAX || has_alternatives)
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0);
+    }
+  else
+    {
+    if (ket != OP_KET || has_alternatives)
+      stacksize++;
+
+    stacksize += BACKTRACK_AS(bracket_backtrack)->u.framesize + 1;
+    allocate_stack(common, stacksize);
+
+    if (needs_control_head)
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
+
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+    OP2(SLJIT_ADD, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw));
+
+    stacksize = needs_control_head ? 1 : 0;
+    if (ket != OP_KET || has_alternatives)
+      {
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0);
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0);
+      stacksize++;
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0);
+      }
+    else
+      {
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0);
+      }
+    init_frame(common, ccbegin, NULL, BACKTRACK_AS(bracket_backtrack)->u.framesize + stacksize, stacksize + 1);
+    }
+  }
+else if (opcode == OP_CBRA || opcode == OP_SCBRA)
+  {
+  /* Saving the previous values. */
+  if (common->optimized_cbracket[offset >> 1] != 0)
+    {
+    SLJIT_ASSERT(private_data_ptr == OVECTOR(offset));
+    allocate_stack(common, 2);
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr + sizeof(sljit_sw));
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0);
+    }
+  else
+    {
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+    allocate_stack(common, 1);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
+    }
+  }
+else if (opcode == OP_ASSERT_NA || opcode == OP_ASSERTBACK_NA || opcode == OP_SCRIPT_RUN || opcode == OP_SBRA || opcode == OP_SCOND)
+  {
+  /* Saving the previous value. */
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+  allocate_stack(common, 1);
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0);
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
+  }
+else if (has_alternatives)
+  {
+  /* Pushing the starting string pointer. */
+  allocate_stack(common, 1);
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+  }
+
+/* Generating code for the first alternative. */
+if (opcode == OP_COND || opcode == OP_SCOND)
+  {
+  if (*matchingpath == OP_CREF)
+    {
+    SLJIT_ASSERT(has_alternatives);
+    add_jump(compiler, &(BACKTRACK_AS(bracket_backtrack)->u.condfailed),
+      CMP(SLJIT_EQUAL, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(matchingpath, 1) << 1), SLJIT_MEM1(SLJIT_SP), OVECTOR(1)));
+    matchingpath += 1 + IMM2_SIZE;
+    }
+  else if (*matchingpath == OP_DNCREF)
+    {
+    SLJIT_ASSERT(has_alternatives);
+
+    i = GET2(matchingpath, 1 + IMM2_SIZE);
+    slot = common->name_table + GET2(matchingpath, 1) * common->name_entry_size;
+    OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0);
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1));
+    OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(slot, 0) << 1), TMP1, 0);
+    slot += common->name_entry_size;
+    i--;
+    while (i-- > 0)
+      {
+      OP2(SLJIT_SUB, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(slot, 0) << 1), TMP1, 0);
+      OP2(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, TMP2, 0, STR_PTR, 0);
+      slot += common->name_entry_size;
+      }
+    OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0);
+    add_jump(compiler, &(BACKTRACK_AS(bracket_backtrack)->u.condfailed), JUMP(SLJIT_ZERO));
+    matchingpath += 1 + 2 * IMM2_SIZE;
+    }
+  else if ((*matchingpath >= OP_RREF && *matchingpath <= OP_TRUE) || *matchingpath == OP_FAIL)
+    {
+    /* Never has other case. */
+    BACKTRACK_AS(bracket_backtrack)->u.condfailed = NULL;
+    SLJIT_ASSERT(!has_alternatives);
+
+    if (*matchingpath == OP_TRUE)
+      {
+      stacksize = 1;
+      matchingpath++;
+      }
+    else if (*matchingpath == OP_FALSE || *matchingpath == OP_FAIL)
+      stacksize = 0;
+    else if (*matchingpath == OP_RREF)
+      {
+      stacksize = GET2(matchingpath, 1);
+      if (common->currententry == NULL)
+        stacksize = 0;
+      else if (stacksize == RREF_ANY)
+        stacksize = 1;
+      else if (common->currententry->start == 0)
+        stacksize = stacksize == 0;
+      else
+        stacksize = stacksize == (int)GET2(common->start, common->currententry->start + 1 + LINK_SIZE);
+
+      if (stacksize != 0)
+        matchingpath += 1 + IMM2_SIZE;
+      }
+    else
+      {
+      if (common->currententry == NULL || common->currententry->start == 0)
+        stacksize = 0;
+      else
+        {
+        stacksize = GET2(matchingpath, 1 + IMM2_SIZE);
+        slot = common->name_table + GET2(matchingpath, 1) * common->name_entry_size;
+        i = (int)GET2(common->start, common->currententry->start + 1 + LINK_SIZE);
+        while (stacksize > 0)
+          {
+          if ((int)GET2(slot, 0) == i)
+            break;
+          slot += common->name_entry_size;
+          stacksize--;
+          }
+        }
+
+      if (stacksize != 0)
+        matchingpath += 1 + 2 * IMM2_SIZE;
+      }
+
+      /* The stacksize == 0 is a common "else" case. */
+      if (stacksize == 0)
+        {
+        if (*cc == OP_ALT)
+          {
+          matchingpath = cc + 1 + LINK_SIZE;
+          cc += GET(cc, 1);
+          }
+        else
+          matchingpath = cc;
+        }
+    }
+  else
+    {
+    SLJIT_ASSERT(has_alternatives && *matchingpath >= OP_ASSERT && *matchingpath <= OP_ASSERTBACK_NOT);
+    /* Similar code as PUSH_BACKTRACK macro. */
+    assert = sljit_alloc_memory(compiler, sizeof(assert_backtrack));
+    if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+      return NULL;
+    memset(assert, 0, sizeof(assert_backtrack));
+    assert->common.cc = matchingpath;
+    BACKTRACK_AS(bracket_backtrack)->u.assert = assert;
+    matchingpath = compile_assert_matchingpath(common, matchingpath, assert, TRUE);
+    }
+  }
+
+compile_matchingpath(common, matchingpath, cc, backtrack);
+if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+  return NULL;
+
+if (opcode == OP_ASSERT_NA || opcode == OP_ASSERTBACK_NA)
+  OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+
+if (opcode == OP_ONCE)
+  match_once_common(common, ket, BACKTRACK_AS(bracket_backtrack)->u.framesize, private_data_ptr, has_alternatives, needs_control_head);
+
+if (opcode == OP_SCRIPT_RUN)
+  match_script_run_common(common, private_data_ptr, backtrack);
+
+stacksize = 0;
+if (repeat_type == OP_MINUPTO)
+  {
+  /* We need to preserve the counter. TMP2 will be used below. */
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), repeat_ptr);
+  stacksize++;
+  }
+if (ket != OP_KET || bra != OP_BRA)
+  stacksize++;
+if (offset != 0)
+  {
+  if (common->capture_last_ptr != 0)
+    stacksize++;
+  if (common->optimized_cbracket[offset >> 1] == 0)
+    stacksize += 2;
+  }
+if (has_alternatives && opcode != OP_ONCE)
+  stacksize++;
+
+if (stacksize > 0)
+  allocate_stack(common, stacksize);
+
+stacksize = 0;
+if (repeat_type == OP_MINUPTO)
+  {
+  /* TMP2 was set above. */
+  OP2(SLJIT_SUB, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP2, 0, SLJIT_IMM, 1);
+  stacksize++;
+  }
+
+if (ket != OP_KET || bra != OP_BRA)
+  {
+  if (ket != OP_KET)
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0);
+  else
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0);
+  stacksize++;
+  }
+
+if (offset != 0)
+  stacksize = match_capture_common(common, stacksize, offset, private_data_ptr);
+
+/* Skip and count the other alternatives. */
+i = 1;
+while (*cc == OP_ALT)
+  {
+  cc += GET(cc, 1);
+  i++;
+  }
+
+if (has_alternatives)
+  {
+  if (opcode != OP_ONCE)
+    {
+    if (i <= 3)
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0);
+    else
+      BACKTRACK_AS(bracket_backtrack)->u.matching_put_label = sljit_emit_put_label(compiler, SLJIT_MEM1(STACK_TOP), STACK(stacksize));
+    }
+  if (ket != OP_KETRMAX)
+    BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL();
+  }
+
+/* Must be after the matchingpath label. */
+if (offset != 0 && common->optimized_cbracket[offset >> 1] != 0)
+  {
+  SLJIT_ASSERT(private_data_ptr == OVECTOR(offset + 0));
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0);
+  }
+
+if (ket == OP_KETRMAX)
+  {
+  if (repeat_type != 0)
+    {
+    if (has_alternatives)
+      BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL();
+    OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1);
+    JUMPTO(SLJIT_NOT_ZERO, rmax_label);
+    /* Drop STR_PTR for greedy plus quantifier. */
+    if (opcode != OP_ONCE)
+      free_stack(common, 1);
+    }
+  else if (opcode < OP_BRA || opcode >= OP_SBRA)
+    {
+    if (has_alternatives)
+      BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL();
+
+    /* Checking zero-length iteration. */
+    if (opcode != OP_ONCE)
+      {
+      /* This case includes opcodes such as OP_SCRIPT_RUN. */
+      CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0, rmax_label);
+      /* Drop STR_PTR for greedy plus quantifier. */
+      if (bra != OP_BRAZERO)
+        free_stack(common, 1);
+      }
+    else
+      /* TMP2 must contain the starting STR_PTR. */
+      CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0, rmax_label);
+    }
+  else
+    JUMPTO(SLJIT_JUMP, rmax_label);
+  BACKTRACK_AS(bracket_backtrack)->recursive_matchingpath = LABEL();
+  }
+
+if (repeat_type == OP_EXACT)
+  {
+  count_match(common);
+  OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1);
+  JUMPTO(SLJIT_NOT_ZERO, rmax_label);
+  }
+else if (repeat_type == OP_UPTO)
+  {
+  /* We need to preserve the counter. */
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), repeat_ptr);
+  allocate_stack(common, 1);
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
+  }
+
+if (bra == OP_BRAZERO)
+  BACKTRACK_AS(bracket_backtrack)->zero_matchingpath = LABEL();
+
+if (bra == OP_BRAMINZERO)
+  {
+  /* This is a backtrack path! (From the viewpoint of OP_BRAMINZERO) */
+  JUMPTO(SLJIT_JUMP, ((braminzero_backtrack *)parent)->matchingpath);
+  if (braminzero != NULL)
+    {
+    JUMPHERE(braminzero);
+    /* We need to release the end pointer to perform the
+    backtrack for the zero-length iteration. When
+    framesize is < 0, OP_ONCE will do the release itself. */
+    if (opcode == OP_ONCE && BACKTRACK_AS(bracket_backtrack)->u.framesize >= 0)
+      {
+      OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+      add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+      OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (BACKTRACK_AS(bracket_backtrack)->u.framesize - 1) * sizeof(sljit_sw));
+      }
+    else if (ket == OP_KETRMIN && opcode != OP_ONCE)
+      free_stack(common, 1);
+    }
+  /* Continue to the normal backtrack. */
+  }
+
+if ((ket != OP_KET && bra != OP_BRAMINZERO) || bra == OP_BRAZERO)
+  count_match(common);
+
+cc += 1 + LINK_SIZE;
+
+if (opcode == OP_ONCE)
+  {
+  /* We temporarily encode the needs_control_head in the lowest bit.
+     Note: on the target architectures of SLJIT the ((x << 1) >> 1) returns
+     the same value for small signed numbers (including negative numbers). */
+  BACKTRACK_AS(bracket_backtrack)->u.framesize = (int)((unsigned)BACKTRACK_AS(bracket_backtrack)->u.framesize << 1) | (needs_control_head ? 1 : 0);
+  }
+return cc + repeat_length;
+}
+
+static PCRE2_SPTR compile_bracketpos_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+PCRE2_UCHAR opcode;
+int private_data_ptr;
+int cbraprivptr = 0;
+BOOL needs_control_head;
+int framesize;
+int stacksize;
+int offset = 0;
+BOOL zero = FALSE;
+PCRE2_SPTR ccbegin = NULL;
+int stack; /* Also contains the offset of control head. */
+struct sljit_label *loop = NULL;
+struct jump_list *emptymatch = NULL;
+
+PUSH_BACKTRACK(sizeof(bracketpos_backtrack), cc, NULL);
+if (*cc == OP_BRAPOSZERO)
+  {
+  zero = TRUE;
+  cc++;
+  }
+
+opcode = *cc;
+private_data_ptr = PRIVATE_DATA(cc);
+SLJIT_ASSERT(private_data_ptr != 0);
+BACKTRACK_AS(bracketpos_backtrack)->private_data_ptr = private_data_ptr;
+switch(opcode)
+  {
+  case OP_BRAPOS:
+  case OP_SBRAPOS:
+  ccbegin = cc + 1 + LINK_SIZE;
+  break;
+
+  case OP_CBRAPOS:
+  case OP_SCBRAPOS:
+  offset = GET2(cc, 1 + LINK_SIZE);
+  /* This case cannot be optimized in the same was as
+  normal capturing brackets. */
+  SLJIT_ASSERT(common->optimized_cbracket[offset] == 0);
+  cbraprivptr = OVECTOR_PRIV(offset);
+  offset <<= 1;
+  ccbegin = cc + 1 + LINK_SIZE + IMM2_SIZE;
+  break;
+
+  default:
+  SLJIT_UNREACHABLE();
+  break;
+  }
+
+framesize = get_framesize(common, cc, NULL, FALSE, &needs_control_head);
+BACKTRACK_AS(bracketpos_backtrack)->framesize = framesize;
+if (framesize < 0)
+  {
+  if (offset != 0)
+    {
+    stacksize = 2;
+    if (common->capture_last_ptr != 0)
+      stacksize++;
+    }
+  else
+    stacksize = 1;
+
+  if (needs_control_head)
+    stacksize++;
+  if (!zero)
+    stacksize++;
+
+  BACKTRACK_AS(bracketpos_backtrack)->stacksize = stacksize;
+  allocate_stack(common, stacksize);
+  if (framesize == no_frame)
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0);
+
+  stack = 0;
+  if (offset != 0)
+    {
+    stack = 2;
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0);
+    if (common->capture_last_ptr != 0)
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0);
+    if (needs_control_head)
+      OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+    if (common->capture_last_ptr != 0)
+      {
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0);
+      stack = 3;
+      }
+    }
+  else
+    {
+    if (needs_control_head)
+      OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+    stack = 1;
+    }
+
+  if (needs_control_head)
+    stack++;
+  if (!zero)
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), SLJIT_IMM, 1);
+  if (needs_control_head)
+    {
+    stack--;
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP2, 0);
+    }
+  }
+else
+  {
+  stacksize = framesize + 1;
+  if (!zero)
+    stacksize++;
+  if (needs_control_head)
+    stacksize++;
+  if (offset == 0)
+    stacksize++;
+  BACKTRACK_AS(bracketpos_backtrack)->stacksize = stacksize;
+
+  allocate_stack(common, stacksize);
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+  if (needs_control_head)
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+  OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw));
+
+  stack = 0;
+  if (!zero)
+    {
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 1);
+    stack = 1;
+    }
+  if (needs_control_head)
+    {
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP2, 0);
+    stack++;
+    }
+  if (offset == 0)
+    {
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), STR_PTR, 0);
+    stack++;
+    }
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP1, 0);
+  init_frame(common, cc, NULL, stacksize - 1, stacksize - framesize);
+  stack -= 1 + (offset == 0);
+  }
+
+if (offset != 0)
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), cbraprivptr, STR_PTR, 0);
+
+loop = LABEL();
+while (*cc != OP_KETRPOS)
+  {
+  backtrack->top = NULL;
+  backtrack->topbacktracks = NULL;
+  cc += GET(cc, 1);
+
+  compile_matchingpath(common, ccbegin, cc, backtrack);
+  if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+    return NULL;
+
+  if (framesize < 0)
+    {
+    if (framesize == no_frame)
+      OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+
+    if (offset != 0)
+      {
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr);
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0);
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), cbraprivptr, STR_PTR, 0);
+      if (common->capture_last_ptr != 0)
+        OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, offset >> 1);
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0);
+      }
+    else
+      {
+      if (opcode == OP_SBRAPOS)
+        OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+      }
+
+    /* Even if the match is empty, we need to reset the control head. */
+    if (needs_control_head)
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(stack));
+
+    if (opcode == OP_SBRAPOS || opcode == OP_SCBRAPOS)
+      add_jump(compiler, &emptymatch, CMP(SLJIT_EQUAL, TMP1, 0, STR_PTR, 0));
+
+    if (!zero)
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0);
+    }
+  else
+    {
+    if (offset != 0)
+      {
+      OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, stacksize * sizeof(sljit_sw));
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr);
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0);
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), cbraprivptr, STR_PTR, 0);
+      if (common->capture_last_ptr != 0)
+        OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, offset >> 1);
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0);
+      }
+    else
+      {
+      OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+      OP2(SLJIT_SUB, STACK_TOP, 0, TMP2, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw));
+      if (opcode == OP_SBRAPOS)
+        OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), STACK(-framesize - 2));
+      OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), STACK(-framesize - 2), STR_PTR, 0);
+      }
+
+    /* Even if the match is empty, we need to reset the control head. */
+    if (needs_control_head)
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(stack));
+
+    if (opcode == OP_SBRAPOS || opcode == OP_SCBRAPOS)
+      add_jump(compiler, &emptymatch, CMP(SLJIT_EQUAL, TMP1, 0, STR_PTR, 0));
+
+    if (!zero)
+      {
+      if (framesize < 0)
+        OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0);
+      else
+        OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+      }
+    }
+
+  JUMPTO(SLJIT_JUMP, loop);
+  flush_stubs(common);
+
+  compile_backtrackingpath(common, backtrack->top);
+  if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+    return NULL;
+  set_jumps(backtrack->topbacktracks, LABEL());
+
+  if (framesize < 0)
+    {
+    if (offset != 0)
+      OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr);
+    else
+      OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    }
+  else
+    {
+    if (offset != 0)
+      {
+      /* Last alternative. */
+      if (*cc == OP_KETRPOS)
+        OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+      OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr);
+      }
+    else
+      {
+      OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+      OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP2), STACK(-framesize - 2));
+      }
+    }
+
+  if (*cc == OP_KETRPOS)
+    break;
+  ccbegin = cc + 1 + LINK_SIZE;
+  }
+
+/* We don't have to restore the control head in case of a failed match. */
+
+backtrack->topbacktracks = NULL;
+if (!zero)
+  {
+  if (framesize < 0)
+    add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0));
+  else /* TMP2 is set to [private_data_ptr] above. */
+    add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(TMP2), STACK(-stacksize), SLJIT_IMM, 0));
+  }
+
+/* None of them matched. */
+set_jumps(emptymatch, LABEL());
+count_match(common);
+return cc + 1 + LINK_SIZE;
+}
+
+static SLJIT_INLINE PCRE2_SPTR get_iterator_parameters(compiler_common *common, PCRE2_SPTR cc, PCRE2_UCHAR *opcode, PCRE2_UCHAR *type, sljit_u32 *max, sljit_u32 *exact, PCRE2_SPTR *end)
+{
+int class_len;
+
+*opcode = *cc;
+*exact = 0;
+
+if (*opcode >= OP_STAR && *opcode <= OP_POSUPTO)
+  {
+  cc++;
+  *type = OP_CHAR;
+  }
+else if (*opcode >= OP_STARI && *opcode <= OP_POSUPTOI)
+  {
+  cc++;
+  *type = OP_CHARI;
+  *opcode -= OP_STARI - OP_STAR;
+  }
+else if (*opcode >= OP_NOTSTAR && *opcode <= OP_NOTPOSUPTO)
+  {
+  cc++;
+  *type = OP_NOT;
+  *opcode -= OP_NOTSTAR - OP_STAR;
+  }
+else if (*opcode >= OP_NOTSTARI && *opcode <= OP_NOTPOSUPTOI)
+  {
+  cc++;
+  *type = OP_NOTI;
+  *opcode -= OP_NOTSTARI - OP_STAR;
+  }
+else if (*opcode >= OP_TYPESTAR && *opcode <= OP_TYPEPOSUPTO)
+  {
+  cc++;
+  *opcode -= OP_TYPESTAR - OP_STAR;
+  *type = OP_END;
+  }
+else
+  {
+  SLJIT_ASSERT(*opcode == OP_CLASS || *opcode == OP_NCLASS || *opcode == OP_XCLASS);
+  *type = *opcode;
+  cc++;
+  class_len = (*type < OP_XCLASS) ? (int)(1 + (32 / sizeof(PCRE2_UCHAR))) : GET(cc, 0);
+  *opcode = cc[class_len - 1];
+
+  if (*opcode >= OP_CRSTAR && *opcode <= OP_CRMINQUERY)
+    {
+    *opcode -= OP_CRSTAR - OP_STAR;
+    *end = cc + class_len;
+
+    if (*opcode == OP_PLUS || *opcode == OP_MINPLUS)
+      {
+      *exact = 1;
+      *opcode -= OP_PLUS - OP_STAR;
+      }
+    }
+  else if (*opcode >= OP_CRPOSSTAR && *opcode <= OP_CRPOSQUERY)
+    {
+    *opcode -= OP_CRPOSSTAR - OP_POSSTAR;
+    *end = cc + class_len;
+
+    if (*opcode == OP_POSPLUS)
+      {
+      *exact = 1;
+      *opcode = OP_POSSTAR;
+      }
+    }
+  else
+    {
+    SLJIT_ASSERT(*opcode == OP_CRRANGE || *opcode == OP_CRMINRANGE || *opcode == OP_CRPOSRANGE);
+    *max = GET2(cc, (class_len + IMM2_SIZE));
+    *exact = GET2(cc, class_len);
+
+    if (*max == 0)
+      {
+      if (*opcode == OP_CRPOSRANGE)
+        *opcode = OP_POSSTAR;
+      else
+        *opcode -= OP_CRRANGE - OP_STAR;
+      }
+    else
+      {
+      *max -= *exact;
+      if (*max == 0)
+        *opcode = OP_EXACT;
+      else if (*max == 1)
+        {
+        if (*opcode == OP_CRPOSRANGE)
+          *opcode = OP_POSQUERY;
+        else
+          *opcode -= OP_CRRANGE - OP_QUERY;
+        }
+      else
+        {
+        if (*opcode == OP_CRPOSRANGE)
+          *opcode = OP_POSUPTO;
+        else
+          *opcode -= OP_CRRANGE - OP_UPTO;
+        }
+      }
+    *end = cc + class_len + 2 * IMM2_SIZE;
+    }
+  return cc;
+  }
+
+switch(*opcode)
+  {
+  case OP_EXACT:
+  *exact = GET2(cc, 0);
+  cc += IMM2_SIZE;
+  break;
+
+  case OP_PLUS:
+  case OP_MINPLUS:
+  *exact = 1;
+  *opcode -= OP_PLUS - OP_STAR;
+  break;
+
+  case OP_POSPLUS:
+  *exact = 1;
+  *opcode = OP_POSSTAR;
+  break;
+
+  case OP_UPTO:
+  case OP_MINUPTO:
+  case OP_POSUPTO:
+  *max = GET2(cc, 0);
+  cc += IMM2_SIZE;
+  break;
+  }
+
+if (*type == OP_END)
+  {
+  *type = *cc;
+  *end = next_opcode(common, cc);
+  cc++;
+  return cc;
+  }
+
+*end = cc + 1;
+#ifdef SUPPORT_UNICODE
+if (common->utf && HAS_EXTRALEN(*cc)) *end += GET_EXTRALEN(*cc);
+#endif
+return cc;
+}
+
+static PCRE2_SPTR compile_iterator_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+PCRE2_UCHAR opcode;
+PCRE2_UCHAR type;
+sljit_u32 max = 0, exact;
+sljit_s32 early_fail_ptr = PRIVATE_DATA(cc + 1);
+sljit_s32 early_fail_type;
+BOOL charpos_enabled;
+PCRE2_UCHAR charpos_char;
+unsigned int charpos_othercasebit;
+PCRE2_SPTR end;
+jump_list *no_match = NULL;
+jump_list *no_char1_match = NULL;
+struct sljit_jump *jump = NULL;
+struct sljit_label *label;
+int private_data_ptr = PRIVATE_DATA(cc);
+int base = (private_data_ptr == 0) ? SLJIT_MEM1(STACK_TOP) : SLJIT_MEM1(SLJIT_SP);
+int offset0 = (private_data_ptr == 0) ? STACK(0) : private_data_ptr;
+int offset1 = (private_data_ptr == 0) ? STACK(1) : private_data_ptr + (int)sizeof(sljit_sw);
+int tmp_base, tmp_offset;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+BOOL use_tmp;
+#endif
+
+PUSH_BACKTRACK(sizeof(char_iterator_backtrack), cc, NULL);
+
+early_fail_type = (early_fail_ptr & 0x7);
+early_fail_ptr >>= 3;
+
+/* During recursion, these optimizations are disabled. */
+if (common->early_fail_start_ptr == 0)
+  {
+  early_fail_ptr = 0;
+  early_fail_type = type_skip;
+  }
+
+SLJIT_ASSERT(common->fast_forward_bc_ptr != NULL || early_fail_ptr == 0
+  || (early_fail_ptr >= common->early_fail_start_ptr && early_fail_ptr <= common->early_fail_end_ptr));
+
+if (early_fail_type == type_fail)
+  add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), early_fail_ptr));
+
+cc = get_iterator_parameters(common, cc, &opcode, &type, &max, &exact, &end);
+
+if (type != OP_EXTUNI)
+  {
+  tmp_base = TMP3;
+  tmp_offset = 0;
+  }
+else
+  {
+  tmp_base = SLJIT_MEM1(SLJIT_SP);
+  tmp_offset = POSSESSIVE0;
+  }
+
+/* Handle fixed part first. */
+if (exact > 1)
+  {
+  SLJIT_ASSERT(early_fail_ptr == 0);
+
+  if (common->mode == PCRE2_JIT_COMPLETE
+#ifdef SUPPORT_UNICODE
+      && !common->utf
+#endif
+      && type != OP_ANYNL && type != OP_EXTUNI)
+    {
+    OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(exact));
+    add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_GREATER, TMP1, 0, STR_END, 0));
+    OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, exact);
+    label = LABEL();
+    compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, FALSE);
+    OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+    JUMPTO(SLJIT_NOT_ZERO, label);
+    }
+  else
+    {
+    OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, exact);
+    label = LABEL();
+    compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, TRUE);
+    OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+    JUMPTO(SLJIT_NOT_ZERO, label);
+    }
+  }
+else if (exact == 1)
+  {
+  compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, TRUE);
+
+  if (early_fail_type == type_fail_range)
+    {
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), early_fail_ptr);
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), early_fail_ptr + (int)sizeof(sljit_sw));
+    OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, TMP2, 0);
+    OP2(SLJIT_SUB, TMP2, 0, STR_PTR, 0, TMP2, 0);
+    add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_LESS_EQUAL, TMP2, 0, TMP1, 0));
+
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr + (int)sizeof(sljit_sw), STR_PTR, 0);
+    }
+  }
+
+switch(opcode)
+  {
+  case OP_STAR:
+  case OP_UPTO:
+  SLJIT_ASSERT(early_fail_ptr == 0 || opcode == OP_STAR);
+
+  if (type == OP_ANYNL || type == OP_EXTUNI)
+    {
+    SLJIT_ASSERT(private_data_ptr == 0);
+    SLJIT_ASSERT(early_fail_ptr == 0);
+
+    allocate_stack(common, 2);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0);
+
+    if (opcode == OP_UPTO)
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, SLJIT_IMM, max);
+
+    label = LABEL();
+    compile_char1_matchingpath(common, type, cc, &BACKTRACK_AS(char_iterator_backtrack)->u.backtracks, TRUE);
+    if (opcode == OP_UPTO)
+      {
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0);
+      OP2(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+      jump = JUMP(SLJIT_ZERO);
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, TMP1, 0);
+      }
+
+    /* We cannot use TMP3 because of allocate_stack. */
+    allocate_stack(common, 1);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+    JUMPTO(SLJIT_JUMP, label);
+    if (jump != NULL)
+      JUMPHERE(jump);
+    BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL();
+    break;
+    }
+#ifdef SUPPORT_UNICODE
+  else if (type == OP_ALLANY && !common->invalid_utf)
+#else
+  else if (type == OP_ALLANY)
+#endif
+    {
+    if (opcode == OP_STAR)
+      {
+      if (private_data_ptr == 0)
+        allocate_stack(common, 2);
+
+      OP1(SLJIT_MOV, base, offset0, STR_END, 0);
+      OP1(SLJIT_MOV, base, offset1, STR_PTR, 0);
+
+      OP1(SLJIT_MOV, STR_PTR, 0, STR_END, 0);
+      process_partial_match(common);
+
+      if (early_fail_ptr != 0)
+        OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_END, 0);
+      BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL();
+      break;
+      }
+#ifdef SUPPORT_UNICODE
+    else if (!common->utf)
+#else
+    else
+#endif
+      {
+      if (private_data_ptr == 0)
+        allocate_stack(common, 2);
+
+      OP1(SLJIT_MOV, base, offset1, STR_PTR, 0);
+      OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(max));
+
+      if (common->mode == PCRE2_JIT_COMPLETE)
+        {
+        OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_PTR, 0, STR_END, 0);
+        CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0);
+        }
+      else
+        {
+        jump = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, STR_END, 0);
+        process_partial_match(common);
+        JUMPHERE(jump);
+        }
+
+      OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+
+      if (early_fail_ptr != 0)
+        OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0);
+      BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL();
+      break;
+      }
+    }
+
+  charpos_enabled = FALSE;
+  charpos_char = 0;
+  charpos_othercasebit = 0;
+
+  if ((type != OP_CHAR && type != OP_CHARI) && (*end == OP_CHAR || *end == OP_CHARI))
+    {
+#ifdef SUPPORT_UNICODE
+    charpos_enabled = !common->utf || !HAS_EXTRALEN(end[1]);
+#else
+    charpos_enabled = TRUE;
+#endif
+    if (charpos_enabled && *end == OP_CHARI && char_has_othercase(common, end + 1))
+      {
+      charpos_othercasebit = char_get_othercase_bit(common, end + 1);
+      if (charpos_othercasebit == 0)
+        charpos_enabled = FALSE;
+      }
+
+    if (charpos_enabled)
+      {
+      charpos_char = end[1];
+      /* Consume the OP_CHAR opcode. */
+      end += 2;
+#if PCRE2_CODE_UNIT_WIDTH == 8
+      SLJIT_ASSERT((charpos_othercasebit >> 8) == 0);
+#elif PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+      SLJIT_ASSERT((charpos_othercasebit >> 9) == 0);
+      if ((charpos_othercasebit & 0x100) != 0)
+        charpos_othercasebit = (charpos_othercasebit & 0xff) << 8;
+#endif
+      if (charpos_othercasebit != 0)
+        charpos_char |= charpos_othercasebit;
+
+      BACKTRACK_AS(char_iterator_backtrack)->u.charpos.enabled = TRUE;
+      BACKTRACK_AS(char_iterator_backtrack)->u.charpos.chr = charpos_char;
+      BACKTRACK_AS(char_iterator_backtrack)->u.charpos.othercasebit = charpos_othercasebit;
+      }
+    }
+
+  if (charpos_enabled)
+    {
+    if (opcode == OP_UPTO)
+      OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max + 1);
+
+    /* Search the first instance of charpos_char. */
+    jump = JUMP(SLJIT_JUMP);
+    label = LABEL();
+    if (opcode == OP_UPTO)
+      {
+      OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+      add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_ZERO));
+      }
+    compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, FALSE);
+    if (early_fail_ptr != 0)
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0);
+    JUMPHERE(jump);
+
+    detect_partial_match(common, &backtrack->topbacktracks);
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+    if (charpos_othercasebit != 0)
+      OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, charpos_othercasebit);
+    CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, charpos_char, label);
+
+    if (private_data_ptr == 0)
+      allocate_stack(common, 2);
+    OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+    OP1(SLJIT_MOV, base, offset1, STR_PTR, 0);
+
+    if (opcode == OP_UPTO)
+      {
+      OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+      add_jump(compiler, &no_match, JUMP(SLJIT_ZERO));
+      }
+
+    /* Search the last instance of charpos_char. */
+    label = LABEL();
+    compile_char1_matchingpath(common, type, cc, &no_match, FALSE);
+    if (early_fail_ptr != 0)
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0);
+    detect_partial_match(common, &no_match);
+    OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+    if (charpos_othercasebit != 0)
+      OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, charpos_othercasebit);
+
+    if (opcode == OP_STAR)
+      {
+      CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, charpos_char, label);
+      OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+      JUMPTO(SLJIT_JUMP, label);
+      }
+    else
+      {
+      jump = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, charpos_char);
+      OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+      JUMPHERE(jump);
+      OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+      JUMPTO(SLJIT_NOT_ZERO, label);
+      }
+
+    set_jumps(no_match, LABEL());
+    OP2(SLJIT_ADD, STR_PTR, 0, base, offset0, SLJIT_IMM, IN_UCHARS(1));
+    OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+    }
+  else
+    {
+    if (private_data_ptr == 0)
+      allocate_stack(common, 2);
+
+    OP1(SLJIT_MOV, base, offset1, STR_PTR, 0);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+    use_tmp = (!HAS_VIRTUAL_REGISTERS && opcode == OP_STAR);
+    SLJIT_ASSERT(!use_tmp || tmp_base == TMP3);
+
+    if (common->utf)
+      OP1(SLJIT_MOV, use_tmp ? TMP3 : base, use_tmp ? 0 : offset0, STR_PTR, 0);
+#endif
+    if (opcode == OP_UPTO)
+      OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max);
+
+    detect_partial_match(common, &no_match);
+    label = LABEL();
+    compile_char1_matchingpath(common, type, cc, &no_char1_match, FALSE);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+    if (common->utf)
+      OP1(SLJIT_MOV, use_tmp ? TMP3 : base, use_tmp ? 0 : offset0, STR_PTR, 0);
+#endif
+
+    if (opcode == OP_UPTO)
+      {
+      OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+      add_jump(compiler, &no_match, JUMP(SLJIT_ZERO));
+      }
+
+    detect_partial_match_to(common, label);
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+    set_jumps(no_char1_match, LABEL());
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+    if (common->utf)
+      {
+      set_jumps(no_match, LABEL());
+      if (use_tmp)
+        {
+        OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0);
+        OP1(SLJIT_MOV, base, offset0, TMP3, 0);
+        }
+      else
+        OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+      }
+    else
+#endif
+      {
+      OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+      set_jumps(no_match, LABEL());
+      OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+      }
+
+    if (early_fail_ptr != 0)
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0);
+    }
+
+  BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL();
+  break;
+
+  case OP_MINSTAR:
+  if (private_data_ptr == 0)
+    allocate_stack(common, 1);
+  OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+  BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL();
+  if (early_fail_ptr != 0)
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0);
+  break;
+
+  case OP_MINUPTO:
+  SLJIT_ASSERT(early_fail_ptr == 0);
+  if (private_data_ptr == 0)
+    allocate_stack(common, 2);
+  OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+  OP1(SLJIT_MOV, base, offset1, SLJIT_IMM, max + 1);
+  BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL();
+  break;
+
+  case OP_QUERY:
+  case OP_MINQUERY:
+  SLJIT_ASSERT(early_fail_ptr == 0);
+  if (private_data_ptr == 0)
+    allocate_stack(common, 1);
+  OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+  if (opcode == OP_QUERY)
+    compile_char1_matchingpath(common, type, cc, &BACKTRACK_AS(char_iterator_backtrack)->u.backtracks, TRUE);
+  BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL();
+  break;
+
+  case OP_EXACT:
+  break;
+
+  case OP_POSSTAR:
+#if defined SUPPORT_UNICODE
+  if (type == OP_ALLANY && !common->invalid_utf)
+#else
+  if (type == OP_ALLANY)
+#endif
+    {
+    OP1(SLJIT_MOV, STR_PTR, 0, STR_END, 0);
+    process_partial_match(common);
+    if (early_fail_ptr != 0)
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_END, 0);
+    break;
+    }
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+  if (common->utf)
+    {
+    OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
+    detect_partial_match(common, &no_match);
+    label = LABEL();
+    compile_char1_matchingpath(common, type, cc, &no_match, FALSE);
+    OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
+    detect_partial_match_to(common, label);
+
+    set_jumps(no_match, LABEL());
+    OP1(SLJIT_MOV, STR_PTR, 0, tmp_base, tmp_offset);
+    if (early_fail_ptr != 0)
+      {
+      if (!HAS_VIRTUAL_REGISTERS && tmp_base == TMP3)
+        OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, TMP3, 0);
+      else
+        OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0);
+      }
+    break;
+    }
+#endif
+
+  detect_partial_match(common, &no_match);
+  label = LABEL();
+  compile_char1_matchingpath(common, type, cc, &no_char1_match, FALSE);
+  detect_partial_match_to(common, label);
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+  set_jumps(no_char1_match, LABEL());
+  OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  set_jumps(no_match, LABEL());
+  if (early_fail_ptr != 0)
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0);
+  break;
+
+  case OP_POSUPTO:
+  SLJIT_ASSERT(early_fail_ptr == 0);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+  if (common->utf)
+    {
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, STR_PTR, 0);
+    OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max);
+
+    detect_partial_match(common, &no_match);
+    label = LABEL();
+    compile_char1_matchingpath(common, type, cc, &no_match, FALSE);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, STR_PTR, 0);
+    OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+    add_jump(compiler, &no_match, JUMP(SLJIT_ZERO));
+    detect_partial_match_to(common, label);
+
+    set_jumps(no_match, LABEL());
+    OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1);
+    break;
+    }
+#endif
+
+  if (type == OP_ALLANY)
+    {
+    OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(max));
+
+    if (common->mode == PCRE2_JIT_COMPLETE)
+      {
+      OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_PTR, 0, STR_END, 0);
+      CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0);
+      }
+    else
+      {
+      jump = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, STR_END, 0);
+      process_partial_match(common);
+      JUMPHERE(jump);
+      }
+    break;
+    }
+
+  OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max);
+
+  detect_partial_match(common, &no_match);
+  label = LABEL();
+  compile_char1_matchingpath(common, type, cc, &no_char1_match, FALSE);
+  OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+  add_jump(compiler, &no_match, JUMP(SLJIT_ZERO));
+  detect_partial_match_to(common, label);
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+  set_jumps(no_char1_match, LABEL());
+  OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  set_jumps(no_match, LABEL());
+  break;
+
+  case OP_POSQUERY:
+  SLJIT_ASSERT(early_fail_ptr == 0);
+  OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
+  compile_char1_matchingpath(common, type, cc, &no_match, TRUE);
+  OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
+  set_jumps(no_match, LABEL());
+  OP1(SLJIT_MOV, STR_PTR, 0, tmp_base, tmp_offset);
+  break;
+
+  default:
+  SLJIT_UNREACHABLE();
+  break;
+  }
+
+count_match(common);
+return end;
+}
+
+static SLJIT_INLINE PCRE2_SPTR compile_fail_accept_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+
+PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL);
+
+if (*cc == OP_FAIL)
+  {
+  add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_JUMP));
+  return cc + 1;
+  }
+
+if (*cc == OP_ACCEPT && common->currententry == NULL && (common->re->overall_options & PCRE2_ENDANCHORED) != 0)
+  add_jump(compiler, &common->reset_match, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, STR_END, 0));
+
+if (*cc == OP_ASSERT_ACCEPT || common->currententry != NULL || !common->might_be_empty)
+  {
+  /* No need to check notempty conditions. */
+  if (common->accept_label == NULL)
+    add_jump(compiler, &common->accept, JUMP(SLJIT_JUMP));
+  else
+    JUMPTO(SLJIT_JUMP, common->accept_label);
+  return cc + 1;
+  }
+
+if (common->accept_label == NULL)
+  add_jump(compiler, &common->accept, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0)));
+else
+  CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), common->accept_label);
+
+if (HAS_VIRTUAL_REGISTERS)
+  {
+  OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+  OP1(SLJIT_MOV_U32, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, options));
+  }
+else
+  OP1(SLJIT_MOV_U32, TMP2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options));
+
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY);
+add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_NOT_ZERO));
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY_ATSTART);
+if (common->accept_label == NULL)
+  add_jump(compiler, &common->accept, JUMP(SLJIT_ZERO));
+else
+  JUMPTO(SLJIT_ZERO, common->accept_label);
+
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(HAS_VIRTUAL_REGISTERS ? TMP1 : ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, str));
+if (common->accept_label == NULL)
+  add_jump(compiler, &common->accept, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0));
+else
+  CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0, common->accept_label);
+add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_JUMP));
+return cc + 1;
+}
+
+static SLJIT_INLINE PCRE2_SPTR compile_close_matchingpath(compiler_common *common, PCRE2_SPTR cc)
+{
+DEFINE_COMPILER;
+int offset = GET2(cc, 1);
+BOOL optimized_cbracket = common->optimized_cbracket[offset] != 0;
+
+/* Data will be discarded anyway... */
+if (common->currententry != NULL)
+  return cc + 1 + IMM2_SIZE;
+
+if (!optimized_cbracket)
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR_PRIV(offset));
+offset <<= 1;
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0);
+if (!optimized_cbracket)
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0);
+return cc + 1 + IMM2_SIZE;
+}
+
+static SLJIT_INLINE PCRE2_SPTR compile_control_verb_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+PCRE2_UCHAR opcode = *cc;
+PCRE2_SPTR ccend = cc + 1;
+
+if (opcode == OP_COMMIT_ARG || opcode == OP_PRUNE_ARG ||
+    opcode == OP_SKIP_ARG || opcode == OP_THEN_ARG)
+  ccend += 2 + cc[1];
+
+PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL);
+
+if (opcode == OP_SKIP)
+  {
+  allocate_stack(common, 1);
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+  return ccend;
+  }
+
+if (opcode == OP_COMMIT_ARG || opcode == OP_PRUNE_ARG || opcode == OP_THEN_ARG)
+  {
+  if (HAS_VIRTUAL_REGISTERS)
+    OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)(cc + 2));
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, TMP2, 0);
+  OP1(SLJIT_MOV, SLJIT_MEM1(HAS_VIRTUAL_REGISTERS ? TMP1 : ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, mark_ptr), TMP2, 0);
+  }
+
+return ccend;
+}
+
+static PCRE2_UCHAR then_trap_opcode[1] = { OP_THEN_TRAP };
+
+static SLJIT_INLINE void compile_then_trap_matchingpath(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+BOOL needs_control_head;
+int size;
+
+PUSH_BACKTRACK_NOVALUE(sizeof(then_trap_backtrack), cc);
+common->then_trap = BACKTRACK_AS(then_trap_backtrack);
+BACKTRACK_AS(then_trap_backtrack)->common.cc = then_trap_opcode;
+BACKTRACK_AS(then_trap_backtrack)->start = (sljit_sw)(cc - common->start);
+BACKTRACK_AS(then_trap_backtrack)->framesize = get_framesize(common, cc, ccend, FALSE, &needs_control_head);
+
+size = BACKTRACK_AS(then_trap_backtrack)->framesize;
+size = 3 + (size < 0 ? 0 : size);
+
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+allocate_stack(common, size);
+if (size > 3)
+  OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0, SLJIT_IMM, (size - 3) * sizeof(sljit_sw));
+else
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0);
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 1), SLJIT_IMM, BACKTRACK_AS(then_trap_backtrack)->start);
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 2), SLJIT_IMM, type_then_trap);
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 3), TMP2, 0);
+
+size = BACKTRACK_AS(then_trap_backtrack)->framesize;
+if (size >= 0)
+  init_frame(common, cc, ccend, size - 1, 0);
+}
+
+static void compile_matchingpath(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+BOOL has_then_trap = FALSE;
+then_trap_backtrack *save_then_trap = NULL;
+
+SLJIT_ASSERT(*ccend == OP_END || (*ccend >= OP_ALT && *ccend <= OP_KETRPOS));
+
+if (common->has_then && common->then_offsets[cc - common->start] != 0)
+  {
+  SLJIT_ASSERT(*ccend != OP_END && common->control_head_ptr != 0);
+  has_then_trap = TRUE;
+  save_then_trap = common->then_trap;
+  /* Tail item on backtrack. */
+  compile_then_trap_matchingpath(common, cc, ccend, parent);
+  }
+
+while (cc < ccend)
+  {
+  switch(*cc)
+    {
+    case OP_SOD:
+    case OP_SOM:
+    case OP_NOT_WORD_BOUNDARY:
+    case OP_WORD_BOUNDARY:
+    case OP_EODN:
+    case OP_EOD:
+    case OP_DOLL:
+    case OP_DOLLM:
+    case OP_CIRC:
+    case OP_CIRCM:
+    case OP_REVERSE:
+    cc = compile_simple_assertion_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks);
+    break;
+
+    case OP_NOT_DIGIT:
+    case OP_DIGIT:
+    case OP_NOT_WHITESPACE:
+    case OP_WHITESPACE:
+    case OP_NOT_WORDCHAR:
+    case OP_WORDCHAR:
+    case OP_ANY:
+    case OP_ALLANY:
+    case OP_ANYBYTE:
+    case OP_NOTPROP:
+    case OP_PROP:
+    case OP_ANYNL:
+    case OP_NOT_HSPACE:
+    case OP_HSPACE:
+    case OP_NOT_VSPACE:
+    case OP_VSPACE:
+    case OP_EXTUNI:
+    case OP_NOT:
+    case OP_NOTI:
+    cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE);
+    break;
+
+    case OP_SET_SOM:
+    PUSH_BACKTRACK_NOVALUE(sizeof(backtrack_common), cc);
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0));
+    allocate_stack(common, 1);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), STR_PTR, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
+    cc++;
+    break;
+
+    case OP_CHAR:
+    case OP_CHARI:
+    if (common->mode == PCRE2_JIT_COMPLETE)
+      cc = compile_charn_matchingpath(common, cc, ccend, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks);
+    else
+      cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE);
+    break;
+
+    case OP_STAR:
+    case OP_MINSTAR:
+    case OP_PLUS:
+    case OP_MINPLUS:
+    case OP_QUERY:
+    case OP_MINQUERY:
+    case OP_UPTO:
+    case OP_MINUPTO:
+    case OP_EXACT:
+    case OP_POSSTAR:
+    case OP_POSPLUS:
+    case OP_POSQUERY:
+    case OP_POSUPTO:
+    case OP_STARI:
+    case OP_MINSTARI:
+    case OP_PLUSI:
+    case OP_MINPLUSI:
+    case OP_QUERYI:
+    case OP_MINQUERYI:
+    case OP_UPTOI:
+    case OP_MINUPTOI:
+    case OP_EXACTI:
+    case OP_POSSTARI:
+    case OP_POSPLUSI:
+    case OP_POSQUERYI:
+    case OP_POSUPTOI:
+    case OP_NOTSTAR:
+    case OP_NOTMINSTAR:
+    case OP_NOTPLUS:
+    case OP_NOTMINPLUS:
+    case OP_NOTQUERY:
+    case OP_NOTMINQUERY:
+    case OP_NOTUPTO:
+    case OP_NOTMINUPTO:
+    case OP_NOTEXACT:
+    case OP_NOTPOSSTAR:
+    case OP_NOTPOSPLUS:
+    case OP_NOTPOSQUERY:
+    case OP_NOTPOSUPTO:
+    case OP_NOTSTARI:
+    case OP_NOTMINSTARI:
+    case OP_NOTPLUSI:
+    case OP_NOTMINPLUSI:
+    case OP_NOTQUERYI:
+    case OP_NOTMINQUERYI:
+    case OP_NOTUPTOI:
+    case OP_NOTMINUPTOI:
+    case OP_NOTEXACTI:
+    case OP_NOTPOSSTARI:
+    case OP_NOTPOSPLUSI:
+    case OP_NOTPOSQUERYI:
+    case OP_NOTPOSUPTOI:
+    case OP_TYPESTAR:
+    case OP_TYPEMINSTAR:
+    case OP_TYPEPLUS:
+    case OP_TYPEMINPLUS:
+    case OP_TYPEQUERY:
+    case OP_TYPEMINQUERY:
+    case OP_TYPEUPTO:
+    case OP_TYPEMINUPTO:
+    case OP_TYPEEXACT:
+    case OP_TYPEPOSSTAR:
+    case OP_TYPEPOSPLUS:
+    case OP_TYPEPOSQUERY:
+    case OP_TYPEPOSUPTO:
+    cc = compile_iterator_matchingpath(common, cc, parent);
+    break;
+
+    case OP_CLASS:
+    case OP_NCLASS:
+    if (cc[1 + (32 / sizeof(PCRE2_UCHAR))] >= OP_CRSTAR && cc[1 + (32 / sizeof(PCRE2_UCHAR))] <= OP_CRPOSRANGE)
+      cc = compile_iterator_matchingpath(common, cc, parent);
+    else
+      cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE);
+    break;
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+    case OP_XCLASS:
+    if (*(cc + GET(cc, 1)) >= OP_CRSTAR && *(cc + GET(cc, 1)) <= OP_CRPOSRANGE)
+      cc = compile_iterator_matchingpath(common, cc, parent);
+    else
+      cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE);
+    break;
+#endif
+
+    case OP_REF:
+    case OP_REFI:
+    if (cc[1 + IMM2_SIZE] >= OP_CRSTAR && cc[1 + IMM2_SIZE] <= OP_CRPOSRANGE)
+      cc = compile_ref_iterator_matchingpath(common, cc, parent);
+    else
+      {
+      compile_ref_matchingpath(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE, FALSE);
+      cc += 1 + IMM2_SIZE;
+      }
+    break;
+
+    case OP_DNREF:
+    case OP_DNREFI:
+    if (cc[1 + 2 * IMM2_SIZE] >= OP_CRSTAR && cc[1 + 2 * IMM2_SIZE] <= OP_CRPOSRANGE)
+      cc = compile_ref_iterator_matchingpath(common, cc, parent);
+    else
+      {
+      compile_dnref_search(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks);
+      compile_ref_matchingpath(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE, FALSE);
+      cc += 1 + 2 * IMM2_SIZE;
+      }
+    break;
+
+    case OP_RECURSE:
+    cc = compile_recurse_matchingpath(common, cc, parent);
+    break;
+
+    case OP_CALLOUT:
+    case OP_CALLOUT_STR:
+    cc = compile_callout_matchingpath(common, cc, parent);
+    break;
+
+    case OP_ASSERT:
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK:
+    case OP_ASSERTBACK_NOT:
+    PUSH_BACKTRACK_NOVALUE(sizeof(assert_backtrack), cc);
+    cc = compile_assert_matchingpath(common, cc, BACKTRACK_AS(assert_backtrack), FALSE);
+    break;
+
+    case OP_BRAMINZERO:
+    PUSH_BACKTRACK_NOVALUE(sizeof(braminzero_backtrack), cc);
+    cc = bracketend(cc + 1);
+    if (*(cc - 1 - LINK_SIZE) != OP_KETRMIN)
+      {
+      allocate_stack(common, 1);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+      }
+    else
+      {
+      allocate_stack(common, 2);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), STR_PTR, 0);
+      }
+    BACKTRACK_AS(braminzero_backtrack)->matchingpath = LABEL();
+    count_match(common);
+    break;
+
+    case OP_ASSERT_NA:
+    case OP_ASSERTBACK_NA:
+    case OP_ONCE:
+    case OP_SCRIPT_RUN:
+    case OP_BRA:
+    case OP_CBRA:
+    case OP_COND:
+    case OP_SBRA:
+    case OP_SCBRA:
+    case OP_SCOND:
+    cc = compile_bracket_matchingpath(common, cc, parent);
+    break;
+
+    case OP_BRAZERO:
+    if (cc[1] > OP_ASSERTBACK_NOT)
+      cc = compile_bracket_matchingpath(common, cc, parent);
+    else
+      {
+      PUSH_BACKTRACK_NOVALUE(sizeof(assert_backtrack), cc);
+      cc = compile_assert_matchingpath(common, cc, BACKTRACK_AS(assert_backtrack), FALSE);
+      }
+    break;
+
+    case OP_BRAPOS:
+    case OP_CBRAPOS:
+    case OP_SBRAPOS:
+    case OP_SCBRAPOS:
+    case OP_BRAPOSZERO:
+    cc = compile_bracketpos_matchingpath(common, cc, parent);
+    break;
+
+    case OP_MARK:
+    PUSH_BACKTRACK_NOVALUE(sizeof(backtrack_common), cc);
+    SLJIT_ASSERT(common->mark_ptr != 0);
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr);
+    allocate_stack(common, common->has_skip_arg ? 5 : 1);
+    if (HAS_VIRTUAL_REGISTERS)
+      OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(common->has_skip_arg ? 4 : 0), TMP2, 0);
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)(cc + 2));
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, TMP2, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(HAS_VIRTUAL_REGISTERS ? TMP1 : ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, mark_ptr), TMP2, 0);
+    if (common->has_skip_arg)
+      {
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, type_mark);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), SLJIT_IMM, (sljit_sw)(cc + 2));
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(3), STR_PTR, 0);
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0);
+      }
+    cc += 1 + 2 + cc[1];
+    break;
+
+    case OP_PRUNE:
+    case OP_PRUNE_ARG:
+    case OP_SKIP:
+    case OP_SKIP_ARG:
+    case OP_THEN:
+    case OP_THEN_ARG:
+    case OP_COMMIT:
+    case OP_COMMIT_ARG:
+    cc = compile_control_verb_matchingpath(common, cc, parent);
+    break;
+
+    case OP_FAIL:
+    case OP_ACCEPT:
+    case OP_ASSERT_ACCEPT:
+    cc = compile_fail_accept_matchingpath(common, cc, parent);
+    break;
+
+    case OP_CLOSE:
+    cc = compile_close_matchingpath(common, cc);
+    break;
+
+    case OP_SKIPZERO:
+    cc = bracketend(cc + 1);
+    break;
+
+    default:
+    SLJIT_UNREACHABLE();
+    return;
+    }
+  if (cc == NULL)
+    return;
+  }
+
+if (has_then_trap)
+  {
+  /* Head item on backtrack. */
+  PUSH_BACKTRACK_NOVALUE(sizeof(then_trap_backtrack), cc);
+  BACKTRACK_AS(then_trap_backtrack)->common.cc = then_trap_opcode;
+  BACKTRACK_AS(then_trap_backtrack)->then_trap = common->then_trap;
+  common->then_trap = save_then_trap;
+  }
+SLJIT_ASSERT(cc == ccend);
+}
+
+#undef PUSH_BACKTRACK
+#undef PUSH_BACKTRACK_NOVALUE
+#undef BACKTRACK_AS
+
+#define COMPILE_BACKTRACKINGPATH(current) \
+  do \
+    { \
+    compile_backtrackingpath(common, (current)); \
+    if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) \
+      return; \
+    } \
+  while (0)
+
+#define CURRENT_AS(type) ((type *)current)
+
+static void compile_iterator_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+PCRE2_SPTR cc = current->cc;
+PCRE2_UCHAR opcode;
+PCRE2_UCHAR type;
+sljit_u32 max = 0, exact;
+struct sljit_label *label = NULL;
+struct sljit_jump *jump = NULL;
+jump_list *jumplist = NULL;
+PCRE2_SPTR end;
+int private_data_ptr = PRIVATE_DATA(cc);
+int base = (private_data_ptr == 0) ? SLJIT_MEM1(STACK_TOP) : SLJIT_MEM1(SLJIT_SP);
+int offset0 = (private_data_ptr == 0) ? STACK(0) : private_data_ptr;
+int offset1 = (private_data_ptr == 0) ? STACK(1) : private_data_ptr + (int)sizeof(sljit_sw);
+
+cc = get_iterator_parameters(common, cc, &opcode, &type, &max, &exact, &end);
+
+switch(opcode)
+  {
+  case OP_STAR:
+  case OP_UPTO:
+  if (type == OP_ANYNL || type == OP_EXTUNI)
+    {
+    SLJIT_ASSERT(private_data_ptr == 0);
+    set_jumps(CURRENT_AS(char_iterator_backtrack)->u.backtracks, LABEL());
+    OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    free_stack(common, 1);
+    CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(char_iterator_backtrack)->matchingpath);
+    }
+  else
+    {
+    if (CURRENT_AS(char_iterator_backtrack)->u.charpos.enabled)
+      {
+      OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+      OP1(SLJIT_MOV, TMP2, 0, base, offset1);
+      OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+      jump = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0);
+      label = LABEL();
+      OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+      OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+      if (CURRENT_AS(char_iterator_backtrack)->u.charpos.othercasebit != 0)
+        OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, CURRENT_AS(char_iterator_backtrack)->u.charpos.othercasebit);
+      CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CURRENT_AS(char_iterator_backtrack)->u.charpos.chr, CURRENT_AS(char_iterator_backtrack)->matchingpath);
+      move_back(common, NULL, TRUE);
+      CMPTO(SLJIT_GREATER, STR_PTR, 0, TMP2, 0, label);
+      }
+    else
+      {
+      OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+      jump = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, base, offset1);
+      move_back(common, NULL, TRUE);
+      OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+      JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath);
+      }
+    JUMPHERE(jump);
+    if (private_data_ptr == 0)
+      free_stack(common, 2);
+    }
+  break;
+
+  case OP_MINSTAR:
+  OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+  compile_char1_matchingpath(common, type, cc, &jumplist, TRUE);
+  OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+  JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath);
+  set_jumps(jumplist, LABEL());
+  if (private_data_ptr == 0)
+    free_stack(common, 1);
+  break;
+
+  case OP_MINUPTO:
+  OP1(SLJIT_MOV, TMP1, 0, base, offset1);
+  OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+  OP2(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+  add_jump(compiler, &jumplist, JUMP(SLJIT_ZERO));
+
+  OP1(SLJIT_MOV, base, offset1, TMP1, 0);
+  compile_char1_matchingpath(common, type, cc, &jumplist, TRUE);
+  OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+  JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath);
+
+  set_jumps(jumplist, LABEL());
+  if (private_data_ptr == 0)
+    free_stack(common, 2);
+  break;
+
+  case OP_QUERY:
+  OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+  OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0);
+  CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(char_iterator_backtrack)->matchingpath);
+  jump = JUMP(SLJIT_JUMP);
+  set_jumps(CURRENT_AS(char_iterator_backtrack)->u.backtracks, LABEL());
+  OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+  OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0);
+  JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath);
+  JUMPHERE(jump);
+  if (private_data_ptr == 0)
+    free_stack(common, 1);
+  break;
+
+  case OP_MINQUERY:
+  OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+  OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0);
+  jump = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
+  compile_char1_matchingpath(common, type, cc, &jumplist, TRUE);
+  JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath);
+  set_jumps(jumplist, LABEL());
+  JUMPHERE(jump);
+  if (private_data_ptr == 0)
+    free_stack(common, 1);
+  break;
+
+  case OP_EXACT:
+  case OP_POSSTAR:
+  case OP_POSQUERY:
+  case OP_POSUPTO:
+  break;
+
+  default:
+  SLJIT_UNREACHABLE();
+  break;
+  }
+
+set_jumps(current->topbacktracks, LABEL());
+}
+
+static SLJIT_INLINE void compile_ref_iterator_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+PCRE2_SPTR cc = current->cc;
+BOOL ref = (*cc == OP_REF || *cc == OP_REFI);
+PCRE2_UCHAR type;
+
+type = cc[ref ? 1 + IMM2_SIZE : 1 + 2 * IMM2_SIZE];
+
+if ((type & 0x1) == 0)
+  {
+  /* Maximize case. */
+  set_jumps(current->topbacktracks, LABEL());
+  OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+  free_stack(common, 1);
+  CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(ref_iterator_backtrack)->matchingpath);
+  return;
+  }
+
+OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(ref_iterator_backtrack)->matchingpath);
+set_jumps(current->topbacktracks, LABEL());
+free_stack(common, ref ? 2 : 3);
+}
+
+static SLJIT_INLINE void compile_recurse_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+recurse_entry *entry;
+
+if (!CURRENT_AS(recurse_backtrack)->inlined_pattern)
+  {
+  entry = CURRENT_AS(recurse_backtrack)->entry;
+  if (entry->backtrack_label == NULL)
+    add_jump(compiler, &entry->backtrack_calls, JUMP(SLJIT_FAST_CALL));
+  else
+    JUMPTO(SLJIT_FAST_CALL, entry->backtrack_label);
+  CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, CURRENT_AS(recurse_backtrack)->matchingpath);
+  }
+else
+  compile_backtrackingpath(common, current->top);
+
+set_jumps(current->topbacktracks, LABEL());
+}
+
+static void compile_assert_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+PCRE2_SPTR cc = current->cc;
+PCRE2_UCHAR bra = OP_BRA;
+struct sljit_jump *brajump = NULL;
+
+SLJIT_ASSERT(*cc != OP_BRAMINZERO);
+if (*cc == OP_BRAZERO)
+  {
+  bra = *cc;
+  cc++;
+  }
+
+if (bra == OP_BRAZERO)
+  {
+  SLJIT_ASSERT(current->topbacktracks == NULL);
+  OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+  }
+
+if (CURRENT_AS(assert_backtrack)->framesize < 0)
+  {
+  set_jumps(current->topbacktracks, LABEL());
+
+  if (bra == OP_BRAZERO)
+    {
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+    CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(assert_backtrack)->matchingpath);
+    free_stack(common, 1);
+    }
+  return;
+  }
+
+if (bra == OP_BRAZERO)
+  {
+  if (*cc == OP_ASSERT_NOT || *cc == OP_ASSERTBACK_NOT)
+    {
+    OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+    CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(assert_backtrack)->matchingpath);
+    free_stack(common, 1);
+    return;
+    }
+  free_stack(common, 1);
+  brajump = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
+  }
+
+if (*cc == OP_ASSERT || *cc == OP_ASSERTBACK)
+  {
+  OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(assert_backtrack)->private_data_ptr);
+  add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2));
+  OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(assert_backtrack)->framesize - 1) * sizeof(sljit_sw));
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(assert_backtrack)->private_data_ptr, TMP1, 0);
+
+  set_jumps(current->topbacktracks, LABEL());
+  }
+else
+  set_jumps(current->topbacktracks, LABEL());
+
+if (bra == OP_BRAZERO)
+  {
+  /* We know there is enough place on the stack. */
+  OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+  JUMPTO(SLJIT_JUMP, CURRENT_AS(assert_backtrack)->matchingpath);
+  JUMPHERE(brajump);
+  }
+}
+
+static void compile_bracket_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+int opcode, stacksize, alt_count, alt_max;
+int offset = 0;
+int private_data_ptr = CURRENT_AS(bracket_backtrack)->private_data_ptr;
+int repeat_ptr = 0, repeat_type = 0, repeat_count = 0;
+PCRE2_SPTR cc = current->cc;
+PCRE2_SPTR ccbegin;
+PCRE2_SPTR ccprev;
+PCRE2_UCHAR bra = OP_BRA;
+PCRE2_UCHAR ket;
+assert_backtrack *assert;
+BOOL has_alternatives;
+BOOL needs_control_head = FALSE;
+struct sljit_jump *brazero = NULL;
+struct sljit_jump *next_alt = NULL;
+struct sljit_jump *once = NULL;
+struct sljit_jump *cond = NULL;
+struct sljit_label *rmin_label = NULL;
+struct sljit_label *exact_label = NULL;
+struct sljit_put_label *put_label = NULL;
+
+if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO)
+  {
+  bra = *cc;
+  cc++;
+  }
+
+opcode = *cc;
+ccbegin = bracketend(cc) - 1 - LINK_SIZE;
+ket = *ccbegin;
+if (ket == OP_KET && PRIVATE_DATA(ccbegin) != 0)
+  {
+  repeat_ptr = PRIVATE_DATA(ccbegin);
+  repeat_type = PRIVATE_DATA(ccbegin + 2);
+  repeat_count = PRIVATE_DATA(ccbegin + 3);
+  SLJIT_ASSERT(repeat_type != 0 && repeat_count != 0);
+  if (repeat_type == OP_UPTO)
+    ket = OP_KETRMAX;
+  if (repeat_type == OP_MINUPTO)
+    ket = OP_KETRMIN;
+  }
+ccbegin = cc;
+cc += GET(cc, 1);
+has_alternatives = *cc == OP_ALT;
+if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND))
+  has_alternatives = (ccbegin[1 + LINK_SIZE] >= OP_ASSERT && ccbegin[1 + LINK_SIZE] <= OP_ASSERTBACK_NOT) || CURRENT_AS(bracket_backtrack)->u.condfailed != NULL;
+if (opcode == OP_CBRA || opcode == OP_SCBRA)
+  offset = (GET2(ccbegin, 1 + LINK_SIZE)) << 1;
+if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN))
+  opcode = OP_SCOND;
+
+alt_max = has_alternatives ? no_alternatives(ccbegin) : 0;
+
+/* Decoding the needs_control_head in framesize. */
+if (opcode == OP_ONCE)
+  {
+  needs_control_head = (CURRENT_AS(bracket_backtrack)->u.framesize & 0x1) != 0;
+  CURRENT_AS(bracket_backtrack)->u.framesize >>= 1;
+  }
+
+if (ket != OP_KET && repeat_type != 0)
+  {
+  /* TMP1 is used in OP_KETRMIN below. */
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+  free_stack(common, 1);
+  if (repeat_type == OP_UPTO)
+    OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), repeat_ptr, TMP1, 0, SLJIT_IMM, 1);
+  else
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), repeat_ptr, TMP1, 0);
+  }
+
+if (ket == OP_KETRMAX)
+  {
+  if (bra == OP_BRAZERO)
+    {
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    free_stack(common, 1);
+    brazero = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0);
+    }
+  }
+else if (ket == OP_KETRMIN)
+  {
+  if (bra != OP_BRAMINZERO)
+    {
+    OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    if (repeat_type != 0)
+      {
+      /* TMP1 was set a few lines above. */
+      CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, CURRENT_AS(bracket_backtrack)->recursive_matchingpath);
+      /* Drop STR_PTR for non-greedy plus quantifier. */
+      if (opcode != OP_ONCE)
+        free_stack(common, 1);
+      }
+    else if (opcode >= OP_SBRA || opcode == OP_ONCE)
+      {
+      /* Checking zero-length iteration. */
+      if (opcode != OP_ONCE || CURRENT_AS(bracket_backtrack)->u.framesize < 0)
+        CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, CURRENT_AS(bracket_backtrack)->recursive_matchingpath);
+      else
+        {
+        OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+        CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), STACK(-CURRENT_AS(bracket_backtrack)->u.framesize - 2), CURRENT_AS(bracket_backtrack)->recursive_matchingpath);
+        }
+      /* Drop STR_PTR for non-greedy plus quantifier. */
+      if (opcode != OP_ONCE)
+        free_stack(common, 1);
+      }
+    else
+      JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->recursive_matchingpath);
+    }
+  rmin_label = LABEL();
+  if (repeat_type != 0)
+    OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1);
+  }
+else if (bra == OP_BRAZERO)
+  {
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+  free_stack(common, 1);
+  brazero = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0);
+  }
+else if (repeat_type == OP_EXACT)
+  {
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1);
+  exact_label = LABEL();
+  }
+
+if (offset != 0)
+  {
+  if (common->capture_last_ptr != 0)
+    {
+    SLJIT_ASSERT(common->optimized_cbracket[offset >> 1] == 0);
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, TMP1, 0);
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(2));
+    free_stack(common, 3);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP2, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP1, 0);
+    }
+  else if (common->optimized_cbracket[offset >> 1] == 0)
+    {
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+    free_stack(common, 2);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP2, 0);
+    }
+  }
+
+if (SLJIT_UNLIKELY(opcode == OP_ONCE))
+  {
+  if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0)
+    {
+    OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+    add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+    OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(bracket_backtrack)->u.framesize - 1) * sizeof(sljit_sw));
+    }
+  once = JUMP(SLJIT_JUMP);
+  }
+else if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND))
+  {
+  if (has_alternatives)
+    {
+    /* Always exactly one alternative. */
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    free_stack(common, 1);
+
+    alt_max = 2;
+    next_alt = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0);
+    }
+  }
+else if (has_alternatives)
+  {
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+  free_stack(common, 1);
+
+  if (alt_max > 3)
+    {
+    sljit_emit_ijump(compiler, SLJIT_JUMP, TMP1, 0);
+
+    SLJIT_ASSERT(CURRENT_AS(bracket_backtrack)->u.matching_put_label);
+    sljit_set_put_label(CURRENT_AS(bracket_backtrack)->u.matching_put_label, LABEL());
+    sljit_emit_op0(compiler, SLJIT_ENDBR);
+    }
+  else
+    next_alt = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0);
+  }
+
+COMPILE_BACKTRACKINGPATH(current->top);
+if (current->topbacktracks)
+  set_jumps(current->topbacktracks, LABEL());
+
+if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND))
+  {
+  /* Conditional block always has at most one alternative. */
+  if (ccbegin[1 + LINK_SIZE] >= OP_ASSERT && ccbegin[1 + LINK_SIZE] <= OP_ASSERTBACK_NOT)
+    {
+    SLJIT_ASSERT(has_alternatives);
+    assert = CURRENT_AS(bracket_backtrack)->u.assert;
+    if (assert->framesize >= 0 && (ccbegin[1 + LINK_SIZE] == OP_ASSERT || ccbegin[1 + LINK_SIZE] == OP_ASSERTBACK))
+      {
+      OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr);
+      add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2));
+      OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (assert->framesize - 1) * sizeof(sljit_sw));
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, TMP1, 0);
+      }
+    cond = JUMP(SLJIT_JUMP);
+    set_jumps(CURRENT_AS(bracket_backtrack)->u.assert->condfailed, LABEL());
+    }
+  else if (CURRENT_AS(bracket_backtrack)->u.condfailed != NULL)
+    {
+    SLJIT_ASSERT(has_alternatives);
+    cond = JUMP(SLJIT_JUMP);
+    set_jumps(CURRENT_AS(bracket_backtrack)->u.condfailed, LABEL());
+    }
+  else
+    SLJIT_ASSERT(!has_alternatives);
+  }
+
+if (has_alternatives)
+  {
+  alt_count = 1;
+  do
+    {
+    current->top = NULL;
+    current->topbacktracks = NULL;
+    current->nextbacktracks = NULL;
+    /* Conditional blocks always have an additional alternative, even if it is empty. */
+    if (*cc == OP_ALT)
+      {
+      ccprev = cc + 1 + LINK_SIZE;
+      cc += GET(cc, 1);
+      if (opcode != OP_COND && opcode != OP_SCOND)
+        {
+        if (opcode != OP_ONCE)
+          {
+          if (private_data_ptr != 0)
+            OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+          else
+            OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+          }
+        else
+          OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(needs_control_head ? 1 : 0));
+        }
+      compile_matchingpath(common, ccprev, cc, current);
+      if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+        return;
+
+      if (opcode == OP_ASSERT_NA || opcode == OP_ASSERTBACK_NA)
+        OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+
+      if (opcode == OP_SCRIPT_RUN)
+        match_script_run_common(common, private_data_ptr, current);
+      }
+
+    /* Instructions after the current alternative is successfully matched. */
+    /* There is a similar code in compile_bracket_matchingpath. */
+    if (opcode == OP_ONCE)
+      match_once_common(common, ket, CURRENT_AS(bracket_backtrack)->u.framesize, private_data_ptr, has_alternatives, needs_control_head);
+
+    stacksize = 0;
+    if (repeat_type == OP_MINUPTO)
+      {
+      /* We need to preserve the counter. TMP2 will be used below. */
+      OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), repeat_ptr);
+      stacksize++;
+      }
+    if (ket != OP_KET || bra != OP_BRA)
+      stacksize++;
+    if (offset != 0)
+      {
+      if (common->capture_last_ptr != 0)
+        stacksize++;
+      if (common->optimized_cbracket[offset >> 1] == 0)
+        stacksize += 2;
+      }
+    if (opcode != OP_ONCE)
+      stacksize++;
+
+    if (stacksize > 0)
+      allocate_stack(common, stacksize);
+
+    stacksize = 0;
+    if (repeat_type == OP_MINUPTO)
+      {
+      /* TMP2 was set above. */
+      OP2(SLJIT_SUB, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP2, 0, SLJIT_IMM, 1);
+      stacksize++;
+      }
+
+    if (ket != OP_KET || bra != OP_BRA)
+      {
+      if (ket != OP_KET)
+        OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0);
+      else
+        OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0);
+      stacksize++;
+      }
+
+    if (offset != 0)
+      stacksize = match_capture_common(common, stacksize, offset, private_data_ptr);
+
+    if (opcode != OP_ONCE)
+      {
+      if (alt_max <= 3)
+        OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, alt_count);
+      else
+        put_label = sljit_emit_put_label(compiler, SLJIT_MEM1(STACK_TOP), STACK(stacksize));
+      }
+
+    if (offset != 0 && ket == OP_KETRMAX && common->optimized_cbracket[offset >> 1] != 0)
+      {
+      /* If ket is not OP_KETRMAX, this code path is executed after the jump to alternative_matchingpath. */
+      SLJIT_ASSERT(private_data_ptr == OVECTOR(offset + 0));
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0);
+      }
+
+    JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->alternative_matchingpath);
+
+    if (opcode != OP_ONCE)
+      {
+      if (alt_max <= 3)
+        {
+        JUMPHERE(next_alt);
+        alt_count++;
+        if (alt_count < alt_max)
+          {
+          SLJIT_ASSERT(alt_count == 2 && alt_max == 3);
+          next_alt = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 1);
+          }
+        }
+      else
+        {
+        sljit_set_put_label(put_label, LABEL());
+        sljit_emit_op0(compiler, SLJIT_ENDBR);
+        }
+      }
+
+    COMPILE_BACKTRACKINGPATH(current->top);
+    if (current->topbacktracks)
+      set_jumps(current->topbacktracks, LABEL());
+    SLJIT_ASSERT(!current->nextbacktracks);
+    }
+  while (*cc == OP_ALT);
+
+  if (cond != NULL)
+    {
+    SLJIT_ASSERT(opcode == OP_COND || opcode == OP_SCOND);
+    assert = CURRENT_AS(bracket_backtrack)->u.assert;
+    if ((ccbegin[1 + LINK_SIZE] == OP_ASSERT_NOT || ccbegin[1 + LINK_SIZE] == OP_ASSERTBACK_NOT) && assert->framesize >= 0)
+      {
+      OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr);
+      add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2));
+      OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (assert->framesize - 1) * sizeof(sljit_sw));
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, TMP1, 0);
+      }
+    JUMPHERE(cond);
+    }
+
+  /* Free the STR_PTR. */
+  if (private_data_ptr == 0)
+    free_stack(common, 1);
+  }
+
+if (offset != 0)
+  {
+  /* Using both tmp register is better for instruction scheduling. */
+  if (common->optimized_cbracket[offset >> 1] != 0)
+    {
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+    free_stack(common, 2);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP2, 0);
+    }
+  else
+    {
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    free_stack(common, 1);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0);
+    }
+  }
+else if (opcode == OP_ASSERT_NA || opcode == OP_ASSERTBACK_NA || opcode == OP_SCRIPT_RUN || opcode == OP_SBRA || opcode == OP_SCOND)
+  {
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(0));
+  free_stack(common, 1);
+  }
+else if (opcode == OP_ONCE)
+  {
+  cc = ccbegin + GET(ccbegin, 1);
+  stacksize = needs_control_head ? 1 : 0;
+
+  if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0)
+    {
+    /* Reset head and drop saved frame. */
+    stacksize += CURRENT_AS(bracket_backtrack)->u.framesize + ((ket != OP_KET || *cc == OP_ALT) ? 2 : 1);
+    }
+  else if (ket == OP_KETRMAX || (*cc == OP_ALT && ket != OP_KETRMIN))
+    {
+    /* The STR_PTR must be released. */
+    stacksize++;
+    }
+
+  if (stacksize > 0)
+    free_stack(common, stacksize);
+
+  JUMPHERE(once);
+  /* Restore previous private_data_ptr */
+  if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0)
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-CURRENT_AS(bracket_backtrack)->u.framesize - 1));
+  else if (ket == OP_KETRMIN)
+    {
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+    /* See the comment below. */
+    free_stack(common, 2);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0);
+    }
+  }
+
+if (repeat_type == OP_EXACT)
+  {
+  OP2(SLJIT_ADD, TMP1, 0, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1);
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), repeat_ptr, TMP1, 0);
+  CMPTO(SLJIT_LESS_EQUAL, TMP1, 0, SLJIT_IMM, repeat_count, exact_label);
+  }
+else if (ket == OP_KETRMAX)
+  {
+  OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+  if (bra != OP_BRAZERO)
+    free_stack(common, 1);
+
+  CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(bracket_backtrack)->recursive_matchingpath);
+  if (bra == OP_BRAZERO)
+    {
+    OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+    JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->zero_matchingpath);
+    JUMPHERE(brazero);
+    free_stack(common, 1);
+    }
+  }
+else if (ket == OP_KETRMIN)
+  {
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+
+  /* OP_ONCE removes everything in case of a backtrack, so we don't
+  need to explicitly release the STR_PTR. The extra release would
+  affect badly the free_stack(2) above. */
+  if (opcode != OP_ONCE)
+    free_stack(common, 1);
+  CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, rmin_label);
+  if (opcode == OP_ONCE)
+    free_stack(common, bra == OP_BRAMINZERO ? 2 : 1);
+  else if (bra == OP_BRAMINZERO)
+    free_stack(common, 1);
+  }
+else if (bra == OP_BRAZERO)
+  {
+  OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+  JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->zero_matchingpath);
+  JUMPHERE(brazero);
+  }
+}
+
+static SLJIT_INLINE void compile_bracketpos_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+int offset;
+struct sljit_jump *jump;
+
+if (CURRENT_AS(bracketpos_backtrack)->framesize < 0)
+  {
+  if (*current->cc == OP_CBRAPOS || *current->cc == OP_SCBRAPOS)
+    {
+    offset = (GET2(current->cc, 1 + LINK_SIZE)) << 1;
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0);
+    if (common->capture_last_ptr != 0)
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(2));
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP2, 0);
+    if (common->capture_last_ptr != 0)
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, TMP1, 0);
+    }
+  set_jumps(current->topbacktracks, LABEL());
+  free_stack(common, CURRENT_AS(bracketpos_backtrack)->stacksize);
+  return;
+  }
+
+OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(bracketpos_backtrack)->private_data_ptr);
+add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(bracketpos_backtrack)->framesize - 1) * sizeof(sljit_sw));
+
+if (current->topbacktracks)
+  {
+  jump = JUMP(SLJIT_JUMP);
+  set_jumps(current->topbacktracks, LABEL());
+  /* Drop the stack frame. */
+  free_stack(common, CURRENT_AS(bracketpos_backtrack)->stacksize);
+  JUMPHERE(jump);
+  }
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(bracketpos_backtrack)->private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-CURRENT_AS(bracketpos_backtrack)->framesize - 1));
+}
+
+static SLJIT_INLINE void compile_braminzero_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+assert_backtrack backtrack;
+
+current->top = NULL;
+current->topbacktracks = NULL;
+current->nextbacktracks = NULL;
+if (current->cc[1] > OP_ASSERTBACK_NOT)
+  {
+  /* Manual call of compile_bracket_matchingpath and compile_bracket_backtrackingpath. */
+  compile_bracket_matchingpath(common, current->cc, current);
+  compile_bracket_backtrackingpath(common, current->top);
+  }
+else
+  {
+  memset(&backtrack, 0, sizeof(backtrack));
+  backtrack.common.cc = current->cc;
+  backtrack.matchingpath = CURRENT_AS(braminzero_backtrack)->matchingpath;
+  /* Manual call of compile_assert_matchingpath. */
+  compile_assert_matchingpath(common, current->cc, &backtrack, FALSE);
+  }
+SLJIT_ASSERT(!current->nextbacktracks && !current->topbacktracks);
+}
+
+static SLJIT_INLINE void compile_control_verb_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+PCRE2_UCHAR opcode = *current->cc;
+struct sljit_label *loop;
+struct sljit_jump *jump;
+
+if (opcode == OP_THEN || opcode == OP_THEN_ARG)
+  {
+  if (common->then_trap != NULL)
+    {
+    SLJIT_ASSERT(common->control_head_ptr != 0);
+
+    OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, type_then_trap);
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, common->then_trap->start);
+    jump = JUMP(SLJIT_JUMP);
+
+    loop = LABEL();
+    OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    JUMPHERE(jump);
+    CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0, loop);
+    CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(2), TMP2, 0, loop);
+    add_jump(compiler, &common->then_trap->quit, JUMP(SLJIT_JUMP));
+    return;
+    }
+  else if (!common->local_quit_available && common->in_positive_assertion)
+    {
+    add_jump(compiler, &common->positive_assertion_quit, JUMP(SLJIT_JUMP));
+    return;
+    }
+  }
+
+if (common->local_quit_available)
+  {
+  /* Abort match with a fail. */
+  if (common->quit_label == NULL)
+    add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP));
+  else
+    JUMPTO(SLJIT_JUMP, common->quit_label);
+  return;
+  }
+
+if (opcode == OP_SKIP_ARG)
+  {
+  SLJIT_ASSERT(common->control_head_ptr != 0 && TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1);
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+  OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, (sljit_sw)(current->cc + 2));
+  sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(do_search_mark));
+
+  OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_R0, 0);
+  add_jump(compiler, &common->reset_match, CMP(SLJIT_NOT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 0));
+  return;
+  }
+
+if (opcode == OP_SKIP)
+  OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+else
+  OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_IMM, 0);
+add_jump(compiler, &common->reset_match, JUMP(SLJIT_JUMP));
+}
+
+static SLJIT_INLINE void compile_then_trap_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+int size;
+
+if (CURRENT_AS(then_trap_backtrack)->then_trap)
+  {
+  common->then_trap = CURRENT_AS(then_trap_backtrack)->then_trap;
+  return;
+  }
+
+size = CURRENT_AS(then_trap_backtrack)->framesize;
+size = 3 + (size < 0 ? 0 : size);
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(size - 3));
+free_stack(common, size);
+jump = JUMP(SLJIT_JUMP);
+
+set_jumps(CURRENT_AS(then_trap_backtrack)->quit, LABEL());
+/* STACK_TOP is set by THEN. */
+if (CURRENT_AS(then_trap_backtrack)->framesize >= 0)
+  {
+  add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+  OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(then_trap_backtrack)->framesize - 1) * sizeof(sljit_sw));
+  }
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+free_stack(common, 3);
+
+JUMPHERE(jump);
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, TMP1, 0);
+}
+
+static void compile_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+then_trap_backtrack *save_then_trap = common->then_trap;
+
+while (current)
+  {
+  if (current->nextbacktracks != NULL)
+    set_jumps(current->nextbacktracks, LABEL());
+  switch(*current->cc)
+    {
+    case OP_SET_SOM:
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    free_stack(common, 1);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), TMP1, 0);
+    break;
+
+    case OP_STAR:
+    case OP_MINSTAR:
+    case OP_PLUS:
+    case OP_MINPLUS:
+    case OP_QUERY:
+    case OP_MINQUERY:
+    case OP_UPTO:
+    case OP_MINUPTO:
+    case OP_EXACT:
+    case OP_POSSTAR:
+    case OP_POSPLUS:
+    case OP_POSQUERY:
+    case OP_POSUPTO:
+    case OP_STARI:
+    case OP_MINSTARI:
+    case OP_PLUSI:
+    case OP_MINPLUSI:
+    case OP_QUERYI:
+    case OP_MINQUERYI:
+    case OP_UPTOI:
+    case OP_MINUPTOI:
+    case OP_EXACTI:
+    case OP_POSSTARI:
+    case OP_POSPLUSI:
+    case OP_POSQUERYI:
+    case OP_POSUPTOI:
+    case OP_NOTSTAR:
+    case OP_NOTMINSTAR:
+    case OP_NOTPLUS:
+    case OP_NOTMINPLUS:
+    case OP_NOTQUERY:
+    case OP_NOTMINQUERY:
+    case OP_NOTUPTO:
+    case OP_NOTMINUPTO:
+    case OP_NOTEXACT:
+    case OP_NOTPOSSTAR:
+    case OP_NOTPOSPLUS:
+    case OP_NOTPOSQUERY:
+    case OP_NOTPOSUPTO:
+    case OP_NOTSTARI:
+    case OP_NOTMINSTARI:
+    case OP_NOTPLUSI:
+    case OP_NOTMINPLUSI:
+    case OP_NOTQUERYI:
+    case OP_NOTMINQUERYI:
+    case OP_NOTUPTOI:
+    case OP_NOTMINUPTOI:
+    case OP_NOTEXACTI:
+    case OP_NOTPOSSTARI:
+    case OP_NOTPOSPLUSI:
+    case OP_NOTPOSQUERYI:
+    case OP_NOTPOSUPTOI:
+    case OP_TYPESTAR:
+    case OP_TYPEMINSTAR:
+    case OP_TYPEPLUS:
+    case OP_TYPEMINPLUS:
+    case OP_TYPEQUERY:
+    case OP_TYPEMINQUERY:
+    case OP_TYPEUPTO:
+    case OP_TYPEMINUPTO:
+    case OP_TYPEEXACT:
+    case OP_TYPEPOSSTAR:
+    case OP_TYPEPOSPLUS:
+    case OP_TYPEPOSQUERY:
+    case OP_TYPEPOSUPTO:
+    case OP_CLASS:
+    case OP_NCLASS:
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+    case OP_XCLASS:
+#endif
+    compile_iterator_backtrackingpath(common, current);
+    break;
+
+    case OP_REF:
+    case OP_REFI:
+    case OP_DNREF:
+    case OP_DNREFI:
+    compile_ref_iterator_backtrackingpath(common, current);
+    break;
+
+    case OP_RECURSE:
+    compile_recurse_backtrackingpath(common, current);
+    break;
+
+    case OP_ASSERT:
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK:
+    case OP_ASSERTBACK_NOT:
+    compile_assert_backtrackingpath(common, current);
+    break;
+
+    case OP_ASSERT_NA:
+    case OP_ASSERTBACK_NA:
+    case OP_ONCE:
+    case OP_SCRIPT_RUN:
+    case OP_BRA:
+    case OP_CBRA:
+    case OP_COND:
+    case OP_SBRA:
+    case OP_SCBRA:
+    case OP_SCOND:
+    compile_bracket_backtrackingpath(common, current);
+    break;
+
+    case OP_BRAZERO:
+    if (current->cc[1] > OP_ASSERTBACK_NOT)
+      compile_bracket_backtrackingpath(common, current);
+    else
+      compile_assert_backtrackingpath(common, current);
+    break;
+
+    case OP_BRAPOS:
+    case OP_CBRAPOS:
+    case OP_SBRAPOS:
+    case OP_SCBRAPOS:
+    case OP_BRAPOSZERO:
+    compile_bracketpos_backtrackingpath(common, current);
+    break;
+
+    case OP_BRAMINZERO:
+    compile_braminzero_backtrackingpath(common, current);
+    break;
+
+    case OP_MARK:
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(common->has_skip_arg ? 4 : 0));
+    if (common->has_skip_arg)
+      OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    free_stack(common, common->has_skip_arg ? 5 : 1);
+    OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, TMP1, 0);
+    if (common->has_skip_arg)
+      OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, TMP2, 0);
+    break;
+
+    case OP_THEN:
+    case OP_THEN_ARG:
+    case OP_PRUNE:
+    case OP_PRUNE_ARG:
+    case OP_SKIP:
+    case OP_SKIP_ARG:
+    compile_control_verb_backtrackingpath(common, current);
+    break;
+
+    case OP_COMMIT:
+    case OP_COMMIT_ARG:
+    if (!common->local_quit_available)
+      OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH);
+    if (common->quit_label == NULL)
+      add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP));
+    else
+      JUMPTO(SLJIT_JUMP, common->quit_label);
+    break;
+
+    case OP_CALLOUT:
+    case OP_CALLOUT_STR:
+    case OP_FAIL:
+    case OP_ACCEPT:
+    case OP_ASSERT_ACCEPT:
+    set_jumps(current->topbacktracks, LABEL());
+    break;
+
+    case OP_THEN_TRAP:
+    /* A virtual opcode for then traps. */
+    compile_then_trap_backtrackingpath(common, current);
+    break;
+
+    default:
+    SLJIT_UNREACHABLE();
+    break;
+    }
+  current = current->prev;
+  }
+common->then_trap = save_then_trap;
+}
+
+static SLJIT_INLINE void compile_recurse(compiler_common *common)
+{
+DEFINE_COMPILER;
+PCRE2_SPTR cc = common->start + common->currententry->start;
+PCRE2_SPTR ccbegin = cc + 1 + LINK_SIZE + (*cc == OP_BRA ? 0 : IMM2_SIZE);
+PCRE2_SPTR ccend = bracketend(cc) - (1 + LINK_SIZE);
+BOOL needs_control_head;
+BOOL has_quit;
+BOOL has_accept;
+int private_data_size = get_recurse_data_length(common, ccbegin, ccend, &needs_control_head, &has_quit, &has_accept);
+int alt_count, alt_max, local_size;
+backtrack_common altbacktrack;
+jump_list *match = NULL;
+struct sljit_jump *next_alt = NULL;
+struct sljit_jump *accept_exit = NULL;
+struct sljit_label *quit;
+struct sljit_put_label *put_label = NULL;
+
+/* Recurse captures then. */
+common->then_trap = NULL;
+
+SLJIT_ASSERT(*cc == OP_BRA || *cc == OP_CBRA || *cc == OP_CBRAPOS || *cc == OP_SCBRA || *cc == OP_SCBRAPOS);
+
+alt_max = no_alternatives(cc);
+alt_count = 0;
+
+/* Matching path. */
+SLJIT_ASSERT(common->currententry->entry_label == NULL && common->recursive_head_ptr != 0);
+common->currententry->entry_label = LABEL();
+set_jumps(common->currententry->entry_calls, common->currententry->entry_label);
+
+sljit_emit_fast_enter(compiler, TMP2, 0);
+count_match(common);
+
+local_size = (alt_max > 1) ? 2 : 1;
+
+/* (Reversed) stack layout:
+   [private data][return address][optional: str ptr] ... [optional: alternative index][recursive_head_ptr] */
+
+allocate_stack(common, private_data_size + local_size);
+/* Save return address. */
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(local_size - 1), TMP2, 0);
+
+copy_recurse_data(common, ccbegin, ccend, recurse_copy_from_global, local_size, private_data_size + local_size, has_quit);
+
+/* This variable is saved and restored all time when we enter or exit from a recursive context. */
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr, STACK_TOP, 0);
+
+if (needs_control_head)
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0);
+
+if (alt_max > 1)
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+
+memset(&altbacktrack, 0, sizeof(backtrack_common));
+common->quit_label = NULL;
+common->accept_label = NULL;
+common->quit = NULL;
+common->accept = NULL;
+altbacktrack.cc = ccbegin;
+cc += GET(cc, 1);
+while (1)
+  {
+  altbacktrack.top = NULL;
+  altbacktrack.topbacktracks = NULL;
+
+  if (altbacktrack.cc != ccbegin)
+    OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+
+  compile_matchingpath(common, altbacktrack.cc, cc, &altbacktrack);
+  if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+    return;
+
+  allocate_stack(common, (alt_max > 1 || has_accept) ? 2 : 1);
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr);
+
+  if (alt_max > 1 || has_accept)
+    {
+    if (alt_max > 3)
+      put_label = sljit_emit_put_label(compiler, SLJIT_MEM1(STACK_TOP), STACK(1));
+    else
+      OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, alt_count);
+    }
+
+  add_jump(compiler, &match, JUMP(SLJIT_JUMP));
+
+  if (alt_count == 0)
+    {
+    /* Backtracking path entry. */
+    SLJIT_ASSERT(common->currententry->backtrack_label == NULL);
+    common->currententry->backtrack_label = LABEL();
+    set_jumps(common->currententry->backtrack_calls, common->currententry->backtrack_label);
+
+    sljit_emit_fast_enter(compiler, TMP1, 0);
+
+    if (has_accept)
+      accept_exit = CMP(SLJIT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, -1);
+
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+    /* Save return address. */
+    OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), STACK(local_size - 1), TMP1, 0);
+
+    copy_recurse_data(common, ccbegin, ccend, recurse_swap_global, local_size, private_data_size + local_size, has_quit);
+
+    if (alt_max > 1)
+      {
+      OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+      free_stack(common, 2);
+
+      if (alt_max > 3)
+        {
+        sljit_emit_ijump(compiler, SLJIT_JUMP, TMP1, 0);
+        sljit_set_put_label(put_label, LABEL());
+        sljit_emit_op0(compiler, SLJIT_ENDBR);
+        }
+      else
+        next_alt = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0);
+      }
+    else
+      free_stack(common, has_accept ? 2 : 1);
+    }
+  else if (alt_max > 3)
+    {
+    sljit_set_put_label(put_label, LABEL());
+    sljit_emit_op0(compiler, SLJIT_ENDBR);
+    }
+  else
+    {
+    JUMPHERE(next_alt);
+    if (alt_count + 1 < alt_max)
+      {
+      SLJIT_ASSERT(alt_count == 1 && alt_max == 3);
+      next_alt = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 1);
+      }
+    }
+
+  alt_count++;
+
+  compile_backtrackingpath(common, altbacktrack.top);
+  if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+    return;
+  set_jumps(altbacktrack.topbacktracks, LABEL());
+
+  if (*cc != OP_ALT)
+    break;
+
+  altbacktrack.cc = cc + 1 + LINK_SIZE;
+  cc += GET(cc, 1);
+  }
+
+/* No alternative is matched. */
+
+quit = LABEL();
+
+copy_recurse_data(common, ccbegin, ccend, recurse_copy_private_to_global, local_size, private_data_size + local_size, has_quit);
+
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(local_size - 1));
+free_stack(common, private_data_size + local_size);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
+OP_SRC(SLJIT_FAST_RETURN, TMP2, 0);
+
+if (common->quit != NULL)
+  {
+  SLJIT_ASSERT(has_quit);
+
+  set_jumps(common->quit, LABEL());
+  OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr);
+  copy_recurse_data(common, ccbegin, ccend, recurse_copy_shared_to_global, local_size, private_data_size + local_size, has_quit);
+  JUMPTO(SLJIT_JUMP, quit);
+  }
+
+if (has_accept)
+  {
+  JUMPHERE(accept_exit);
+  free_stack(common, 2);
+
+  /* Save return address. */
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(local_size - 1), TMP1, 0);
+
+  copy_recurse_data(common, ccbegin, ccend, recurse_copy_kept_shared_to_global, local_size, private_data_size + local_size, has_quit);
+
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(local_size - 1));
+  free_stack(common, private_data_size + local_size);
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
+  OP_SRC(SLJIT_FAST_RETURN, TMP2, 0);
+  }
+
+if (common->accept != NULL)
+  {
+  SLJIT_ASSERT(has_accept);
+
+  set_jumps(common->accept, LABEL());
+
+  OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr);
+  OP1(SLJIT_MOV, TMP2, 0, STACK_TOP, 0);
+
+  allocate_stack(common, 2);
+  OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, -1);
+  }
+
+set_jumps(match, LABEL());
+
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
+
+copy_recurse_data(common, ccbegin, ccend, recurse_swap_global, local_size, private_data_size + local_size, has_quit);
+
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP2), STACK(local_size - 1));
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 1);
+OP_SRC(SLJIT_FAST_RETURN, TMP2, 0);
+}
+
+#undef COMPILE_BACKTRACKINGPATH
+#undef CURRENT_AS
+
+#define PUBLIC_JIT_COMPILE_CONFIGURATION_OPTIONS \
+  (PCRE2_JIT_INVALID_UTF)
+
+static int jit_compile(pcre2_code *code, sljit_u32 mode)
+{
+pcre2_real_code *re = (pcre2_real_code *)code;
+struct sljit_compiler *compiler;
+backtrack_common rootbacktrack;
+compiler_common common_data;
+compiler_common *common = &common_data;
+const sljit_u8 *tables = re->tables;
+void *allocator_data = &re->memctl;
+int private_data_size;
+PCRE2_SPTR ccend;
+executable_functions *functions;
+void *executable_func;
+sljit_uw executable_size;
+sljit_uw total_length;
+struct sljit_label *mainloop_label = NULL;
+struct sljit_label *continue_match_label;
+struct sljit_label *empty_match_found_label = NULL;
+struct sljit_label *empty_match_backtrack_label = NULL;
+struct sljit_label *reset_match_label;
+struct sljit_label *quit_label;
+struct sljit_jump *jump;
+struct sljit_jump *minlength_check_failed = NULL;
+struct sljit_jump *empty_match = NULL;
+struct sljit_jump *end_anchor_failed = NULL;
+jump_list *reqcu_not_found = NULL;
+
+SLJIT_ASSERT(tables);
+
+#if HAS_VIRTUAL_REGISTERS == 1
+SLJIT_ASSERT(sljit_get_register_index(TMP3) < 0 && sljit_get_register_index(ARGUMENTS) < 0 && sljit_get_register_index(RETURN_ADDR) < 0);
+#elif HAS_VIRTUAL_REGISTERS == 0
+SLJIT_ASSERT(sljit_get_register_index(TMP3) >= 0 && sljit_get_register_index(ARGUMENTS) >= 0 && sljit_get_register_index(RETURN_ADDR) >= 0);
+#else
+#error "Invalid value for HAS_VIRTUAL_REGISTERS"
+#endif
+
+memset(&rootbacktrack, 0, sizeof(backtrack_common));
+memset(common, 0, sizeof(compiler_common));
+common->re = re;
+common->name_table = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code));
+rootbacktrack.cc = common->name_table + re->name_count * re->name_entry_size;
+
+#ifdef SUPPORT_UNICODE
+common->invalid_utf = (mode & PCRE2_JIT_INVALID_UTF) != 0;
+#endif /* SUPPORT_UNICODE */
+mode &= ~PUBLIC_JIT_COMPILE_CONFIGURATION_OPTIONS;
+
+common->start = rootbacktrack.cc;
+common->read_only_data_head = NULL;
+common->fcc = tables + fcc_offset;
+common->lcc = (sljit_sw)(tables + lcc_offset);
+common->mode = mode;
+common->might_be_empty = (re->minlength == 0) || (re->flags & PCRE2_MATCH_EMPTY);
+common->allow_empty_partial = (re->max_lookbehind > 0) || (re->flags & PCRE2_MATCH_EMPTY);
+common->nltype = NLTYPE_FIXED;
+switch(re->newline_convention)
+  {
+  case PCRE2_NEWLINE_CR: common->newline = CHAR_CR; break;
+  case PCRE2_NEWLINE_LF: common->newline = CHAR_NL; break;
+  case PCRE2_NEWLINE_CRLF: common->newline = (CHAR_CR << 8) | CHAR_NL; break;
+  case PCRE2_NEWLINE_ANY: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANY; break;
+  case PCRE2_NEWLINE_ANYCRLF: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANYCRLF; break;
+  case PCRE2_NEWLINE_NUL: common->newline = CHAR_NUL; break;
+  default: return PCRE2_ERROR_INTERNAL;
+  }
+common->nlmax = READ_CHAR_MAX;
+common->nlmin = 0;
+if (re->bsr_convention == PCRE2_BSR_UNICODE)
+  common->bsr_nltype = NLTYPE_ANY;
+else if (re->bsr_convention == PCRE2_BSR_ANYCRLF)
+  common->bsr_nltype = NLTYPE_ANYCRLF;
+else
+  {
+#ifdef BSR_ANYCRLF
+  common->bsr_nltype = NLTYPE_ANYCRLF;
+#else
+  common->bsr_nltype = NLTYPE_ANY;
+#endif
+  }
+common->bsr_nlmax = READ_CHAR_MAX;
+common->bsr_nlmin = 0;
+common->endonly = (re->overall_options & PCRE2_DOLLAR_ENDONLY) != 0;
+common->ctypes = (sljit_sw)(tables + ctypes_offset);
+common->name_count = re->name_count;
+common->name_entry_size = re->name_entry_size;
+common->unset_backref = (re->overall_options & PCRE2_MATCH_UNSET_BACKREF) != 0;
+common->alt_circumflex = (re->overall_options & PCRE2_ALT_CIRCUMFLEX) != 0;
+#ifdef SUPPORT_UNICODE
+/* PCRE_UTF[16|32] have the same value as PCRE_UTF8. */
+common->utf = (re->overall_options & PCRE2_UTF) != 0;
+common->ucp = (re->overall_options & PCRE2_UCP) != 0;
+if (common->utf)
+  {
+  if (common->nltype == NLTYPE_ANY)
+    common->nlmax = 0x2029;
+  else if (common->nltype == NLTYPE_ANYCRLF)
+    common->nlmax = (CHAR_CR > CHAR_NL) ? CHAR_CR : CHAR_NL;
+  else
+    {
+    /* We only care about the first newline character. */
+    common->nlmax = common->newline & 0xff;
+    }
+
+  if (common->nltype == NLTYPE_FIXED)
+    common->nlmin = common->newline & 0xff;
+  else
+    common->nlmin = (CHAR_CR < CHAR_NL) ? CHAR_CR : CHAR_NL;
+
+  if (common->bsr_nltype == NLTYPE_ANY)
+    common->bsr_nlmax = 0x2029;
+  else
+    common->bsr_nlmax = (CHAR_CR > CHAR_NL) ? CHAR_CR : CHAR_NL;
+  common->bsr_nlmin = (CHAR_CR < CHAR_NL) ? CHAR_CR : CHAR_NL;
+  }
+else
+  common->invalid_utf = FALSE;
+#endif /* SUPPORT_UNICODE */
+ccend = bracketend(common->start);
+
+/* Calculate the local space size on the stack. */
+common->ovector_start = LIMIT_MATCH + sizeof(sljit_sw);
+common->optimized_cbracket = (sljit_u8 *)SLJIT_MALLOC(re->top_bracket + 1, allocator_data);
+if (!common->optimized_cbracket)
+  return PCRE2_ERROR_NOMEMORY;
+#if defined DEBUG_FORCE_UNOPTIMIZED_CBRAS && DEBUG_FORCE_UNOPTIMIZED_CBRAS == 1
+memset(common->optimized_cbracket, 0, re->top_bracket + 1);
+#else
+memset(common->optimized_cbracket, 1, re->top_bracket + 1);
+#endif
+
+SLJIT_ASSERT(*common->start == OP_BRA && ccend[-(1 + LINK_SIZE)] == OP_KET);
+#if defined DEBUG_FORCE_UNOPTIMIZED_CBRAS && DEBUG_FORCE_UNOPTIMIZED_CBRAS == 2
+common->capture_last_ptr = common->ovector_start;
+common->ovector_start += sizeof(sljit_sw);
+#endif
+if (!check_opcode_types(common, common->start, ccend))
+  {
+  SLJIT_FREE(common->optimized_cbracket, allocator_data);
+  return PCRE2_ERROR_NOMEMORY;
+  }
+
+/* Checking flags and updating ovector_start. */
+if (mode == PCRE2_JIT_COMPLETE && (re->flags & PCRE2_LASTSET) != 0 && (re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0)
+  {
+  common->req_char_ptr = common->ovector_start;
+  common->ovector_start += sizeof(sljit_sw);
+  }
+if (mode != PCRE2_JIT_COMPLETE)
+  {
+  common->start_used_ptr = common->ovector_start;
+  common->ovector_start += sizeof(sljit_sw);
+  if (mode == PCRE2_JIT_PARTIAL_SOFT)
+    {
+    common->hit_start = common->ovector_start;
+    common->ovector_start += sizeof(sljit_sw);
+    }
+  }
+if ((re->overall_options & (PCRE2_FIRSTLINE | PCRE2_USE_OFFSET_LIMIT)) != 0)
+  {
+  common->match_end_ptr = common->ovector_start;
+  common->ovector_start += sizeof(sljit_sw);
+  }
+#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD
+common->control_head_ptr = 1;
+#endif
+if (common->control_head_ptr != 0)
+  {
+  common->control_head_ptr = common->ovector_start;
+  common->ovector_start += sizeof(sljit_sw);
+  }
+if (common->has_set_som)
+  {
+  /* Saving the real start pointer is necessary. */
+  common->start_ptr = common->ovector_start;
+  common->ovector_start += sizeof(sljit_sw);
+  }
+
+/* Aligning ovector to even number of sljit words. */
+if ((common->ovector_start & sizeof(sljit_sw)) != 0)
+  common->ovector_start += sizeof(sljit_sw);
+
+if (common->start_ptr == 0)
+  common->start_ptr = OVECTOR(0);
+
+/* Capturing brackets cannot be optimized if callouts are allowed. */
+if (common->capture_last_ptr != 0)
+  memset(common->optimized_cbracket, 0, re->top_bracket + 1);
+
+SLJIT_ASSERT(!(common->req_char_ptr != 0 && common->start_used_ptr != 0));
+common->cbra_ptr = OVECTOR_START + (re->top_bracket + 1) * 2 * sizeof(sljit_sw);
+
+total_length = ccend - common->start;
+common->private_data_ptrs = (sljit_s32 *)SLJIT_MALLOC(total_length * (sizeof(sljit_s32) + (common->has_then ? 1 : 0)), allocator_data);
+if (!common->private_data_ptrs)
+  {
+  SLJIT_FREE(common->optimized_cbracket, allocator_data);
+  return PCRE2_ERROR_NOMEMORY;
+  }
+memset(common->private_data_ptrs, 0, total_length * sizeof(sljit_s32));
+
+private_data_size = common->cbra_ptr + (re->top_bracket + 1) * sizeof(sljit_sw);
+set_private_data_ptrs(common, &private_data_size, ccend);
+if ((re->overall_options & PCRE2_ANCHORED) == 0 && (re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0 && !common->has_skip_in_assert_back)
+  detect_early_fail(common, common->start, &private_data_size, 0, 0);
+
+SLJIT_ASSERT(common->early_fail_start_ptr <= common->early_fail_end_ptr);
+
+if (private_data_size > SLJIT_MAX_LOCAL_SIZE)
+  {
+  SLJIT_FREE(common->private_data_ptrs, allocator_data);
+  SLJIT_FREE(common->optimized_cbracket, allocator_data);
+  return PCRE2_ERROR_NOMEMORY;
+  }
+
+if (common->has_then)
+  {
+  common->then_offsets = (sljit_u8 *)(common->private_data_ptrs + total_length);
+  memset(common->then_offsets, 0, total_length);
+  set_then_offsets(common, common->start, NULL);
+  }
+
+compiler = sljit_create_compiler(allocator_data, NULL);
+if (!compiler)
+  {
+  SLJIT_FREE(common->optimized_cbracket, allocator_data);
+  SLJIT_FREE(common->private_data_ptrs, allocator_data);
+  return PCRE2_ERROR_NOMEMORY;
+  }
+common->compiler = compiler;
+
+/* Main pcre_jit_exec entry. */
+sljit_emit_enter(compiler, 0, SLJIT_ARG1(SW), 5, 5, 0, 0, private_data_size);
+
+/* Register init. */
+reset_ovector(common, (re->top_bracket + 1) * 2);
+if (common->req_char_ptr != 0)
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->req_char_ptr, SLJIT_R0, 0);
+
+OP1(SLJIT_MOV, ARGUMENTS, 0, SLJIT_S0, 0);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_S0, 0);
+OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
+OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, end));
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack));
+OP1(SLJIT_MOV_U32, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, limit_match));
+OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, end));
+OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, start));
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LIMIT_MATCH, TMP1, 0);
+
+if (common->early_fail_start_ptr < common->early_fail_end_ptr)
+  reset_early_fail(common);
+
+if (mode == PCRE2_JIT_PARTIAL_SOFT)
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, -1);
+if (common->mark_ptr != 0)
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, SLJIT_IMM, 0);
+if (common->control_head_ptr != 0)
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0);
+
+/* Main part of the matching */
+if ((re->overall_options & PCRE2_ANCHORED) == 0)
+  {
+  mainloop_label = mainloop_entry(common);
+  continue_match_label = LABEL();
+  /* Forward search if possible. */
+  if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0)
+    {
+    if (mode == PCRE2_JIT_COMPLETE && fast_forward_first_n_chars(common))
+      ;
+    else if ((re->flags & PCRE2_FIRSTSET) != 0)
+      fast_forward_first_char(common);
+    else if ((re->flags & PCRE2_STARTLINE) != 0)
+      fast_forward_newline(common);
+    else if ((re->flags & PCRE2_FIRSTMAPSET) != 0)
+      fast_forward_start_bits(common);
+    }
+  }
+else
+  continue_match_label = LABEL();
+
+if (mode == PCRE2_JIT_COMPLETE && re->minlength > 0 && (re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0)
+  {
+  OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH);
+  OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(re->minlength));
+  minlength_check_failed = CMP(SLJIT_GREATER, TMP2, 0, STR_END, 0);
+  }
+if (common->req_char_ptr != 0)
+  reqcu_not_found = search_requested_char(common, (PCRE2_UCHAR)(re->last_codeunit), (re->flags & PCRE2_LASTCASELESS) != 0, (re->flags & PCRE2_FIRSTSET) != 0);
+
+/* Store the current STR_PTR in OVECTOR(0). */
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), STR_PTR, 0);
+/* Copy the limit of allowed recursions. */
+OP1(SLJIT_MOV, COUNT_MATCH, 0, SLJIT_MEM1(SLJIT_SP), LIMIT_MATCH);
+if (common->capture_last_ptr != 0)
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, 0);
+if (common->fast_forward_bc_ptr != NULL)
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), PRIVATE_DATA(common->fast_forward_bc_ptr + 1) >> 3, STR_PTR, 0);
+
+if (common->start_ptr != OVECTOR(0))
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_ptr, STR_PTR, 0);
+
+/* Copy the beginning of the string. */
+if (mode == PCRE2_JIT_PARTIAL_SOFT)
+  {
+  jump = CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, -1);
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
+  JUMPHERE(jump);
+  }
+else if (mode == PCRE2_JIT_PARTIAL_HARD)
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
+
+compile_matchingpath(common, common->start, ccend, &rootbacktrack);
+if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+  {
+  sljit_free_compiler(compiler);
+  SLJIT_FREE(common->optimized_cbracket, allocator_data);
+  SLJIT_FREE(common->private_data_ptrs, allocator_data);
+  PRIV(jit_free_rodata)(common->read_only_data_head, allocator_data);
+  return PCRE2_ERROR_NOMEMORY;
+  }
+
+if ((re->overall_options & PCRE2_ENDANCHORED) != 0)
+  end_anchor_failed = CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, STR_END, 0);
+
+if (common->might_be_empty)
+  {
+  empty_match = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0));
+  empty_match_found_label = LABEL();
+  }
+
+common->accept_label = LABEL();
+if (common->accept != NULL)
+  set_jumps(common->accept, common->accept_label);
+
+/* This means we have a match. Update the ovector. */
+copy_ovector(common, re->top_bracket + 1);
+common->quit_label = common->abort_label = LABEL();
+if (common->quit != NULL)
+  set_jumps(common->quit, common->quit_label);
+if (common->abort != NULL)
+  set_jumps(common->abort, common->abort_label);
+if (minlength_check_failed != NULL)
+  SET_LABEL(minlength_check_failed, common->abort_label);
+
+sljit_emit_op0(compiler, SLJIT_SKIP_FRAMES_BEFORE_RETURN);
+sljit_emit_return(compiler, SLJIT_MOV, SLJIT_RETURN_REG, 0);
+
+if (common->failed_match != NULL)
+  {
+  SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE);
+  set_jumps(common->failed_match, LABEL());
+  OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH);
+  JUMPTO(SLJIT_JUMP, common->abort_label);
+  }
+
+if ((re->overall_options & PCRE2_ENDANCHORED) != 0)
+  JUMPHERE(end_anchor_failed);
+
+if (mode != PCRE2_JIT_COMPLETE)
+  {
+  common->partialmatchlabel = LABEL();
+  set_jumps(common->partialmatch, common->partialmatchlabel);
+  return_with_partial_match(common, common->quit_label);
+  }
+
+if (common->might_be_empty)
+  empty_match_backtrack_label = LABEL();
+compile_backtrackingpath(common, rootbacktrack.top);
+if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+  {
+  sljit_free_compiler(compiler);
+  SLJIT_FREE(common->optimized_cbracket, allocator_data);
+  SLJIT_FREE(common->private_data_ptrs, allocator_data);
+  PRIV(jit_free_rodata)(common->read_only_data_head, allocator_data);
+  return PCRE2_ERROR_NOMEMORY;
+  }
+
+SLJIT_ASSERT(rootbacktrack.prev == NULL);
+reset_match_label = LABEL();
+
+if (mode == PCRE2_JIT_PARTIAL_SOFT)
+  {
+  /* Update hit_start only in the first time. */
+  jump = CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0);
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr);
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, -1);
+  OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, TMP1, 0);
+  JUMPHERE(jump);
+  }
+
+/* Check we have remaining characters. */
+if ((re->overall_options & PCRE2_ANCHORED) == 0 && common->match_end_ptr != 0)
+  {
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+  }
+
+OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP),
+    (common->fast_forward_bc_ptr != NULL) ? (PRIVATE_DATA(common->fast_forward_bc_ptr + 1) >> 3) : common->start_ptr);
+
+if ((re->overall_options & PCRE2_ANCHORED) == 0)
+  {
+  if (common->ff_newline_shortcut != NULL)
+    {
+    /* There cannot be more newlines if PCRE2_FIRSTLINE is set. */
+    if ((re->overall_options & PCRE2_FIRSTLINE) == 0)
+      {
+      if (common->match_end_ptr != 0)
+        {
+        OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
+        OP1(SLJIT_MOV, STR_END, 0, TMP1, 0);
+        CMPTO(SLJIT_LESS, STR_PTR, 0, TMP1, 0, common->ff_newline_shortcut);
+        OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+        }
+      else
+        CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, common->ff_newline_shortcut);
+      }
+    }
+  else
+    CMPTO(SLJIT_LESS, STR_PTR, 0, (common->match_end_ptr == 0) ? STR_END : TMP1, 0, mainloop_label);
+  }
+
+/* No more remaining characters. */
+if (reqcu_not_found != NULL)
+  set_jumps(reqcu_not_found, LABEL());
+
+if (mode == PCRE2_JIT_PARTIAL_SOFT)
+  CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, -1, common->partialmatchlabel);
+
+OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH);
+JUMPTO(SLJIT_JUMP, common->quit_label);
+
+flush_stubs(common);
+
+if (common->might_be_empty)
+  {
+  JUMPHERE(empty_match);
+  OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+  OP1(SLJIT_MOV_U32, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, options));
+  OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY);
+  JUMPTO(SLJIT_NOT_ZERO, empty_match_backtrack_label);
+  OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY_ATSTART);
+  JUMPTO(SLJIT_ZERO, empty_match_found_label);
+  OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
+  CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0, empty_match_found_label);
+  JUMPTO(SLJIT_JUMP, empty_match_backtrack_label);
+  }
+
+common->fast_forward_bc_ptr = NULL;
+common->early_fail_start_ptr = 0;
+common->early_fail_end_ptr = 0;
+common->currententry = common->entries;
+common->local_quit_available = TRUE;
+quit_label = common->quit_label;
+while (common->currententry != NULL)
+  {
+  /* Might add new entries. */
+  compile_recurse(common);
+  if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+    {
+    sljit_free_compiler(compiler);
+    SLJIT_FREE(common->optimized_cbracket, allocator_data);
+    SLJIT_FREE(common->private_data_ptrs, allocator_data);
+    PRIV(jit_free_rodata)(common->read_only_data_head, allocator_data);
+    return PCRE2_ERROR_NOMEMORY;
+    }
+  flush_stubs(common);
+  common->currententry = common->currententry->next;
+  }
+common->local_quit_available = FALSE;
+common->quit_label = quit_label;
+
+/* Allocating stack, returns with PCRE_ERROR_JIT_STACKLIMIT if fails. */
+/* This is a (really) rare case. */
+set_jumps(common->stackalloc, LABEL());
+/* RETURN_ADDR is not a saved register. */
+sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+
+SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1);
+
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, STR_PTR, 0);
+OP1(SLJIT_MOV, SLJIT_R0, 0, ARGUMENTS, 0);
+OP2(SLJIT_SUB, SLJIT_R1, 0, STACK_LIMIT, 0, SLJIT_IMM, STACK_GROWTH_RATE);
+OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, stack));
+OP1(SLJIT_MOV, STACK_LIMIT, 0, TMP2, 0);
+
+sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_stack_resize));
+
+jump = CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
+OP1(SLJIT_MOV, TMP2, 0, STACK_LIMIT, 0);
+OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_RETURN_REG, 0);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1);
+OP_SRC(SLJIT_FAST_RETURN, TMP1, 0);
+
+/* Allocation failed. */
+JUMPHERE(jump);
+/* We break the return address cache here, but this is a really rare case. */
+OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_JIT_STACKLIMIT);
+JUMPTO(SLJIT_JUMP, common->quit_label);
+
+/* Call limit reached. */
+set_jumps(common->calllimit, LABEL());
+OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_MATCHLIMIT);
+JUMPTO(SLJIT_JUMP, common->quit_label);
+
+if (common->revertframes != NULL)
+  {
+  set_jumps(common->revertframes, LABEL());
+  do_revertframes(common);
+  }
+if (common->wordboundary != NULL)
+  {
+  set_jumps(common->wordboundary, LABEL());
+  check_wordboundary(common);
+  }
+if (common->anynewline != NULL)
+  {
+  set_jumps(common->anynewline, LABEL());
+  check_anynewline(common);
+  }
+if (common->hspace != NULL)
+  {
+  set_jumps(common->hspace, LABEL());
+  check_hspace(common);
+  }
+if (common->vspace != NULL)
+  {
+  set_jumps(common->vspace, LABEL());
+  check_vspace(common);
+  }
+if (common->casefulcmp != NULL)
+  {
+  set_jumps(common->casefulcmp, LABEL());
+  do_casefulcmp(common);
+  }
+if (common->caselesscmp != NULL)
+  {
+  set_jumps(common->caselesscmp, LABEL());
+  do_caselesscmp(common);
+  }
+if (common->reset_match != NULL)
+  {
+  set_jumps(common->reset_match, LABEL());
+  do_reset_match(common, (re->top_bracket + 1) * 2);
+  CMPTO(SLJIT_GREATER, STR_PTR, 0, TMP1, 0, continue_match_label);
+  OP1(SLJIT_MOV, STR_PTR, 0, TMP1, 0);
+  JUMPTO(SLJIT_JUMP, reset_match_label);
+  }
+#ifdef SUPPORT_UNICODE
+#if PCRE2_CODE_UNIT_WIDTH == 8
+if (common->utfreadchar != NULL)
+  {
+  set_jumps(common->utfreadchar, LABEL());
+  do_utfreadchar(common);
+  }
+if (common->utfreadtype8 != NULL)
+  {
+  set_jumps(common->utfreadtype8, LABEL());
+  do_utfreadtype8(common);
+  }
+if (common->utfpeakcharback != NULL)
+  {
+  set_jumps(common->utfpeakcharback, LABEL());
+  do_utfpeakcharback(common);
+  }
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+#if PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16
+if (common->utfreadchar_invalid != NULL)
+  {
+  set_jumps(common->utfreadchar_invalid, LABEL());
+  do_utfreadchar_invalid(common);
+  }
+if (common->utfreadnewline_invalid != NULL)
+  {
+  set_jumps(common->utfreadnewline_invalid, LABEL());
+  do_utfreadnewline_invalid(common);
+  }
+if (common->utfmoveback_invalid)
+  {
+  set_jumps(common->utfmoveback_invalid, LABEL());
+  do_utfmoveback_invalid(common);
+  }
+if (common->utfpeakcharback_invalid)
+  {
+  set_jumps(common->utfpeakcharback_invalid, LABEL());
+  do_utfpeakcharback_invalid(common);
+  }
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16 */
+if (common->getucd != NULL)
+  {
+  set_jumps(common->getucd, LABEL());
+  do_getucd(common);
+  }
+if (common->getucdtype != NULL)
+  {
+  set_jumps(common->getucdtype, LABEL());
+  do_getucdtype(common);
+  }
+#endif /* SUPPORT_UNICODE */
+
+SLJIT_FREE(common->optimized_cbracket, allocator_data);
+SLJIT_FREE(common->private_data_ptrs, allocator_data);
+
+executable_func = sljit_generate_code(compiler);
+executable_size = sljit_get_generated_code_size(compiler);
+sljit_free_compiler(compiler);
+
+if (executable_func == NULL)
+  {
+  PRIV(jit_free_rodata)(common->read_only_data_head, allocator_data);
+  return PCRE2_ERROR_NOMEMORY;
+  }
+
+/* Reuse the function descriptor if possible. */
+if (re->executable_jit != NULL)
+  functions = (executable_functions *)re->executable_jit;
+else
+  {
+  functions = SLJIT_MALLOC(sizeof(executable_functions), allocator_data);
+  if (functions == NULL)
+    {
+    /* This case is highly unlikely since we just recently
+    freed a lot of memory. Not impossible though. */
+    sljit_free_code(executable_func, NULL);
+    PRIV(jit_free_rodata)(common->read_only_data_head, allocator_data);
+    return PCRE2_ERROR_NOMEMORY;
+    }
+  memset(functions, 0, sizeof(executable_functions));
+  functions->top_bracket = re->top_bracket + 1;
+  functions->limit_match = re->limit_match;
+  re->executable_jit = functions;
+  }
+
+/* Turn mode into an index. */
+if (mode == PCRE2_JIT_COMPLETE)
+  mode = 0;
+else
+  mode = (mode == PCRE2_JIT_PARTIAL_SOFT) ? 1 : 2;
+
+SLJIT_ASSERT(mode < JIT_NUMBER_OF_COMPILE_MODES);
+functions->executable_funcs[mode] = executable_func;
+functions->read_only_data_heads[mode] = common->read_only_data_head;
+functions->executable_sizes[mode] = executable_size;
+return 0;
+}
+
+#endif
+
+/*************************************************
+*        JIT compile a Regular Expression        *
+*************************************************/
+
+/* This function used JIT to convert a previously-compiled pattern into machine
+code.
+
+Arguments:
+  code          a compiled pattern
+  options       JIT option bits
+
+Returns:        0: success or (*NOJIT) was used
+               <0: an error code
+*/
+
+#define PUBLIC_JIT_COMPILE_OPTIONS \
+  (PCRE2_JIT_COMPLETE|PCRE2_JIT_PARTIAL_SOFT|PCRE2_JIT_PARTIAL_HARD|PCRE2_JIT_INVALID_UTF)
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_jit_compile(pcre2_code *code, uint32_t options)
+{
+pcre2_real_code *re = (pcre2_real_code *)code;
+
+if (code == NULL)
+  return PCRE2_ERROR_NULL;
+
+if ((options & ~PUBLIC_JIT_COMPILE_OPTIONS) != 0)
+  return PCRE2_ERROR_JIT_BADOPTION;
+
+/* Support for invalid UTF was first introduced in JIT, with the option
+PCRE2_JIT_INVALID_UTF. Later, support was added to the interpreter, and the
+compile-time option PCRE2_MATCH_INVALID_UTF was created. This is now the
+preferred feature, with the earlier option deprecated. However, for backward
+compatibility, if the earlier option is set, it forces the new option so that
+if JIT matching falls back to the interpreter, there is still support for
+invalid UTF. However, if this function has already been successfully called
+without PCRE2_JIT_INVALID_UTF and without PCRE2_MATCH_INVALID_UTF (meaning that
+non-invalid-supporting JIT code was compiled), give an error.
+
+If in the future support for PCRE2_JIT_INVALID_UTF is withdrawn, the following
+actions are needed:
+
+  1. Remove the definition from pcre2.h.in and from the list in
+     PUBLIC_JIT_COMPILE_OPTIONS above.
+
+  2. Replace PCRE2_JIT_INVALID_UTF with a local flag in this module.
+
+  3. Replace PCRE2_JIT_INVALID_UTF in pcre2_jit_test.c.
+
+  4. Delete the following short block of code. The setting of "re" and
+     "functions" can be moved into the JIT-only block below, but if that is
+     done, (void)re and (void)functions will be needed in the non-JIT case, to
+     avoid compiler warnings.
+*/
+
+#ifdef SUPPORT_JIT
+executable_functions *functions = (executable_functions *)re->executable_jit;
+static int executable_allocator_is_working = 0;
+#endif
+
+if ((options & PCRE2_JIT_INVALID_UTF) != 0)
+  {
+  if ((re->overall_options & PCRE2_MATCH_INVALID_UTF) == 0)
+    {
+#ifdef SUPPORT_JIT
+    if (functions != NULL) return PCRE2_ERROR_JIT_BADOPTION;
+#endif
+    re->overall_options |= PCRE2_MATCH_INVALID_UTF;
+    }
+  }
+
+/* The above tests are run with and without JIT support. This means that
+PCRE2_JIT_INVALID_UTF propagates back into the regex options (ensuring
+interpreter support) even in the absence of JIT. But now, if there is no JIT
+support, give an error return. */
+
+#ifndef SUPPORT_JIT
+return PCRE2_ERROR_JIT_BADOPTION;
+#else  /* SUPPORT_JIT */
+
+/* There is JIT support. Do the necessary. */
+
+if ((re->flags & PCRE2_NOJIT) != 0) return 0;
+
+if (executable_allocator_is_working == 0)
+  {
+  /* Checks whether the executable allocator is working. This check
+     might run multiple times in multi-threaded environments, but the
+     result should not be affected by it. */
+  void *ptr = SLJIT_MALLOC_EXEC(32, NULL);
+
+  executable_allocator_is_working = -1;
+
+  if (ptr != NULL)
+    {
+    SLJIT_FREE_EXEC(((sljit_u8*)(ptr)) + SLJIT_EXEC_OFFSET(ptr), NULL);
+    executable_allocator_is_working = 1;
+    }
+  }
+
+if (executable_allocator_is_working < 0)
+  return PCRE2_ERROR_NOMEMORY;
+
+if ((re->overall_options & PCRE2_MATCH_INVALID_UTF) != 0)
+  options |= PCRE2_JIT_INVALID_UTF;
+
+if ((options & PCRE2_JIT_COMPLETE) != 0 && (functions == NULL
+    || functions->executable_funcs[0] == NULL)) {
+  uint32_t excluded_options = (PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_PARTIAL_HARD);
+  int result = jit_compile(code, options & ~excluded_options);
+  if (result != 0)
+    return result;
+  }
+
+if ((options & PCRE2_JIT_PARTIAL_SOFT) != 0 && (functions == NULL
+    || functions->executable_funcs[1] == NULL)) {
+  uint32_t excluded_options = (PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_HARD);
+  int result = jit_compile(code, options & ~excluded_options);
+  if (result != 0)
+    return result;
+  }
+
+if ((options & PCRE2_JIT_PARTIAL_HARD) != 0 && (functions == NULL
+    || functions->executable_funcs[2] == NULL)) {
+  uint32_t excluded_options = (PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT);
+  int result = jit_compile(code, options & ~excluded_options);
+  if (result != 0)
+    return result;
+  }
+
+return 0;
+
+#endif  /* SUPPORT_JIT */
+}
+
+/* JIT compiler uses an all-in-one approach. This improves security,
+   since the code generator functions are not exported. */
+
+#define INCLUDED_FROM_PCRE2_JIT_COMPILE
+
+#include "pcre2_jit_match.c"
+#include "pcre2_jit_misc.c"
+
+/* End of pcre2_jit_compile.c */
diff --git a/src/c/pcre2/src/pcre2_jit_match.c b/src/c/pcre2/src/pcre2_jit_match.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_jit_match.c
@@ -0,0 +1,186 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifndef INCLUDED_FROM_PCRE2_JIT_COMPILE
+#error This file must be included from pcre2_jit_compile.c.
+#endif
+
+#ifdef SUPPORT_JIT
+
+static SLJIT_NOINLINE int jit_machine_stack_exec(jit_arguments *arguments, jit_function executable_func)
+{
+sljit_u8 local_space[MACHINE_STACK_SIZE];
+struct sljit_stack local_stack;
+
+local_stack.min_start = local_space;
+local_stack.start = local_space;
+local_stack.end = local_space + MACHINE_STACK_SIZE;
+local_stack.top = local_space + MACHINE_STACK_SIZE;
+arguments->stack = &local_stack;
+return executable_func(arguments);
+}
+
+#endif
+
+
+/*************************************************
+*              Do a JIT pattern match            *
+*************************************************/
+
+/* This function runs a JIT pattern match.
+
+Arguments:
+  code            points to the compiled expression
+  subject         points to the subject string
+  length          length of subject string (may contain binary zeros)
+  start_offset    where to start in the subject string
+  options         option bits
+  match_data      points to a match_data block
+  mcontext        points to a match context
+
+Returns:          > 0 => success; value is the number of ovector pairs filled
+                  = 0 => success, but ovector is not big enough
+                   -1 => failed to match (PCRE_ERROR_NOMATCH)
+                 < -1 => some kind of unexpected problem
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_jit_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length,
+  PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data,
+  pcre2_match_context *mcontext)
+{
+#ifndef SUPPORT_JIT
+
+(void)code;
+(void)subject;
+(void)length;
+(void)start_offset;
+(void)options;
+(void)match_data;
+(void)mcontext;
+return PCRE2_ERROR_JIT_BADOPTION;
+
+#else  /* SUPPORT_JIT */
+
+pcre2_real_code *re = (pcre2_real_code *)code;
+executable_functions *functions = (executable_functions *)re->executable_jit;
+pcre2_jit_stack *jit_stack;
+uint32_t oveccount = match_data->oveccount;
+uint32_t max_oveccount;
+union {
+   void *executable_func;
+   jit_function call_executable_func;
+} convert_executable_func;
+jit_arguments arguments;
+int rc;
+int index = 0;
+
+if ((options & PCRE2_PARTIAL_HARD) != 0)
+  index = 2;
+else if ((options & PCRE2_PARTIAL_SOFT) != 0)
+  index = 1;
+
+if (functions == NULL || functions->executable_funcs[index] == NULL)
+  return PCRE2_ERROR_JIT_BADOPTION;
+
+/* Sanity checks should be handled by pcre_exec. */
+arguments.str = subject + start_offset;
+arguments.begin = subject;
+arguments.end = subject + length;
+arguments.match_data = match_data;
+arguments.startchar_ptr = subject;
+arguments.mark_ptr = NULL;
+arguments.options = options;
+
+if (mcontext != NULL)
+  {
+  arguments.callout = mcontext->callout;
+  arguments.callout_data = mcontext->callout_data;
+  arguments.offset_limit = mcontext->offset_limit;
+  arguments.limit_match = (mcontext->match_limit < re->limit_match)?
+    mcontext->match_limit : re->limit_match;
+  if (mcontext->jit_callback != NULL)
+    jit_stack = mcontext->jit_callback(mcontext->jit_callback_data);
+  else
+    jit_stack = (pcre2_jit_stack *)mcontext->jit_callback_data;
+  }
+else
+  {
+  arguments.callout = NULL;
+  arguments.callout_data = NULL;
+  arguments.offset_limit = PCRE2_UNSET;
+  arguments.limit_match = (MATCH_LIMIT < re->limit_match)?
+    MATCH_LIMIT : re->limit_match;
+  jit_stack = NULL;
+  }
+
+
+max_oveccount = functions->top_bracket;
+if (oveccount > max_oveccount)
+  oveccount = max_oveccount;
+arguments.oveccount = oveccount << 1;
+
+
+convert_executable_func.executable_func = functions->executable_funcs[index];
+if (jit_stack != NULL)
+  {
+  arguments.stack = (struct sljit_stack *)(jit_stack->stack);
+  rc = convert_executable_func.call_executable_func(&arguments);
+  }
+else
+  rc = jit_machine_stack_exec(&arguments, convert_executable_func.call_executable_func);
+
+if (rc > (int)oveccount)
+  rc = 0;
+match_data->code = re;
+match_data->subject = (rc >= 0 || rc == PCRE2_ERROR_PARTIAL)? subject : NULL;
+match_data->rc = rc;
+match_data->startchar = arguments.startchar_ptr - subject;
+match_data->leftchar = 0;
+match_data->rightchar = 0;
+match_data->mark = arguments.mark_ptr;
+match_data->matchedby = PCRE2_MATCHEDBY_JIT;
+
+return match_data->rc;
+
+#endif  /* SUPPORT_JIT */
+}
+
+/* End of pcre2_jit_match.c */
diff --git a/src/c/pcre2/src/pcre2_jit_misc.c b/src/c/pcre2/src/pcre2_jit_misc.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_jit_misc.c
@@ -0,0 +1,232 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+         New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifndef INCLUDED_FROM_PCRE2_JIT_COMPILE
+#error This file must be included from pcre2_jit_compile.c.
+#endif
+
+
+
+/*************************************************
+*           Free JIT read-only data              *
+*************************************************/
+
+void
+PRIV(jit_free_rodata)(void *current, void *allocator_data)
+{
+#ifndef SUPPORT_JIT
+(void)current;
+(void)allocator_data;
+#else  /* SUPPORT_JIT */
+void *next;
+
+SLJIT_UNUSED_ARG(allocator_data);
+
+while (current != NULL)
+  {
+  next = *(void**)current;
+  SLJIT_FREE(current, allocator_data);
+  current = next;
+  }
+
+#endif /* SUPPORT_JIT */
+}
+
+/*************************************************
+*           Free JIT compiled code               *
+*************************************************/
+
+void
+PRIV(jit_free)(void *executable_jit, pcre2_memctl *memctl)
+{
+#ifndef SUPPORT_JIT
+(void)executable_jit;
+(void)memctl;
+#else  /* SUPPORT_JIT */
+
+executable_functions *functions = (executable_functions *)executable_jit;
+void *allocator_data = memctl;
+int i;
+
+for (i = 0; i < JIT_NUMBER_OF_COMPILE_MODES; i++)
+  {
+  if (functions->executable_funcs[i] != NULL)
+    sljit_free_code(functions->executable_funcs[i], NULL);
+  PRIV(jit_free_rodata)(functions->read_only_data_heads[i], allocator_data);
+  }
+
+SLJIT_FREE(functions, allocator_data);
+
+#endif /* SUPPORT_JIT */
+}
+
+
+/*************************************************
+*            Free unused JIT memory              *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_jit_free_unused_memory(pcre2_general_context *gcontext)
+{
+#ifndef SUPPORT_JIT
+(void)gcontext;     /* Suppress warning */
+#else  /* SUPPORT_JIT */
+SLJIT_UNUSED_ARG(gcontext);
+sljit_free_unused_memory_exec();
+#endif  /* SUPPORT_JIT */
+}
+
+
+
+/*************************************************
+*            Allocate a JIT stack                *
+*************************************************/
+
+PCRE2_EXP_DEFN pcre2_jit_stack * PCRE2_CALL_CONVENTION
+pcre2_jit_stack_create(size_t startsize, size_t maxsize,
+  pcre2_general_context *gcontext)
+{
+#ifndef SUPPORT_JIT
+
+(void)gcontext;
+(void)startsize;
+(void)maxsize;
+return NULL;
+
+#else  /* SUPPORT_JIT */
+
+pcre2_jit_stack *jit_stack;
+
+if (startsize < 1 || maxsize < 1)
+  return NULL;
+if (startsize > maxsize)
+  startsize = maxsize;
+startsize = (startsize + STACK_GROWTH_RATE - 1) & ~(STACK_GROWTH_RATE - 1);
+maxsize = (maxsize + STACK_GROWTH_RATE - 1) & ~(STACK_GROWTH_RATE - 1);
+
+jit_stack = PRIV(memctl_malloc)(sizeof(pcre2_real_jit_stack), (pcre2_memctl *)gcontext);
+if (jit_stack == NULL) return NULL;
+jit_stack->stack = sljit_allocate_stack(startsize, maxsize, &jit_stack->memctl);
+if (jit_stack->stack == NULL)
+  {
+  jit_stack->memctl.free(jit_stack, jit_stack->memctl.memory_data);
+  return NULL;
+  }
+return jit_stack;
+
+#endif
+}
+
+
+/*************************************************
+*         Assign a JIT stack to a pattern        *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_jit_stack_assign(pcre2_match_context *mcontext, pcre2_jit_callback callback,
+  void *callback_data)
+{
+#ifndef SUPPORT_JIT
+(void)mcontext;
+(void)callback;
+(void)callback_data;
+#else  /* SUPPORT_JIT */
+
+if (mcontext == NULL) return;
+mcontext->jit_callback = callback;
+mcontext->jit_callback_data = callback_data;
+
+#endif  /* SUPPORT_JIT */
+}
+
+
+/*************************************************
+*               Free a JIT stack                 *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_jit_stack_free(pcre2_jit_stack *jit_stack)
+{
+#ifndef SUPPORT_JIT
+(void)jit_stack;
+#else  /* SUPPORT_JIT */
+if (jit_stack != NULL)
+  {
+  sljit_free_stack((struct sljit_stack *)(jit_stack->stack), &jit_stack->memctl);
+  jit_stack->memctl.free(jit_stack, jit_stack->memctl.memory_data);
+  }
+#endif  /* SUPPORT_JIT */
+}
+
+
+/*************************************************
+*               Get target CPU type              *
+*************************************************/
+
+const char*
+PRIV(jit_get_target)(void)
+{
+#ifndef SUPPORT_JIT
+return "JIT is not supported";
+#else  /* SUPPORT_JIT */
+return sljit_get_platform_name();
+#endif  /* SUPPORT_JIT */
+}
+
+
+/*************************************************
+*              Get size of JIT code              *
+*************************************************/
+
+size_t
+PRIV(jit_get_size)(void *executable_jit)
+{
+#ifndef SUPPORT_JIT
+(void)executable_jit;
+return 0;
+#else  /* SUPPORT_JIT */
+sljit_uw *executable_sizes = ((executable_functions *)executable_jit)->executable_sizes;
+SLJIT_COMPILE_ASSERT(JIT_NUMBER_OF_COMPILE_MODES == 3, number_of_compile_modes_changed);
+return executable_sizes[0] + executable_sizes[1] + executable_sizes[2];
+#endif
+}
+
+/* End of pcre2_jit_misc.c */
diff --git a/src/c/pcre2/src/pcre2_jit_neon_inc.h b/src/c/pcre2/src/pcre2_jit_neon_inc.h
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_jit_neon_inc.h
@@ -0,0 +1,343 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+            This module by Zoltan Herczeg and Sebastian Pop
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2019 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+# if defined(FFCS)
+#  if defined(FF_UTF)
+#   define FF_FUN ffcs_utf
+#  else
+#   define FF_FUN ffcs
+#  endif
+
+# elif defined(FFCS_2)
+#  if defined(FF_UTF)
+#   define FF_FUN ffcs_2_utf
+#  else
+#   define FF_FUN ffcs_2
+#  endif
+
+# elif defined(FFCS_MASK)
+#  if defined(FF_UTF)
+#   define FF_FUN ffcs_mask_utf
+#  else
+#   define FF_FUN ffcs_mask
+#  endif
+
+# elif defined(FFCPS_0)
+#  if defined (FF_UTF)
+#   define FF_FUN ffcps_0_utf
+#  else
+#   define FF_FUN ffcps_0
+#  endif
+
+# elif defined (FFCPS_1)
+#  if defined (FF_UTF)
+#   define FF_FUN ffcps_1_utf
+#  else
+#   define FF_FUN ffcps_1
+#  endif
+
+# elif defined (FFCPS_DEFAULT)
+#  if defined (FF_UTF)
+#   define FF_FUN ffcps_default_utf
+#  else
+#   define FF_FUN ffcps_default
+#  endif
+# endif
+
+static sljit_u8* SLJIT_FUNC FF_FUN(sljit_u8 *str_end, sljit_u8 *str_ptr, sljit_uw offs1, sljit_uw offs2, sljit_uw chars)
+#undef FF_FUN
+{
+quad_word qw;
+int_char ic;
+ic.x = chars;
+
+#if defined(FFCS)
+sljit_u8 c1 = ic.c.c1;
+vect_t vc1 = VDUPQ(c1);
+
+#elif defined(FFCS_2)
+sljit_u8 c1 = ic.c.c1;
+vect_t vc1 = VDUPQ(c1);
+sljit_u8 c2 = ic.c.c2;
+vect_t vc2 = VDUPQ(c2);
+
+#elif defined(FFCS_MASK)
+sljit_u8 c1 = ic.c.c1;
+vect_t vc1 = VDUPQ(c1);
+sljit_u8 mask = ic.c.c2;
+vect_t vmask = VDUPQ(mask);
+#endif
+
+#if defined(FFCPS)
+compare_type compare1_type = compare_match1;
+compare_type compare2_type = compare_match1;
+vect_t cmp1a, cmp1b, cmp2a, cmp2b;
+const sljit_u32 diff = IN_UCHARS(offs1 - offs2);
+PCRE2_UCHAR char1a = ic.c.c1;
+PCRE2_UCHAR char2a = ic.c.c3;
+
+# ifdef FFCPS_CHAR1A2A
+cmp1a = VDUPQ(char1a);
+cmp2a = VDUPQ(char2a);
+cmp1b = VDUPQ(0); /* to avoid errors on older compilers -Werror=maybe-uninitialized */
+cmp2b = VDUPQ(0); /* to avoid errors on older compilers -Werror=maybe-uninitialized */
+# else
+PCRE2_UCHAR char1b = ic.c.c2;
+PCRE2_UCHAR char2b = ic.c.c4;
+if (char1a == char1b)
+  {
+  cmp1a = VDUPQ(char1a);
+  cmp1b = VDUPQ(0); /* to avoid errors on older compilers -Werror=maybe-uninitialized */
+  }
+else
+  {
+  sljit_u32 bit1 = char1a ^ char1b;
+  if (is_powerof2(bit1))
+    {
+    compare1_type = compare_match1i;
+    cmp1a = VDUPQ(char1a | bit1);
+    cmp1b = VDUPQ(bit1);
+    }
+  else
+    {
+    compare1_type = compare_match2;
+    cmp1a = VDUPQ(char1a);
+    cmp1b = VDUPQ(char1b);
+    }
+  }
+
+if (char2a == char2b)
+  {
+  cmp2a = VDUPQ(char2a);
+  cmp2b = VDUPQ(0); /* to avoid errors on older compilers -Werror=maybe-uninitialized */
+  }
+else
+  {
+  sljit_u32 bit2 = char2a ^ char2b;
+  if (is_powerof2(bit2))
+    {
+    compare2_type = compare_match1i;
+    cmp2a = VDUPQ(char2a | bit2);
+    cmp2b = VDUPQ(bit2);
+    }
+  else
+    {
+    compare2_type = compare_match2;
+    cmp2a = VDUPQ(char2a);
+    cmp2b = VDUPQ(char2b);
+    }
+  }
+# endif
+
+str_ptr += IN_UCHARS(offs1);
+#endif
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+vect_t char_mask = VDUPQ(0xff);
+#endif
+
+#if defined(FF_UTF)
+restart:;
+#endif
+
+#if defined(FFCPS)
+sljit_u8 *p1 = str_ptr - diff;
+#endif
+sljit_s32 align_offset = ((uint64_t)str_ptr & 0xf);
+str_ptr = (sljit_u8 *) ((uint64_t)str_ptr & ~0xf);
+vect_t data = VLD1Q(str_ptr);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+data = VANDQ(data, char_mask);
+#endif
+ 
+#if defined(FFCS)
+vect_t eq = VCEQQ(data, vc1);
+
+#elif defined(FFCS_2)
+vect_t eq1 = VCEQQ(data, vc1);
+vect_t eq2 = VCEQQ(data, vc2);
+vect_t eq = VORRQ(eq1, eq2);    
+
+#elif defined(FFCS_MASK)
+vect_t eq = VORRQ(data, vmask);
+eq = VCEQQ(eq, vc1);
+
+#elif defined(FFCPS)
+# if defined(FFCPS_DIFF1)
+vect_t prev_data = data;
+# endif
+
+vect_t data2;
+if (p1 < str_ptr)
+  {
+  data2 = VLD1Q(str_ptr - diff);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+  data2 = VANDQ(data2, char_mask);
+#endif
+  }
+else
+  data2 = shift_left_n_lanes(data, offs1 - offs2);
+ 
+if (compare1_type == compare_match1)
+  data = VCEQQ(data, cmp1a);
+else
+  data = fast_forward_char_pair_compare(compare1_type, data, cmp1a, cmp1b);
+
+if (compare2_type == compare_match1)
+  data2 = VCEQQ(data2, cmp2a);
+else
+  data2 = fast_forward_char_pair_compare(compare2_type, data2, cmp2a, cmp2b);
+
+vect_t eq = VANDQ(data, data2);
+#endif
+
+VST1Q(qw.mem, eq);
+/* Ignore matches before the first STR_PTR. */
+if (align_offset < 8)
+  {
+  qw.dw[0] >>= align_offset * 8;
+  if (qw.dw[0])
+    {
+    str_ptr += align_offset + __builtin_ctzll(qw.dw[0]) / 8;
+    goto match;
+    }
+  if (qw.dw[1])
+    {
+    str_ptr += 8 + __builtin_ctzll(qw.dw[1]) / 8;
+    goto match;
+    }
+  }
+else
+  {
+  qw.dw[1] >>= (align_offset - 8) * 8;
+  if (qw.dw[1])
+    {
+    str_ptr += align_offset + __builtin_ctzll(qw.dw[1]) / 8;
+    goto match;
+    }
+  }
+str_ptr += 16;
+
+while (str_ptr < str_end)
+  {
+  vect_t orig_data = VLD1Q(str_ptr);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+  orig_data = VANDQ(orig_data, char_mask);
+#endif
+  data = orig_data;
+
+#if defined(FFCS)
+  eq = VCEQQ(data, vc1);
+
+#elif defined(FFCS_2)
+  eq1 = VCEQQ(data, vc1);
+  eq2 = VCEQQ(data, vc2);
+  eq = VORRQ(eq1, eq2);    
+
+#elif defined(FFCS_MASK)
+  eq = VORRQ(data, vmask);
+  eq = VCEQQ(eq, vc1);
+#endif
+
+#if defined(FFCPS)
+# if defined (FFCPS_DIFF1)
+  data2 = VEXTQ(prev_data, data, VECTOR_FACTOR - 1);
+# else
+  data2 = VLD1Q(str_ptr - diff);
+#  if PCRE2_CODE_UNIT_WIDTH != 8
+  data2 = VANDQ(data2, char_mask);
+#  endif
+# endif
+
+# ifdef FFCPS_CHAR1A2A
+  data = VCEQQ(data, cmp1a);
+  data2 = VCEQQ(data2, cmp2a);
+# else
+  if (compare1_type == compare_match1)
+    data = VCEQQ(data, cmp1a);
+  else
+    data = fast_forward_char_pair_compare(compare1_type, data, cmp1a, cmp1b);
+  if (compare2_type == compare_match1)
+    data2 = VCEQQ(data2, cmp2a);
+  else
+    data2 = fast_forward_char_pair_compare(compare2_type, data2, cmp2a, cmp2b);
+# endif
+
+  eq = VANDQ(data, data2);
+#endif
+
+  VST1Q(qw.mem, eq);
+  if (qw.dw[0])
+    str_ptr += __builtin_ctzll(qw.dw[0]) / 8;
+  else if (qw.dw[1])
+    str_ptr += 8 + __builtin_ctzll(qw.dw[1]) / 8;
+  else {
+    str_ptr += 16;
+#if defined (FFCPS_DIFF1)
+    prev_data = orig_data;
+#endif
+    continue;
+  }
+
+match:;
+  if (str_ptr >= str_end)
+    /* Failed match. */
+    return NULL;
+
+#if defined(FF_UTF)
+  if (utf_continue(str_ptr + IN_UCHARS(-offs1)))
+    {
+    /* Not a match. */
+    str_ptr += IN_UCHARS(1);
+    goto restart;
+    }
+#endif
+
+  /* Match. */
+#if defined (FFCPS)
+  str_ptr -= IN_UCHARS(offs1);
+#endif
+  return str_ptr;
+  }
+
+/* Failed match. */
+return NULL;
+}
diff --git a/src/c/pcre2/src/pcre2_jit_simd_inc.h b/src/c/pcre2/src/pcre2_jit_simd_inc.h
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_jit_simd_inc.h
@@ -0,0 +1,1123 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+                    This module by Zoltan Herczeg
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2019 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) && !(defined SUPPORT_VALGRIND)
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+static struct sljit_jump *jump_if_utf_char_start(struct sljit_compiler *compiler, sljit_s32 reg)
+{
+#if PCRE2_CODE_UNIT_WIDTH == 8
+OP2(SLJIT_AND, reg, 0, reg, 0, SLJIT_IMM, 0xc0);
+return CMP(SLJIT_NOT_EQUAL, reg, 0, SLJIT_IMM, 0x80);
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+OP2(SLJIT_AND, reg, 0, reg, 0, SLJIT_IMM, 0xfc00);
+return CMP(SLJIT_NOT_EQUAL, reg, 0, SLJIT_IMM, 0xdc00);
+#else
+#error "Unknown code width"
+#endif
+}
+#endif
+
+static sljit_s32 character_to_int32(PCRE2_UCHAR chr)
+{
+sljit_u32 value = chr;
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define SSE2_COMPARE_TYPE_INDEX 0
+return (sljit_s32)((value << 24) | (value << 16) | (value << 8) | value);
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+#define SSE2_COMPARE_TYPE_INDEX 1
+return (sljit_s32)((value << 16) | value);
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+#define SSE2_COMPARE_TYPE_INDEX 2
+return (sljit_s32)(value);
+#else
+#error "Unsupported unit width"
+#endif
+}
+
+static void load_from_mem_sse2(struct sljit_compiler *compiler, sljit_s32 dst_xmm_reg, sljit_s32 src_general_reg, sljit_s8 offset)
+{
+sljit_u8 instruction[5];
+
+SLJIT_ASSERT(dst_xmm_reg < 8);
+SLJIT_ASSERT(src_general_reg < 8);
+
+/* MOVDQA xmm1, xmm2/m128 */
+instruction[0] = ((sljit_u8)offset & 0xf) == 0 ? 0x66 : 0xf3;
+instruction[1] = 0x0f;
+instruction[2] = 0x6f;
+
+if (offset == 0)
+  {
+  instruction[3] = (dst_xmm_reg << 3) | src_general_reg;
+  sljit_emit_op_custom(compiler, instruction, 4);
+  return;
+  }
+
+instruction[3] = 0x40 | (dst_xmm_reg << 3) | src_general_reg;
+instruction[4] = (sljit_u8)offset;
+sljit_emit_op_custom(compiler, instruction, 5);
+}
+
+typedef enum {
+    sse2_compare_match1,
+    sse2_compare_match1i,
+    sse2_compare_match2,
+} sse2_compare_type;
+
+static void fast_forward_char_pair_sse2_compare(struct sljit_compiler *compiler, sse2_compare_type compare_type,
+  int step, sljit_s32 dst_ind, sljit_s32 cmp1_ind, sljit_s32 cmp2_ind, sljit_s32 tmp_ind)
+{
+sljit_u8 instruction[4];
+instruction[0] = 0x66;
+instruction[1] = 0x0f;
+
+SLJIT_ASSERT(step >= 0 && step <= 3);
+
+if (compare_type != sse2_compare_match2)
+  {
+  if (step == 0)
+    {
+    if (compare_type == sse2_compare_match1i)
+      {
+      /* POR xmm1, xmm2/m128 */
+      /* instruction[0] = 0x66; */
+      /* instruction[1] = 0x0f; */
+      instruction[2] = 0xeb;
+      instruction[3] = 0xc0 | (dst_ind << 3) | cmp2_ind;
+      sljit_emit_op_custom(compiler, instruction, 4);
+      }
+    return;
+    }
+
+  if (step != 2)
+    return;
+
+  /* PCMPEQB/W/D xmm1, xmm2/m128 */
+  /* instruction[0] = 0x66; */
+  /* instruction[1] = 0x0f; */
+  instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX;
+  instruction[3] = 0xc0 | (dst_ind << 3) | cmp1_ind;
+  sljit_emit_op_custom(compiler, instruction, 4);
+  return;
+  }
+
+switch (step)
+  {
+  case 0:
+  /* MOVDQA xmm1, xmm2/m128 */
+  /* instruction[0] = 0x66; */
+  /* instruction[1] = 0x0f; */
+  instruction[2] = 0x6f;
+  instruction[3] = 0xc0 | (tmp_ind << 3) | dst_ind;
+  sljit_emit_op_custom(compiler, instruction, 4);
+  return;
+
+  case 1:
+  /* PCMPEQB/W/D xmm1, xmm2/m128 */
+  /* instruction[0] = 0x66; */
+  /* instruction[1] = 0x0f; */
+  instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX;
+  instruction[3] = 0xc0 | (dst_ind << 3) | cmp1_ind;
+  sljit_emit_op_custom(compiler, instruction, 4);
+  return;
+
+  case 2:
+  /* PCMPEQB/W/D xmm1, xmm2/m128 */
+  /* instruction[0] = 0x66; */
+  /* instruction[1] = 0x0f; */
+  instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX;
+  instruction[3] = 0xc0 | (tmp_ind << 3) | cmp2_ind;
+  sljit_emit_op_custom(compiler, instruction, 4);
+  return;
+
+  case 3:
+  /* POR xmm1, xmm2/m128 */
+  /* instruction[0] = 0x66; */
+  /* instruction[1] = 0x0f; */
+  instruction[2] = 0xeb;
+  instruction[3] = 0xc0 | (dst_ind << 3) | tmp_ind;
+  sljit_emit_op_custom(compiler, instruction, 4);
+  return;
+  }
+}
+
+#define JIT_HAS_FAST_FORWARD_CHAR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SSE2))
+
+static void fast_forward_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset)
+{
+DEFINE_COMPILER;
+struct sljit_label *start;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+struct sljit_label *restart;
+#endif
+struct sljit_jump *quit;
+struct sljit_jump *partial_quit[2];
+sse2_compare_type compare_type = sse2_compare_match1;
+sljit_u8 instruction[8];
+sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1);
+sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR);
+sljit_s32 data_ind = 0;
+sljit_s32 tmp_ind = 1;
+sljit_s32 cmp1_ind = 2;
+sljit_s32 cmp2_ind = 3;
+sljit_u32 bit = 0;
+int i;
+
+SLJIT_UNUSED_ARG(offset);
+
+if (char1 != char2)
+  {
+  bit = char1 ^ char2;
+  compare_type = sse2_compare_match1i;
+
+  if (!is_powerof2(bit))
+    {
+    bit = 0;
+    compare_type = sse2_compare_match2;
+    }
+  }
+
+partial_quit[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+if (common->mode == PCRE2_JIT_COMPLETE)
+  add_jump(compiler, &common->failed_match, partial_quit[0]);
+
+/* First part (unaligned start) */
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1 | bit));
+
+SLJIT_ASSERT(tmp1_reg_ind < 8);
+
+/* MOVD xmm, r/m32 */
+instruction[0] = 0x66;
+instruction[1] = 0x0f;
+instruction[2] = 0x6e;
+instruction[3] = 0xc0 | (cmp1_ind << 3) | tmp1_reg_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+if (char1 != char2)
+  {
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(bit != 0 ? bit : char2));
+
+  /* MOVD xmm, r/m32 */
+  instruction[3] = 0xc0 | (cmp2_ind << 3) | tmp1_reg_ind;
+  sljit_emit_op_custom(compiler, instruction, 4);
+  }
+
+OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0);
+
+/* PSHUFD xmm1, xmm2/m128, imm8 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0x70;
+instruction[3] = 0xc0 | (cmp1_ind << 3) | cmp1_ind;
+instruction[4] = 0;
+sljit_emit_op_custom(compiler, instruction, 5);
+
+if (char1 != char2)
+  {
+  /* PSHUFD xmm1, xmm2/m128, imm8 */
+  instruction[3] = 0xc0 | (cmp2_ind << 3) | cmp2_ind;
+  sljit_emit_op_custom(compiler, instruction, 5);
+  }
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+restart = LABEL();
+#endif
+OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf);
+
+load_from_mem_sse2(compiler, data_ind, str_ptr_reg_ind, 0);
+for (i = 0; i < 4; i++)
+  fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+/* PMOVMSKB reg, xmm */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0xd7;
+instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | data_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+quit = CMP(SLJIT_NOT_ZERO, TMP1, 0, SLJIT_IMM, 0);
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+/* Second part (aligned) */
+start = LABEL();
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
+
+partial_quit[1] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+if (common->mode == PCRE2_JIT_COMPLETE)
+  add_jump(compiler, &common->failed_match, partial_quit[1]);
+
+load_from_mem_sse2(compiler, data_ind, str_ptr_reg_ind, 0);
+for (i = 0; i < 4; i++)
+  fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+/* PMOVMSKB reg, xmm */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0xd7;
+instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | data_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start);
+
+JUMPHERE(quit);
+
+/* BSF r32, r/m32 */
+instruction[0] = 0x0f;
+instruction[1] = 0xbc;
+instruction[2] = 0xc0 | (tmp1_reg_ind << 3) | tmp1_reg_ind;
+sljit_emit_op_custom(compiler, instruction, 3);
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+
+if (common->mode != PCRE2_JIT_COMPLETE)
+  {
+  JUMPHERE(partial_quit[0]);
+  JUMPHERE(partial_quit[1]);
+  OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_PTR, 0, STR_END, 0);
+  CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0);
+  }
+else
+  add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+if (common->utf && offset > 0)
+  {
+  SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE);
+
+  OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offset));
+
+  quit = jump_if_utf_char_start(compiler, TMP1);
+
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+  OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0);
+  JUMPTO(SLJIT_JUMP, restart);
+
+  JUMPHERE(quit);
+  }
+#endif
+}
+
+#define JIT_HAS_FAST_REQUESTED_CHAR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SSE2))
+
+static jump_list *fast_requested_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2)
+{
+DEFINE_COMPILER;
+struct sljit_label *start;
+struct sljit_jump *quit;
+jump_list *not_found = NULL;
+sse2_compare_type compare_type = sse2_compare_match1;
+sljit_u8 instruction[8];
+sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1);
+sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR);
+sljit_s32 data_ind = 0;
+sljit_s32 tmp_ind = 1;
+sljit_s32 cmp1_ind = 2;
+sljit_s32 cmp2_ind = 3;
+sljit_u32 bit = 0;
+int i;
+
+if (char1 != char2)
+  {
+  bit = char1 ^ char2;
+  compare_type = sse2_compare_match1i;
+
+  if (!is_powerof2(bit))
+    {
+    bit = 0;
+    compare_type = sse2_compare_match2;
+    }
+  }
+
+add_jump(compiler, &not_found, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0));
+OP1(SLJIT_MOV, TMP2, 0, TMP1, 0);
+OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0);
+
+/* First part (unaligned start) */
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1 | bit));
+
+SLJIT_ASSERT(tmp1_reg_ind < 8);
+
+/* MOVD xmm, r/m32 */
+instruction[0] = 0x66;
+instruction[1] = 0x0f;
+instruction[2] = 0x6e;
+instruction[3] = 0xc0 | (cmp1_ind << 3) | tmp1_reg_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+if (char1 != char2)
+  {
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(bit != 0 ? bit : char2));
+
+  /* MOVD xmm, r/m32 */
+  instruction[3] = 0xc0 | (cmp2_ind << 3) | tmp1_reg_ind;
+  sljit_emit_op_custom(compiler, instruction, 4);
+  }
+
+OP1(SLJIT_MOV, STR_PTR, 0, TMP2, 0);
+
+/* PSHUFD xmm1, xmm2/m128, imm8 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0x70;
+instruction[3] = 0xc0 | (cmp1_ind << 3) | cmp1_ind;
+instruction[4] = 0;
+sljit_emit_op_custom(compiler, instruction, 5);
+
+if (char1 != char2)
+  {
+  /* PSHUFD xmm1, xmm2/m128, imm8 */
+  instruction[3] = 0xc0 | (cmp2_ind << 3) | cmp2_ind;
+  sljit_emit_op_custom(compiler, instruction, 5);
+  }
+
+OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf);
+
+load_from_mem_sse2(compiler, data_ind, str_ptr_reg_ind, 0);
+for (i = 0; i < 4; i++)
+  fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+/* PMOVMSKB reg, xmm */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0xd7;
+instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | data_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+quit = CMP(SLJIT_NOT_ZERO, TMP1, 0, SLJIT_IMM, 0);
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+/* Second part (aligned) */
+start = LABEL();
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
+
+add_jump(compiler, &not_found, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+load_from_mem_sse2(compiler, data_ind, str_ptr_reg_ind, 0);
+for (i = 0; i < 4; i++)
+  fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+/* PMOVMSKB reg, xmm */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0xd7;
+instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | data_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start);
+
+JUMPHERE(quit);
+
+/* BSF r32, r/m32 */
+instruction[0] = 0x0f;
+instruction[1] = 0xbc;
+instruction[2] = 0xc0 | (tmp1_reg_ind << 3) | tmp1_reg_ind;
+sljit_emit_op_custom(compiler, instruction, 3);
+
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, STR_PTR, 0);
+add_jump(compiler, &not_found, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0));
+
+OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0);
+return not_found;
+}
+
+#ifndef _WIN64
+
+static SLJIT_INLINE sljit_u32 max_fast_forward_char_pair_offset(void)
+{
+#if PCRE2_CODE_UNIT_WIDTH == 8
+return 15;
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+return 7;
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+return 3;
+#else
+#error "Unsupported unit width"
+#endif
+}
+
+#define JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SSE2))
+
+static void fast_forward_char_pair_simd(compiler_common *common, sljit_s32 offs1,
+  PCRE2_UCHAR char1a, PCRE2_UCHAR char1b, sljit_s32 offs2, PCRE2_UCHAR char2a, PCRE2_UCHAR char2b)
+{
+DEFINE_COMPILER;
+sse2_compare_type compare1_type = sse2_compare_match1;
+sse2_compare_type compare2_type = sse2_compare_match1;
+sljit_u32 bit1 = 0;
+sljit_u32 bit2 = 0;
+sljit_u32 diff = IN_UCHARS(offs1 - offs2);
+sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1);
+sljit_s32 tmp2_reg_ind = sljit_get_register_index(TMP2);
+sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR);
+sljit_s32 data1_ind = 0;
+sljit_s32 data2_ind = 1;
+sljit_s32 tmp1_ind = 2;
+sljit_s32 tmp2_ind = 3;
+sljit_s32 cmp1a_ind = 4;
+sljit_s32 cmp1b_ind = 5;
+sljit_s32 cmp2a_ind = 6;
+sljit_s32 cmp2b_ind = 7;
+struct sljit_label *start;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+struct sljit_label *restart;
+#endif
+struct sljit_jump *jump[2];
+sljit_u8 instruction[8];
+int i;
+
+SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2);
+SLJIT_ASSERT(diff <= IN_UCHARS(max_fast_forward_char_pair_offset()));
+SLJIT_ASSERT(tmp1_reg_ind < 8 && tmp2_reg_ind == 1);
+
+/* Initialize. */
+if (common->match_end_ptr != 0)
+  {
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+  OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
+  OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offs1 + 1));
+
+  OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP1, 0, STR_END, 0);
+  CMOV(SLJIT_LESS, STR_END, TMP1, 0);
+  }
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1));
+add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+/* MOVD xmm, r/m32 */
+instruction[0] = 0x66;
+instruction[1] = 0x0f;
+instruction[2] = 0x6e;
+
+if (char1a == char1b)
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a));
+else
+  {
+  bit1 = char1a ^ char1b;
+  if (is_powerof2(bit1))
+    {
+    compare1_type = sse2_compare_match1i;
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a | bit1));
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(bit1));
+    }
+  else
+    {
+    compare1_type = sse2_compare_match2;
+    bit1 = 0;
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a));
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(char1b));
+    }
+  }
+
+instruction[3] = 0xc0 | (cmp1a_ind << 3) | tmp1_reg_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+if (char1a != char1b)
+  {
+  instruction[3] = 0xc0 | (cmp1b_ind << 3) | tmp2_reg_ind;
+  sljit_emit_op_custom(compiler, instruction, 4);
+  }
+
+if (char2a == char2b)
+  OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a));
+else
+  {
+  bit2 = char2a ^ char2b;
+  if (is_powerof2(bit2))
+    {
+    compare2_type = sse2_compare_match1i;
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a | bit2));
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(bit2));
+    }
+  else
+    {
+    compare2_type = sse2_compare_match2;
+    bit2 = 0;
+    OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a));
+    OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(char2b));
+    }
+  }
+
+instruction[3] = 0xc0 | (cmp2a_ind << 3) | tmp1_reg_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+if (char2a != char2b)
+  {
+  instruction[3] = 0xc0 | (cmp2b_ind << 3) | tmp2_reg_ind;
+  sljit_emit_op_custom(compiler, instruction, 4);
+  }
+
+/* PSHUFD xmm1, xmm2/m128, imm8 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0x70;
+instruction[4] = 0;
+
+instruction[3] = 0xc0 | (cmp1a_ind << 3) | cmp1a_ind;
+sljit_emit_op_custom(compiler, instruction, 5);
+
+if (char1a != char1b)
+  {
+  instruction[3] = 0xc0 | (cmp1b_ind << 3) | cmp1b_ind;
+  sljit_emit_op_custom(compiler, instruction, 5);
+  }
+
+instruction[3] = 0xc0 | (cmp2a_ind << 3) | cmp2a_ind;
+sljit_emit_op_custom(compiler, instruction, 5);
+
+if (char2a != char2b)
+  {
+  instruction[3] = 0xc0 | (cmp2b_ind << 3) | cmp2b_ind;
+  sljit_emit_op_custom(compiler, instruction, 5);
+  }
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+restart = LABEL();
+#endif
+
+OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, diff);
+OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0);
+OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf);
+
+load_from_mem_sse2(compiler, data1_ind, str_ptr_reg_ind, 0);
+
+jump[0] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_PTR, 0);
+
+load_from_mem_sse2(compiler, data2_ind, str_ptr_reg_ind, -(sljit_s8)diff);
+jump[1] = JUMP(SLJIT_JUMP);
+
+JUMPHERE(jump[0]);
+
+/* MOVDQA xmm1, xmm2/m128 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0x6f;
+instruction[3] = 0xc0 | (data2_ind << 3) | data1_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+/* PSLLDQ xmm1, imm8 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0x73;
+instruction[3] = 0xc0 | (7 << 3) | data2_ind;
+instruction[4] = diff;
+sljit_emit_op_custom(compiler, instruction, 5);
+
+JUMPHERE(jump[1]);
+
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf);
+
+for (i = 0; i < 4; i++)
+  {
+  fast_forward_char_pair_sse2_compare(compiler, compare2_type, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp2_ind);
+  fast_forward_char_pair_sse2_compare(compiler, compare1_type, i, data1_ind, cmp1a_ind, cmp1b_ind, tmp1_ind);
+  }
+
+/* PAND xmm1, xmm2/m128 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0xdb;
+instruction[3] = 0xc0 | (data1_ind << 3) | data2_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+/* PMOVMSKB reg, xmm */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0xd7;
+instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | 0;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+/* Ignore matches before the first STR_PTR. */
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+jump[0] = CMP(SLJIT_NOT_ZERO, TMP1, 0, SLJIT_IMM, 0);
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+/* Main loop. */
+start = LABEL();
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
+add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+load_from_mem_sse2(compiler, data1_ind, str_ptr_reg_ind, 0);
+load_from_mem_sse2(compiler, data2_ind, str_ptr_reg_ind, -(sljit_s8)diff);
+
+for (i = 0; i < 4; i++)
+  {
+  fast_forward_char_pair_sse2_compare(compiler, compare1_type, i, data1_ind, cmp1a_ind, cmp1b_ind, tmp2_ind);
+  fast_forward_char_pair_sse2_compare(compiler, compare2_type, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp1_ind);
+  }
+
+/* PAND xmm1, xmm2/m128 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0xdb;
+instruction[3] = 0xc0 | (data1_ind << 3) | data2_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+/* PMOVMSKB reg, xmm */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0xd7;
+instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | 0;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start);
+
+JUMPHERE(jump[0]);
+
+/* BSF r32, r/m32 */
+instruction[0] = 0x0f;
+instruction[1] = 0xbc;
+instruction[2] = 0xc0 | (tmp1_reg_ind << 3) | tmp1_reg_ind;
+sljit_emit_op_custom(compiler, instruction, 3);
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+
+add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+if (common->match_end_ptr != 0)
+  OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+if (common->utf)
+  {
+  OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offs1));
+
+  jump[0] = jump_if_utf_char_start(compiler, TMP1);
+
+  OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+  CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, restart);
+
+  add_jump(compiler, &common->failed_match, JUMP(SLJIT_JUMP));
+
+  JUMPHERE(jump[0]);
+  }
+#endif
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1));
+
+if (common->match_end_ptr != 0)
+  OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+}
+
+#endif /* !_WIN64 */
+
+#undef SSE2_COMPARE_TYPE_INDEX
+
+#endif /* SLJIT_CONFIG_X86 && !SUPPORT_VALGRIND */
+
+#if (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64 && (defined __ARM_NEON || defined __ARM_NEON__))
+
+#include <arm_neon.h>
+
+typedef union {
+  unsigned int x;
+  struct { unsigned char c1, c2, c3, c4; } c;
+} int_char;
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+static SLJIT_INLINE int utf_continue(sljit_u8 *s)
+{
+#if PCRE2_CODE_UNIT_WIDTH == 8
+return (*s & 0xc0) == 0x80;
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+return (*s & 0xfc00) == 0xdc00;
+#else
+#error "Unknown code width"
+#endif
+}
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+# define VECTOR_FACTOR 16
+# define vect_t uint8x16_t
+# define VLD1Q(X) vld1q_u8((sljit_u8 *)(X))
+# define VCEQQ vceqq_u8
+# define VORRQ vorrq_u8
+# define VST1Q vst1q_u8
+# define VDUPQ vdupq_n_u8
+# define VEXTQ vextq_u8
+# define VANDQ vandq_u8
+typedef union {
+       uint8_t mem[16];
+       uint64_t dw[2];
+} quad_word;
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+# define VECTOR_FACTOR 8
+# define vect_t uint16x8_t
+# define VLD1Q(X) vld1q_u16((sljit_u16 *)(X))
+# define VCEQQ vceqq_u16
+# define VORRQ vorrq_u16
+# define VST1Q vst1q_u16
+# define VDUPQ vdupq_n_u16
+# define VEXTQ vextq_u16
+# define VANDQ vandq_u16
+typedef union {
+       uint16_t mem[8];
+       uint64_t dw[2];
+} quad_word;
+#else
+# define VECTOR_FACTOR 4
+# define vect_t uint32x4_t
+# define VLD1Q(X) vld1q_u32((sljit_u32 *)(X))
+# define VCEQQ vceqq_u32
+# define VORRQ vorrq_u32
+# define VST1Q vst1q_u32
+# define VDUPQ vdupq_n_u32
+# define VEXTQ vextq_u32
+# define VANDQ vandq_u32
+typedef union {
+       uint32_t mem[4];
+       uint64_t dw[2];
+} quad_word;
+#endif
+
+#define FFCS
+#include "pcre2_jit_neon_inc.h"
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+# define FF_UTF
+# include "pcre2_jit_neon_inc.h"
+# undef FF_UTF
+#endif
+#undef FFCS
+
+#define FFCS_2
+#include "pcre2_jit_neon_inc.h"
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+# define FF_UTF
+# include "pcre2_jit_neon_inc.h"
+# undef FF_UTF
+#endif
+#undef FFCS_2
+
+#define FFCS_MASK
+#include "pcre2_jit_neon_inc.h"
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+# define FF_UTF
+# include "pcre2_jit_neon_inc.h"
+# undef FF_UTF
+#endif
+#undef FFCS_MASK
+
+#define JIT_HAS_FAST_FORWARD_CHAR_SIMD 1
+
+static void fast_forward_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset)
+{
+DEFINE_COMPILER;
+int_char ic;
+struct sljit_jump *partial_quit;
+/* Save temporary registers. */
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STR_PTR, 0);
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP3, 0);
+
+/* Prepare function arguments */
+OP1(SLJIT_MOV, SLJIT_R0, 0, STR_END, 0);
+OP1(SLJIT_MOV, SLJIT_R1, 0, STR_PTR, 0);
+OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, offset);
+
+if (char1 == char2)
+  {
+    ic.c.c1 = char1;
+    ic.c.c2 = char2;
+    OP1(SLJIT_MOV, SLJIT_R4, 0, SLJIT_IMM, ic.x);
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+  if (common->utf && offset > 0)
+    sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(UW) | SLJIT_ARG3(UW) | SLJIT_ARG4(UW),
+                     SLJIT_IMM, SLJIT_FUNC_OFFSET(ffcs_utf));
+  else
+    sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(UW) | SLJIT_ARG3(UW) | SLJIT_ARG4(UW),
+                     SLJIT_IMM, SLJIT_FUNC_OFFSET(ffcs));
+#else
+  sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(UW) | SLJIT_ARG3(UW) | SLJIT_ARG4(UW),
+                   SLJIT_IMM, SLJIT_FUNC_OFFSET(ffcs));
+#endif
+  }
+else
+  {
+  PCRE2_UCHAR mask = char1 ^ char2;
+  if (is_powerof2(mask))
+    {
+    ic.c.c1 = char1 | mask;
+    ic.c.c2 = mask;
+    OP1(SLJIT_MOV, SLJIT_R4, 0, SLJIT_IMM, ic.x);
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+    if (common->utf && offset > 0)
+      sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(UW) | SLJIT_ARG3(UW) | SLJIT_ARG4(UW),
+                       SLJIT_IMM, SLJIT_FUNC_OFFSET(ffcs_mask_utf));
+    else
+      sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(UW) | SLJIT_ARG3(UW) | SLJIT_ARG4(UW),
+                       SLJIT_IMM, SLJIT_FUNC_OFFSET(ffcs_mask));
+#else
+    sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(UW) | SLJIT_ARG3(UW) | SLJIT_ARG4(UW),
+                     SLJIT_IMM, SLJIT_FUNC_OFFSET(ffcs_mask));
+#endif
+    }
+  else
+    {
+      ic.c.c1 = char1;
+      ic.c.c2 = char2;
+      OP1(SLJIT_MOV, SLJIT_R4, 0, SLJIT_IMM, ic.x);
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+    if (common->utf && offset > 0)
+      sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(UW) | SLJIT_ARG3(UW) | SLJIT_ARG4(UW),
+                       SLJIT_IMM, SLJIT_FUNC_OFFSET(ffcs_2_utf));
+    else
+      sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(UW) | SLJIT_ARG3(UW) | SLJIT_ARG4(UW),
+                       SLJIT_IMM, SLJIT_FUNC_OFFSET(ffcs_2));
+#else
+    sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(UW) | SLJIT_ARG3(UW) | SLJIT_ARG4(UW),
+                     SLJIT_IMM, SLJIT_FUNC_OFFSET(ffcs_2));
+#endif
+    }
+  }
+/* Restore registers. */
+OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+OP1(SLJIT_MOV, TMP3, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1);
+
+/* Check return value. */
+partial_quit = CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
+if (common->mode == PCRE2_JIT_COMPLETE)
+  add_jump(compiler, &common->failed_match, partial_quit);
+
+/* Fast forward STR_PTR to the result of memchr. */
+OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0);
+
+if (common->mode != PCRE2_JIT_COMPLETE)
+  JUMPHERE(partial_quit);
+}
+
+typedef enum {
+  compare_match1,
+  compare_match1i,
+  compare_match2,
+} compare_type;
+
+static inline vect_t fast_forward_char_pair_compare(compare_type ctype, vect_t dst, vect_t cmp1, vect_t cmp2)
+{
+if (ctype == compare_match2)
+  {
+  vect_t tmp = dst;
+  dst = VCEQQ(dst, cmp1);
+  tmp = VCEQQ(tmp, cmp2);
+  dst = VORRQ(dst, tmp);
+  return dst;
+  }
+
+if (ctype == compare_match1i)
+  dst = VORRQ(dst, cmp2);
+dst = VCEQQ(dst, cmp1);
+return dst;
+}
+
+static SLJIT_INLINE sljit_u32 max_fast_forward_char_pair_offset(void)
+{
+#if PCRE2_CODE_UNIT_WIDTH == 8
+return 15;
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+return 7;
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+return 3;
+#else
+#error "Unsupported unit width"
+#endif
+}
+
+/* ARM doesn't have a shift left across lanes. */
+static SLJIT_INLINE vect_t shift_left_n_lanes(vect_t a, sljit_u8 n)
+{
+vect_t zero = VDUPQ(0);
+SLJIT_ASSERT(0 < n && n < VECTOR_FACTOR);
+/* VEXTQ takes an immediate as last argument. */
+#define C(X) case X: return VEXTQ(zero, a, VECTOR_FACTOR - X);
+switch (n)
+  {
+  C(1); C(2); C(3);
+#if PCRE2_CODE_UNIT_WIDTH != 32
+  C(4); C(5); C(6); C(7);
+# if PCRE2_CODE_UNIT_WIDTH != 16
+  C(8); C(9); C(10); C(11); C(12); C(13); C(14); C(15);
+# endif
+#endif
+  default:
+    /* Based on the ASSERT(0 < n && n < VECTOR_FACTOR) above, this won't
+       happen. The return is still here for compilers to not warn. */
+    return a;
+  }
+}
+
+#define FFCPS
+#define FFCPS_DIFF1
+#define FFCPS_CHAR1A2A
+
+#define FFCPS_0
+#include "pcre2_jit_neon_inc.h"
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+# define FF_UTF
+# include "pcre2_jit_neon_inc.h"
+# undef FF_UTF
+#endif
+#undef FFCPS_0
+
+#undef FFCPS_CHAR1A2A
+
+#define FFCPS_1
+#include "pcre2_jit_neon_inc.h"
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+# define FF_UTF
+# include "pcre2_jit_neon_inc.h"
+# undef FF_UTF
+#endif
+#undef FFCPS_1
+
+#undef FFCPS_DIFF1
+
+#define FFCPS_DEFAULT
+#include "pcre2_jit_neon_inc.h"
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+# define FF_UTF
+# include "pcre2_jit_neon_inc.h"
+# undef FF_UTF
+#endif
+#undef FFCPS
+
+#define JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD 1
+
+static void fast_forward_char_pair_simd(compiler_common *common, sljit_s32 offs1,
+  PCRE2_UCHAR char1a, PCRE2_UCHAR char1b, sljit_s32 offs2, PCRE2_UCHAR char2a, PCRE2_UCHAR char2b)
+{
+DEFINE_COMPILER;
+sljit_u32 diff = IN_UCHARS(offs1 - offs2);
+struct sljit_jump *partial_quit;
+int_char ic;
+SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2);
+SLJIT_ASSERT(diff <= IN_UCHARS(max_fast_forward_char_pair_offset()));
+SLJIT_ASSERT(compiler->scratches == 5);
+
+/* Save temporary register STR_PTR. */
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STR_PTR, 0);
+
+/* Prepare arguments for the function call. */
+if (common->match_end_ptr == 0)
+   OP1(SLJIT_MOV, SLJIT_R0, 0, STR_END, 0);
+else
+  {
+  OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+  OP2(SLJIT_ADD, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_IMM, IN_UCHARS(offs1 + 1));
+
+  OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, STR_END, 0, SLJIT_R0, 0);
+  CMOV(SLJIT_LESS, SLJIT_R0, STR_END, 0);
+  }
+
+OP1(SLJIT_MOV, SLJIT_R1, 0, STR_PTR, 0); 
+OP1(SLJIT_MOV_S32, SLJIT_R2, 0, SLJIT_IMM, offs1);
+OP1(SLJIT_MOV_S32, SLJIT_R3, 0, SLJIT_IMM, offs2);
+ic.c.c1 = char1a;
+ic.c.c2 = char1b;
+ic.c.c3 = char2a;
+ic.c.c4 = char2b;
+OP1(SLJIT_MOV_U32, SLJIT_R4, 0, SLJIT_IMM, ic.x);
+
+if (diff == 1) {
+  if (char1a == char1b && char2a == char2b) {
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+    if (common->utf)
+      sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW) | SLJIT_ARG3(SW) | SLJIT_ARG4(SW),
+                       SLJIT_IMM, SLJIT_FUNC_OFFSET(ffcps_0_utf));
+    else
+#endif
+      sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW) | SLJIT_ARG3(SW) | SLJIT_ARG4(SW),
+                       SLJIT_IMM, SLJIT_FUNC_OFFSET(ffcps_0));
+  } else {
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+    if (common->utf)
+      sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW) | SLJIT_ARG3(SW) | SLJIT_ARG4(SW),
+                       SLJIT_IMM, SLJIT_FUNC_OFFSET(ffcps_1_utf));
+    else
+#endif
+      sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW) | SLJIT_ARG3(SW) | SLJIT_ARG4(SW),
+                       SLJIT_IMM, SLJIT_FUNC_OFFSET(ffcps_1));
+  }
+} else {
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+  if (common->utf)
+    sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW) | SLJIT_ARG3(SW) | SLJIT_ARG4(SW),
+                     SLJIT_IMM, SLJIT_FUNC_OFFSET(ffcps_default_utf));
+  else
+#endif
+    sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW) | SLJIT_ARG3(SW) | SLJIT_ARG4(SW),
+                     SLJIT_IMM, SLJIT_FUNC_OFFSET(ffcps_default));
+}
+
+/* Restore STR_PTR register. */
+OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+
+/* Check return value. */
+partial_quit = CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
+add_jump(compiler, &common->failed_match, partial_quit);
+
+/* Fast forward STR_PTR to the result of memchr. */
+OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0);
+
+JUMPHERE(partial_quit);
+}
+
+#endif /* SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64 */
diff --git a/src/c/pcre2/src/pcre2_jit_test.c b/src/c/pcre2/src/pcre2_jit_test.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_jit_test.c
@@ -0,0 +1,2501 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+         New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#define PCRE2_CODE_UNIT_WIDTH 0
+#include "pcre2.h"
+
+/*
+ Letter characters:
+   \xe6\x92\xad = 0x64ad = 25773 (kanji)
+ Non-letter characters:
+   \xc2\xa1 = 0xa1 =  (Inverted Exclamation Mark)
+   \xf3\xa9\xb7\x80 = 0xe9dc0 = 957888
+   \xed\xa0\x80 = 55296 = 0xd800 (Invalid UTF character)
+   \xed\xb0\x80 = 56320 = 0xdc00 (Invalid UTF character)
+ Newlines:
+   \xc2\x85 = 0x85 = 133 (NExt Line = NEL)
+   \xe2\x80\xa8 = 0x2028 = 8232 (Line Separator)
+ Othercase pairs:
+   \xc3\xa9 = 0xe9 = 233 (e')
+      \xc3\x89 = 0xc9 = 201 (E')
+   \xc3\xa1 = 0xe1 = 225 (a')
+      \xc3\x81 = 0xc1 = 193 (A')
+   \x53 = 0x53 = S
+     \x73 = 0x73 = s
+     \xc5\xbf = 0x17f = 383 (long S)
+   \xc8\xba = 0x23a = 570
+      \xe2\xb1\xa5 = 0x2c65 = 11365
+   \xe1\xbd\xb8 = 0x1f78 = 8056
+      \xe1\xbf\xb8 = 0x1ff8 = 8184
+   \xf0\x90\x90\x80 = 0x10400 = 66560
+      \xf0\x90\x90\xa8 = 0x10428 = 66600
+   \xc7\x84 = 0x1c4 = 452
+     \xc7\x85 = 0x1c5 = 453
+     \xc7\x86 = 0x1c6 = 454
+ Caseless sets:
+   ucp_Armenian - \x{531}-\x{556} -> \x{561}-\x{586}
+   ucp_Coptic - \x{2c80}-\x{2ce3} -> caseless: XOR 0x1
+   ucp_Latin - \x{ff21}-\x{ff3a} -> \x{ff41]-\x{ff5a}
+
+ Mark property:
+   \xcc\x8d = 0x30d = 781
+ Special:
+   \xc2\x80 = 0x80 = 128 (lowest 2 byte character)
+   \xdf\xbf = 0x7ff = 2047 (highest 2 byte character)
+   \xe0\xa0\x80 = 0x800 = 2048 (lowest 2 byte character)
+   \xef\xbf\xbf = 0xffff = 65535 (highest 3 byte character)
+   \xf0\x90\x80\x80 = 0x10000 = 65536 (lowest 4 byte character)
+   \xf4\x8f\xbf\xbf = 0x10ffff = 1114111 (highest allowed utf character)
+*/
+
+static int regression_tests(void);
+static int invalid_utf8_regression_tests(void);
+static int invalid_utf16_regression_tests(void);
+static int invalid_utf32_regression_tests(void);
+
+int main(void)
+{
+	int jit = 0;
+#if defined SUPPORT_PCRE2_8
+	pcre2_config_8(PCRE2_CONFIG_JIT, &jit);
+#elif defined SUPPORT_PCRE2_16
+	pcre2_config_16(PCRE2_CONFIG_JIT, &jit);
+#elif defined SUPPORT_PCRE2_32
+	pcre2_config_32(PCRE2_CONFIG_JIT, &jit);
+#endif
+	if (!jit) {
+		printf("JIT must be enabled to run pcre_jit_test\n");
+		return 1;
+	}
+	return regression_tests()
+		| invalid_utf8_regression_tests()
+		| invalid_utf16_regression_tests()
+		| invalid_utf32_regression_tests();
+}
+
+/* --------------------------------------------------------------------------------------- */
+
+#if !(defined SUPPORT_PCRE2_8) && !(defined SUPPORT_PCRE2_16) && !(defined SUPPORT_PCRE2_32)
+#error SUPPORT_PCRE2_8 or SUPPORT_PCRE2_16 or SUPPORT_PCRE2_32 must be defined
+#endif
+
+#define MU	(PCRE2_MULTILINE | PCRE2_UTF)
+#define MUP	(PCRE2_MULTILINE | PCRE2_UTF | PCRE2_UCP)
+#define CMU	(PCRE2_CASELESS | PCRE2_MULTILINE | PCRE2_UTF)
+#define CMUP	(PCRE2_CASELESS | PCRE2_MULTILINE | PCRE2_UTF | PCRE2_UCP)
+#define M	(PCRE2_MULTILINE)
+#define MP	(PCRE2_MULTILINE | PCRE2_UCP)
+#define U	(PCRE2_UTF)
+#define CM	(PCRE2_CASELESS | PCRE2_MULTILINE)
+
+#define BSR(x)	((x) << 16)
+#define A	PCRE2_NEWLINE_ANYCRLF
+
+#define GET_NEWLINE(x)	((x) & 0xffff)
+#define GET_BSR(x)	((x) >> 16)
+
+#define OFFSET_MASK	0x00ffff
+#define F_NO8		0x010000
+#define F_NO16		0x020000
+#define F_NO32		0x020000
+#define F_NOMATCH	0x040000
+#define F_DIFF		0x080000
+#define F_FORCECONV	0x100000
+#define F_PROPERTY	0x200000
+
+struct regression_test_case {
+	int compile_options;
+	int newline;
+	int match_options;
+	int start_offset;
+	const char *pattern;
+	const char *input;
+};
+
+static struct regression_test_case regression_test_cases[] = {
+	/* Constant strings. */
+	{ MU, A, 0, 0, "AbC", "AbAbC" },
+	{ MU, A, 0, 0, "ACCEPT", "AACACCACCEACCEPACCEPTACCEPTT" },
+	{ CMU, A, 0, 0, "aA#\xc3\xa9\xc3\x81", "aA#Aa#\xc3\x89\xc3\xa1" },
+	{ M, A, 0, 0, "[^a]", "aAbB" },
+	{ CM, A, 0, 0, "[^m]", "mMnN" },
+	{ M, A, 0, 0, "a[^b][^#]", "abacd" },
+	{ CM, A, 0, 0, "A[^B][^E]", "abacd" },
+	{ CMU, A, 0, 0, "[^x][^#]", "XxBll" },
+	{ MU, A, 0, 0, "[^a]", "aaa\xc3\xa1#Ab" },
+	{ CMU, A, 0, 0, "[^A]", "aA\xe6\x92\xad" },
+	{ MU, A, 0, 0, "\\W(\\W)?\\w", "\r\n+bc" },
+	{ MU, A, 0, 0, "\\W(\\W)?\\w", "\n\r+bc" },
+	{ MU, A, 0, 0, "\\W(\\W)?\\w", "\r\r+bc" },
+	{ MU, A, 0, 0, "\\W(\\W)?\\w", "\n\n+bc" },
+	{ MU, A, 0, 0, "[axd]", "sAXd" },
+	{ CMU, A, 0, 0, "[axd]", "sAXd" },
+	{ CMU, A, 0, 0 | F_NOMATCH, "[^axd]", "DxA" },
+	{ MU, A, 0, 0, "[a-dA-C]", "\xe6\x92\xad\xc3\xa9.B" },
+	{ MU, A, 0, 0, "[^a-dA-C]", "\xe6\x92\xad\xc3\xa9" },
+	{ CMU, A, 0, 0, "[^\xc3\xa9]", "\xc3\xa9\xc3\x89." },
+	{ MU, A, 0, 0, "[^\xc3\xa9]", "\xc3\xa9\xc3\x89." },
+	{ MU, A, 0, 0, "[^a]", "\xc2\x80[]" },
+	{ CMU, A, 0, 0, "\xf0\x90\x90\xa7", "\xf0\x90\x91\x8f" },
+	{ CM, A, 0, 0, "1a2b3c4", "1a2B3c51A2B3C4" },
+	{ PCRE2_CASELESS, 0, 0, 0, "\xff#a", "\xff#\xff\xfe##\xff#A" },
+	{ PCRE2_CASELESS, 0, 0, 0, "\xfe", "\xff\xfc#\xfe\xfe" },
+	{ PCRE2_CASELESS, 0, 0, 0, "a1", "Aa1" },
+#ifndef NEVER_BACKSLASH_C
+	{ M, A, 0, 0, "\\Ca", "cda" },
+	{ CM, A, 0, 0, "\\Ca", "CDA" },
+	{ M, A, 0, 0 | F_NOMATCH, "\\Cx", "cda" },
+	{ CM, A, 0, 0 | F_NOMATCH, "\\Cx", "CDA" },
+#endif /* !NEVER_BACKSLASH_C */
+	{ CMUP, A, 0, 0, "\xf0\x90\x90\x80\xf0\x90\x90\xa8", "\xf0\x90\x90\xa8\xf0\x90\x90\x80" },
+	{ CMUP, A, 0, 0, "\xf0\x90\x90\x80{2}", "\xf0\x90\x90\x80#\xf0\x90\x90\xa8\xf0\x90\x90\x80" },
+	{ CMUP, A, 0, 0, "\xf0\x90\x90\xa8{2}", "\xf0\x90\x90\x80#\xf0\x90\x90\xa8\xf0\x90\x90\x80" },
+	{ CMUP, A, 0, 0, "\xe1\xbd\xb8\xe1\xbf\xb8", "\xe1\xbf\xb8\xe1\xbd\xb8" },
+	{ M, A, 0, 0, "[3-57-9]", "5" },
+	{ PCRE2_AUTO_CALLOUT, A, 0, 0, "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+		"12345678901234567890123456789012345678901234567890123456789012345678901234567890" },
+
+	/* Assertions. */
+	{ MU, A, 0, 0, "\\b[^A]", "A_B#" },
+	{ M, A, 0, 0 | F_NOMATCH, "\\b\\W", "\n*" },
+	{ MU, A, 0, 0, "\\B[^,]\\b[^s]\\b", "#X" },
+	{ MP, A, 0, 0, "\\B", "_\xa1" },
+	{ MP, A, 0, 0 | F_PROPERTY, "\\b_\\b[,A]\\B", "_," },
+	{ MUP, A, 0, 0, "\\b", "\xe6\x92\xad!" },
+	{ MUP, A, 0, 0, "\\B", "_\xc2\xa1\xc3\xa1\xc2\x85" },
+	{ MUP, A, 0, 0, "\\b[^A]\\B[^c]\\b[^_]\\B", "_\xc3\xa1\xe2\x80\xa8" },
+	{ MUP, A, 0, 0, "\\b\\w+\\B", "\xc3\x89\xc2\xa1\xe6\x92\xad\xc3\x81\xc3\xa1" },
+	{ MU, A, 0, 0 | F_NOMATCH, "\\b.", "\xcd\xbe" },
+	{ CMUP, A, 0, 0, "\\By", "\xf0\x90\x90\xa8y" },
+	{ M, A, 0, 0 | F_NOMATCH, "\\R^", "\n" },
+	{ M, A, 0, 1 | F_NOMATCH, "^", "\n" },
+	{ 0, 0, 0, 0, "^ab", "ab" },
+	{ 0, 0, 0, 0 | F_NOMATCH, "^ab", "aab" },
+	{ M, PCRE2_NEWLINE_CRLF, 0, 0, "^a", "\r\raa\n\naa\r\naa" },
+	{ MU, A, 0, 0, "^-", "\xe2\x80\xa8--\xc2\x85-\r\n-" },
+	{ M, PCRE2_NEWLINE_ANY, 0, 0, "^-", "a--b--\x85--" },
+	{ MU, PCRE2_NEWLINE_ANY, 0, 0, "^-", "a--\xe2\x80\xa8--" },
+	{ MU, PCRE2_NEWLINE_ANY, 0, 0, "^-", "a--\xc2\x85--" },
+	{ 0, 0, 0, 0, "ab$", "ab" },
+	{ 0, 0, 0, 0 | F_NOMATCH, "ab$", "abab\n\n" },
+	{ PCRE2_DOLLAR_ENDONLY, 0, 0, 0 | F_NOMATCH, "ab$", "abab\r\n" },
+	{ M, PCRE2_NEWLINE_CRLF, 0, 0, "a$", "\r\raa\n\naa\r\naa" },
+	{ M, PCRE2_NEWLINE_ANY, 0, 0, "a$", "aaa" },
+	{ MU, PCRE2_NEWLINE_ANYCRLF, 0, 0, "#$", "#\xc2\x85###\r#" },
+	{ MU, PCRE2_NEWLINE_ANY, 0, 0, "#$", "#\xe2\x80\xa9" },
+	{ 0, PCRE2_NEWLINE_ANY, PCRE2_NOTBOL, 0 | F_NOMATCH, "^a", "aa\naa" },
+	{ M, PCRE2_NEWLINE_ANY, PCRE2_NOTBOL, 0, "^a", "aa\naa" },
+	{ 0, PCRE2_NEWLINE_ANY, PCRE2_NOTEOL, 0 | F_NOMATCH, "a$", "aa\naa" },
+	{ 0, PCRE2_NEWLINE_ANY, PCRE2_NOTEOL, 0 | F_NOMATCH, "a$", "aa\r\n" },
+	{ U | PCRE2_DOLLAR_ENDONLY, PCRE2_NEWLINE_ANY, 0, 0 | F_PROPERTY, "\\p{Any}{2,}$", "aa\r\n" },
+	{ M, PCRE2_NEWLINE_ANY, PCRE2_NOTEOL, 0, "a$", "aa\naa" },
+	{ 0, PCRE2_NEWLINE_CR, 0, 0, ".\\Z", "aaa" },
+	{ U, PCRE2_NEWLINE_CR, 0, 0, "a\\Z", "aaa\r" },
+	{ 0, PCRE2_NEWLINE_CR, 0, 0, ".\\Z", "aaa\n" },
+	{ 0, PCRE2_NEWLINE_CRLF, 0, 0, ".\\Z", "aaa\r" },
+	{ U, PCRE2_NEWLINE_CRLF, 0, 0, ".\\Z", "aaa\n" },
+	{ 0, PCRE2_NEWLINE_CRLF, 0, 0, ".\\Z", "aaa\r\n" },
+	{ U, PCRE2_NEWLINE_ANYCRLF, 0, 0, ".\\Z", "aaa" },
+	{ U, PCRE2_NEWLINE_ANYCRLF, 0, 0, ".\\Z", "aaa\r" },
+	{ U, PCRE2_NEWLINE_ANYCRLF, 0, 0, ".\\Z", "aaa\n" },
+	{ U, PCRE2_NEWLINE_ANYCRLF, 0, 0, ".\\Z", "aaa\r\n" },
+	{ U, PCRE2_NEWLINE_ANYCRLF, 0, 0, ".\\Z", "aaa\xe2\x80\xa8" },
+	{ U, PCRE2_NEWLINE_ANYCRLF, 0, 0, ".\\Z", "aaa" },
+	{ U, PCRE2_NEWLINE_ANYCRLF, 0, 0, ".\\Z", "aaa\r" },
+	{ U, PCRE2_NEWLINE_ANYCRLF, 0, 0, ".\\Z", "aaa\n" },
+	{ U, PCRE2_NEWLINE_ANYCRLF, 0, 0, ".\\Z", "aaa\r\n" },
+	{ U, PCRE2_NEWLINE_ANY, 0, 0, ".\\Z", "aaa\xc2\x85" },
+	{ U, PCRE2_NEWLINE_ANY, 0, 0, ".\\Z", "aaa\xe2\x80\xa8" },
+	{ M, A, 0, 0, "\\Aa", "aaa" },
+	{ M, A, 0, 1 | F_NOMATCH, "\\Aa", "aaa" },
+	{ M, A, 0, 1, "\\Ga", "aaa" },
+	{ M, A, 0, 1 | F_NOMATCH, "\\Ga", "aba" },
+	{ M, A, 0, 0, "a\\z", "aaa" },
+	{ M, A, 0, 0 | F_NOMATCH, "a\\z", "aab" },
+
+	/* Brackets and alternatives. */
+	{ MU, A, 0, 0, "(ab|bb|cd)", "bacde" },
+	{ MU, A, 0, 0, "(?:ab|a)(bc|c)", "ababc" },
+	{ MU, A, 0, 0, "((ab|(cc))|(bb)|(?:cd|efg))", "abac" },
+	{ CMU, A, 0, 0, "((aB|(Cc))|(bB)|(?:cd|EFg))", "AcCe" },
+	{ MU, A, 0, 0, "((ab|(cc))|(bb)|(?:cd|ebg))", "acebebg" },
+	{ MU, A, 0, 0, "(?:(a)|(?:b))(cc|(?:d|e))(a|b)k", "accabdbbccbk" },
+	{ MU, A, 0, 0, "\xc7\x82|\xc6\x82", "\xf1\x83\x82\x82\xc7\x82\xc7\x83" },
+	{ MU, A, 0, 0, "=\xc7\x82|#\xc6\x82", "\xf1\x83\x82\x82=\xc7\x82\xc7\x83" },
+	{ MU, A, 0, 0, "\xc7\x82\xc7\x83|\xc6\x82\xc6\x82", "\xf1\x83\x82\x82\xc7\x82\xc7\x83" },
+	{ MU, A, 0, 0, "\xc6\x82\xc6\x82|\xc7\x83\xc7\x83|\xc8\x84\xc8\x84", "\xf1\x83\x82\x82\xc8\x84\xc8\x84" },
+	{ U, A, 0, 0, "\xe1\x81\x80|\xe2\x82\x80|\xe4\x84\x80", "\xdf\xbf\xc2\x80\xe4\x84\x80" },
+	{ U, A, 0, 0, "(?:\xe1\x81\x80|\xe2\x82\x80|\xe4\x84\x80)#", "\xdf\xbf\xc2\x80#\xe4\x84\x80#" },
+	{ CM, A, 0, 0, "ab|cd", "CD" },
+	{ CM, A, 0, 0, "a1277|a1377|bX487", "bx487" },
+	{ CM, A, 0, 0, "a1277|a1377|bx487", "bX487" },
+
+	/* Greedy and non-greedy ? operators. */
+	{ MU, A, 0, 0, "(?:a)?a", "laab" },
+	{ CMU, A, 0, 0, "(A)?A", "llaab" },
+	{ MU, A, 0, 0, "(a)?\?a", "aab" }, /* ?? is the prefix of trygraphs in GCC. */
+	{ MU, A, 0, 0, "(a)?a", "manm" },
+	{ CMU, A, 0, 0, "(a|b)?\?d((?:e)?)", "ABABdx" },
+	{ MU, A, 0, 0, "(a|b)?\?d((?:e)?)", "abcde" },
+	{ MU, A, 0, 0, "((?:ab)?\?g|b(?:g(nn|d)?\?)?)?\?(?:n)?m", "abgnbgnnbgdnmm" },
+
+	/* Greedy and non-greedy + operators */
+	{ MU, A, 0, 0, "(aa)+aa", "aaaaaaa" },
+	{ MU, A, 0, 0, "(aa)+?aa", "aaaaaaa" },
+	{ MU, A, 0, 0, "(?:aba|ab|a)+l", "ababamababal" },
+	{ MU, A, 0, 0, "(?:aba|ab|a)+?l", "ababamababal" },
+	{ MU, A, 0, 0, "(a(?:bc|cb|b|c)+?|ss)+e", "accssabccbcacbccbbXaccssabccbcacbccbbe" },
+	{ MU, A, 0, 0, "(a(?:bc|cb|b|c)+|ss)+?e", "accssabccbcacbccbbXaccssabccbcacbccbbe" },
+	{ MU, A, 0, 0, "(?:(b(c)+?)+)?\?(?:(bc)+|(cb)+)+(?:m)+", "bccbcccbcbccbcbPbccbcccbcbccbcbmmn" },
+
+	/* Greedy and non-greedy * operators */
+	{ CMU, A, 0, 0, "(?:AA)*AB", "aaaaaaamaaaaaaab" },
+	{ MU, A, 0, 0, "(?:aa)*?ab", "aaaaaaamaaaaaaab" },
+	{ MU, A, 0, 0, "(aa|ab)*ab", "aaabaaab" },
+	{ CMU, A, 0, 0, "(aa|Ab)*?aB", "aaabaaab" },
+	{ MU, A, 0, 0, "(a|b)*(?:a)*(?:b)*m", "abbbaaababanabbbaaababamm" },
+	{ MU, A, 0, 0, "(a|b)*?(?:a)*?(?:b)*?m", "abbbaaababanabbbaaababamm" },
+	{ M, A, 0, 0, "a(a(\\1*)a|(b)b+){0}a", "aa" },
+	{ M, A, 0, 0, "((?:a|)*){0}a", "a" },
+
+	/* Combining ? + * operators */
+	{ MU, A, 0, 0, "((bm)+)?\?(?:a)*(bm)+n|((am)+?)?(?:a)+(am)*n", "bmbmabmamaaamambmaman" },
+	{ MU, A, 0, 0, "(((ab)?cd)*ef)+g", "abcdcdefcdefefmabcdcdefcdefefgg" },
+	{ MU, A, 0, 0, "(((ab)?\?cd)*?ef)+?g", "abcdcdefcdefefmabcdcdefcdefefgg" },
+	{ MU, A, 0, 0, "(?:(ab)?c|(?:ab)+?d)*g", "ababcdccababddg" },
+	{ MU, A, 0, 0, "(?:(?:ab)?\?c|(ab)+d)*?g", "ababcdccababddg" },
+
+	/* Single character iterators. */
+	{ MU, A, 0, 0, "(a+aab)+aaaab", "aaaabcaaaabaabcaabcaaabaaaab" },
+	{ MU, A, 0, 0, "(a*a*aab)+x", "aaaaabaabaaabmaabx" },
+	{ MU, A, 0, 0, "(a*?(b|ab)a*?)+x", "aaaabcxbbaabaacbaaabaabax" },
+	{ MU, A, 0, 0, "(a+(ab|ad)a+)+x", "aaabaaaadaabaaabaaaadaaax" },
+	{ MU, A, 0, 0, "(a?(a)a?)+(aaa)", "abaaabaaaaaaaa" },
+	{ MU, A, 0, 0, "(a?\?(a)a?\?)+(b)", "aaaacaaacaacacbaaab" },
+	{ MU, A, 0, 0, "(a{0,4}(b))+d", "aaaaaabaabcaaaaabaaaaabd" },
+	{ MU, A, 0, 0, "(a{0,4}?[^b])+d+(a{0,4}[^b])d+", "aaaaadaaaacaadddaaddd" },
+	{ MU, A, 0, 0, "(ba{2})+c", "baabaaabacbaabaac" },
+	{ MU, A, 0, 0, "(a*+bc++)+", "aaabbcaaabcccab" },
+	{ MU, A, 0, 0, "(a?+[^b])+", "babaacacb" },
+	{ MU, A, 0, 0, "(a{0,3}+b)(a{0,3}+b)(a{0,3}+)[^c]", "abaabaaacbaabaaaac" },
+	{ CMU, A, 0, 0, "([a-c]+[d-f]+?)+?g", "aBdacdehAbDaFgA" },
+	{ CMU, A, 0, 0, "[c-f]+k", "DemmFke" },
+	{ MU, A, 0, 0, "([DGH]{0,4}M)+", "GGDGHDGMMHMDHHGHM" },
+	{ MU, A, 0, 0, "([a-c]{4,}s)+", "abasabbasbbaabsbba" },
+	{ CMU, A, 0, 0, "[ace]{3,7}", "AcbDAcEEcEd" },
+	{ CMU, A, 0, 0, "[ace]{3,7}?", "AcbDAcEEcEd" },
+	{ CMU, A, 0, 0, "[ace]{3,}", "AcbDAcEEcEd" },
+	{ CMU, A, 0, 0, "[ace]{3,}?", "AcbDAcEEcEd" },
+	{ MU, A, 0, 0, "[ckl]{2,}?g", "cdkkmlglglkcg" },
+	{ CMU, A, 0, 0, "[ace]{5}?", "AcCebDAcEEcEd" },
+	{ MU, A, 0, 0, "([AbC]{3,5}?d)+", "BACaAbbAEAACCbdCCbdCCAAbb" },
+	{ MU, A, 0, 0, "([^ab]{0,}s){2}", "abaabcdsABamsDDs" },
+	{ MU, A, 0, 0, "\\b\\w+\\B", "x,a_cd" },
+	{ MUP, A, 0, 0, "\\b[^\xc2\xa1]+\\B", "\xc3\x89\xc2\xa1\xe6\x92\xad\xc3\x81\xc3\xa1" },
+	{ CMU, A, 0, 0, "[^b]+(a*)([^c]?d{3})", "aaaaddd" },
+	{ CMUP, A, 0, 0, "\xe1\xbd\xb8{2}", "\xe1\xbf\xb8#\xe1\xbf\xb8\xe1\xbd\xb8" },
+	{ CMU, A, 0, 0, "[^\xf0\x90\x90\x80]{2,4}@", "\xf0\x90\x90\xa8\xf0\x90\x90\x80###\xf0\x90\x90\x80@@@" },
+	{ CMU, A, 0, 0, "[^\xe1\xbd\xb8][^\xc3\xa9]", "\xe1\xbd\xb8\xe1\xbf\xb8\xc3\xa9\xc3\x89#" },
+	{ MU, A, 0, 0, "[^\xe1\xbd\xb8][^\xc3\xa9]", "\xe1\xbd\xb8\xe1\xbf\xb8\xc3\xa9\xc3\x89#" },
+	{ MU, A, 0, 0, "[^\xe1\xbd\xb8]{3,}?", "##\xe1\xbd\xb8#\xe1\xbd\xb8#\xc3\x89#\xe1\xbd\xb8" },
+	{ MU, A, 0, 0, "\\d+123", "987654321,01234" },
+	{ MU, A, 0, 0, "abcd*|\\w+xy", "aaaaa,abxyz" },
+	{ MU, A, 0, 0, "(?:abc|((?:amc|\\b\\w*xy)))", "aaaaa,abxyz" },
+	{ MU, A, 0, 0, "a(?R)|([a-z]++)#", ".abcd.abcd#."},
+	{ MU, A, 0, 0, "a(?R)|([a-z]++)#", ".abcd.mbcd#."},
+	{ MU, A, 0, 0, ".[ab]*.", "xx" },
+	{ MU, A, 0, 0, ".[ab]*a", "xxa" },
+	{ MU, A, 0, 0, ".[ab]?.", "xx" },
+	{ MU, A, 0, 0, "_[ab]+_*a", "_aa" },
+
+	/* Bracket repeats with limit. */
+	{ MU, A, 0, 0, "(?:(ab){2}){5}M", "abababababababababababM" },
+	{ MU, A, 0, 0, "(?:ab|abab){1,5}M", "abababababababababababM" },
+	{ MU, A, 0, 0, "(?>ab|abab){1,5}M", "abababababababababababM" },
+	{ MU, A, 0, 0, "(?:ab|abab){1,5}?M", "abababababababababababM" },
+	{ MU, A, 0, 0, "(?>ab|abab){1,5}?M", "abababababababababababM" },
+	{ MU, A, 0, 0, "(?:(ab){1,4}?){1,3}?M", "abababababababababababababM" },
+	{ MU, A, 0, 0, "(?:(ab){1,4}){1,3}abababababababababababM", "ababababababababababababM" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(?:(ab){1,4}){1,3}abababababababababababM", "abababababababababababM" },
+	{ MU, A, 0, 0, "(ab){4,6}?M", "abababababababM" },
+
+	/* Basic character sets. */
+	{ MU, A, 0, 0, "(?:\\s)+(?:\\S)+", "ab \t\xc3\xa9\xe6\x92\xad " },
+	{ MU, A, 0, 0, "(\\w)*(k)(\\W)?\?", "abcdef abck11" },
+	{ MU, A, 0, 0, "\\((\\d)+\\)\\D", "a() (83 (8)2 (9)ab" },
+	{ MU, A, 0, 0, "\\w(\\s|(?:\\d)*,)+\\w\\wb", "a 5, 4,, bb 5, 4,, aab" },
+	{ MU, A, 0, 0, "(\\v+)(\\V+)", "\x0e\xc2\x85\xe2\x80\xa8\x0b\x09\xe2\x80\xa9" },
+	{ MU, A, 0, 0, "(\\h+)(\\H+)", "\xe2\x80\xa8\xe2\x80\x80\x20\xe2\x80\x8a\xe2\x81\x9f\xe3\x80\x80\x09\x20\xc2\xa0\x0a" },
+	{ MU, A, 0, 0, "x[bcef]+", "xaxdxecbfg" },
+	{ MU, A, 0, 0, "x[bcdghij]+", "xaxexfxdgbjk" },
+	{ MU, A, 0, 0, "x[^befg]+", "xbxexacdhg" },
+	{ MU, A, 0, 0, "x[^bcdl]+", "xlxbxaekmd" },
+	{ MU, A, 0, 0, "x[^bcdghi]+", "xbxdxgxaefji" },
+	{ MU, A, 0, 0, "x[B-Fb-f]+", "xaxAxgxbfBFG" },
+	{ CMU, A, 0, 0, "\\x{e9}+", "#\xf0\x90\x90\xa8\xc3\xa8\xc3\xa9\xc3\x89\xc3\x88" },
+	{ CMU, A, 0, 0, "[^\\x{e9}]+", "\xc3\xa9#\xf0\x90\x90\xa8\xc3\xa8\xc3\x88\xc3\x89" },
+	{ MU, A, 0, 0, "[\\x02\\x7e]+", "\xc3\x81\xe1\xbf\xb8\xf0\x90\x90\xa8\x01\x02\x7e\x7f" },
+	{ MU, A, 0, 0, "[^\\x02\\x7e]+", "\x02\xc3\x81\xe1\xbf\xb8\xf0\x90\x90\xa8\x01\x7f\x7e" },
+	{ MU, A, 0, 0, "[\\x{81}-\\x{7fe}]+", "#\xe1\xbf\xb8\xf0\x90\x90\xa8\xc2\x80\xc2\x81\xdf\xbe\xdf\xbf" },
+	{ MU, A, 0, 0, "[^\\x{81}-\\x{7fe}]+", "\xc2\x81#\xe1\xbf\xb8\xf0\x90\x90\xa8\xc2\x80\xdf\xbf\xdf\xbe" },
+	{ MU, A, 0, 0, "[\\x{801}-\\x{fffe}]+", "#\xc3\xa9\xf0\x90\x90\x80\xe0\xa0\x80\xe0\xa0\x81\xef\xbf\xbe\xef\xbf\xbf" },
+	{ MU, A, 0, 0, "[^\\x{801}-\\x{fffe}]+", "\xe0\xa0\x81#\xc3\xa9\xf0\x90\x90\x80\xe0\xa0\x80\xef\xbf\xbf\xef\xbf\xbe" },
+	{ MU, A, 0, 0, "[\\x{10001}-\\x{10fffe}]+", "#\xc3\xa9\xe2\xb1\xa5\xf0\x90\x80\x80\xf0\x90\x80\x81\xf4\x8f\xbf\xbe\xf4\x8f\xbf\xbf" },
+	{ MU, A, 0, 0, "[^\\x{10001}-\\x{10fffe}]+", "\xf0\x90\x80\x81#\xc3\xa9\xe2\xb1\xa5\xf0\x90\x80\x80\xf4\x8f\xbf\xbf\xf4\x8f\xbf\xbe" },
+	{ CMU, A, 0, 0 | F_NOMATCH, "^[\\x{0100}-\\x{017f}]", " " },
+
+	/* Unicode properties. */
+	{ MUP, A, 0, 0, "[1-5\xc3\xa9\\w]", "\xc3\xa1_" },
+	{ MUP, A, 0, 0 | F_PROPERTY, "[\xc3\x81\\p{Ll}]", "A_\xc3\x89\xc3\xa1" },
+	{ MUP, A, 0, 0, "[\\Wd-h_x-z]+", "a\xc2\xa1#_yhzdxi" },
+	{ MUP, A, 0, 0 | F_NOMATCH | F_PROPERTY, "[\\P{Any}]", "abc" },
+	{ MUP, A, 0, 0 | F_NOMATCH | F_PROPERTY, "[^\\p{Any}]", "abc" },
+	{ MUP, A, 0, 0 | F_NOMATCH | F_PROPERTY, "[\\P{Any}\xc3\xa1-\xc3\xa8]", "abc" },
+	{ MUP, A, 0, 0 | F_NOMATCH | F_PROPERTY, "[^\\p{Any}\xc3\xa1-\xc3\xa8]", "abc" },
+	{ MUP, A, 0, 0 | F_NOMATCH | F_PROPERTY, "[\xc3\xa1-\xc3\xa8\\P{Any}]", "abc" },
+	{ MUP, A, 0, 0 | F_NOMATCH | F_PROPERTY, "[^\xc3\xa1-\xc3\xa8\\p{Any}]", "abc" },
+	{ MUP, A, 0, 0 | F_PROPERTY, "[\xc3\xa1-\xc3\xa8\\p{Any}]", "abc" },
+	{ MUP, A, 0, 0 | F_PROPERTY, "[^\xc3\xa1-\xc3\xa8\\P{Any}]", "abc" },
+	{ MUP, A, 0, 0, "[b-\xc3\xa9\\s]", "a\xc\xe6\x92\xad" },
+	{ CMUP, A, 0, 0, "[\xc2\x85-\xc2\x89\xc3\x89]", "\xc2\x84\xc3\xa9" },
+	{ MUP, A, 0, 0, "[^b-d^&\\s]{3,}", "db^ !a\xe2\x80\xa8_ae" },
+	{ MUP, A, 0, 0 | F_PROPERTY, "[^\\S\\P{Any}][\\sN]{1,3}[\\P{N}]{4}", "\xe2\x80\xaa\xa N\x9\xc3\xa9_0" },
+	{ MU, A, 0, 0 | F_PROPERTY, "[^\\P{L}\x9!D-F\xa]{2,3}", "\x9,.DF\xa.CG\xc3\x81" },
+	{ CMUP, A, 0, 0, "[\xc3\xa1-\xc3\xa9_\xe2\x80\xa0-\xe2\x80\xaf]{1,5}[^\xe2\x80\xa0-\xe2\x80\xaf]", "\xc2\xa1\xc3\x89\xc3\x89\xe2\x80\xaf_\xe2\x80\xa0" },
+	{ MUP, A, 0, 0 | F_PROPERTY, "[\xc3\xa2-\xc3\xa6\xc3\x81-\xc3\x84\xe2\x80\xa8-\xe2\x80\xa9\xe6\x92\xad\\p{Zs}]{2,}", "\xe2\x80\xa7\xe2\x80\xa9\xe6\x92\xad \xe6\x92\xae" },
+	{ MUP, A, 0, 0 | F_PROPERTY, "[\\P{L&}]{2}[^\xc2\x85-\xc2\x89\\p{Ll}\\p{Lu}]{2}", "\xc3\xa9\xe6\x92\xad.a\xe6\x92\xad|\xc2\x8a#" },
+	{ PCRE2_UCP, 0, 0, 0 | F_PROPERTY, "[a-b\\s]{2,5}[^a]", "AB  baaa" },
+	{ MUP, 0, 0, 0 | F_NOMATCH, "[^\\p{Hangul}\\p{Z}]", " " },
+
+	/* Possible empty brackets. */
+	{ MU, A, 0, 0, "(?:|ab||bc|a)+d", "abcxabcabd" },
+	{ MU, A, 0, 0, "(|ab||bc|a)+d", "abcxabcabd" },
+	{ MU, A, 0, 0, "(?:|ab||bc|a)*d", "abcxabcabd" },
+	{ MU, A, 0, 0, "(|ab||bc|a)*d", "abcxabcabd" },
+	{ MU, A, 0, 0, "(?:|ab||bc|a)+?d", "abcxabcabd" },
+	{ MU, A, 0, 0, "(|ab||bc|a)+?d", "abcxabcabd" },
+	{ MU, A, 0, 0, "(?:|ab||bc|a)*?d", "abcxabcabd" },
+	{ MU, A, 0, 0, "(|ab||bc|a)*?d", "abcxabcabd" },
+	{ MU, A, 0, 0, "(((a)*?|(?:ba)+)+?|(?:|c|ca)*)*m", "abaacaccabacabalabaacaccabacabamm" },
+	{ MU, A, 0, 0, "(?:((?:a)*|(ba)+?)+|(|c|ca)*?)*?m", "abaacaccabacabalabaacaccabacabamm" },
+
+	/* Start offset. */
+	{ MU, A, 0, 3, "(\\d|(?:\\w)*\\w)+", "0ac01Hb" },
+	{ MU, A, 0, 4 | F_NOMATCH, "(\\w\\W\\w)+", "ab#d" },
+	{ MU, A, 0, 2 | F_NOMATCH, "(\\w\\W\\w)+", "ab#d" },
+	{ MU, A, 0, 1, "(\\w\\W\\w)+", "ab#d" },
+
+	/* Newline. */
+	{ M, PCRE2_NEWLINE_CRLF, 0, 0, "\\W{0,2}[^#]{3}", "\r\n#....." },
+	{ M, PCRE2_NEWLINE_CR, 0, 0, "\\W{0,2}[^#]{3}", "\r\n#....." },
+	{ M, PCRE2_NEWLINE_CRLF, 0, 0, "\\W{1,3}[^#]", "\r\n##...." },
+	{ MU, A, PCRE2_NO_UTF_CHECK, 1, "^.a", "\n\x80\nxa" },
+	{ MU, A, 0, 1, "^", "\r\n" },
+	{ M, PCRE2_NEWLINE_CRLF, 0, 1 | F_NOMATCH, "^", "\r\n" },
+	{ M, PCRE2_NEWLINE_CRLF, 0, 1, "^", "\r\na" },
+
+	/* Any character except newline or any newline. */
+	{ 0, PCRE2_NEWLINE_CRLF, 0, 0, ".", "\r" },
+	{ U, PCRE2_NEWLINE_CRLF, 0, 0, ".(.).", "a\xc3\xa1\r\n\n\r\r" },
+	{ 0, PCRE2_NEWLINE_ANYCRLF, 0, 0, ".(.)", "a\rb\nc\r\n\xc2\x85\xe2\x80\xa8" },
+	{ U, PCRE2_NEWLINE_ANYCRLF, 0, 0, ".(.)", "a\rb\nc\r\n\xc2\x85\xe2\x80\xa8" },
+	{ U, PCRE2_NEWLINE_ANY, 0, 0, "(.).", "a\rb\nc\r\n\xc2\x85\xe2\x80\xa9$de" },
+	{ U, PCRE2_NEWLINE_ANYCRLF, 0, 0 | F_NOMATCH, ".(.).", "\xe2\x80\xa8\nb\r" },
+	{ 0, PCRE2_NEWLINE_ANY, 0, 0, "(.)(.)", "#\x85#\r#\n#\r\n#\x84" },
+	{ U, PCRE2_NEWLINE_ANY, 0, 0, "(.+)#", "#\rMn\xc2\x85#\n###" },
+	{ 0, BSR(PCRE2_BSR_ANYCRLF), 0, 0, "\\R", "\r" },
+	{ 0, BSR(PCRE2_BSR_ANYCRLF), 0, 0, "\\R", "\x85#\r\n#" },
+	{ U, BSR(PCRE2_BSR_UNICODE), 0, 0, "\\R", "ab\xe2\x80\xa8#c" },
+	{ U, BSR(PCRE2_BSR_UNICODE), 0, 0, "\\R", "ab\r\nc" },
+	{ U, PCRE2_NEWLINE_CRLF | BSR(PCRE2_BSR_UNICODE), 0, 0, "(\\R.)+", "\xc2\x85\r\n#\xe2\x80\xa8\n\r\n\r" },
+	{ MU, A, 0, 0 | F_NOMATCH, "\\R+", "ab" },
+	{ MU, A, 0, 0, "\\R+", "ab\r\n\r" },
+	{ MU, A, 0, 0, "\\R*", "ab\r\n\r" },
+	{ MU, A, 0, 0, "\\R*", "\r\n\r" },
+	{ MU, A, 0, 0, "\\R{2,4}", "\r\nab\r\r" },
+	{ MU, A, 0, 0, "\\R{2,4}", "\r\nab\n\n\n\r\r\r" },
+	{ MU, A, 0, 0, "\\R{2,}", "\r\nab\n\n\n\r\r\r" },
+	{ MU, A, 0, 0, "\\R{0,3}", "\r\n\r\n\r\n\r\n\r\n" },
+	{ MU, A, 0, 0 | F_NOMATCH, "\\R+\\R\\R", "\r\n\r\n" },
+	{ MU, A, 0, 0, "\\R+\\R\\R", "\r\r\r" },
+	{ MU, A, 0, 0, "\\R*\\R\\R", "\n\r" },
+	{ MU, A, 0, 0 | F_NOMATCH, "\\R{2,4}\\R\\R", "\r\r\r" },
+	{ MU, A, 0, 0, "\\R{2,4}\\R\\R", "\r\r\r\r" },
+
+	/* Atomic groups (no fallback from "next" direction). */
+	{ MU, A, 0, 0 | F_NOMATCH, "(?>ab)ab", "bab" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(?>(ab))ab", "bab" },
+	{ MU, A, 0, 0, "(?>ab)+abc(?>de)*def(?>gh)?ghe(?>ij)+?k(?>lm)*?n(?>op)?\?op",
+			"bababcdedefgheijijklmlmnop" },
+	{ MU, A, 0, 0, "(?>a(b)+a|(ab)?\?(b))an", "abban" },
+	{ MU, A, 0, 0, "(?>ab+a|(?:ab)?\?b)an", "abban" },
+	{ MU, A, 0, 0, "((?>ab|ad|)*?)(?>|c)*abad", "abababcababad" },
+	{ MU, A, 0, 0, "(?>(aa|b|)*+(?>(##)|###)*d|(aa)(?>(baa)?)m)", "aabaa#####da" },
+	{ MU, A, 0, 0, "((?>a|)+?)b", "aaacaaab" },
+	{ MU, A, 0, 0, "(?>x|)*$", "aaa" },
+	{ MU, A, 0, 0, "(?>(x)|)*$", "aaa" },
+	{ MU, A, 0, 0, "(?>x|())*$", "aaa" },
+	{ MU, A, 0, 0, "((?>[cxy]a|[a-d])*?)b", "aaa+ aaab" },
+	{ MU, A, 0, 0, "((?>[cxy](a)|[a-d])*?)b", "aaa+ aaab" },
+	{ MU, A, 0, 0, "(?>((?>(a+))))bab|(?>((?>(a+))))bb", "aaaabaaabaabab" },
+	{ MU, A, 0, 0, "(?>(?>a+))bab|(?>(?>a+))bb", "aaaabaaabaabab" },
+	{ MU, A, 0, 0, "(?>(a)c|(?>(c)|(a))a)b*?bab", "aaaabaaabaabab" },
+	{ MU, A, 0, 0, "(?>ac|(?>c|a)a)b*?bab", "aaaabaaabaabab" },
+	{ MU, A, 0, 0, "(?>(b)b|(a))*b(?>(c)|d)?x", "ababcaaabdbx" },
+	{ MU, A, 0, 0, "(?>bb|a)*b(?>c|d)?x", "ababcaaabdbx" },
+	{ MU, A, 0, 0, "(?>(bb)|a)*b(?>c|(d))?x", "ababcaaabdbx" },
+	{ MU, A, 0, 0, "(?>(a))*?(?>(a))+?(?>(a))??x", "aaaaaacccaaaaabax" },
+	{ MU, A, 0, 0, "(?>a)*?(?>a)+?(?>a)??x", "aaaaaacccaaaaabax" },
+	{ MU, A, 0, 0, "(?>(a)|)*?(?>(a)|)+?(?>(a)|)??x", "aaaaaacccaaaaabax" },
+	{ MU, A, 0, 0, "(?>a|)*?(?>a|)+?(?>a|)??x", "aaaaaacccaaaaabax" },
+	{ MU, A, 0, 0, "(?>a(?>(a{0,2}))*?b|aac)+b", "aaaaaaacaaaabaaaaacaaaabaacaaabb" },
+	{ CM, A, 0, 0, "(?>((?>a{32}|b+|(a*))?(?>c+|d*)?\?)+e)+?f", "aaccebbdde bbdaaaccebbdee bbdaaaccebbdeef" },
+	{ MU, A, 0, 0, "(?>(?:(?>aa|a||x)+?b|(?>aa|a||(x))+?c)?(?>[ad]{0,2})*?d)+d", "aaacdbaabdcabdbaaacd aacaabdbdcdcaaaadaabcbaadd" },
+	{ MU, A, 0, 0, "(?>(?:(?>aa|a||(x))+?b|(?>aa|a||x)+?c)?(?>[ad]{0,2})*?d)+d", "aaacdbaabdcabdbaaacd aacaabdbdcdcaaaadaabcbaadd" },
+	{ MU, A, 0, 0 | F_PROPERTY, "\\X", "\xcc\x8d\xcc\x8d" },
+	{ MU, A, 0, 0 | F_PROPERTY, "\\X", "\xcc\x8d\xcc\x8d#\xcc\x8d\xcc\x8d" },
+	{ MU, A, 0, 0 | F_PROPERTY, "\\X+..", "\xcc\x8d#\xcc\x8d#\xcc\x8d\xcc\x8d" },
+	{ MU, A, 0, 0 | F_PROPERTY, "\\X{2,4}", "abcdef" },
+	{ MU, A, 0, 0 | F_PROPERTY, "\\X{2,4}?", "abcdef" },
+	{ MU, A, 0, 0 | F_NOMATCH | F_PROPERTY, "\\X{2,4}..", "#\xcc\x8d##" },
+	{ MU, A, 0, 0 | F_PROPERTY, "\\X{2,4}..", "#\xcc\x8d#\xcc\x8d##" },
+	{ MU, A, 0, 0, "(c(ab)?+ab)+", "cabcababcab" },
+	{ MU, A, 0, 0, "(?>(a+)b)+aabab", "aaaabaaabaabab" },
+
+	/* Possessive quantifiers. */
+	{ MU, A, 0, 0, "(?:a|b)++m", "mababbaaxababbaam" },
+	{ MU, A, 0, 0, "(?:a|b)*+m", "mababbaaxababbaam" },
+	{ MU, A, 0, 0, "(?:a|b)*+m", "ababbaaxababbaam" },
+	{ MU, A, 0, 0, "(a|b)++m", "mababbaaxababbaam" },
+	{ MU, A, 0, 0, "(a|b)*+m", "mababbaaxababbaam" },
+	{ MU, A, 0, 0, "(a|b)*+m", "ababbaaxababbaam" },
+	{ MU, A, 0, 0, "(a|b(*ACCEPT))++m", "maaxab" },
+	{ MU, A, 0, 0, "(?:b*)++m", "bxbbxbbbxm" },
+	{ MU, A, 0, 0, "(?:b*)++m", "bxbbxbbbxbbm" },
+	{ MU, A, 0, 0, "(?:b*)*+m", "bxbbxbbbxm" },
+	{ MU, A, 0, 0, "(?:b*)*+m", "bxbbxbbbxbbm" },
+	{ MU, A, 0, 0, "(b*)++m", "bxbbxbbbxm" },
+	{ MU, A, 0, 0, "(b*)++m", "bxbbxbbbxbbm" },
+	{ MU, A, 0, 0, "(b*)*+m", "bxbbxbbbxm" },
+	{ MU, A, 0, 0, "(b*)*+m", "bxbbxbbbxbbm" },
+	{ MU, A, 0, 0, "(?:a|(b))++m", "mababbaaxababbaam" },
+	{ MU, A, 0, 0, "(?:(a)|b)*+m", "mababbaaxababbaam" },
+	{ MU, A, 0, 0, "(?:(a)|(b))*+m", "ababbaaxababbaam" },
+	{ MU, A, 0, 0, "(a|(b))++m", "mababbaaxababbaam" },
+	{ MU, A, 0, 0, "((a)|b)*+m", "mababbaaxababbaam" },
+	{ MU, A, 0, 0, "((a)|(b))*+m", "ababbaaxababbaam" },
+	{ MU, A, 0, 0, "(a|(b)(*ACCEPT))++m", "maaxab" },
+	{ MU, A, 0, 0, "(?:(b*))++m", "bxbbxbbbxm" },
+	{ MU, A, 0, 0, "(?:(b*))++m", "bxbbxbbbxbbm" },
+	{ MU, A, 0, 0, "(?:(b*))*+m", "bxbbxbbbxm" },
+	{ MU, A, 0, 0, "(?:(b*))*+m", "bxbbxbbbxbbm" },
+	{ MU, A, 0, 0, "((b*))++m", "bxbbxbbbxm" },
+	{ MU, A, 0, 0, "((b*))++m", "bxbbxbbbxbbm" },
+	{ MU, A, 0, 0, "((b*))*+m", "bxbbxbbbxm" },
+	{ MU, A, 0, 0, "((b*))*+m", "bxbbxbbbxbbm" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(?>(b{2,4}))(?:(?:(aa|c))++m|(?:(aa|c))+n)", "bbaacaaccaaaacxbbbmbn" },
+	{ MU, A, 0, 0, "((?:b)++a)+(cd)*+m", "bbababbacdcdnbbababbacdcdm" },
+	{ MU, A, 0, 0, "((?:(b))++a)+((c)d)*+m", "bbababbacdcdnbbababbacdcdm" },
+	{ MU, A, 0, 0, "(?:(?:(?:ab)*+k)++(?:n(?:cd)++)*+)*+m", "ababkkXababkkabkncXababkkabkncdcdncdXababkkabkncdcdncdkkabkncdXababkkabkncdcdncdkkabkncdm" },
+	{ MU, A, 0, 0, "(?:((ab)*+(k))++(n(?:c(d))++)*+)*+m", "ababkkXababkkabkncXababkkabkncdcdncdXababkkabkncdcdncdkkabkncdXababkkabkncdcdncdkkabkncdm" },
+
+	/* Back references. */
+	{ MU, A, 0, 0, "(aa|bb)(\\1*)(ll|)(\\3*)bbbbbbc", "aaaaaabbbbbbbbc" },
+	{ CMU, A, 0, 0, "(aa|bb)(\\1+)(ll|)(\\3+)bbbbbbc", "bBbbBbCbBbbbBbbcbbBbbbBBbbC" },
+	{ CM, A, 0, 0, "(a{2,4})\\1", "AaAaaAaA" },
+	{ MU, A, 0, 0, "(aa|bb)(\\1?)aa(\\1?)(ll|)(\\4+)bbc", "aaaaaaaabbaabbbbaabbbbc" },
+	{ MU, A, 0, 0, "(aa|bb)(\\1{0,5})(ll|)(\\3{0,5})cc", "bbxxbbbbxxaaaaaaaaaaaaaaaacc" },
+	{ MU, A, 0, 0, "(aa|bb)(\\1{3,5})(ll|)(\\3{3,5})cc", "bbbbbbbbbbbbaaaaaaccbbbbbbbbbbbbbbcc" },
+	{ MU, A, 0, 0, "(aa|bb)(\\1{3,})(ll|)(\\3{3,})cc", "bbbbbbbbbbbbaaaaaaccbbbbbbbbbbbbbbcc" },
+	{ MU, A, 0, 0, "(\\w+)b(\\1+)c", "GabGaGaDbGaDGaDc" },
+	{ MU, A, 0, 0, "(?:(aa)|b)\\1?b", "bb" },
+	{ CMU, A, 0, 0, "(aa|bb)(\\1*?)aa(\\1+?)", "bBBbaaAAaaAAaa" },
+	{ MU, A, 0, 0, "(aa|bb)(\\1*?)(dd|)cc(\\3+?)", "aaaaaccdd" },
+	{ CMU, A, 0, 0, "(?:(aa|bb)(\\1?\?)cc){2}(\\1?\?)", "aAaABBbbAAaAcCaAcCaA" },
+	{ MU, A, 0, 0, "(?:(aa|bb)(\\1{3,5}?)){2}(dd|)(\\3{3,5}?)", "aaaaaabbbbbbbbbbaaaaaaaaaaaaaa" },
+	{ CM, A, 0, 0, "(?:(aa|bb)(\\1{3,}?)){2}(dd|)(\\3{3,}?)", "aaaaaabbbbbbbbbbaaaaaaaaaaaaaa" },
+	{ MU, A, 0, 0, "(?:(aa|bb)(\\1{0,3}?)){2}(dd|)(\\3{0,3}?)b(\\1{0,3}?)(\\1{0,3})", "aaaaaaaaaaaaaaabaaaaa" },
+	{ MU, A, 0, 0, "(a(?:\\1|)a){3}b", "aaaaaaaaaaab" },
+	{ M, A, 0, 0, "(a?)b(\\1\\1*\\1+\\1?\\1*?\\1+?\\1??\\1*+\\1++\\1?+\\1{4}\\1{3,5}\\1{4,}\\1{0,5}\\1{3,5}?\\1{4,}?\\1{0,5}?\\1{3,5}+\\1{4,}+\\1{0,5}+#){2}d", "bb#b##d" },
+	{ MUP, A, 0, 0 | F_PROPERTY, "(\\P{N})\\1{2,}", ".www." },
+	{ MUP, A, 0, 0 | F_PROPERTY, "(\\P{N})\\1{0,2}", "wwwww." },
+	{ MUP, A, 0, 0 | F_PROPERTY, "(\\P{N})\\1{1,2}ww", "wwww" },
+	{ MUP, A, 0, 0 | F_PROPERTY, "(\\P{N})\\1{1,2}ww", "wwwww" },
+	{ PCRE2_UCP, 0, 0, 0 | F_PROPERTY, "(\\P{N})\\1{2,}", ".www." },
+	{ CMUP, A, 0, 0, "(\xf0\x90\x90\x80)\\1", "\xf0\x90\x90\xa8\xf0\x90\x90\xa8" },
+	{ MU | PCRE2_DUPNAMES, A, 0, 0 | F_NOMATCH, "\\k<A>{1,3}(?<A>aa)(?<A>bb)", "aabb" },
+	{ MU | PCRE2_DUPNAMES | PCRE2_MATCH_UNSET_BACKREF, A, 0, 0, "\\k<A>{1,3}(?<A>aa)(?<A>bb)", "aabb" },
+	{ MU | PCRE2_DUPNAMES | PCRE2_MATCH_UNSET_BACKREF, A, 0, 0, "\\k<A>*(?<A>aa)(?<A>bb)", "aabb" },
+	{ MU | PCRE2_DUPNAMES, A, 0, 0, "(?<A>aa)(?<A>bb)\\k<A>{0,3}aaaaaa", "aabbaaaaaa" },
+	{ MU | PCRE2_DUPNAMES, A, 0, 0, "(?<A>aa)(?<A>bb)\\k<A>{2,5}bb", "aabbaaaabb" },
+	{ MU | PCRE2_DUPNAMES, A, 0, 0, "(?:(?<A>aa)|(?<A>bb))\\k<A>{0,3}m", "aaaaaaaabbbbaabbbbm" },
+	{ MU | PCRE2_DUPNAMES, A, 0, 0 | F_NOMATCH, "\\k<A>{1,3}?(?<A>aa)(?<A>bb)", "aabb" },
+	{ MU | PCRE2_DUPNAMES | PCRE2_MATCH_UNSET_BACKREF, A, 0, 0, "\\k<A>{1,3}?(?<A>aa)(?<A>bb)", "aabb" },
+	{ MU | PCRE2_DUPNAMES, A, 0, 0, "\\k<A>*?(?<A>aa)(?<A>bb)", "aabb" },
+	{ MU | PCRE2_DUPNAMES, A, 0, 0, "(?:(?<A>aa)|(?<A>bb))\\k<A>{0,3}?m", "aaaaaabbbbbbaabbbbbbbbbbm" },
+	{ MU | PCRE2_DUPNAMES, A, 0, 0, "(?:(?<A>aa)|(?<A>bb))\\k<A>*?m", "aaaaaabbbbbbaabbbbbbbbbbm" },
+	{ MU | PCRE2_DUPNAMES, A, 0, 0, "(?:(?<A>aa)|(?<A>bb))\\k<A>{2,3}?", "aaaabbbbaaaabbbbbbbbbb" },
+	{ CMU | PCRE2_DUPNAMES, A, 0, 0, "(?:(?<A>AA)|(?<A>BB))\\k<A>{0,3}M", "aaaaaaaabbbbaabbbbm" },
+	{ CMU | PCRE2_DUPNAMES, A, 0, 0, "(?:(?<A>AA)|(?<A>BB))\\k<A>{1,3}M", "aaaaaaaabbbbaabbbbm" },
+	{ CMU | PCRE2_DUPNAMES, A, 0, 0, "(?:(?<A>AA)|(?<A>BB))\\k<A>{0,3}?M", "aaaaaabbbbbbaabbbbbbbbbbm" },
+	{ CMU | PCRE2_DUPNAMES, A, 0, 0, "(?:(?<A>AA)|(?<A>BB))\\k<A>{2,3}?", "aaaabbbbaaaabbbbbbbbbb" },
+
+	/* Assertions. */
+	{ MU, A, 0, 0, "(?=xx|yy|zz)\\w{4}", "abczzdefg" },
+	{ MU, A, 0, 0, "(?=((\\w+)b){3}|ab)", "dbbbb ab" },
+	{ MU, A, 0, 0, "(?!ab|bc|cd)[a-z]{2}", "Xabcdef" },
+	{ MU, A, 0, 0, "(?<=aaa|aa|a)a", "aaa" },
+	{ MU, A, 0, 2, "(?<=aaa|aa|a)a", "aaa" },
+	{ M, A, 0, 0, "(?<=aaa|aa|a)a", "aaa" },
+	{ M, A, 0, 2, "(?<=aaa|aa|a)a", "aaa" },
+	{ MU, A, 0, 0, "(\\d{2})(?!\\w+c|(((\\w?)m){2}n)+|\\1)", "x5656" },
+	{ MU, A, 0, 0, "((?=((\\d{2,6}\\w){2,}))\\w{5,20}K){2,}", "567v09708K12l00M00 567v09708K12l00M00K45K" },
+	{ MU, A, 0, 0, "(?=(?:(?=\\S+a)\\w*(b)){3})\\w+\\d", "bba bbab nbbkba nbbkba0kl" },
+	{ MU, A, 0, 0, "(?>a(?>(b+))a(?=(..)))*?k", "acabbcabbaabacabaabbakk" },
+	{ MU, A, 0, 0, "((?(?=(a))a)+k)", "bbak" },
+	{ MU, A, 0, 0, "((?(?=a)a)+k)", "bbak" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(?=(?>(a))m)amk", "a k" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(?!(?>(a))m)amk", "a k" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(?>(?=(a))am)amk", "a k" },
+	{ MU, A, 0, 0, "(?=(?>a|(?=(?>(b+))a|c)[a-c]+)*?m)[a-cm]+k", "aaam bbam baaambaam abbabba baaambaamk" },
+	{ MU, A, 0, 0, "(?> ?\?\\b(?(?=\\w{1,4}(a))m)\\w{0,8}bc){2,}?", "bca ssbc mabd ssbc mabc" },
+	{ MU, A, 0, 0, "(?:(?=ab)?[^n][^n])+m", "ababcdabcdcdabnababcdabcdcdabm" },
+	{ MU, A, 0, 0, "(?:(?=a(b))?[^n][^n])+m", "ababcdabcdcdabnababcdabcdcdabm" },
+	{ MU, A, 0, 0, "(?:(?=.(.))??\\1.)+m", "aabbbcbacccanaabbbcbacccam" },
+	{ MU, A, 0, 0, "(?:(?=.)??[a-c])+m", "abacdcbacacdcaccam" },
+	{ MU, A, 0, 0, "((?!a)?(?!([^a]))?)+$", "acbab" },
+	{ MU, A, 0, 0, "((?!a)?\?(?!([^a]))?\?)+$", "acbab" },
+	{ MU, A, 0, 0, "a(?=(?C)\\B(?C`x`))b", "ab" },
+	{ MU, A, 0, 0, "a(?!(?C)\\B(?C`x`))bb|ab", "abb" },
+	{ MU, A, 0, 0, "a(?=\\b|(?C)\\B(?C`x`))b", "ab" },
+	{ MU, A, 0, 0, "a(?!\\b|(?C)\\B(?C`x`))bb|ab", "abb" },
+	{ MU, A, 0, 0, "c(?(?=(?C)\\B(?C`x`))ab|a)", "cab" },
+	{ MU, A, 0, 0, "c(?(?!(?C)\\B(?C`x`))ab|a)", "cab" },
+	{ MU, A, 0, 0, "c(?(?=\\b|(?C)\\B(?C`x`))ab|a)", "cab" },
+	{ MU, A, 0, 0, "c(?(?!\\b|(?C)\\B(?C`x`))ab|a)", "cab" },
+	{ MU, A, 0, 0, "a(?=)b", "ab" },
+	{ MU, A, 0, 0 | F_NOMATCH, "a(?!)b", "ab" },
+
+	/* Not empty, ACCEPT, FAIL */
+	{ MU, A, PCRE2_NOTEMPTY, 0 | F_NOMATCH, "a*", "bcx" },
+	{ MU, A, PCRE2_NOTEMPTY, 0, "a*", "bcaad" },
+	{ MU, A, PCRE2_NOTEMPTY, 0, "a*?", "bcaad" },
+	{ MU, A, PCRE2_NOTEMPTY_ATSTART, 0, "a*", "bcaad" },
+	{ MU, A, 0, 0, "a(*ACCEPT)b", "ab" },
+	{ MU, A, PCRE2_NOTEMPTY, 0 | F_NOMATCH, "a*(*ACCEPT)b", "bcx" },
+	{ MU, A, PCRE2_NOTEMPTY, 0, "a*(*ACCEPT)b", "bcaad" },
+	{ MU, A, PCRE2_NOTEMPTY, 0, "a*?(*ACCEPT)b", "bcaad" },
+	{ MU, A, PCRE2_NOTEMPTY, 0 | F_NOMATCH, "(?:z|a*(*ACCEPT)b)", "bcx" },
+	{ MU, A, PCRE2_NOTEMPTY, 0, "(?:z|a*(*ACCEPT)b)", "bcaad" },
+	{ MU, A, PCRE2_NOTEMPTY, 0, "(?:z|a*?(*ACCEPT)b)", "bcaad" },
+	{ MU, A, PCRE2_NOTEMPTY_ATSTART, 0, "a*(*ACCEPT)b", "bcx" },
+	{ MU, A, PCRE2_NOTEMPTY_ATSTART, 0 | F_NOMATCH, "a*(*ACCEPT)b", "" },
+	{ MU, A, 0, 0, "((a(*ACCEPT)b))", "ab" },
+	{ MU, A, 0, 0, "(a(*FAIL)a|a)", "aaa" },
+	{ MU, A, 0, 0, "(?=ab(*ACCEPT)b)a", "ab" },
+	{ MU, A, 0, 0, "(?=(?:x|ab(*ACCEPT)b))", "ab" },
+	{ MU, A, 0, 0, "(?=(a(b(*ACCEPT)b)))a", "ab" },
+	{ MU, A, PCRE2_NOTEMPTY, 0, "(?=a*(*ACCEPT))c", "c" },
+	{ MU, A, PCRE2_NOTEMPTY, 0 | F_NOMATCH, "(?=A)", "AB" },
+
+	/* Conditional blocks. */
+	{ MU, A, 0, 0, "(?(?=(a))a|b)+k", "ababbalbbadabak" },
+	{ MU, A, 0, 0, "(?(?!(b))a|b)+k", "ababbalbbadabak" },
+	{ MU, A, 0, 0, "(?(?=a)a|b)+k", "ababbalbbadabak" },
+	{ MU, A, 0, 0, "(?(?!b)a|b)+k", "ababbalbbadabak" },
+	{ MU, A, 0, 0, "(?(?=(a))a*|b*)+k", "ababbalbbadabak" },
+	{ MU, A, 0, 0, "(?(?!(b))a*|b*)+k", "ababbalbbadabak" },
+	{ MU, A, 0, 0, "(?(?!(b))(?:aaaaaa|a)|(?:bbbbbb|b))+aaaak", "aaaaaaaaaaaaaa bbbbbbbbbbbbbbb aaaaaaak" },
+	{ MU, A, 0, 0, "(?(?!b)(?:aaaaaa|a)|(?:bbbbbb|b))+aaaak", "aaaaaaaaaaaaaa bbbbbbbbbbbbbbb aaaaaaak" },
+	{ MU, A, 0, 0 | F_DIFF, "(?(?!(b))(?:aaaaaa|a)|(?:bbbbbb|b))+bbbbk", "aaaaaaaaaaaaaa bbbbbbbbbbbbbbb bbbbbbbk" },
+	{ MU, A, 0, 0, "(?(?!b)(?:aaaaaa|a)|(?:bbbbbb|b))+bbbbk", "aaaaaaaaaaaaaa bbbbbbbbbbbbbbb bbbbbbbk" },
+	{ MU, A, 0, 0, "(?(?=a)a*|b*)+k", "ababbalbbadabak" },
+	{ MU, A, 0, 0, "(?(?!b)a*|b*)+k", "ababbalbbadabak" },
+	{ MU, A, 0, 0, "(?(?=a)ab)", "a" },
+	{ MU, A, 0, 0, "(?(?<!b)c)", "b" },
+	{ MU, A, 0, 0, "(?(DEFINE)a(b))", "a" },
+	{ MU, A, 0, 0, "a(?(DEFINE)(?:b|(?:c?)+)*)", "a" },
+	{ MU, A, 0, 0, "(?(?=.[a-c])[k-l]|[A-D])", "kdB" },
+	{ MU, A, 0, 0, "(?(?!.{0,4}[cd])(aa|bb)|(cc|dd))+", "aabbccddaa" },
+	{ MU, A, 0, 0, "(?(?=[^#@]*@)(aaab|aa|aba)|(aba|aab)){3,}", "aaabaaaba#aaabaaaba#aaabaaaba@" },
+	{ MU, A, 0, 0, "((?=\\w{5})\\w(?(?=\\w*k)\\d|[a-f_])*\\w\\s)+", "mol m10kk m088k _f_a_ mbkkl" },
+	{ MU, A, 0, 0, "(c)?\?(?(1)a|b)", "cdcaa" },
+	{ MU, A, 0, 0, "(c)?\?(?(1)a|b)", "cbb" },
+	{ MU, A, 0, 0 | F_DIFF, "(?(?=(a))(aaaa|a?))+aak", "aaaaab aaaaak" },
+	{ MU, A, 0, 0, "(?(?=a)(aaaa|a?))+aak", "aaaaab aaaaak" },
+	{ MU, A, 0, 0, "(?(?!(b))(aaaa|a?))+aak", "aaaaab aaaaak" },
+	{ MU, A, 0, 0, "(?(?!b)(aaaa|a?))+aak", "aaaaab aaaaak" },
+	{ MU, A, 0, 0 | F_DIFF, "(?(?=(a))a*)+aak", "aaaaab aaaaak" },
+	{ MU, A, 0, 0, "(?(?=a)a*)+aak", "aaaaab aaaaak" },
+	{ MU, A, 0, 0, "(?(?!(b))a*)+aak", "aaaaab aaaaak" },
+	{ MU, A, 0, 0, "(?(?!b)a*)+aak", "aaaaab aaaaak" },
+	{ MU, A, 0, 0, "(?(?=(?=(?!(x))a)aa)aaa|(?(?=(?!y)bb)bbb))*k", "abaabbaaabbbaaabbb abaabbaaabbbaaabbbk" },
+	{ MU, A, 0, 0, "(?P<Name>a)?(?P<Name2>b)?(?(Name)c|d)*l", "bc ddd abccabccl" },
+	{ MU, A, 0, 0, "(?P<Name>a)?(?P<Name2>b)?(?(Name)c|d)+?dd", "bcabcacdb bdddd" },
+	{ MU, A, 0, 0, "(?P<Name>a)?(?P<Name2>b)?(?(Name)c|d)+l", "ababccddabdbccd abcccl" },
+	{ MU, A, 0, 0, "((?:a|aa)(?(1)aaa))x", "aax" },
+	{ MU, A, 0, 0, "(?(?!)a|b)", "ab" },
+	{ MU, A, 0, 0, "(?(?!)a)", "ab" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(?(?!)a|b)", "ac" },
+
+	/* Set start of match. */
+	{ MU, A, 0, 0, "(?:\\Ka)*aaaab", "aaaaaaaa aaaaaaabb" },
+	{ MU, A, 0, 0, "(?>\\Ka\\Ka)*aaaab", "aaaaaaaa aaaaaaaaaabb" },
+	{ MU, A, 0, 0, "a+\\K(?<=\\Gaa)a", "aaaaaa" },
+	{ MU, A, PCRE2_NOTEMPTY, 0 | F_NOMATCH, "a\\K(*ACCEPT)b", "aa" },
+	{ MU, A, PCRE2_NOTEMPTY_ATSTART, 0, "a\\K(*ACCEPT)b", "aa" },
+
+	/* First line. */
+	{ MU | PCRE2_FIRSTLINE, A, 0, 0 | F_PROPERTY, "\\p{Any}a", "bb\naaa" },
+	{ MU | PCRE2_FIRSTLINE, A, 0, 0 | F_NOMATCH | F_PROPERTY, "\\p{Any}a", "bb\r\naaa" },
+	{ MU | PCRE2_FIRSTLINE, A, 0, 0, "(?<=a)", "a" },
+	{ MU | PCRE2_FIRSTLINE, A, 0, 0 | F_NOMATCH, "[^a][^b]", "ab" },
+	{ MU | PCRE2_FIRSTLINE, A, 0, 0 | F_NOMATCH, "a", "\na" },
+	{ MU | PCRE2_FIRSTLINE, A, 0, 0 | F_NOMATCH, "[abc]", "\na" },
+	{ MU | PCRE2_FIRSTLINE, A, 0, 0 | F_NOMATCH, "^a", "\na" },
+	{ MU | PCRE2_FIRSTLINE, A, 0, 0 | F_NOMATCH, "^(?<=\n)", "\na" },
+	{ MU | PCRE2_FIRSTLINE, A, 0, 0, "\xf0\x90\x90\x80", "\xf0\x90\x90\x80" },
+	{ MU | PCRE2_FIRSTLINE, PCRE2_NEWLINE_ANY, 0, 0 | F_NOMATCH, "#", "\xc2\x85#" },
+	{ M | PCRE2_FIRSTLINE, PCRE2_NEWLINE_ANY, 0, 0 | F_NOMATCH, "#", "\x85#" },
+	{ MU | PCRE2_FIRSTLINE, PCRE2_NEWLINE_ANY, 0, 0 | F_NOMATCH, "^#", "\xe2\x80\xa8#" },
+	{ MU | PCRE2_FIRSTLINE, PCRE2_NEWLINE_CRLF, 0, 0 | F_PROPERTY, "\\p{Any}", "\r\na" },
+	{ MU | PCRE2_FIRSTLINE, PCRE2_NEWLINE_CRLF, 0, 0, ".", "\r" },
+	{ MU | PCRE2_FIRSTLINE, PCRE2_NEWLINE_CRLF, 0, 0, "a", "\ra" },
+	{ MU | PCRE2_FIRSTLINE, PCRE2_NEWLINE_CRLF, 0, 0 | F_NOMATCH, "ba", "bbb\r\nba" },
+	{ MU | PCRE2_FIRSTLINE, PCRE2_NEWLINE_CRLF, 0, 0 | F_NOMATCH | F_PROPERTY, "\\p{Any}{4}|a", "\r\na" },
+	{ MU | PCRE2_FIRSTLINE, PCRE2_NEWLINE_CRLF, 0, 1, ".", "\r\n" },
+	{ PCRE2_FIRSTLINE | PCRE2_DOTALL, PCRE2_NEWLINE_LF, 0, 0 | F_NOMATCH, "ab.", "ab" },
+	{ MU | PCRE2_FIRSTLINE, A, 0, 1 | F_NOMATCH, "^[a-d0-9]", "\nxx\nd" },
+	{ PCRE2_FIRSTLINE | PCRE2_DOTALL, PCRE2_NEWLINE_ANY, 0, 0, "....a", "012\n0a" },
+	{ MU | PCRE2_FIRSTLINE, A, 0, 0, "[aC]", "a" },
+
+	/* Recurse. */
+	{ MU, A, 0, 0, "(a)(?1)", "aa" },
+	{ MU, A, 0, 0, "((a))(?1)", "aa" },
+	{ MU, A, 0, 0, "(b|a)(?1)", "aa" },
+	{ MU, A, 0, 0, "(b|(a))(?1)", "aa" },
+	{ MU, A, 0, 0 | F_NOMATCH, "((a)(b)(?:a*))(?1)", "aba" },
+	{ MU, A, 0, 0, "((a)(b)(?:a*))(?1)", "abab" },
+	{ MU, A, 0, 0, "((a+)c(?2))b(?1)", "aacaabaca" },
+	{ MU, A, 0, 0, "((?2)b|(a)){2}(?1)", "aabab" },
+	{ MU, A, 0, 0, "(?1)(a)*+(?2)(b(?1))", "aababa" },
+	{ MU, A, 0, 0, "(?1)(((a(*ACCEPT)))b)", "axaa" },
+	{ MU, A, 0, 0, "(?1)(?(DEFINE) (((ac(*ACCEPT)))b) )", "akaac" },
+	{ MU, A, 0, 0, "(a+)b(?1)b\\1", "abaaabaaaaa" },
+	{ MU, A, 0, 0, "(?(DEFINE)(aa|a))(?1)ab", "aab" },
+	{ MU, A, 0, 0, "(?(DEFINE)(a\\Kb))(?1)+ababc", "abababxabababc" },
+	{ MU, A, 0, 0, "(a\\Kb)(?1)+ababc", "abababxababababc" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(a\\Kb)(?1)+ababc", "abababxababababxc" },
+	{ MU, A, 0, 0, "b|<(?R)*>", "<<b>" },
+	{ MU, A, 0, 0, "(a\\K){0}(?:(?1)b|ac)", "ac" },
+	{ MU, A, 0, 0, "(?(DEFINE)(a(?2)|b)(b(?1)|(a)))(?:(?1)|(?2))m", "ababababnababababaam" },
+	{ MU, A, 0, 0, "(a)((?(R)a|b))(?2)", "aabbabaa" },
+	{ MU, A, 0, 0, "(a)((?(R2)a|b))(?2)", "aabbabaa" },
+	{ MU, A, 0, 0, "(a)((?(R1)a|b))(?2)", "ababba" },
+	{ MU, A, 0, 0, "(?(R0)aa|bb(?R))", "abba aabb bbaa" },
+	{ MU, A, 0, 0, "((?(R)(?:aaaa|a)|(?:(aaaa)|(a)))+)(?1)$", "aaaaaaaaaa aaaa" },
+	{ MU, A, 0, 0, "(?P<Name>a(?(R&Name)a|b))(?1)", "aab abb abaa" },
+	{ MU, A, 0, 0, "((?(R)a|(?1)){3})", "XaaaaaaaaaX" },
+	{ MU, A, 0, 0, "((?:(?(R)a|(?1))){3})", "XaaaaaaaaaX" },
+	{ MU, A, 0, 0, "((?(R)a|(?1)){1,3})aaaaaa", "aaaaaaaaXaaaaaaaaa" },
+	{ MU, A, 0, 0, "((?(R)a|(?1)){1,3}?)M", "aaaM" },
+	{ MU, A, 0, 0, "((.)(?:.|\\2(?1))){0}#(?1)#", "#aabbccdde# #aabbccddee#" },
+	{ MU, A, 0, 0, "((.)(?:\\2|\\2{4}b)){0}#(?:(?1))+#", "#aaaab# #aaaaab#" },
+
+	/* 16 bit specific tests. */
+	{ CM, A, 0, 0 | F_FORCECONV, "\xc3\xa1", "\xc3\x81\xc3\xa1" },
+	{ CM, A, 0, 0 | F_FORCECONV, "\xe1\xbd\xb8", "\xe1\xbf\xb8\xe1\xbd\xb8" },
+	{ CM, A, 0, 0 | F_FORCECONV, "[\xc3\xa1]", "\xc3\x81\xc3\xa1" },
+	{ CM, A, 0, 0 | F_FORCECONV, "[\xe1\xbd\xb8]", "\xe1\xbf\xb8\xe1\xbd\xb8" },
+	{ CM, A, 0, 0 | F_FORCECONV, "[a-\xed\xb0\x80]", "A" },
+	{ CM, A, 0, 0 | F_NO8 | F_FORCECONV, "[a-\\x{dc00}]", "B" },
+	{ CM, A, 0, 0 | F_NO8 | F_NOMATCH | F_FORCECONV, "[b-\\x{dc00}]", "a" },
+	{ CM, A, 0, 0 | F_NO8 | F_FORCECONV, "\xed\xa0\x80\\x{d800}\xed\xb0\x80\\x{dc00}", "\xed\xa0\x80\xed\xa0\x80\xed\xb0\x80\xed\xb0\x80" },
+	{ CM, A, 0, 0 | F_NO8 | F_FORCECONV, "[\xed\xa0\x80\\x{d800}]{1,2}?[\xed\xb0\x80\\x{dc00}]{1,2}?#", "\xed\xa0\x80\xed\xa0\x80\xed\xb0\x80\xed\xb0\x80#" },
+	{ CM, A, 0, 0 | F_FORCECONV, "[\xed\xa0\x80\xed\xb0\x80#]{0,3}(?<=\xed\xb0\x80.)", "\xed\xa0\x80#\xed\xa0\x80##\xed\xb0\x80\xed\xa0\x80" },
+	{ CM, A, 0, 0 | F_FORCECONV, "[\xed\xa0\x80-\xed\xb3\xbf]", "\xed\x9f\xbf\xed\xa0\x83" },
+	{ CM, A, 0, 0 | F_FORCECONV, "[\xed\xa0\x80-\xed\xb3\xbf]", "\xed\xb4\x80\xed\xb3\xb0" },
+	{ CM, A, 0, 0 | F_NO8 | F_FORCECONV, "[\\x{d800}-\\x{dcff}]", "\xed\x9f\xbf\xed\xa0\x83" },
+	{ CM, A, 0, 0 | F_NO8 | F_FORCECONV, "[\\x{d800}-\\x{dcff}]", "\xed\xb4\x80\xed\xb3\xb0" },
+	{ CM, A, 0, 0 | F_FORCECONV, "[\xed\xa0\x80-\xef\xbf\xbf]+[\x1-\xed\xb0\x80]+#", "\xed\xa0\x85\xc3\x81\xed\xa0\x85\xef\xbf\xb0\xc2\x85\xed\xa9\x89#" },
+	{ CM, A, 0, 0 | F_FORCECONV, "[\xed\xa0\x80][\xed\xb0\x80]{2,}", "\xed\xa0\x80\xed\xb0\x80\xed\xa0\x80\xed\xb0\x80\xed\xb0\x80\xed\xb0\x80" },
+	{ M, A, 0, 0 | F_FORCECONV, "[^\xed\xb0\x80]{3,}?", "##\xed\xb0\x80#\xed\xb0\x80#\xc3\x89#\xed\xb0\x80" },
+	{ M, A, 0, 0 | F_NO8 | F_FORCECONV, "[^\\x{dc00}]{3,}?", "##\xed\xb0\x80#\xed\xb0\x80#\xc3\x89#\xed\xb0\x80" },
+	{ CM, A, 0, 0 | F_FORCECONV, ".\\B.", "\xed\xa0\x80\xed\xb0\x80" },
+	{ CM, A, 0, 0 | F_FORCECONV, "\\D+(?:\\d+|.)\\S+(?:\\s+|.)\\W+(?:\\w+|.)\xed\xa0\x80\xed\xa0\x80", "\xed\xa0\x80\xed\xa0\x80\xed\xa0\x80\xed\xa0\x80\xed\xa0\x80\xed\xa0\x80\xed\xa0\x80\xed\xa0\x80" },
+	{ CM, A, 0, 0 | F_FORCECONV, "\\d*\\s*\\w*\xed\xa0\x80\xed\xa0\x80", "\xed\xa0\x80\xed\xa0\x80" },
+	{ CM, A, 0, 0 | F_FORCECONV | F_NOMATCH, "\\d*?\\D*?\\s*?\\S*?\\w*?\\W*?##", "\xed\xa0\x80\xed\xa0\x80\xed\xa0\x80\xed\xa0\x80#" },
+	{ CM | PCRE2_EXTENDED, A, 0, 0 | F_FORCECONV, "\xed\xa0\x80 \xed\xb0\x80 !", "\xed\xa0\x80\xed\xb0\x80!" },
+	{ CM, A, 0, 0 | F_FORCECONV, "\xed\xa0\x80+#[^#]+\xed\xa0\x80", "\xed\xa0\x80#a\xed\xa0\x80" },
+	{ CM, A, 0, 0 | F_FORCECONV, "(\xed\xa0\x80+)#\\1", "\xed\xa0\x80\xed\xa0\x80#\xed\xa0\x80\xed\xa0\x80" },
+	{ M, PCRE2_NEWLINE_ANY, 0, 0 | F_NO8 | F_FORCECONV, "^-", "a--\xe2\x80\xa8--" },
+	{ 0, BSR(PCRE2_BSR_UNICODE), 0, 0 | F_NO8 | F_FORCECONV, "\\R", "ab\xe2\x80\xa8" },
+	{ 0, 0, 0, 0 | F_NO8 | F_FORCECONV, "\\v", "ab\xe2\x80\xa9" },
+	{ 0, 0, 0, 0 | F_NO8 | F_FORCECONV, "\\h", "ab\xe1\xa0\x8e" },
+	{ 0, 0, 0, 0 | F_NO8 | F_FORCECONV, "\\v+?\\V+?#", "\xe2\x80\xa9\xe2\x80\xa9\xef\xbf\xbf\xef\xbf\xbf#" },
+	{ 0, 0, 0, 0 | F_NO8 | F_FORCECONV, "\\h+?\\H+?#", "\xe1\xa0\x8e\xe1\xa0\x8e\xef\xbf\xbf\xef\xbf\xbf#" },
+
+	/* Partial matching. */
+	{ MU, A, PCRE2_PARTIAL_SOFT, 0, "ab", "a" },
+	{ MU, A, PCRE2_PARTIAL_SOFT, 0, "ab|a", "a" },
+	{ MU, A, PCRE2_PARTIAL_HARD, 0, "ab|a", "a" },
+	{ MU, A, PCRE2_PARTIAL_SOFT, 0, "\\b#", "a" },
+	{ MU, A, PCRE2_PARTIAL_SOFT, 0, "(?<=a)b", "a" },
+	{ MU, A, PCRE2_PARTIAL_SOFT, 0, "abc|(?<=xxa)bc", "xxab" },
+	{ MU, A, PCRE2_PARTIAL_SOFT, 0, "a\\B", "a" },
+	{ MU, A, PCRE2_PARTIAL_HARD, 0, "a\\b", "a" },
+
+	/* (*MARK) verb. */
+	{ MU, A, 0, 0, "a(*MARK:aa)a", "ababaa" },
+	{ MU, A, 0, 0 | F_NOMATCH, "a(*:aa)a", "abab" },
+	{ MU, A, 0, 0, "a(*:aa)(b(*:bb)b|bc)", "abc" },
+	{ MU, A, 0, 0 | F_NOMATCH, "a(*:1)x|b(*:2)y", "abc" },
+	{ MU, A, 0, 0, "(?>a(*:aa))b|ac", "ac" },
+	{ MU, A, 0, 0, "(?(DEFINE)(a(*:aa)))(?1)", "a" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(?(DEFINE)((a)(*:aa)))(?1)b", "aa" },
+	{ MU, A, 0, 0, "(?(DEFINE)(a(*:aa)))a(?1)b|aac", "aac" },
+	{ MU, A, 0, 0, "(a(*:aa)){0}(?:b(?1)b|c)+c", "babbab cc" },
+	{ MU, A, 0, 0, "(a(*:aa)){0}(?:b(?1)b)+", "babba" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(a(*:aa)){0}(?:b(?1)b)+", "ba" },
+	{ MU, A, 0, 0, "(a\\K(*:aa)){0}(?:b(?1)b|c)+c", "babbab cc" },
+	{ MU, A, 0, 0, "(a\\K(*:aa)){0}(?:b(?1)b)+", "babba" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(a\\K(*:aa)){0}(?:b(?1)b)+", "ba" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(*:mark)m", "a" },
+
+	/* (*COMMIT) verb. */
+	{ MU, A, 0, 0 | F_NOMATCH, "a(*COMMIT)b", "ac" },
+	{ MU, A, 0, 0, "aa(*COMMIT)b", "xaxaab" },
+	{ MU, A, 0, 0 | F_NOMATCH, "a(*COMMIT)(*:msg)b|ac", "ac" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(a(*COMMIT)b)++", "abac" },
+	{ MU, A, 0, 0 | F_NOMATCH, "((a)(*COMMIT)b)++", "abac" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(?=a(*COMMIT)b)ab|ad", "ad" },
+
+	/* (*PRUNE) verb. */
+	{ MU, A, 0, 0, "aa\\K(*PRUNE)b", "aaab" },
+	{ MU, A, 0, 0, "aa(*PRUNE:bb)b|a", "aa" },
+	{ MU, A, 0, 0, "(a)(a)(*PRUNE)b|(a)", "aa" },
+	{ MU, A, 0, 0, "(a)(a)(a)(a)(a)(a)(a)(a)(*PRUNE)b|(a)", "aaaaaaaa" },
+	{ MU, A, PCRE2_PARTIAL_SOFT, 0, "a(*PRUNE)a|", "a" },
+	{ MU, A, PCRE2_PARTIAL_SOFT, 0, "a(*PRUNE)a|m", "a" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(?=a(*PRUNE)b)ab|ad", "ad" },
+	{ MU, A, 0, 0, "a(*COMMIT)(*PRUNE)d|bc", "abc" },
+	{ MU, A, 0, 0, "(?=a(*COMMIT)b)a(*PRUNE)c|bc", "abc" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(*COMMIT)(?=a(*COMMIT)b)a(*PRUNE)c|bc", "abc" },
+	{ MU, A, 0, 0, "(?=(a)(*COMMIT)b)a(*PRUNE)c|bc", "abc" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(*COMMIT)(?=(a)(*COMMIT)b)a(*PRUNE)c|bc", "abc" },
+	{ MU, A, 0, 0, "(a(*COMMIT)b){0}a(?1)(*PRUNE)c|bc", "abc" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(a(*COMMIT)b){0}a(*COMMIT)(?1)(*PRUNE)c|bc", "abc" },
+	{ MU, A, 0, 0, "(a(*COMMIT)b)++(*PRUNE)d|c", "ababc" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(*COMMIT)(a(*COMMIT)b)++(*PRUNE)d|c", "ababc" },
+	{ MU, A, 0, 0, "((a)(*COMMIT)b)++(*PRUNE)d|c", "ababc" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(*COMMIT)((a)(*COMMIT)b)++(*PRUNE)d|c", "ababc" },
+	{ MU, A, 0, 0, "(?>a(*COMMIT)b)*abab(*PRUNE)d|ba", "ababab" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(*COMMIT)(?>a(*COMMIT)b)*abab(*PRUNE)d|ba", "ababab" },
+	{ MU, A, 0, 0, "(?>a(*COMMIT)b)+abab(*PRUNE)d|ba", "ababab" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(*COMMIT)(?>a(*COMMIT)b)+abab(*PRUNE)d|ba", "ababab" },
+	{ MU, A, 0, 0, "(?>a(*COMMIT)b)?ab(*PRUNE)d|ba", "aba" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(*COMMIT)(?>a(*COMMIT)b)?ab(*PRUNE)d|ba", "aba" },
+	{ MU, A, 0, 0, "(?>a(*COMMIT)b)*?n(*PRUNE)d|ba", "abababn" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(*COMMIT)(?>a(*COMMIT)b)*?n(*PRUNE)d|ba", "abababn" },
+	{ MU, A, 0, 0, "(?>a(*COMMIT)b)+?n(*PRUNE)d|ba", "abababn" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(*COMMIT)(?>a(*COMMIT)b)+?n(*PRUNE)d|ba", "abababn" },
+	{ MU, A, 0, 0, "(?>a(*COMMIT)b)??n(*PRUNE)d|bn", "abn" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(*COMMIT)(?>a(*COMMIT)b)??n(*PRUNE)d|bn", "abn" },
+
+	/* (*SKIP) verb. */
+	{ MU, A, 0, 0 | F_NOMATCH, "(?=a(*SKIP)b)ab|ad", "ad" },
+	{ MU, A, 0, 0, "(\\w+(*SKIP)#)", "abcd,xyz#," },
+	{ MU, A, 0, 0, "\\w+(*SKIP)#|mm", "abcd,xyz#," },
+	{ MU, A, 0, 0 | F_NOMATCH, "b+(?<=(*SKIP)#c)|b+", "#bbb" },
+
+	/* (*THEN) verb. */
+	{ MU, A, 0, 0, "((?:a(*THEN)|aab)(*THEN)c|a+)+m", "aabcaabcaabcaabcnacm" },
+	{ MU, A, 0, 0 | F_NOMATCH, "((?:a(*THEN)|aab)(*THEN)c|a+)+m", "aabcm" },
+	{ MU, A, 0, 0, "((?:a(*THEN)|aab)c|a+)+m", "aabcaabcnmaabcaabcm" },
+	{ MU, A, 0, 0, "((?:a|aab)(*THEN)c|a+)+m", "aam" },
+	{ MU, A, 0, 0, "((?:a(*COMMIT)|aab)(*THEN)c|a+)+m", "aam" },
+	{ MU, A, 0, 0, "(?(?=a(*THEN)b)ab|ad)", "ad" },
+	{ MU, A, 0, 0, "(?(?!a(*THEN)b)ad|add)", "add" },
+	{ MU, A, 0, 0 | F_NOMATCH, "(?(?=a)a(*THEN)b|ad)", "ad" },
+	{ MU, A, 0, 0, "(?!(?(?=a)ab|b(*THEN)d))bn|bnn", "bnn" },
+	{ MU, A, 0, 0, "(?=(*THEN: ))* ", " " },
+	{ MU, A, 0, 0, "a(*THEN)(?R) |", "a" },
+
+	/* Recurse and control verbs. */
+	{ MU, A, 0, 0, "(a(*ACCEPT)b){0}a(?1)b", "aacaabb" },
+	{ MU, A, 0, 0, "((a)\\2(*ACCEPT)b){0}a(?1)b", "aaacaaabb" },
+	{ MU, A, 0, 0, "((ab|a(*ACCEPT)x)+|ababababax){0}_(?1)_", "_ababababax_ _ababababa_" },
+	{ MU, A, 0, 0, "((.)(?:A(*ACCEPT)|(?1)\\2)){0}_(?1)_", "_bcdaAdcb_bcdaAdcb_" },
+	{ MU, A, 0, 0, "((*MARK:m)(?:a|a(*COMMIT)b|aa)){0}_(?1)_", "_ab_" },
+	{ MU, A, 0, 0, "((*MARK:m)(?:a|a(*COMMIT)b|aa)){0}_(?1)_|(_aa_)", "_aa_" },
+	{ MU, A, 0, 0, "(a(*COMMIT)(?:b|bb)|c(*ACCEPT)d|dd){0}_(?1)+_", "_ax_ _cd_ _abbb_ _abcd_ _abbcdd_" },
+	{ MU, A, 0, 0, "((.)(?:.|(*COMMIT)\\2{3}(*ACCEPT).*|.*)){0}_(?1){0,4}_", "_aaaabbbbccccddd_ _aaaabbbbccccdddd_" },
+
+#ifdef SUPPORT_UNICODE
+	/* Script runs and iterations. */
+	{ MU, A, 0, 0, "!(*sr:\\w\\w|\\w\\w\\w)*#", "!abcdefghijklmno!abcdefghijklmno!abcdef#" },
+	{ MU, A, 0, 0, "!(*sr:\\w\\w|\\w\\w\\w)+#", "!abcdefghijklmno!abcdefghijklmno!abcdef#" },
+	{ MU, A, 0, 0, "!(*sr:\\w\\w|\\w\\w\\w)*?#", "!abcdefghijklmno!abcdefghijklmno!abcdef#" },
+	{ MU, A, 0, 0, "!(*sr:\\w\\w|\\w\\w\\w)+?#", "!abcdefghijklmno!abcdefghijklmno!abcdef#" },
+	{ MU, A, 0, 0, "!(*sr:\\w\\w|\\w\\w\\w)*+#", "!abcdefghijklmno!abcdefghijklmno!abcdef#" },
+	{ MU, A, 0, 0, "!(*sr:\\w\\w|\\w\\w\\w)++#", "!abcdefghijklmno!abcdefghijklmno!abcdef#" },
+	{ MU, A, 0, 0, "!(*sr:\\w\\w|\\w\\w\\w)?#", "!ab!abc!ab!ab#" },
+	{ MU, A, 0, 0, "!(*sr:\\w\\w|\\w\\w\\w)??#", "!ab!abc!ab!ab#" },
+#endif
+
+	/* Deep recursion. */
+	{ MU, A, 0, 0, "((((?:(?:(?:\\w)+)?)*|(?>\\w)+?)+|(?>\\w)?\?)*)?\\s", "aaaaa+ " },
+	{ MU, A, 0, 0, "(?:((?:(?:(?:\\w*?)+)??|(?>\\w)?|\\w*+)*)+)+?\\s", "aa+ " },
+	{ MU, A, 0, 0, "((a?)+)+b", "aaaaaaaaaaaa b" },
+
+	/* Deep recursion: Stack limit reached. */
+	{ M, A, 0, 0 | F_NOMATCH, "a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaa" },
+	{ M, A, 0, 0 | F_NOMATCH, "(?:a+)+b", "aaaaaaaaaaaaaaaaaaaaaaaa b" },
+	{ M, A, 0, 0 | F_NOMATCH, "(?:a+?)+?b", "aaaaaaaaaaaaaaaaaaaaaaaa b" },
+	{ M, A, 0, 0 | F_NOMATCH, "(?:a*)*b", "aaaaaaaaaaaaaaaaaaaaaaaa b" },
+	{ M, A, 0, 0 | F_NOMATCH, "(?:a*?)*?b", "aaaaaaaaaaaaaaaaaaaaaaaa b" },
+
+	{ 0, 0, 0, 0, NULL, NULL }
+};
+
+#ifdef SUPPORT_PCRE2_8
+static pcre2_jit_stack_8* callback8(void *arg)
+{
+	return (pcre2_jit_stack_8 *)arg;
+}
+#endif
+
+#ifdef SUPPORT_PCRE2_16
+static pcre2_jit_stack_16* callback16(void *arg)
+{
+	return (pcre2_jit_stack_16 *)arg;
+}
+#endif
+
+#ifdef SUPPORT_PCRE2_32
+static pcre2_jit_stack_32* callback32(void *arg)
+{
+	return (pcre2_jit_stack_32 *)arg;
+}
+#endif
+
+#ifdef SUPPORT_PCRE2_8
+static pcre2_jit_stack_8 *stack8;
+
+static pcre2_jit_stack_8 *getstack8(void)
+{
+	if (!stack8)
+		stack8 = pcre2_jit_stack_create_8(1, 1024 * 1024, NULL);
+	return stack8;
+}
+
+static void setstack8(pcre2_match_context_8 *mcontext)
+{
+	if (!mcontext) {
+		if (stack8)
+			pcre2_jit_stack_free_8(stack8);
+		stack8 = NULL;
+		return;
+	}
+
+	pcre2_jit_stack_assign_8(mcontext, callback8, getstack8());
+}
+#endif /* SUPPORT_PCRE2_8 */
+
+#ifdef SUPPORT_PCRE2_16
+static pcre2_jit_stack_16 *stack16;
+
+static pcre2_jit_stack_16 *getstack16(void)
+{
+	if (!stack16)
+		stack16 = pcre2_jit_stack_create_16(1, 1024 * 1024, NULL);
+	return stack16;
+}
+
+static void setstack16(pcre2_match_context_16 *mcontext)
+{
+	if (!mcontext) {
+		if (stack16)
+			pcre2_jit_stack_free_16(stack16);
+		stack16 = NULL;
+		return;
+	}
+
+	pcre2_jit_stack_assign_16(mcontext, callback16, getstack16());
+}
+#endif /* SUPPORT_PCRE2_16 */
+
+#ifdef SUPPORT_PCRE2_32
+static pcre2_jit_stack_32 *stack32;
+
+static pcre2_jit_stack_32 *getstack32(void)
+{
+	if (!stack32)
+		stack32 = pcre2_jit_stack_create_32(1, 1024 * 1024, NULL);
+	return stack32;
+}
+
+static void setstack32(pcre2_match_context_32 *mcontext)
+{
+	if (!mcontext) {
+		if (stack32)
+			pcre2_jit_stack_free_32(stack32);
+		stack32 = NULL;
+		return;
+	}
+
+	pcre2_jit_stack_assign_32(mcontext, callback32, getstack32());
+}
+#endif /* SUPPORT_PCRE2_32 */
+
+#ifdef SUPPORT_PCRE2_16
+
+static int convert_utf8_to_utf16(PCRE2_SPTR8 input, PCRE2_UCHAR16 *output, int *offsetmap, int max_length)
+{
+	PCRE2_SPTR8 iptr = input;
+	PCRE2_UCHAR16 *optr = output;
+	unsigned int c;
+
+	if (max_length == 0)
+		return 0;
+
+	while (*iptr && max_length > 1) {
+		c = 0;
+		if (offsetmap)
+			*offsetmap++ = (int)(iptr - (unsigned char*)input);
+
+		if (*iptr < 0xc0)
+			c = *iptr++;
+		else if (!(*iptr & 0x20)) {
+			c = ((iptr[0] & 0x1f) << 6) | (iptr[1] & 0x3f);
+			iptr += 2;
+		} else if (!(*iptr & 0x10)) {
+			c = ((iptr[0] & 0x0f) << 12) | ((iptr[1] & 0x3f) << 6) | (iptr[2] & 0x3f);
+			iptr += 3;
+		} else if (!(*iptr & 0x08)) {
+			c = ((iptr[0] & 0x07) << 18) | ((iptr[1] & 0x3f) << 12) | ((iptr[2] & 0x3f) << 6) | (iptr[3] & 0x3f);
+			iptr += 4;
+		}
+
+		if (c < 65536) {
+			*optr++ = c;
+			max_length--;
+		} else if (max_length <= 2) {
+			*optr = '\0';
+			return (int)(optr - output);
+		} else {
+			c -= 0x10000;
+			*optr++ = 0xd800 | ((c >> 10) & 0x3ff);
+			*optr++ = 0xdc00 | (c & 0x3ff);
+			max_length -= 2;
+			if (offsetmap)
+				offsetmap++;
+		}
+	}
+	if (offsetmap)
+		*offsetmap = (int)(iptr - (unsigned char*)input);
+	*optr = '\0';
+	return (int)(optr - output);
+}
+
+static int copy_char8_to_char16(PCRE2_SPTR8 input, PCRE2_UCHAR16 *output, int max_length)
+{
+	PCRE2_SPTR8 iptr = input;
+	PCRE2_UCHAR16 *optr = output;
+
+	if (max_length == 0)
+		return 0;
+
+	while (*iptr && max_length > 1) {
+		*optr++ = *iptr++;
+		max_length--;
+	}
+	*optr = '\0';
+	return (int)(optr - output);
+}
+
+#define REGTEST_MAX_LENGTH16 4096
+static PCRE2_UCHAR16 regtest_buf16[REGTEST_MAX_LENGTH16];
+static int regtest_offsetmap16[REGTEST_MAX_LENGTH16];
+
+#endif /* SUPPORT_PCRE2_16 */
+
+#ifdef SUPPORT_PCRE2_32
+
+static int convert_utf8_to_utf32(PCRE2_SPTR8 input, PCRE2_UCHAR32 *output, int *offsetmap, int max_length)
+{
+	PCRE2_SPTR8 iptr = input;
+	PCRE2_UCHAR32 *optr = output;
+	unsigned int c;
+
+	if (max_length == 0)
+		return 0;
+
+	while (*iptr && max_length > 1) {
+		c = 0;
+		if (offsetmap)
+			*offsetmap++ = (int)(iptr - (unsigned char*)input);
+
+		if (*iptr < 0xc0)
+			c = *iptr++;
+		else if (!(*iptr & 0x20)) {
+			c = ((iptr[0] & 0x1f) << 6) | (iptr[1] & 0x3f);
+			iptr += 2;
+		} else if (!(*iptr & 0x10)) {
+			c = ((iptr[0] & 0x0f) << 12) | ((iptr[1] & 0x3f) << 6) | (iptr[2] & 0x3f);
+			iptr += 3;
+		} else if (!(*iptr & 0x08)) {
+			c = ((iptr[0] & 0x07) << 18) | ((iptr[1] & 0x3f) << 12) | ((iptr[2] & 0x3f) << 6) | (iptr[3] & 0x3f);
+			iptr += 4;
+		}
+
+		*optr++ = c;
+		max_length--;
+	}
+	if (offsetmap)
+		*offsetmap = (int)(iptr - (unsigned char*)input);
+	*optr = 0;
+	return (int)(optr - output);
+}
+
+static int copy_char8_to_char32(PCRE2_SPTR8 input, PCRE2_UCHAR32 *output, int max_length)
+{
+	PCRE2_SPTR8 iptr = input;
+	PCRE2_UCHAR32 *optr = output;
+
+	if (max_length == 0)
+		return 0;
+
+	while (*iptr && max_length > 1) {
+		*optr++ = *iptr++;
+		max_length--;
+	}
+	*optr = '\0';
+	return (int)(optr - output);
+}
+
+#define REGTEST_MAX_LENGTH32 4096
+static PCRE2_UCHAR32 regtest_buf32[REGTEST_MAX_LENGTH32];
+static int regtest_offsetmap32[REGTEST_MAX_LENGTH32];
+
+#endif /* SUPPORT_PCRE2_32 */
+
+static int check_ascii(const char *input)
+{
+	const unsigned char *ptr = (unsigned char *)input;
+	while (*ptr) {
+		if (*ptr > 127)
+			return 0;
+		ptr++;
+	}
+	return 1;
+}
+
+#define OVECTOR_SIZE 15
+
+static int regression_tests(void)
+{
+	struct regression_test_case *current = regression_test_cases;
+	int error;
+	PCRE2_SIZE err_offs;
+	int is_successful;
+	int is_ascii;
+	int total = 0;
+	int successful = 0;
+	int successful_row = 0;
+	int counter = 0;
+	int jit_compile_mode;
+	int utf = 0;
+	int disabled_options = 0;
+	int i;
+#ifdef SUPPORT_PCRE2_8
+	pcre2_code_8 *re8;
+	pcre2_compile_context_8 *ccontext8;
+	pcre2_match_data_8 *mdata8_1;
+	pcre2_match_data_8 *mdata8_2;
+	pcre2_match_context_8 *mcontext8;
+	PCRE2_SIZE *ovector8_1 = NULL;
+	PCRE2_SIZE *ovector8_2 = NULL;
+	int return_value8[2];
+#endif
+#ifdef SUPPORT_PCRE2_16
+	pcre2_code_16 *re16;
+	pcre2_compile_context_16 *ccontext16;
+	pcre2_match_data_16 *mdata16_1;
+	pcre2_match_data_16 *mdata16_2;
+	pcre2_match_context_16 *mcontext16;
+	PCRE2_SIZE *ovector16_1 = NULL;
+	PCRE2_SIZE *ovector16_2 = NULL;
+	int return_value16[2];
+	int length16;
+#endif
+#ifdef SUPPORT_PCRE2_32
+	pcre2_code_32 *re32;
+	pcre2_compile_context_32 *ccontext32;
+	pcre2_match_data_32 *mdata32_1;
+	pcre2_match_data_32 *mdata32_2;
+	pcre2_match_context_32 *mcontext32;
+	PCRE2_SIZE *ovector32_1 = NULL;
+	PCRE2_SIZE *ovector32_2 = NULL;
+	int return_value32[2];
+	int length32;
+#endif
+
+#if defined SUPPORT_PCRE2_8
+	PCRE2_UCHAR8 cpu_info[128];
+#elif defined SUPPORT_PCRE2_16
+	PCRE2_UCHAR16 cpu_info[128];
+#elif defined SUPPORT_PCRE2_32
+	PCRE2_UCHAR32 cpu_info[128];
+#endif
+#if defined SUPPORT_UNICODE && ((defined(SUPPORT_PCRE2_8) + defined(SUPPORT_PCRE2_16) + defined(SUPPORT_PCRE2_32)) >= 2)
+	int return_value;
+#endif
+
+	/* This test compares the behaviour of interpreter and JIT. Although disabling
+	utf or ucp may make tests fail, if the pcre_exec result is the SAME, it is
+	still considered successful from pcre_jit_test point of view. */
+
+#if defined SUPPORT_PCRE2_8
+	pcre2_config_8(PCRE2_CONFIG_JITTARGET, &cpu_info);
+#elif defined SUPPORT_PCRE2_16
+	pcre2_config_16(PCRE2_CONFIG_JITTARGET, &cpu_info);
+#elif defined SUPPORT_PCRE2_32
+	pcre2_config_32(PCRE2_CONFIG_JITTARGET, &cpu_info);
+#endif
+
+	printf("Running JIT regression tests\n");
+	printf("  target CPU of SLJIT compiler: ");
+	for (i = 0; cpu_info[i]; i++)
+		printf("%c", (char)(cpu_info[i]));
+	printf("\n");
+
+#if defined SUPPORT_PCRE2_8
+	pcre2_config_8(PCRE2_CONFIG_UNICODE, &utf);
+#elif defined SUPPORT_PCRE2_16
+	pcre2_config_16(PCRE2_CONFIG_UNICODE, &utf);
+#elif defined SUPPORT_PCRE2_32
+	pcre2_config_32(PCRE2_CONFIG_UNICODE, &utf);
+#endif
+
+	if (!utf)
+		disabled_options |= PCRE2_UTF;
+#ifdef SUPPORT_PCRE2_8
+	printf("  in  8 bit mode with UTF-8  %s:\n", utf ? "enabled" : "disabled");
+#endif
+#ifdef SUPPORT_PCRE2_16
+	printf("  in 16 bit mode with UTF-16 %s:\n", utf ? "enabled" : "disabled");
+#endif
+#ifdef SUPPORT_PCRE2_32
+	printf("  in 32 bit mode with UTF-32 %s:\n", utf ? "enabled" : "disabled");
+#endif
+
+	while (current->pattern) {
+		/* printf("\nPattern: %s :\n", current->pattern); */
+		total++;
+		is_ascii = 0;
+		if (!(current->start_offset & F_PROPERTY))
+			is_ascii = check_ascii(current->pattern) && check_ascii(current->input);
+
+		if (current->match_options & PCRE2_PARTIAL_SOFT)
+			jit_compile_mode = PCRE2_JIT_PARTIAL_SOFT;
+		else if (current->match_options & PCRE2_PARTIAL_HARD)
+			jit_compile_mode = PCRE2_JIT_PARTIAL_HARD;
+		else
+			jit_compile_mode = PCRE2_JIT_COMPLETE;
+		error = 0;
+#ifdef SUPPORT_PCRE2_8
+		re8 = NULL;
+		ccontext8 = pcre2_compile_context_create_8(NULL);
+		if (ccontext8) {
+			if (GET_NEWLINE(current->newline))
+				pcre2_set_newline_8(ccontext8, GET_NEWLINE(current->newline));
+			if (GET_BSR(current->newline))
+				pcre2_set_bsr_8(ccontext8, GET_BSR(current->newline));
+
+			if (!(current->start_offset & F_NO8)) {
+				re8 = pcre2_compile_8((PCRE2_SPTR8)current->pattern, PCRE2_ZERO_TERMINATED,
+					current->compile_options & ~disabled_options,
+					&error, &err_offs, ccontext8);
+
+				if (!re8 && (utf || is_ascii))
+					printf("\n8 bit: Cannot compile pattern \"%s\": %d\n", current->pattern, error);
+			}
+			pcre2_compile_context_free_8(ccontext8);
+		}
+		else
+			printf("\n8 bit: Cannot allocate compile context\n");
+#endif
+#ifdef SUPPORT_PCRE2_16
+		if ((current->compile_options & PCRE2_UTF) || (current->start_offset & F_FORCECONV))
+			convert_utf8_to_utf16((PCRE2_SPTR8)current->pattern, regtest_buf16, NULL, REGTEST_MAX_LENGTH16);
+		else
+			copy_char8_to_char16((PCRE2_SPTR8)current->pattern, regtest_buf16, REGTEST_MAX_LENGTH16);
+
+		re16 = NULL;
+		ccontext16 = pcre2_compile_context_create_16(NULL);
+		if (ccontext16) {
+			if (GET_NEWLINE(current->newline))
+				pcre2_set_newline_16(ccontext16, GET_NEWLINE(current->newline));
+			if (GET_BSR(current->newline))
+				pcre2_set_bsr_16(ccontext16, GET_BSR(current->newline));
+
+			if (!(current->start_offset & F_NO16)) {
+				re16 = pcre2_compile_16(regtest_buf16, PCRE2_ZERO_TERMINATED,
+					current->compile_options & ~disabled_options,
+					&error, &err_offs, ccontext16);
+
+				if (!re16 && (utf || is_ascii))
+					printf("\n16 bit: Cannot compile pattern \"%s\": %d\n", current->pattern, error);
+			}
+			pcre2_compile_context_free_16(ccontext16);
+		}
+		else
+			printf("\n16 bit: Cannot allocate compile context\n");
+#endif
+#ifdef SUPPORT_PCRE2_32
+		if ((current->compile_options & PCRE2_UTF) || (current->start_offset & F_FORCECONV))
+			convert_utf8_to_utf32((PCRE2_SPTR8)current->pattern, regtest_buf32, NULL, REGTEST_MAX_LENGTH32);
+		else
+			copy_char8_to_char32((PCRE2_SPTR8)current->pattern, regtest_buf32, REGTEST_MAX_LENGTH32);
+
+		re32 = NULL;
+		ccontext32 = pcre2_compile_context_create_32(NULL);
+		if (ccontext32) {
+			if (GET_NEWLINE(current->newline))
+				pcre2_set_newline_32(ccontext32, GET_NEWLINE(current->newline));
+			if (GET_BSR(current->newline))
+				pcre2_set_bsr_32(ccontext32, GET_BSR(current->newline));
+
+			if (!(current->start_offset & F_NO32)) {
+				re32 = pcre2_compile_32(regtest_buf32, PCRE2_ZERO_TERMINATED,
+					current->compile_options & ~disabled_options,
+					&error, &err_offs, ccontext32);
+
+				if (!re32 && (utf || is_ascii))
+					printf("\n32 bit: Cannot compile pattern \"%s\": %d\n", current->pattern, error);
+			}
+			pcre2_compile_context_free_32(ccontext32);
+		}
+		else
+			printf("\n32 bit: Cannot allocate compile context\n");
+#endif
+
+		counter++;
+		if ((counter & 0x3) != 0) {
+#ifdef SUPPORT_PCRE2_8
+			setstack8(NULL);
+#endif
+#ifdef SUPPORT_PCRE2_16
+			setstack16(NULL);
+#endif
+#ifdef SUPPORT_PCRE2_32
+			setstack32(NULL);
+#endif
+		}
+
+#ifdef SUPPORT_PCRE2_8
+		return_value8[0] = -1000;
+		return_value8[1] = -1000;
+		mdata8_1 = pcre2_match_data_create_8(OVECTOR_SIZE, NULL);
+		mdata8_2 = pcre2_match_data_create_8(OVECTOR_SIZE, NULL);
+		mcontext8 = pcre2_match_context_create_8(NULL);
+		if (!mdata8_1 || !mdata8_2 || !mcontext8) {
+			printf("\n8 bit: Cannot allocate match data\n");
+			pcre2_match_data_free_8(mdata8_1);
+			pcre2_match_data_free_8(mdata8_2);
+			pcre2_match_context_free_8(mcontext8);
+			pcre2_code_free_8(re8);
+			re8 = NULL;
+		} else {
+			ovector8_1 = pcre2_get_ovector_pointer_8(mdata8_1);
+			ovector8_2 = pcre2_get_ovector_pointer_8(mdata8_2);
+			for (i = 0; i < OVECTOR_SIZE * 2; ++i)
+				ovector8_1[i] = -2;
+			for (i = 0; i < OVECTOR_SIZE * 2; ++i)
+				ovector8_2[i] = -2;
+			pcre2_set_match_limit_8(mcontext8, 10000000);
+		}
+		if (re8) {
+			return_value8[1] = pcre2_match_8(re8, (PCRE2_SPTR8)current->input, strlen(current->input),
+				current->start_offset & OFFSET_MASK, current->match_options, mdata8_2, mcontext8);
+
+			if (pcre2_jit_compile_8(re8, jit_compile_mode)) {
+				printf("\n8 bit: JIT compiler does not support \"%s\"\n", current->pattern);
+			} else if ((counter & 0x1) != 0) {
+				setstack8(mcontext8);
+				return_value8[0] = pcre2_match_8(re8, (PCRE2_SPTR8)current->input, strlen(current->input),
+					current->start_offset & OFFSET_MASK, current->match_options, mdata8_1, mcontext8);
+			} else {
+				pcre2_jit_stack_assign_8(mcontext8, NULL, getstack8());
+				return_value8[0] = pcre2_jit_match_8(re8, (PCRE2_SPTR8)current->input, strlen(current->input),
+					current->start_offset & OFFSET_MASK, current->match_options, mdata8_1, mcontext8);
+			}
+		}
+#endif
+
+#ifdef SUPPORT_PCRE2_16
+		return_value16[0] = -1000;
+		return_value16[1] = -1000;
+		mdata16_1 = pcre2_match_data_create_16(OVECTOR_SIZE, NULL);
+		mdata16_2 = pcre2_match_data_create_16(OVECTOR_SIZE, NULL);
+		mcontext16 = pcre2_match_context_create_16(NULL);
+		if (!mdata16_1 || !mdata16_2 || !mcontext16) {
+			printf("\n16 bit: Cannot allocate match data\n");
+			pcre2_match_data_free_16(mdata16_1);
+			pcre2_match_data_free_16(mdata16_2);
+			pcre2_match_context_free_16(mcontext16);
+			pcre2_code_free_16(re16);
+			re16 = NULL;
+		} else {
+			ovector16_1 = pcre2_get_ovector_pointer_16(mdata16_1);
+			ovector16_2 = pcre2_get_ovector_pointer_16(mdata16_2);
+			for (i = 0; i < OVECTOR_SIZE * 2; ++i)
+				ovector16_1[i] = -2;
+			for (i = 0; i < OVECTOR_SIZE * 2; ++i)
+				ovector16_2[i] = -2;
+			pcre2_set_match_limit_16(mcontext16, 10000000);
+		}
+		if (re16) {
+			if ((current->compile_options & PCRE2_UTF) || (current->start_offset & F_FORCECONV))
+				length16 = convert_utf8_to_utf16((PCRE2_SPTR8)current->input, regtest_buf16, regtest_offsetmap16, REGTEST_MAX_LENGTH16);
+			else
+				length16 = copy_char8_to_char16((PCRE2_SPTR8)current->input, regtest_buf16, REGTEST_MAX_LENGTH16);
+
+			return_value16[1] = pcre2_match_16(re16, regtest_buf16, length16,
+				current->start_offset & OFFSET_MASK, current->match_options, mdata16_2, mcontext16);
+
+			if (pcre2_jit_compile_16(re16, jit_compile_mode)) {
+				printf("\n16 bit: JIT compiler does not support \"%s\"\n", current->pattern);
+			} else if ((counter & 0x1) != 0) {
+				setstack16(mcontext16);
+				return_value16[0] = pcre2_match_16(re16, regtest_buf16, length16,
+					current->start_offset & OFFSET_MASK, current->match_options, mdata16_1, mcontext16);
+			} else {
+				pcre2_jit_stack_assign_16(mcontext16, NULL, getstack16());
+				return_value16[0] = pcre2_jit_match_16(re16, regtest_buf16, length16,
+					current->start_offset & OFFSET_MASK, current->match_options, mdata16_1, mcontext16);
+			}
+		}
+#endif
+
+#ifdef SUPPORT_PCRE2_32
+		return_value32[0] = -1000;
+		return_value32[1] = -1000;
+		mdata32_1 = pcre2_match_data_create_32(OVECTOR_SIZE, NULL);
+		mdata32_2 = pcre2_match_data_create_32(OVECTOR_SIZE, NULL);
+		mcontext32 = pcre2_match_context_create_32(NULL);
+		if (!mdata32_1 || !mdata32_2 || !mcontext32) {
+			printf("\n32 bit: Cannot allocate match data\n");
+			pcre2_match_data_free_32(mdata32_1);
+			pcre2_match_data_free_32(mdata32_2);
+			pcre2_match_context_free_32(mcontext32);
+			pcre2_code_free_32(re32);
+			re32 = NULL;
+		} else {
+			ovector32_1 = pcre2_get_ovector_pointer_32(mdata32_1);
+			ovector32_2 = pcre2_get_ovector_pointer_32(mdata32_2);
+			for (i = 0; i < OVECTOR_SIZE * 2; ++i)
+				ovector32_1[i] = -2;
+			for (i = 0; i < OVECTOR_SIZE * 2; ++i)
+				ovector32_2[i] = -2;
+			pcre2_set_match_limit_32(mcontext32, 10000000);
+		}
+		if (re32) {
+			if ((current->compile_options & PCRE2_UTF) || (current->start_offset & F_FORCECONV))
+				length32 = convert_utf8_to_utf32((PCRE2_SPTR8)current->input, regtest_buf32, regtest_offsetmap32, REGTEST_MAX_LENGTH32);
+			else
+				length32 = copy_char8_to_char32((PCRE2_SPTR8)current->input, regtest_buf32, REGTEST_MAX_LENGTH32);
+
+			return_value32[1] = pcre2_match_32(re32, regtest_buf32, length32,
+				current->start_offset & OFFSET_MASK, current->match_options, mdata32_2, mcontext32);
+
+			if (pcre2_jit_compile_32(re32, jit_compile_mode)) {
+				printf("\n32 bit: JIT compiler does not support \"%s\"\n", current->pattern);
+			} else if ((counter & 0x1) != 0) {
+				setstack32(mcontext32);
+				return_value32[0] = pcre2_match_32(re32, regtest_buf32, length32,
+					current->start_offset & OFFSET_MASK, current->match_options, mdata32_1, mcontext32);
+			} else {
+				pcre2_jit_stack_assign_32(mcontext32, NULL, getstack32());
+				return_value32[0] = pcre2_jit_match_32(re32, regtest_buf32, length32,
+					current->start_offset & OFFSET_MASK, current->match_options, mdata32_1, mcontext32);
+			}
+		}
+#endif
+
+		/* printf("[%d-%d-%d|%d-%d|%d-%d|%d-%d]%s",
+			return_value8[0], return_value16[0], return_value32[0],
+			(int)ovector8_1[0], (int)ovector8_1[1],
+			(int)ovector16_1[0], (int)ovector16_1[1],
+			(int)ovector32_1[0], (int)ovector32_1[1],
+			(current->compile_options & PCRE2_CASELESS) ? "C" : ""); */
+
+		/* If F_DIFF is set, just run the test, but do not compare the results.
+		Segfaults can still be captured. */
+
+		is_successful = 1;
+		if (!(current->start_offset & F_DIFF)) {
+#if defined SUPPORT_UNICODE && ((defined(SUPPORT_PCRE2_8) + defined(SUPPORT_PCRE2_16) + defined(SUPPORT_PCRE2_32)) >= 2)
+			if (!(current->start_offset & F_FORCECONV)) {
+
+				/* All results must be the same. */
+#ifdef SUPPORT_PCRE2_8
+				if ((return_value = return_value8[0]) != return_value8[1]) {
+					printf("\n8 bit: Return value differs(J8:%d,I8:%d): [%d] '%s' @ '%s'\n",
+						return_value8[0], return_value8[1], total, current->pattern, current->input);
+					is_successful = 0;
+				} else
+#endif
+#ifdef SUPPORT_PCRE2_16
+				if ((return_value = return_value16[0]) != return_value16[1]) {
+					printf("\n16 bit: Return value differs(J16:%d,I16:%d): [%d] '%s' @ '%s'\n",
+						return_value16[0], return_value16[1], total, current->pattern, current->input);
+					is_successful = 0;
+				} else
+#endif
+#ifdef SUPPORT_PCRE2_32
+				if ((return_value = return_value32[0]) != return_value32[1]) {
+					printf("\n32 bit: Return value differs(J32:%d,I32:%d): [%d] '%s' @ '%s'\n",
+						return_value32[0], return_value32[1], total, current->pattern, current->input);
+					is_successful = 0;
+				} else
+#endif
+#if defined SUPPORT_PCRE2_8 && defined SUPPORT_PCRE2_16
+				if (return_value8[0] != return_value16[0]) {
+					printf("\n8 and 16 bit: Return value differs(J8:%d,J16:%d): [%d] '%s' @ '%s'\n",
+						return_value8[0], return_value16[0],
+						total, current->pattern, current->input);
+					is_successful = 0;
+				} else
+#endif
+#if defined SUPPORT_PCRE2_8 && defined SUPPORT_PCRE2_32
+				if (return_value8[0] != return_value32[0]) {
+					printf("\n8 and 32 bit: Return value differs(J8:%d,J32:%d): [%d] '%s' @ '%s'\n",
+						return_value8[0], return_value32[0],
+						total, current->pattern, current->input);
+					is_successful = 0;
+				} else
+#endif
+#if defined SUPPORT_PCRE2_16 && defined SUPPORT_PCRE2_32
+				if (return_value16[0] != return_value32[0]) {
+					printf("\n16 and 32 bit: Return value differs(J16:%d,J32:%d): [%d] '%s' @ '%s'\n",
+						return_value16[0], return_value32[0],
+						total, current->pattern, current->input);
+					is_successful = 0;
+				} else
+#endif
+				if (return_value >= 0 || return_value == PCRE2_ERROR_PARTIAL) {
+					if (return_value == PCRE2_ERROR_PARTIAL) {
+						return_value = 2;
+					} else {
+						return_value *= 2;
+					}
+#ifdef SUPPORT_PCRE2_8
+					return_value8[0] = return_value;
+#endif
+#ifdef SUPPORT_PCRE2_16
+					return_value16[0] = return_value;
+#endif
+#ifdef SUPPORT_PCRE2_32
+					return_value32[0] = return_value;
+#endif
+					/* Transform back the results. */
+					if (current->compile_options & PCRE2_UTF) {
+#ifdef SUPPORT_PCRE2_16
+						for (i = 0; i < return_value; ++i) {
+							if (ovector16_1[i] != PCRE2_UNSET)
+								ovector16_1[i] = regtest_offsetmap16[ovector16_1[i]];
+							if (ovector16_2[i] != PCRE2_UNSET)
+								ovector16_2[i] = regtest_offsetmap16[ovector16_2[i]];
+						}
+#endif
+#ifdef SUPPORT_PCRE2_32
+						for (i = 0; i < return_value; ++i) {
+							if (ovector32_1[i] != PCRE2_UNSET)
+								ovector32_1[i] = regtest_offsetmap32[ovector32_1[i]];
+							if (ovector32_2[i] != PCRE2_UNSET)
+								ovector32_2[i] = regtest_offsetmap32[ovector32_2[i]];
+						}
+#endif
+					}
+
+					for (i = 0; i < return_value; ++i) {
+#if defined SUPPORT_PCRE2_8 && defined SUPPORT_PCRE2_16
+						if (ovector8_1[i] != ovector8_2[i] || ovector8_1[i] != ovector16_1[i] || ovector8_1[i] != ovector16_2[i]) {
+							printf("\n8 and 16 bit: Ovector[%d] value differs(J8:%d,I8:%d,J16:%d,I16:%d): [%d] '%s' @ '%s' \n",
+								i, (int)ovector8_1[i], (int)ovector8_2[i], (int)ovector16_1[i], (int)ovector16_2[i],
+								total, current->pattern, current->input);
+							is_successful = 0;
+						}
+#endif
+#if defined SUPPORT_PCRE2_8 && defined SUPPORT_PCRE2_32
+						if (ovector8_1[i] != ovector8_2[i] || ovector8_1[i] != ovector32_1[i] || ovector8_1[i] != ovector32_2[i]) {
+							printf("\n8 and 32 bit: Ovector[%d] value differs(J8:%d,I8:%d,J32:%d,I32:%d): [%d] '%s' @ '%s' \n",
+								i, (int)ovector8_1[i], (int)ovector8_2[i], (int)ovector32_1[i], (int)ovector32_2[i],
+								total, current->pattern, current->input);
+							is_successful = 0;
+						}
+#endif
+#if defined SUPPORT_PCRE2_16 && defined SUPPORT_PCRE2_32
+						if (ovector16_1[i] != ovector16_2[i] || ovector16_1[i] != ovector32_1[i] || ovector16_1[i] != ovector32_2[i]) {
+							printf("\n16 and 32 bit: Ovector[%d] value differs(J16:%d,I16:%d,J32:%d,I32:%d): [%d] '%s' @ '%s' \n",
+								i, (int)ovector16_1[i], (int)ovector16_2[i], (int)ovector32_1[i], (int)ovector32_2[i],
+								total, current->pattern, current->input);
+							is_successful = 0;
+						}
+#endif
+					}
+				}
+			} else
+#endif /* more than one of SUPPORT_PCRE2_8, SUPPORT_PCRE2_16 and SUPPORT_PCRE2_32 */
+			{
+#ifdef SUPPORT_PCRE2_8
+				if (return_value8[0] != return_value8[1]) {
+					printf("\n8 bit: Return value differs(%d:%d): [%d] '%s' @ '%s'\n",
+						return_value8[0], return_value8[1], total, current->pattern, current->input);
+					is_successful = 0;
+				} else if (return_value8[0] >= 0 || return_value8[0] == PCRE2_ERROR_PARTIAL) {
+					if (return_value8[0] == PCRE2_ERROR_PARTIAL)
+						return_value8[0] = 2;
+					else
+						return_value8[0] *= 2;
+
+					for (i = 0; i < return_value8[0]; ++i)
+						if (ovector8_1[i] != ovector8_2[i]) {
+							printf("\n8 bit: Ovector[%d] value differs(%d:%d): [%d] '%s' @ '%s'\n",
+								i, (int)ovector8_1[i], (int)ovector8_2[i], total, current->pattern, current->input);
+							is_successful = 0;
+						}
+				}
+#endif
+
+#ifdef SUPPORT_PCRE2_16
+				if (return_value16[0] != return_value16[1]) {
+					printf("\n16 bit: Return value differs(%d:%d): [%d] '%s' @ '%s'\n",
+						return_value16[0], return_value16[1], total, current->pattern, current->input);
+					is_successful = 0;
+				} else if (return_value16[0] >= 0 || return_value16[0] == PCRE2_ERROR_PARTIAL) {
+					if (return_value16[0] == PCRE2_ERROR_PARTIAL)
+						return_value16[0] = 2;
+					else
+						return_value16[0] *= 2;
+
+					for (i = 0; i < return_value16[0]; ++i)
+						if (ovector16_1[i] != ovector16_2[i]) {
+							printf("\n16 bit: Ovector[%d] value differs(%d:%d): [%d] '%s' @ '%s'\n",
+								i, (int)ovector16_1[i], (int)ovector16_2[i], total, current->pattern, current->input);
+							is_successful = 0;
+						}
+				}
+#endif
+
+#ifdef SUPPORT_PCRE2_32
+				if (return_value32[0] != return_value32[1]) {
+					printf("\n32 bit: Return value differs(%d:%d): [%d] '%s' @ '%s'\n",
+						return_value32[0], return_value32[1], total, current->pattern, current->input);
+					is_successful = 0;
+				} else if (return_value32[0] >= 0 || return_value32[0] == PCRE2_ERROR_PARTIAL) {
+					if (return_value32[0] == PCRE2_ERROR_PARTIAL)
+						return_value32[0] = 2;
+					else
+						return_value32[0] *= 2;
+
+					for (i = 0; i < return_value32[0]; ++i)
+						if (ovector32_1[i] != ovector32_2[i]) {
+							printf("\n32 bit: Ovector[%d] value differs(%d:%d): [%d] '%s' @ '%s'\n",
+								i, (int)ovector32_1[i], (int)ovector32_2[i], total, current->pattern, current->input);
+							is_successful = 0;
+						}
+				}
+#endif
+			}
+		}
+
+		if (is_successful) {
+#ifdef SUPPORT_PCRE2_8
+			if (!(current->start_offset & F_NO8) && (utf || is_ascii)) {
+				if (return_value8[0] < 0 && !(current->start_offset & F_NOMATCH)) {
+					printf("8 bit: Test should match: [%d] '%s' @ '%s'\n",
+						total, current->pattern, current->input);
+					is_successful = 0;
+				}
+
+				if (return_value8[0] >= 0 && (current->start_offset & F_NOMATCH)) {
+					printf("8 bit: Test should not match: [%d] '%s' @ '%s'\n",
+						total, current->pattern, current->input);
+					is_successful = 0;
+				}
+			}
+#endif
+#ifdef SUPPORT_PCRE2_16
+			if (!(current->start_offset & F_NO16) && (utf || is_ascii)) {
+				if (return_value16[0] < 0 && !(current->start_offset & F_NOMATCH)) {
+					printf("16 bit: Test should match: [%d] '%s' @ '%s'\n",
+						total, current->pattern, current->input);
+					is_successful = 0;
+				}
+
+				if (return_value16[0] >= 0 && (current->start_offset & F_NOMATCH)) {
+					printf("16 bit: Test should not match: [%d] '%s' @ '%s'\n",
+						total, current->pattern, current->input);
+					is_successful = 0;
+				}
+			}
+#endif
+#ifdef SUPPORT_PCRE2_32
+			if (!(current->start_offset & F_NO32) && (utf || is_ascii)) {
+				if (return_value32[0] < 0 && !(current->start_offset & F_NOMATCH)) {
+					printf("32 bit: Test should match: [%d] '%s' @ '%s'\n",
+						total, current->pattern, current->input);
+					is_successful = 0;
+				}
+
+				if (return_value32[0] >= 0 && (current->start_offset & F_NOMATCH)) {
+					printf("32 bit: Test should not match: [%d] '%s' @ '%s'\n",
+						total, current->pattern, current->input);
+					is_successful = 0;
+				}
+			}
+#endif
+		}
+
+		if (is_successful) {
+#ifdef SUPPORT_PCRE2_8
+			if (re8 && !(current->start_offset & F_NO8) && pcre2_get_mark_8(mdata8_1) != pcre2_get_mark_8(mdata8_2)) {
+				printf("8 bit: Mark value mismatch: [%d] '%s' @ '%s'\n",
+					total, current->pattern, current->input);
+				is_successful = 0;
+			}
+#endif
+#ifdef SUPPORT_PCRE2_16
+			if (re16 && !(current->start_offset & F_NO16) && pcre2_get_mark_16(mdata16_1) != pcre2_get_mark_16(mdata16_2)) {
+				printf("16 bit: Mark value mismatch: [%d] '%s' @ '%s'\n",
+					total, current->pattern, current->input);
+				is_successful = 0;
+			}
+#endif
+#ifdef SUPPORT_PCRE2_32
+			if (re32 && !(current->start_offset & F_NO32) && pcre2_get_mark_32(mdata32_1) != pcre2_get_mark_32(mdata32_2)) {
+				printf("32 bit: Mark value mismatch: [%d] '%s' @ '%s'\n",
+					total, current->pattern, current->input);
+				is_successful = 0;
+			}
+#endif
+		}
+
+#ifdef SUPPORT_PCRE2_8
+		pcre2_code_free_8(re8);
+		pcre2_match_data_free_8(mdata8_1);
+		pcre2_match_data_free_8(mdata8_2);
+		pcre2_match_context_free_8(mcontext8);
+#endif
+#ifdef SUPPORT_PCRE2_16
+		pcre2_code_free_16(re16);
+		pcre2_match_data_free_16(mdata16_1);
+		pcre2_match_data_free_16(mdata16_2);
+		pcre2_match_context_free_16(mcontext16);
+#endif
+#ifdef SUPPORT_PCRE2_32
+		pcre2_code_free_32(re32);
+		pcre2_match_data_free_32(mdata32_1);
+		pcre2_match_data_free_32(mdata32_2);
+		pcre2_match_context_free_32(mcontext32);
+#endif
+
+		if (is_successful) {
+			successful++;
+			successful_row++;
+			printf(".");
+			if (successful_row >= 60) {
+				successful_row = 0;
+				printf("\n");
+			}
+		} else
+			successful_row = 0;
+
+		fflush(stdout);
+		current++;
+	}
+#ifdef SUPPORT_PCRE2_8
+	setstack8(NULL);
+#endif
+#ifdef SUPPORT_PCRE2_16
+	setstack16(NULL);
+#endif
+#ifdef SUPPORT_PCRE2_32
+	setstack32(NULL);
+#endif
+
+	if (total == successful) {
+		printf("\nAll JIT regression tests are successfully passed.\n");
+		return 0;
+	} else {
+		printf("\nSuccessful test ratio: %d%% (%d failed)\n", successful * 100 / total, total - successful);
+		return 1;
+	}
+}
+
+#if defined SUPPORT_UNICODE
+
+static int check_invalid_utf_result(int pattern_index, const char *type, int result,
+	int match_start, int match_end, PCRE2_SIZE *ovector)
+{
+	if (match_start < 0) {
+		if (result != -1) {
+			printf("Pattern[%d] %s result is not -1.\n", pattern_index, type);
+			return 1;
+		}
+		return 0;
+	}
+
+	if (result <= 0) {
+		printf("Pattern[%d] %s result (%d) is not greater than 0.\n", pattern_index, type, result);
+		return 1;
+	}
+
+	if (ovector[0] != (PCRE2_SIZE)match_start) {
+		printf("Pattern[%d] %s ovector[0] is unexpected (%d instead of %d)\n",
+			pattern_index, type, (int)ovector[0], match_start);
+		return 1;
+	}
+
+	if (ovector[1] != (PCRE2_SIZE)match_end) {
+		printf("Pattern[%d] %s ovector[1] is unexpected (%d instead of %d)\n",
+			pattern_index, type, (int)ovector[1], match_end);
+		return 1;
+	}
+
+	return 0;
+}
+
+#endif /* SUPPORT_UNICODE */
+
+#if defined SUPPORT_UNICODE && defined SUPPORT_PCRE2_8
+
+#define UDA (PCRE2_UTF | PCRE2_DOTALL | PCRE2_ANCHORED)
+#define CI (PCRE2_JIT_COMPLETE | PCRE2_JIT_INVALID_UTF)
+#define CPI (PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_INVALID_UTF)
+
+struct invalid_utf8_regression_test_case {
+	int compile_options;
+	int jit_compile_options;
+	int start_offset;
+	int skip_left;
+	int skip_right;
+	int match_start;
+	int match_end;
+	const char *pattern[2];
+	const char *input;
+};
+
+static const char invalid_utf8_newline_cr;
+
+static const struct invalid_utf8_regression_test_case invalid_utf8_regression_test_cases[] = {
+	{ UDA, CI, 0, 0, 0, 0, 4, { ".", NULL }, "\xf4\x8f\xbf\xbf" },
+	{ UDA, CI, 0, 0, 0, 0, 4, { ".", NULL }, "\xf0\x90\x80\x80" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xf4\x90\x80\x80" },
+	{ UDA, CI, 0, 0, 1, -1, -1, { ".", NULL }, "\xf4\x8f\xbf\xbf" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xf0\x90\x80\x7f" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xf0\x90\x80\xc0" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xf0\x8f\xbf\xbf" },
+	{ UDA, CI, 0, 0, 0, 0, 3, { ".", NULL }, "\xef\xbf\xbf#" },
+	{ UDA, CI, 0, 0, 0, 0, 3, { ".", NULL }, "\xef\xbf\xbf" },
+	{ UDA, CI, 0, 0, 0, 0, 3, { ".", NULL }, "\xe0\xa0\x80#" },
+	{ UDA, CI, 0, 0, 0, 0, 3, { ".", NULL }, "\xe0\xa0\x80" },
+	{ UDA, CI, 0, 0, 2, -1, -1, { ".", NULL }, "\xef\xbf\xbf#" },
+	{ UDA, CI, 0, 0, 1, -1, -1, { ".", NULL }, "\xef\xbf\xbf" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xef\xbf\x7f#" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xef\xbf\xc0" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xe0\x9f\xbf#" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xe0\x9f\xbf" },
+	{ UDA, CI, 0, 0, 0, 0, 3, { ".", NULL }, "\xed\x9f\xbf#" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xed\xa0\x80#" },
+	{ UDA, CI, 0, 0, 0, 0, 3, { ".", NULL }, "\xee\x80\x80#" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xed\xbf\xbf#" },
+	{ UDA, CI, 0, 0, 0, 0, 2, { ".", NULL }, "\xdf\xbf##" },
+	{ UDA, CI, 0, 0, 0, 0, 2, { ".", NULL }, "\xdf\xbf#" },
+	{ UDA, CI, 0, 0, 0, 0, 2, { ".", NULL }, "\xdf\xbf" },
+	{ UDA, CI, 0, 0, 0, 0, 2, { ".", NULL }, "\xc2\x80##" },
+	{ UDA, CI, 0, 0, 0, 0, 2, { ".", NULL }, "\xc2\x80#" },
+	{ UDA, CI, 0, 0, 0, 0, 2, { ".", NULL }, "\xc2\x80" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xe0\x80##" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xdf\xc0##" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xe0\x80" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xdf\xc0" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xc1\xbf##" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xc1\xbf" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\x80###" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\x80" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xf8###" },
+	{ UDA, CI, 0, 0, 0, -1, -1, { ".", NULL }, "\xf8" },
+	{ UDA, CI, 0, 0, 0, 0, 1, { ".", NULL }, "\x7f" },
+
+	{ UDA, CPI, 4, 0, 0, 4, 4, { "\\B", NULL }, "\xf4\x8f\xbf\xbf#" },
+	{ UDA, CPI, 4, 0, 0, -1, -1, { "\\B", "\\b" }, "\xf4\xa0\x80\x80\xf4\xa0\x80\x80" },
+	{ UDA, CPI, 4, 1, 1, -1, -1, { "\\B", "\\b" }, "\xf4\x8f\xbf\xbf\xf4\x8f\xbf\xbf" },
+	{ UDA, CPI, 4, 0, 0, 4, 4, { "\\B", NULL }, "#\xef\xbf\xbf#" },
+	{ UDA, CPI, 4, 0, 0, 4, 4, { "\\B", NULL }, "#\xe0\xa0\x80#" },
+	{ UDA, CPI, 4, 0, 0, 4, 4, { "\\B", NULL }, "\xf0\x90\x80\x80#" },
+	{ UDA, CPI, 4, 0, 0, 4, 4, { "\\B", NULL }, "\xf3\xbf\xbf\xbf#" },
+	{ UDA, CPI, 4, 0, 0, -1, -1, { "\\B", "\\b" }, "\xf0\x8f\xbf\xbf\xf0\x8f\xbf\xbf" },
+	{ UDA, CPI, 4, 0, 0, -1, -1, { "\\B", "\\b" }, "\xf5\x80\x80\x80\xf5\x80\x80\x80" },
+	{ UDA, CPI, 4, 0, 0, -1, -1, { "\\B", "\\b" }, "\xf4\x90\x80\x80\xf4\x90\x80\x80" },
+	{ UDA, CPI, 4, 0, 0, -1, -1, { "\\B", "\\b" }, "\xf4\x8f\xbf\xff\xf4\x8f\xbf\xff" },
+	{ UDA, CPI, 4, 0, 0, -1, -1, { "\\B", "\\b" }, "\xf4\x8f\xff\xbf\xf4\x8f\xff\xbf" },
+	{ UDA, CPI, 4, 0, 1, -1, -1, { "\\B", "\\b" }, "\xef\x80\x80\x80\xef\x80\x80" },
+	{ UDA, CPI, 4, 0, 0, -1, -1, { "\\B", "\\b" }, "\x80\x80\x80\x80\x80\x80\x80\x80" },
+	{ UDA, CPI, 4, 0, 0, -1, -1, { "\\B", "\\b" }, "#\xe0\x9f\xbf\xe0\x9f\xbf#" },
+	{ UDA, CPI, 4, 2, 2, -1, -1, { "\\B", "\\b" }, "#\xe0\xa0\x80\xe0\xa0\x80#" },
+	{ UDA, CPI, 4, 0, 0, -1, -1, { "\\B", "\\b" }, "#\xf0\x80\x80\xf0\x80\x80#" },
+	{ UDA, CPI, 4, 0, 0, -1, -1, { "\\B", "\\b" }, "#\xed\xa0\x80\xed\xa0\x80#" },
+	{ UDA, CPI, 4, 0, 0, 4, 4, { "\\B", NULL }, "##\xdf\xbf#" },
+	{ UDA, CPI, 4, 2, 0, 2, 2, { "\\B", NULL }, "##\xdf\xbf#" },
+	{ UDA, CPI, 4, 0, 0, 4, 4, { "\\B", NULL }, "##\xc2\x80#" },
+	{ UDA, CPI, 4, 2, 0, 2, 2, { "\\B", NULL }, "##\xc2\x80#" },
+	{ UDA, CPI, 4, 0, 0, -1, -1, { "\\B", "\\b" }, "##\xc1\xbf\xc1\xbf##" },
+	{ UDA, CPI, 4, 0, 0, -1, -1, { "\\B", "\\b" }, "##\xdf\xc0\xdf\xc0##" },
+	{ UDA, CPI, 4, 0, 0, -1, -1, { "\\B", "\\b" }, "##\xe0\x80\xe0\x80##" },
+
+	{ UDA, CPI, 3, 0, 0, 3, 3, { "\\B", NULL }, "\xef\xbf\xbf#" },
+	{ UDA, CPI, 3, 0, 0, 3, 3, { "\\B", NULL }, "\xe0\xa0\x80#" },
+	{ UDA, CPI, 3, 0, 0, -1, -1, { "\\B", "\\b" }, "\xe0\x9f\xbf\xe0\x9f\xbf" },
+	{ UDA, CPI, 3, 1, 1, -1, -1, { "\\B", "\\b" }, "\xef\xbf\xbf\xef\xbf\xbf" },
+	{ UDA, CPI, 3, 0, 1, -1, -1, { "\\B", "\\b" }, "\xdf\x80\x80\xdf\x80" },
+	{ UDA, CPI, 3, 0, 0, -1, -1, { "\\B", "\\b" }, "\xef\xbf\xff\xef\xbf\xff" },
+	{ UDA, CPI, 3, 0, 0, -1, -1, { "\\B", "\\b" }, "\xef\xff\xbf\xef\xff\xbf" },
+	{ UDA, CPI, 3, 0, 0, -1, -1, { "\\B", "\\b" }, "\xed\xbf\xbf\xed\xbf\xbf" },
+
+	{ UDA, CPI, 2, 0, 0, 2, 2, { "\\B", NULL }, "\xdf\xbf#" },
+	{ UDA, CPI, 2, 0, 0, 2, 2, { "\\B", NULL }, "\xc2\x80#" },
+	{ UDA, CPI, 2, 1, 1, -1, -1, { "\\B", "\\b" }, "\xdf\xbf\xdf\xbf" },
+	{ UDA, CPI, 2, 0, 0, -1, -1, { "\\B", "\\b" }, "\xc1\xbf\xc1\xbf" },
+	{ UDA, CPI, 2, 0, 0, -1, -1, { "\\B", "\\b" }, "\xe0\x80\xe0\x80" },
+	{ UDA, CPI, 2, 0, 0, -1, -1, { "\\B", "\\b" }, "\xdf\xff\xdf\xff" },
+	{ UDA, CPI, 2, 0, 0, -1, -1, { "\\B", "\\b" }, "\xff\xbf\xff\xbf" },
+
+	{ UDA, CPI, 1, 0, 0, 1, 1, { "\\B", NULL }, "\x7f#" },
+	{ UDA, CPI, 1, 0, 0, 1, 1, { "\\B", NULL }, "\x01#" },
+	{ UDA, CPI, 1, 0, 0, -1, -1, { "\\B", "\\b" }, "\x80\x80" },
+	{ UDA, CPI, 1, 0, 0, -1, -1, { "\\B", "\\b" }, "\xb0\xb0" },
+
+	{ UDA | PCRE2_CASELESS, CPI, 0, 0, 0, 0, 2, { "(.)\\1", NULL }, "aA" },
+	{ UDA | PCRE2_CASELESS, CPI, 0, 0, 0, -1, -1, { "(.)\\1", NULL }, "a\xff" },
+	{ UDA | PCRE2_CASELESS, CPI, 0, 0, 0, 0, 4, { "(.)\\1", NULL }, "\xc3\xa1\xc3\x81" },
+	{ UDA | PCRE2_CASELESS, CPI, 0, 0, 1, -1, -1, { "(.)\\1", NULL }, "\xc3\xa1\xc3\x81" },
+	{ UDA | PCRE2_CASELESS, CPI, 0, 0, 0, -1, -1, { "(.)\\1", NULL }, "\xc2\x80\x80" },
+	{ UDA | PCRE2_CASELESS, CPI, 0, 0, 0, 0, 6, { "(.)\\1", NULL }, "\xe1\xbd\xb8\xe1\xbf\xb8" },
+	{ UDA | PCRE2_CASELESS, CPI, 0, 0, 1, -1, -1, { "(.)\\1", NULL }, "\xe1\xbd\xb8\xe1\xbf\xb8" },
+	{ UDA | PCRE2_CASELESS, CPI, 0, 0, 0, 0, 8, { "(.)\\1", NULL }, "\xf0\x90\x90\x80\xf0\x90\x90\xa8" },
+	{ UDA | PCRE2_CASELESS, CPI, 0, 0, 1, -1, -1, { "(.)\\1", NULL }, "\xf0\x90\x90\x80\xf0\x90\x90\xa8" },
+
+	{ UDA, CPI, 0, 0, 0, 0, 1, { "\\X", NULL }, "A" },
+	{ UDA, CPI, 0, 0, 0, -1, -1, { "\\X", NULL }, "\xff" },
+	{ UDA, CPI, 0, 0, 0, 0, 2, { "\\X", NULL }, "\xc3\xa1" },
+	{ UDA, CPI, 0, 0, 1, -1, -1, { "\\X", NULL }, "\xc3\xa1" },
+	{ UDA, CPI, 0, 0, 0, -1, -1, { "\\X", NULL }, "\xc3\x7f" },
+	{ UDA, CPI, 0, 0, 0, 0, 3, { "\\X", NULL }, "\xe1\xbd\xb8" },
+	{ UDA, CPI, 0, 0, 1, -1, -1, { "\\X", NULL }, "\xe1\xbd\xb8" },
+	{ UDA, CPI, 0, 0, 0, 0, 4, { "\\X", NULL }, "\xf0\x90\x90\x80" },
+	{ UDA, CPI, 0, 0, 1, -1, -1, { "\\X", NULL }, "\xf0\x90\x90\x80" },
+
+	{ UDA, CPI, 0, 0, 0, -1, -1, { "[^#]", NULL }, "#" },
+	{ UDA, CPI, 0, 0, 0, 0, 4, { "[^#]", NULL }, "\xf4\x8f\xbf\xbf" },
+	{ UDA, CPI, 0, 0, 0, -1, -1, { "[^#]", NULL }, "\xf4\x90\x80\x80" },
+	{ UDA, CPI, 0, 0, 0, -1, -1, { "[^#]", NULL }, "\xc1\x80" },
+
+	{ PCRE2_UTF | PCRE2_MULTILINE, CI, 1, 0, 0, 2, 3, { "^\\W", NULL }, " \x0a#"},
+	{ PCRE2_UTF | PCRE2_MULTILINE, CI, 1, 0, 0, 14, 15, { "^\\W", NULL }, " \xc0\x8a#\xe0\x80\x8a#\xf0\x80\x80\x8a#\x0a#"},
+	{ PCRE2_UTF | PCRE2_MULTILINE, CI, 1, 0, 0, 3, 4, { "^\\W", NULL }, " \xf8\x0a#"},
+	{ PCRE2_UTF | PCRE2_MULTILINE, CI, 1, 0, 0, 3, 4, { "^\\W", NULL }, " \xc3\x0a#"},
+	{ PCRE2_UTF | PCRE2_MULTILINE, CI, 1, 0, 0, 3, 4, { "^\\W", NULL }, " \xf1\x0a#"},
+	{ PCRE2_UTF | PCRE2_MULTILINE, CI, 1, 0, 0, 4, 5, { "^\\W", NULL }, " \xf2\xbf\x0a#"},
+	{ PCRE2_UTF | PCRE2_MULTILINE, CI, 1, 0, 0, 5, 6, { "^\\W", NULL }, " \xf2\xbf\xbf\x0a#"},
+	{ PCRE2_UTF | PCRE2_MULTILINE, CI, 1, 0, 0, 3, 4, { "^\\W", NULL }, " \xef\x0a#"},
+	{ PCRE2_UTF | PCRE2_MULTILINE, CI, 1, 0, 0, 4, 5, { "^\\W", NULL }, " \xef\xbf\x0a#"},
+	{ PCRE2_UTF | PCRE2_MULTILINE, CI, 1, 0, 0, 5, 6, { "^\\W", NULL }, " \x85#\xc2\x85#"},
+	{ PCRE2_UTF | PCRE2_MULTILINE, CI, 1, 0, 0, 7, 8, { "^\\W", NULL }, " \xe2\x80\xf8\xe2\x80\xa8#"},
+
+	{ PCRE2_UTF | PCRE2_FIRSTLINE, CI, 0, 0, 0, -1, -1, { "#", NULL }, "\xe2\x80\xf8\xe2\x80\xa8#"},
+	{ PCRE2_UTF | PCRE2_FIRSTLINE, CI, 0, 0, 0, 3, 4, { "#", NULL }, "\xe2\x80\xf8#\xe2\x80\xa8#"},
+	{ PCRE2_UTF | PCRE2_FIRSTLINE, CI, 0, 0, 0, -1, -1, { "#", NULL }, "abcd\xc2\x85#"},
+	{ PCRE2_UTF | PCRE2_FIRSTLINE, CI, 0, 0, 0, 1, 2, { "#", NULL }, "\x85#\xc2\x85#"},
+	{ PCRE2_UTF | PCRE2_FIRSTLINE, CI, 0, 0, 0, 5, 6, { "#", NULL }, "\xef,\x80,\xf8#\x0a"},
+	{ PCRE2_UTF | PCRE2_FIRSTLINE, CI, 0, 0, 0, -1, -1, { "#", NULL }, "\xef,\x80,\xf8\x0a#"},
+
+	{ PCRE2_UTF | PCRE2_NO_START_OPTIMIZE, CI, 0, 0, 0, 4, 8, { "#\xc7\x85#", NULL }, "\x80\x80#\xc7#\xc7\x85#" },
+	{ PCRE2_UTF | PCRE2_NO_START_OPTIMIZE, CI, 0, 0, 0, 7, 11, { "#\xc7\x85#", NULL }, "\x80\x80#\xc7\x80\x80\x80#\xc7\x85#" },
+	{ PCRE2_UTF, CI, 0, 0, 0, 4, 8, { "#\xc7\x85#", NULL }, "\x80\x80#\xc7#\xc7\x85#" },
+	{ PCRE2_UTF, CI, 0, 0, 0, 7, 11, { "#\xc7\x85#", NULL }, "\x80\x80#\xc7\x80\x80\x80#\xc7\x85#" },
+
+	{ PCRE2_UTF | PCRE2_UCP, CI, 0, 0, 0, -1, -1, { "[\\s]", NULL }, "\xed\xa0\x80" },
+
+	/* These two are not invalid UTF tests, but this infrastructure fits better for them. */
+	{ 0, PCRE2_JIT_COMPLETE, 0, 0, 1, -1, -1, { "\\X{2}", NULL }, "\r\n\n" },
+	{ 0, PCRE2_JIT_COMPLETE, 0, 0, 1, -1, -1, { "\\R{2}", NULL }, "\r\n\n" },
+
+	{ PCRE2_UTF | PCRE2_MULTILINE, CI, 0, 0, 0, -1, -1, { "^.a", &invalid_utf8_newline_cr }, "\xc3\xa7#a" },
+
+	{ 0, 0, 0, 0, 0, 0, 0, { NULL, NULL }, NULL }
+};
+
+#undef UDA
+#undef CI
+#undef CPI
+
+static int run_invalid_utf8_test(const struct invalid_utf8_regression_test_case *current,
+	int pattern_index, int i, pcre2_compile_context_8 *ccontext, pcre2_match_data_8 *mdata)
+{
+	pcre2_code_8 *code;
+	int result, errorcode;
+	PCRE2_SIZE length, erroroffset;
+	PCRE2_SIZE *ovector = pcre2_get_ovector_pointer_8(mdata);
+
+	if (current->pattern[i] == NULL)
+		return 1;
+
+	code = pcre2_compile_8((PCRE2_UCHAR8*)current->pattern[i], PCRE2_ZERO_TERMINATED,
+		current->compile_options, &errorcode, &erroroffset, ccontext);
+
+	if (!code) {
+		printf("Pattern[%d:0] cannot be compiled. Error offset: %d\n", pattern_index, (int)erroroffset);
+		return 0;
+	}
+
+	if (pcre2_jit_compile_8(code, current->jit_compile_options) != 0) {
+		printf("Pattern[%d:0] cannot be compiled by the JIT compiler.\n", pattern_index);
+		pcre2_code_free_8(code);
+		return 0;
+	}
+
+	length = (PCRE2_SIZE)(strlen(current->input) - current->skip_left - current->skip_right);
+
+	if (current->jit_compile_options & PCRE2_JIT_COMPLETE) {
+		result = pcre2_jit_match_8(code, (PCRE2_UCHAR8*)(current->input + current->skip_left),
+			length, current->start_offset - current->skip_left, 0, mdata, NULL);
+
+		if (check_invalid_utf_result(pattern_index, "match", result, current->match_start, current->match_end, ovector)) {
+			pcre2_code_free_8(code);
+			return 0;
+		}
+	}
+
+	if (current->jit_compile_options & PCRE2_JIT_PARTIAL_SOFT) {
+		result = pcre2_jit_match_8(code, (PCRE2_UCHAR8*)(current->input + current->skip_left),
+			length, current->start_offset - current->skip_left, PCRE2_PARTIAL_SOFT, mdata, NULL);
+
+		if (check_invalid_utf_result(pattern_index, "partial match", result, current->match_start, current->match_end, ovector)) {
+			pcre2_code_free_8(code);
+			return 0;
+		}
+	}
+
+	pcre2_code_free_8(code);
+	return 1;
+}
+
+static int invalid_utf8_regression_tests(void)
+{
+	const struct invalid_utf8_regression_test_case *current;
+	pcre2_compile_context_8 *ccontext;
+	pcre2_match_data_8 *mdata;
+	int total = 0, successful = 0;
+	int result;
+
+	printf("\nRunning invalid-utf8 JIT regression tests\n");
+
+	ccontext = pcre2_compile_context_create_8(NULL);
+	pcre2_set_newline_8(ccontext, PCRE2_NEWLINE_ANY);
+	mdata = pcre2_match_data_create_8(4, NULL);
+
+	for (current = invalid_utf8_regression_test_cases; current->pattern[0]; current++) {
+		/* printf("\nPattern: %s :\n", current->pattern); */
+		total++;
+
+		result = 1;
+		if (current->pattern[1] != &invalid_utf8_newline_cr)
+		{
+			if (!run_invalid_utf8_test(current, total - 1, 0, ccontext, mdata))
+				result = 0;
+			if (!run_invalid_utf8_test(current, total - 1, 1, ccontext, mdata))
+				result = 0;
+		} else {
+			pcre2_set_newline_8(ccontext, PCRE2_NEWLINE_CR);
+			if (!run_invalid_utf8_test(current, total - 1, 0, ccontext, mdata))
+				result = 0;
+			pcre2_set_newline_8(ccontext, PCRE2_NEWLINE_ANY);
+		}
+
+		if (result) {
+			successful++;
+		}
+
+		printf(".");
+		if ((total % 60) == 0)
+			printf("\n");
+	}
+
+	if ((total % 60) != 0)
+		printf("\n");
+
+	pcre2_match_data_free_8(mdata);
+	pcre2_compile_context_free_8(ccontext);
+
+	if (total == successful) {
+		printf("\nAll invalid UTF8 JIT regression tests are successfully passed.\n");
+		return 0;
+	} else {
+		printf("\nInvalid UTF8 successful test ratio: %d%% (%d failed)\n", successful * 100 / total, total - successful);
+		return 1;
+	}
+}
+
+#else /* !SUPPORT_UNICODE || !SUPPORT_PCRE2_8 */
+
+static int invalid_utf8_regression_tests(void)
+{
+	return 0;
+}
+
+#endif /* SUPPORT_UNICODE && SUPPORT_PCRE2_8 */
+
+#if defined SUPPORT_UNICODE && defined SUPPORT_PCRE2_16
+
+#define UDA (PCRE2_UTF | PCRE2_DOTALL | PCRE2_ANCHORED)
+#define CI (PCRE2_JIT_COMPLETE | PCRE2_JIT_INVALID_UTF)
+#define CPI (PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_INVALID_UTF)
+
+struct invalid_utf16_regression_test_case {
+	int compile_options;
+	int jit_compile_options;
+	int start_offset;
+	int skip_left;
+	int skip_right;
+	int match_start;
+	int match_end;
+	const PCRE2_UCHAR16 *pattern[2];
+	const PCRE2_UCHAR16 *input;
+};
+
+static PCRE2_UCHAR16 allany16[] = { '.', 0 };
+static PCRE2_UCHAR16 non_word_boundary16[] = { '\\', 'B', 0 };
+static PCRE2_UCHAR16 word_boundary16[] = { '\\', 'b', 0 };
+static PCRE2_UCHAR16 backreference16[] = { '(', '.', ')', '\\', '1', 0 };
+static PCRE2_UCHAR16 grapheme16[] = { '\\', 'X', 0 };
+static PCRE2_UCHAR16 nothashmark16[] = { '[', '^', '#', ']', 0 };
+static PCRE2_UCHAR16 afternl16[] = { '^', '\\', 'W', 0 };
+static PCRE2_UCHAR16 generic16[] = { '#', 0xd800, 0xdc00, '#', 0 };
+static PCRE2_UCHAR16 test16_1[] = { 0xd7ff, 0xe000, 0xffff, 0x01, '#', 0 };
+static PCRE2_UCHAR16 test16_2[] = { 0xd800, 0xdc00, 0xd800, 0xdc00, 0 };
+static PCRE2_UCHAR16 test16_3[] = { 0xdbff, 0xdfff, 0xdbff, 0xdfff, 0 };
+static PCRE2_UCHAR16 test16_4[] = { 0xd800, 0xdbff, 0xd800, 0xdbff, 0 };
+static PCRE2_UCHAR16 test16_5[] = { '#', 0xd800, 0xdc00, '#', 0 };
+static PCRE2_UCHAR16 test16_6[] = { 'a', 'A', 0xdc28, 0 };
+static PCRE2_UCHAR16 test16_7[] = { 0xd801, 0xdc00, 0xd801, 0xdc28, 0 };
+static PCRE2_UCHAR16 test16_8[] = { '#', 0xd800, 0xdc00, 0 };
+static PCRE2_UCHAR16 test16_9[] = { ' ', 0x2028, '#', 0 };
+static PCRE2_UCHAR16 test16_10[] = { ' ', 0xdc00, 0xd800, 0x2028, '#', 0 };
+static PCRE2_UCHAR16 test16_11[] = { 0xdc00, 0xdc00, 0xd800, 0xdc00, 0xdc00, '#', 0xd800, 0xdc00, '#', 0 };
+static PCRE2_UCHAR16 test16_12[] = { '#', 0xd800, 0xdc00, 0xd800, '#', 0xd800, 0xdc00, 0xdc00, 0xdc00, '#', 0xd800, 0xdc00, '#', 0 };
+
+static const struct invalid_utf16_regression_test_case invalid_utf16_regression_test_cases[] = {
+	{ UDA, CI, 0, 0, 0, 0, 1, { allany16, NULL }, test16_1 },
+	{ UDA, CI, 1, 0, 0, 1, 2, { allany16, NULL }, test16_1 },
+	{ UDA, CI, 2, 0, 0, 2, 3, { allany16, NULL }, test16_1 },
+	{ UDA, CI, 3, 0, 0, 3, 4, { allany16, NULL }, test16_1 },
+	{ UDA, CI, 0, 0, 0, 0, 2, { allany16, NULL }, test16_2 },
+	{ UDA, CI, 0, 0, 3, -1, -1, { allany16, NULL }, test16_2 },
+	{ UDA, CI, 1, 0, 0, -1, -1, { allany16, NULL }, test16_2 },
+	{ UDA, CI, 0, 0, 0, 0, 2, { allany16, NULL }, test16_3 },
+	{ UDA, CI, 0, 0, 3, -1, -1, { allany16, NULL }, test16_3 },
+	{ UDA, CI, 1, 0, 0, -1, -1, { allany16, NULL }, test16_3 },
+
+	{ UDA, CPI, 1, 0, 0, 1, 1, { non_word_boundary16, NULL }, test16_1 },
+	{ UDA, CPI, 2, 0, 0, 2, 2, { non_word_boundary16, NULL }, test16_1 },
+	{ UDA, CPI, 3, 0, 0, 3, 3, { non_word_boundary16, NULL }, test16_1 },
+	{ UDA, CPI, 4, 0, 0, 4, 4, { non_word_boundary16, NULL }, test16_1 },
+	{ UDA, CPI, 2, 0, 0, 2, 2, { non_word_boundary16, NULL }, test16_2 },
+	{ UDA, CPI, 2, 0, 0, 2, 2, { non_word_boundary16, NULL }, test16_3 },
+	{ UDA, CPI, 2, 1, 1, -1, -1, { non_word_boundary16, word_boundary16 }, test16_2 },
+	{ UDA, CPI, 2, 1, 1, -1, -1, { non_word_boundary16, word_boundary16 }, test16_3 },
+	{ UDA, CPI, 2, 0, 0, -1, -1, { non_word_boundary16, word_boundary16 }, test16_4 },
+	{ UDA, CPI, 2, 0, 0, -1, -1, { non_word_boundary16, word_boundary16 }, test16_5 },
+
+	{ UDA | PCRE2_CASELESS, CPI, 0, 0, 0, 0, 2, { backreference16, NULL }, test16_6 },
+	{ UDA | PCRE2_CASELESS, CPI, 1, 0, 0, -1, -1, { backreference16, NULL }, test16_6 },
+	{ UDA | PCRE2_CASELESS, CPI, 0, 0, 0, 0, 4, { backreference16, NULL }, test16_7 },
+	{ UDA | PCRE2_CASELESS, CPI, 0, 0, 1, -1, -1, { backreference16, NULL }, test16_7 },
+
+	{ UDA, CPI, 0, 0, 0, 0, 1, { grapheme16, NULL }, test16_6 },
+	{ UDA, CPI, 1, 0, 0, 1, 2, { grapheme16, NULL }, test16_6 },
+	{ UDA, CPI, 2, 0, 0, -1, -1, { grapheme16, NULL }, test16_6 },
+	{ UDA, CPI, 0, 0, 0, 0, 2, { grapheme16, NULL }, test16_7 },
+	{ UDA, CPI, 2, 0, 0, 2, 4, { grapheme16, NULL }, test16_7 },
+	{ UDA, CPI, 1, 0, 0, -1, -1, { grapheme16, NULL }, test16_7 },
+
+	{ UDA, CPI, 0, 0, 0, -1, -1, { nothashmark16, NULL }, test16_8 },
+	{ UDA, CPI, 1, 0, 0, 1, 3, { nothashmark16, NULL }, test16_8 },
+	{ UDA, CPI, 2, 0, 0, -1, -1, { nothashmark16, NULL }, test16_8 },
+
+	{ PCRE2_UTF | PCRE2_MULTILINE, CI, 1, 0, 0, 2, 3, { afternl16, NULL }, test16_9 },
+	{ PCRE2_UTF | PCRE2_MULTILINE, CI, 1, 0, 0, 4, 5, { afternl16, NULL }, test16_10 },
+
+	{ PCRE2_UTF | PCRE2_NO_START_OPTIMIZE, CI, 0, 0, 0, 5, 9, { generic16, NULL }, test16_11 },
+	{ PCRE2_UTF | PCRE2_NO_START_OPTIMIZE, CI, 0, 0, 0, 9, 13, { generic16, NULL }, test16_12 },
+	{ PCRE2_UTF, CI, 0, 0, 0, 5, 9, { generic16, NULL }, test16_11 },
+	{ PCRE2_UTF, CI, 0, 0, 0, 9, 13, { generic16, NULL }, test16_12 },
+
+	{ 0, 0, 0, 0, 0, 0, 0, { NULL, NULL }, NULL }
+};
+
+#undef UDA
+#undef CI
+#undef CPI
+
+static int run_invalid_utf16_test(const struct invalid_utf16_regression_test_case *current,
+	int pattern_index, int i, pcre2_compile_context_16 *ccontext, pcre2_match_data_16 *mdata)
+{
+	pcre2_code_16 *code;
+	int result, errorcode;
+	PCRE2_SIZE length, erroroffset;
+	const PCRE2_UCHAR16 *input;
+	PCRE2_SIZE *ovector = pcre2_get_ovector_pointer_16(mdata);
+
+	if (current->pattern[i] == NULL)
+		return 1;
+
+	code = pcre2_compile_16(current->pattern[i], PCRE2_ZERO_TERMINATED,
+		current->compile_options, &errorcode, &erroroffset, ccontext);
+
+	if (!code) {
+		printf("Pattern[%d:0] cannot be compiled. Error offset: %d\n", pattern_index, (int)erroroffset);
+		return 0;
+	}
+
+	if (pcre2_jit_compile_16(code, current->jit_compile_options) != 0) {
+		printf("Pattern[%d:0] cannot be compiled by the JIT compiler.\n", pattern_index);
+		pcre2_code_free_16(code);
+		return 0;
+	}
+
+	input = current->input;
+	length = 0;
+
+	while (*input++ != 0)
+		length++;
+
+	length -= current->skip_left + current->skip_right;
+
+	if (current->jit_compile_options & PCRE2_JIT_COMPLETE) {
+		result = pcre2_jit_match_16(code, (current->input + current->skip_left),
+			length, current->start_offset - current->skip_left, 0, mdata, NULL);
+
+		if (check_invalid_utf_result(pattern_index, "match", result, current->match_start, current->match_end, ovector)) {
+			pcre2_code_free_16(code);
+			return 0;
+		}
+	}
+
+	if (current->jit_compile_options & PCRE2_JIT_PARTIAL_SOFT) {
+		result = pcre2_jit_match_16(code, (current->input + current->skip_left),
+			length, current->start_offset - current->skip_left, PCRE2_PARTIAL_SOFT, mdata, NULL);
+
+		if (check_invalid_utf_result(pattern_index, "partial match", result, current->match_start, current->match_end, ovector)) {
+			pcre2_code_free_16(code);
+			return 0;
+		}
+	}
+
+	pcre2_code_free_16(code);
+	return 1;
+}
+
+static int invalid_utf16_regression_tests(void)
+{
+	const struct invalid_utf16_regression_test_case *current;
+	pcre2_compile_context_16 *ccontext;
+	pcre2_match_data_16 *mdata;
+	int total = 0, successful = 0;
+	int result;
+
+	printf("\nRunning invalid-utf16 JIT regression tests\n");
+
+	ccontext = pcre2_compile_context_create_16(NULL);
+	pcre2_set_newline_16(ccontext, PCRE2_NEWLINE_ANY);
+	mdata = pcre2_match_data_create_16(4, NULL);
+
+	for (current = invalid_utf16_regression_test_cases; current->pattern[0]; current++) {
+		/* printf("\nPattern: %s :\n", current->pattern); */
+		total++;
+
+		result = 1;
+		if (!run_invalid_utf16_test(current, total - 1, 0, ccontext, mdata))
+			result = 0;
+		if (!run_invalid_utf16_test(current, total - 1, 1, ccontext, mdata))
+			result = 0;
+
+		if (result) {
+			successful++;
+		}
+
+		printf(".");
+		if ((total % 60) == 0)
+			printf("\n");
+	}
+
+	if ((total % 60) != 0)
+		printf("\n");
+
+	pcre2_match_data_free_16(mdata);
+	pcre2_compile_context_free_16(ccontext);
+
+	if (total == successful) {
+		printf("\nAll invalid UTF16 JIT regression tests are successfully passed.\n");
+		return 0;
+	} else {
+		printf("\nInvalid UTF16 successful test ratio: %d%% (%d failed)\n", successful * 100 / total, total - successful);
+		return 1;
+	}
+}
+
+#else /* !SUPPORT_UNICODE || !SUPPORT_PCRE2_16 */
+
+static int invalid_utf16_regression_tests(void)
+{
+	return 0;
+}
+
+#endif /* SUPPORT_UNICODE && SUPPORT_PCRE2_16 */
+
+#if defined SUPPORT_UNICODE && defined SUPPORT_PCRE2_32
+
+#define UDA (PCRE2_UTF | PCRE2_DOTALL | PCRE2_ANCHORED)
+#define CI (PCRE2_JIT_COMPLETE | PCRE2_JIT_INVALID_UTF)
+#define CPI (PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_INVALID_UTF)
+
+struct invalid_utf32_regression_test_case {
+	int compile_options;
+	int jit_compile_options;
+	int start_offset;
+	int skip_left;
+	int skip_right;
+	int match_start;
+	int match_end;
+	const PCRE2_UCHAR32 *pattern[2];
+	const PCRE2_UCHAR32 *input;
+};
+
+static PCRE2_UCHAR32 allany32[] = { '.', 0 };
+static PCRE2_UCHAR32 non_word_boundary32[] = { '\\', 'B', 0 };
+static PCRE2_UCHAR32 word_boundary32[] = { '\\', 'b', 0 };
+static PCRE2_UCHAR32 backreference32[] = { '(', '.', ')', '\\', '1', 0 };
+static PCRE2_UCHAR32 grapheme32[] = { '\\', 'X', 0 };
+static PCRE2_UCHAR32 nothashmark32[] = { '[', '^', '#', ']', 0 };
+static PCRE2_UCHAR32 afternl32[] = { '^', '\\', 'W', 0 };
+static PCRE2_UCHAR32 test32_1[] = { 0x10ffff, 0x10ffff, 0x110000, 0x110000, 0x10ffff, 0 };
+static PCRE2_UCHAR32 test32_2[] = { 0xd7ff, 0xe000, 0xd800, 0xdfff, 0xe000, 0xdfff, 0xd800, 0 };
+static PCRE2_UCHAR32 test32_3[] = { 'a', 'A', 0x110000, 0 };
+static PCRE2_UCHAR32 test32_4[] = { '#', 0x10ffff, 0x110000, 0 };
+static PCRE2_UCHAR32 test32_5[] = { ' ', 0x2028, '#', 0 };
+static PCRE2_UCHAR32 test32_6[] = { ' ', 0x110000, 0x2028, '#', 0 };
+
+static const struct invalid_utf32_regression_test_case invalid_utf32_regression_test_cases[] = {
+	{ UDA, CI, 0, 0, 0, 0, 1, { allany32, NULL }, test32_1 },
+	{ UDA, CI, 2, 0, 0, -1, -1, { allany32, NULL }, test32_1 },
+	{ UDA, CI, 0, 0, 0, 0, 1, { allany32, NULL }, test32_2 },
+	{ UDA, CI, 1, 0, 0, 1, 2, { allany32, NULL }, test32_2 },
+	{ UDA, CI, 2, 0, 0, -1, -1, { allany32, NULL }, test32_2 },
+	{ UDA, CI, 3, 0, 0, -1, -1, { allany32, NULL }, test32_2 },
+
+	{ UDA, CPI, 1, 0, 0, 1, 1, { non_word_boundary32, NULL }, test32_1 },
+	{ UDA, CPI, 3, 0, 0, -1, -1, { non_word_boundary32, word_boundary32 }, test32_1 },
+	{ UDA, CPI, 1, 0, 0, 1, 1, { non_word_boundary32, NULL }, test32_2 },
+	{ UDA, CPI, 3, 0, 0, -1, -1, { non_word_boundary32, word_boundary32 }, test32_2 },
+	{ UDA, CPI, 6, 0, 0, -1, -1, { non_word_boundary32, word_boundary32 }, test32_2 },
+
+	{ UDA | PCRE2_CASELESS, CPI, 0, 0, 0, 0, 2, { backreference32, NULL }, test32_3 },
+	{ UDA | PCRE2_CASELESS, CPI, 1, 0, 0, -1, -1, { backreference32, NULL }, test32_3 },
+
+	{ UDA, CPI, 0, 0, 0, 0, 1, { grapheme32, NULL }, test32_1 },
+	{ UDA, CPI, 2, 0, 0, -1, -1, { grapheme32, NULL }, test32_1 },
+	{ UDA, CPI, 1, 0, 0, 1, 2, { grapheme32, NULL }, test32_2 },
+	{ UDA, CPI, 2, 0, 0, -1, -1, { grapheme32, NULL }, test32_2 },
+	{ UDA, CPI, 3, 0, 0, -1, -1, { grapheme32, NULL }, test32_2 },
+	{ UDA, CPI, 4, 0, 0, 4, 5, { grapheme32, NULL }, test32_2 },
+
+	{ UDA, CPI, 0, 0, 0, -1, -1, { nothashmark32, NULL }, test32_4 },
+	{ UDA, CPI, 1, 0, 0, 1, 2, { nothashmark32, NULL }, test32_4 },
+	{ UDA, CPI, 2, 0, 0, -1, -1, { nothashmark32, NULL }, test32_4 },
+	{ UDA, CPI, 1, 0, 0, 1, 2, { nothashmark32, NULL }, test32_2 },
+	{ UDA, CPI, 2, 0, 0, -1, -1, { nothashmark32, NULL }, test32_2 },
+
+	{ PCRE2_UTF | PCRE2_MULTILINE, CI, 1, 0, 0, 2, 3, { afternl32, NULL }, test32_5 },
+	{ PCRE2_UTF | PCRE2_MULTILINE, CI, 1, 0, 0, 3, 4, { afternl32, NULL }, test32_6 },
+
+	{ 0, 0, 0, 0, 0, 0, 0, { NULL, NULL }, NULL }
+};
+
+#undef UDA
+#undef CI
+#undef CPI
+
+static int run_invalid_utf32_test(const struct invalid_utf32_regression_test_case *current,
+	int pattern_index, int i, pcre2_compile_context_32 *ccontext, pcre2_match_data_32 *mdata)
+{
+	pcre2_code_32 *code;
+	int result, errorcode;
+	PCRE2_SIZE length, erroroffset;
+	const PCRE2_UCHAR32 *input;
+	PCRE2_SIZE *ovector = pcre2_get_ovector_pointer_32(mdata);
+
+	if (current->pattern[i] == NULL)
+		return 1;
+
+	code = pcre2_compile_32(current->pattern[i], PCRE2_ZERO_TERMINATED,
+		current->compile_options, &errorcode, &erroroffset, ccontext);
+
+	if (!code) {
+		printf("Pattern[%d:0] cannot be compiled. Error offset: %d\n", pattern_index, (int)erroroffset);
+		return 0;
+	}
+
+	if (pcre2_jit_compile_32(code, current->jit_compile_options) != 0) {
+		printf("Pattern[%d:0] cannot be compiled by the JIT compiler.\n", pattern_index);
+		pcre2_code_free_32(code);
+		return 0;
+	}
+
+	input = current->input;
+	length = 0;
+
+	while (*input++ != 0)
+		length++;
+
+	length -= current->skip_left + current->skip_right;
+
+	if (current->jit_compile_options & PCRE2_JIT_COMPLETE) {
+		result = pcre2_jit_match_32(code, (current->input + current->skip_left),
+			length, current->start_offset - current->skip_left, 0, mdata, NULL);
+
+		if (check_invalid_utf_result(pattern_index, "match", result, current->match_start, current->match_end, ovector)) {
+			pcre2_code_free_32(code);
+			return 0;
+		}
+	}
+
+	if (current->jit_compile_options & PCRE2_JIT_PARTIAL_SOFT) {
+		result = pcre2_jit_match_32(code, (current->input + current->skip_left),
+			length, current->start_offset - current->skip_left, PCRE2_PARTIAL_SOFT, mdata, NULL);
+
+		if (check_invalid_utf_result(pattern_index, "partial match", result, current->match_start, current->match_end, ovector)) {
+			pcre2_code_free_32(code);
+			return 0;
+		}
+	}
+
+	pcre2_code_free_32(code);
+	return 1;
+}
+
+static int invalid_utf32_regression_tests(void)
+{
+	const struct invalid_utf32_regression_test_case *current;
+	pcre2_compile_context_32 *ccontext;
+	pcre2_match_data_32 *mdata;
+	int total = 0, successful = 0;
+	int result;
+
+	printf("\nRunning invalid-utf32 JIT regression tests\n");
+
+	ccontext = pcre2_compile_context_create_32(NULL);
+	pcre2_set_newline_32(ccontext, PCRE2_NEWLINE_ANY);
+	mdata = pcre2_match_data_create_32(4, NULL);
+
+	for (current = invalid_utf32_regression_test_cases; current->pattern[0]; current++) {
+		/* printf("\nPattern: %s :\n", current->pattern); */
+		total++;
+
+		result = 1;
+		if (!run_invalid_utf32_test(current, total - 1, 0, ccontext, mdata))
+			result = 0;
+		if (!run_invalid_utf32_test(current, total - 1, 1, ccontext, mdata))
+			result = 0;
+
+		if (result) {
+			successful++;
+		}
+
+		printf(".");
+		if ((total % 60) == 0)
+			printf("\n");
+	}
+
+	if ((total % 60) != 0)
+		printf("\n");
+
+	pcre2_match_data_free_32(mdata);
+	pcre2_compile_context_free_32(ccontext);
+
+	if (total == successful) {
+		printf("\nAll invalid UTF32 JIT regression tests are successfully passed.\n");
+		return 0;
+	} else {
+		printf("\nInvalid UTF32 successful test ratio: %d%% (%d failed)\n", successful * 100 / total, total - successful);
+		return 1;
+	}
+}
+
+#else /* !SUPPORT_UNICODE || !SUPPORT_PCRE2_32 */
+
+static int invalid_utf32_regression_tests(void)
+{
+	return 0;
+}
+
+#endif /* SUPPORT_UNICODE && SUPPORT_PCRE2_32 */
+
+/* End of pcre2_jit_test.c */
diff --git a/src/c/pcre2/src/pcre2_maketables.c b/src/c/pcre2/src/pcre2_maketables.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_maketables.c
@@ -0,0 +1,163 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2020 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains the external function pcre2_maketables(), which builds
+character tables for PCRE2 in the current locale. The file is compiled on its
+own as part of the PCRE2 library. It is also included in the compilation of
+pcre2_dftables.c as a freestanding program, in which case the macro
+PCRE2_DFTABLES is defined. */
+
+#ifndef PCRE2_DFTABLES    /* Compiling the library */
+#  ifdef HAVE_CONFIG_H
+#  include "config.h"
+#  endif
+#  include "pcre2_internal.h"
+#endif
+
+
+
+/*************************************************
+*           Create PCRE2 character tables        *
+*************************************************/
+
+/* This function builds a set of character tables for use by PCRE2 and returns
+a pointer to them. They are build using the ctype functions, and consequently
+their contents will depend upon the current locale setting. When compiled as
+part of the library, the store is obtained via a general context malloc, if
+supplied, but when PCRE2_DFTABLES is defined (when compiling the pcre2_dftables
+freestanding auxiliary program) malloc() is used, and the function has a
+different name so as not to clash with the prototype in pcre2.h.
+
+Arguments:   none when PCRE2_DFTABLES is defined
+               else a PCRE2 general context or NULL
+Returns:     pointer to the contiguous block of data
+               else NULL if memory allocation failed
+*/
+
+#ifdef PCRE2_DFTABLES  /* Included in freestanding pcre2_dftables program */
+static const uint8_t *maketables(void)
+{
+uint8_t *yield = (uint8_t *)malloc(TABLES_LENGTH);
+
+#else  /* Not PCRE2_DFTABLES, that is, compiling the library */
+PCRE2_EXP_DEFN const uint8_t * PCRE2_CALL_CONVENTION
+pcre2_maketables(pcre2_general_context *gcontext)
+{
+uint8_t *yield = (uint8_t *)((gcontext != NULL)?
+  gcontext->memctl.malloc(TABLES_LENGTH, gcontext->memctl.memory_data) :
+  malloc(TABLES_LENGTH));
+#endif  /* PCRE2_DFTABLES */
+
+int i;
+uint8_t *p;
+
+if (yield == NULL) return NULL;
+p = yield;
+
+/* First comes the lower casing table */
+
+for (i = 0; i < 256; i++) *p++ = tolower(i);
+
+/* Next the case-flipping table */
+
+for (i = 0; i < 256; i++) *p++ = islower(i)? toupper(i) : tolower(i);
+
+/* Then the character class tables. Don't try to be clever and save effort on
+exclusive ones - in some locales things may be different.
+
+Note that the table for "space" includes everything "isspace" gives, including
+VT in the default locale. This makes it work for the POSIX class [:space:].
+From PCRE1 release 8.34 and for all PCRE2 releases it is also correct for Perl
+space, because Perl added VT at release 5.18.
+
+Note also that it is possible for a character to be alnum or alpha without
+being lower or upper, such as "male and female ordinals" (\xAA and \xBA) in the
+fr_FR locale (at least under Debian Linux's locales as of 12/2005). So we must
+test for alnum specially. */
+
+memset(p, 0, cbit_length);
+for (i = 0; i < 256; i++)
+  {
+  if (isdigit(i))  p[cbit_digit  + i/8] |= 1u << (i&7);
+  if (isupper(i))  p[cbit_upper  + i/8] |= 1u << (i&7);
+  if (islower(i))  p[cbit_lower  + i/8] |= 1u << (i&7);
+  if (isalnum(i))  p[cbit_word   + i/8] |= 1u << (i&7);
+  if (i == '_')    p[cbit_word   + i/8] |= 1u << (i&7);
+  if (isspace(i))  p[cbit_space  + i/8] |= 1u << (i&7);
+  if (isxdigit(i)) p[cbit_xdigit + i/8] |= 1u << (i&7);
+  if (isgraph(i))  p[cbit_graph  + i/8] |= 1u << (i&7);
+  if (isprint(i))  p[cbit_print  + i/8] |= 1u << (i&7);
+  if (ispunct(i))  p[cbit_punct  + i/8] |= 1u << (i&7);
+  if (iscntrl(i))  p[cbit_cntrl  + i/8] |= 1u << (i&7);
+  }
+p += cbit_length;
+
+/* Finally, the character type table. In this, we used to exclude VT from the
+white space chars, because Perl didn't recognize it as such for \s and for
+comments within regexes. However, Perl changed at release 5.18, so PCRE1
+changed at release 8.34 and it's always been this way for PCRE2. */
+
+for (i = 0; i < 256; i++)
+  {
+  int x = 0;
+  if (isspace(i)) x += ctype_space;
+  if (isalpha(i)) x += ctype_letter;
+  if (islower(i)) x += ctype_lcletter;
+  if (isdigit(i)) x += ctype_digit;
+  if (isalnum(i) || i == '_') x += ctype_word;
+  *p++ = x;
+  }
+
+return yield;
+}
+
+#ifndef PCRE2_DFTABLES   /* Compiling the library */
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_maketables_free(pcre2_general_context *gcontext, const uint8_t *tables)
+{
+  if (gcontext)
+    gcontext->memctl.free((void *)tables, gcontext->memctl.memory_data);
+  else
+    free((void *)tables);
+}
+#endif
+
+/* End of pcre2_maketables.c */
diff --git a/src/c/pcre2/src/pcre2_match.c b/src/c/pcre2/src/pcre2_match.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_match.c
@@ -0,0 +1,7311 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2015-2020 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* These defines enable debugging code */
+
+/* #define DEBUG_FRAMES_DISPLAY */
+/* #define DEBUG_SHOW_OPS */
+/* #define DEBUG_SHOW_RMATCH */
+
+#ifdef DEBUG_FRAME_DISPLAY
+#include <stdarg.h>
+#endif
+
+/* These defines identify the name of the block containing "static"
+information, and fields within it. */
+
+#define NLBLOCK mb              /* Block containing newline information */
+#define PSSTART start_subject   /* Field containing processed string start */
+#define PSEND   end_subject     /* Field containing processed string end */
+
+#include "pcre2_internal.h"
+
+#define RECURSE_UNSET 0xffffffffu  /* Bigger than max group number */
+
+/* Masks for identifying the public options that are permitted at match time. */
+
+#define PUBLIC_MATCH_OPTIONS \
+  (PCRE2_ANCHORED|PCRE2_ENDANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \
+   PCRE2_NOTEMPTY_ATSTART|PCRE2_NO_UTF_CHECK|PCRE2_PARTIAL_HARD| \
+   PCRE2_PARTIAL_SOFT|PCRE2_NO_JIT|PCRE2_COPY_MATCHED_SUBJECT)
+
+#define PUBLIC_JIT_MATCH_OPTIONS \
+   (PCRE2_NO_UTF_CHECK|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY|\
+    PCRE2_NOTEMPTY_ATSTART|PCRE2_PARTIAL_SOFT|PCRE2_PARTIAL_HARD|\
+    PCRE2_COPY_MATCHED_SUBJECT)
+
+/* Non-error returns from and within the match() function. Error returns are
+externally defined PCRE2_ERROR_xxx codes, which are all negative. */
+
+#define MATCH_MATCH        1
+#define MATCH_NOMATCH      0
+
+/* Special internal returns used in the match() function. Make them
+sufficiently negative to avoid the external error codes. */
+
+#define MATCH_ACCEPT       (-999)
+#define MATCH_KETRPOS      (-998)
+/* The next 5 must be kept together and in sequence so that a test that checks
+for any one of them can use a range. */
+#define MATCH_COMMIT       (-997)
+#define MATCH_PRUNE        (-996)
+#define MATCH_SKIP         (-995)
+#define MATCH_SKIP_ARG     (-994)
+#define MATCH_THEN         (-993)
+#define MATCH_BACKTRACK_MAX MATCH_THEN
+#define MATCH_BACKTRACK_MIN MATCH_COMMIT
+
+/* Group frame type values. Zero means the frame is not a group frame. The
+lower 16 bits are used for data (e.g. the capture number). Group frames are
+used for most groups so that information about the start is easily available at
+the end without having to scan back through intermediate frames (backtrack
+points). */
+
+#define GF_CAPTURE     0x00010000u
+#define GF_NOCAPTURE   0x00020000u
+#define GF_CONDASSERT  0x00030000u
+#define GF_RECURSE     0x00040000u
+
+/* Masks for the identity and data parts of the group frame type. */
+
+#define GF_IDMASK(a)   ((a) & 0xffff0000u)
+#define GF_DATAMASK(a) ((a) & 0x0000ffffu)
+
+/* Repetition types */
+
+enum { REPTYPE_MIN, REPTYPE_MAX, REPTYPE_POS };
+
+/* Min and max values for the common repeats; a maximum of UINT32_MAX =>
+infinity. */
+
+static const uint32_t rep_min[] = {
+  0, 0,       /* * and *? */
+  1, 1,       /* + and +? */
+  0, 0,       /* ? and ?? */
+  0, 0,       /* dummy placefillers for OP_CR[MIN]RANGE */
+  0, 1, 0 };  /* OP_CRPOS{STAR, PLUS, QUERY} */
+
+static const uint32_t rep_max[] = {
+  UINT32_MAX, UINT32_MAX,      /* * and *? */
+  UINT32_MAX, UINT32_MAX,      /* + and +? */
+  1, 1,                        /* ? and ?? */
+  0, 0,                        /* dummy placefillers for OP_CR[MIN]RANGE */
+  UINT32_MAX, UINT32_MAX, 1 }; /* OP_CRPOS{STAR, PLUS, QUERY} */
+
+/* Repetition types - must include OP_CRPOSRANGE (not needed above) */
+
+static const uint32_t rep_typ[] = {
+  REPTYPE_MAX, REPTYPE_MIN,    /* * and *? */
+  REPTYPE_MAX, REPTYPE_MIN,    /* + and +? */
+  REPTYPE_MAX, REPTYPE_MIN,    /* ? and ?? */
+  REPTYPE_MAX, REPTYPE_MIN,    /* OP_CRRANGE and OP_CRMINRANGE */
+  REPTYPE_POS, REPTYPE_POS,    /* OP_CRPOSSTAR, OP_CRPOSPLUS */
+  REPTYPE_POS, REPTYPE_POS };  /* OP_CRPOSQUERY, OP_CRPOSRANGE */
+
+/* Numbers for RMATCH calls at backtracking points. When these lists are
+changed, the code at RETURN_SWITCH below must be updated in sync.  */
+
+enum { RM1=1, RM2,  RM3,  RM4,  RM5,  RM6,  RM7,  RM8,  RM9,  RM10,
+       RM11,  RM12, RM13, RM14, RM15, RM16, RM17, RM18, RM19, RM20,
+       RM21,  RM22, RM23, RM24, RM25, RM26, RM27, RM28, RM29, RM30,
+       RM31,  RM32, RM33, RM34, RM35, RM36 };
+
+#ifdef SUPPORT_WIDE_CHARS
+enum { RM100=100, RM101 };
+#endif
+
+#ifdef SUPPORT_UNICODE
+enum { RM200=200, RM201, RM202, RM203, RM204, RM205, RM206, RM207,
+       RM208,     RM209, RM210, RM211, RM212, RM213, RM214, RM215,
+       RM216,     RM217, RM218, RM219, RM220, RM221, RM222 };
+#endif
+
+/* Define short names for general fields in the current backtrack frame, which
+is always pointed to by the F variable. Occasional references to fields in
+other frames are written out explicitly. There are also some fields in the
+current frame whose names start with "temp" that are used for short-term,
+localised backtracking memory. These are #defined with Lxxx names at the point
+of use and undefined afterwards. */
+
+#define Fback_frame        F->back_frame
+#define Fcapture_last      F->capture_last
+#define Fcurrent_recurse   F->current_recurse
+#define Fecode             F->ecode
+#define Feptr              F->eptr
+#define Fgroup_frame_type  F->group_frame_type
+#define Flast_group_offset F->last_group_offset
+#define Flength            F->length
+#define Fmark              F->mark
+#define Frdepth            F->rdepth
+#define Fstart_match       F->start_match
+#define Foffset_top        F->offset_top
+#define Foccu              F->occu
+#define Fop                F->op
+#define Fovector           F->ovector
+#define Freturn_id         F->return_id
+
+
+#ifdef DEBUG_FRAMES_DISPLAY
+/*************************************************
+*      Display current frames and contents       *
+*************************************************/
+
+/* This debugging function displays the current set of frames and their
+contents. It is not called automatically from anywhere, the intention being
+that calls can be inserted where necessary when debugging frame-related
+problems.
+
+Arguments:
+  f           the file to write to
+  F           the current top frame
+  P           a previous frame of interest
+  frame_size  the frame size
+  mb          points to the match block
+  s           identification text
+
+Returns:    nothing
+*/
+
+static void
+display_frames(FILE *f, heapframe *F, heapframe *P, PCRE2_SIZE frame_size,
+  match_block *mb, const char *s, ...)
+{
+uint32_t i;
+heapframe *Q;
+va_list ap;
+va_start(ap, s);
+
+fprintf(f, "FRAMES ");
+vfprintf(f, s, ap);
+va_end(ap);
+
+if (P != NULL) fprintf(f, " P=%lu",
+  ((char *)P - (char *)(mb->match_frames))/frame_size);
+fprintf(f, "\n");
+
+for (i = 0, Q = mb->match_frames;
+     Q <= F;
+     i++, Q = (heapframe *)((char *)Q + frame_size))
+  {
+  fprintf(f, "Frame %d type=%x subj=%lu code=%d back=%lu id=%d",
+    i, Q->group_frame_type, Q->eptr - mb->start_subject, *(Q->ecode),
+    Q->back_frame, Q->return_id);
+
+  if (Q->last_group_offset == PCRE2_UNSET)
+    fprintf(f, " lgoffset=unset\n");
+  else
+    fprintf(f, " lgoffset=%lu\n",  Q->last_group_offset/frame_size);
+  }
+}
+
+#endif
+
+
+
+/*************************************************
+*                Process a callout               *
+*************************************************/
+
+/* This function is called for all callouts, whether "standalone" or at the
+start of a conditional group. Feptr will be pointing to either OP_CALLOUT or
+OP_CALLOUT_STR. A callout block is allocated in pcre2_match() and initialized
+with fixed values.
+
+Arguments:
+  F          points to the current backtracking frame
+  mb         points to the match block
+  lengthptr  where to return the length of the callout item
+
+Returns:     the return from the callout
+             or 0 if no callout function exists
+*/
+
+static int
+do_callout(heapframe *F, match_block *mb, PCRE2_SIZE *lengthptr)
+{
+int rc;
+PCRE2_SIZE save0, save1;
+PCRE2_SIZE *callout_ovector;
+pcre2_callout_block *cb;
+
+*lengthptr = (*Fecode == OP_CALLOUT)?
+  PRIV(OP_lengths)[OP_CALLOUT] : GET(Fecode, 1 + 2*LINK_SIZE);
+
+if (mb->callout == NULL) return 0;   /* No callout function provided */
+
+/* The original matching code (pre 10.30) worked directly with the ovector
+passed by the user, and this was passed to callouts. Now that the working
+ovector is in the backtracking frame, it no longer needs to reserve space for
+the overall match offsets (which would waste space in the frame). For backward
+compatibility, however, we pass capture_top and offset_vector to the callout as
+if for the extended ovector, and we ensure that the first two slots are unset
+by preserving and restoring their current contents. Picky compilers complain if
+references such as Fovector[-2] are use directly, so we set up a separate
+pointer. */
+
+callout_ovector = (PCRE2_SIZE *)(Fovector) - 2;
+
+/* The cb->version, cb->subject, cb->subject_length, and cb->start_match fields
+are set externally. The first 3 never change; the last is updated for each
+bumpalong. */
+
+cb = mb->cb;
+cb->capture_top      = (uint32_t)Foffset_top/2 + 1;
+cb->capture_last     = Fcapture_last;
+cb->offset_vector    = callout_ovector;
+cb->mark             = mb->nomatch_mark;
+cb->current_position = (PCRE2_SIZE)(Feptr - mb->start_subject);
+cb->pattern_position = GET(Fecode, 1);
+cb->next_item_length = GET(Fecode, 1 + LINK_SIZE);
+
+if (*Fecode == OP_CALLOUT)  /* Numerical callout */
+  {
+  cb->callout_number = Fecode[1 + 2*LINK_SIZE];
+  cb->callout_string_offset = 0;
+  cb->callout_string = NULL;
+  cb->callout_string_length = 0;
+  }
+else  /* String callout */
+  {
+  cb->callout_number = 0;
+  cb->callout_string_offset = GET(Fecode, 1 + 3*LINK_SIZE);
+  cb->callout_string = Fecode + (1 + 4*LINK_SIZE) + 1;
+  cb->callout_string_length =
+    *lengthptr - (1 + 4*LINK_SIZE) - 2;
+  }
+
+save0 = callout_ovector[0];
+save1 = callout_ovector[1];
+callout_ovector[0] = callout_ovector[1] = PCRE2_UNSET;
+rc = mb->callout(cb, mb->callout_data);
+callout_ovector[0] = save0;
+callout_ovector[1] = save1;
+cb->callout_flags = 0;
+return rc;
+}
+
+
+
+/*************************************************
+*          Match a back-reference                *
+*************************************************/
+
+/* This function is called only when it is known that the offset lies within
+the offsets that have so far been used in the match. Note that in caseless
+UTF-8 mode, the number of subject bytes matched may be different to the number
+of reference bytes. (In theory this could also happen in UTF-16 mode, but it
+seems unlikely.)
+
+Arguments:
+  offset      index into the offset vector
+  caseless    TRUE if caseless
+  F           the current backtracking frame pointer
+  mb          points to match block
+  lengthptr   pointer for returning the length matched
+
+Returns:      = 0 sucessful match; number of code units matched is set
+              < 0 no match
+              > 0 partial match
+*/
+
+static int
+match_ref(PCRE2_SIZE offset, BOOL caseless, heapframe *F, match_block *mb,
+  PCRE2_SIZE *lengthptr)
+{
+PCRE2_SPTR p;
+PCRE2_SIZE length;
+PCRE2_SPTR eptr;
+PCRE2_SPTR eptr_start;
+
+/* Deal with an unset group. The default is no match, but there is an option to
+match an empty string. */
+
+if (offset >= Foffset_top || Fovector[offset] == PCRE2_UNSET)
+  {
+  if ((mb->poptions & PCRE2_MATCH_UNSET_BACKREF) != 0)
+    {
+    *lengthptr = 0;
+    return 0;      /* Match */
+    }
+  else return -1;  /* No match */
+  }
+
+/* Separate the caseless and UTF cases for speed. */
+
+eptr = eptr_start = Feptr;
+p = mb->start_subject + Fovector[offset];
+length = Fovector[offset+1] - Fovector[offset];
+
+if (caseless)
+  {
+#if defined SUPPORT_UNICODE
+  BOOL utf = (mb->poptions & PCRE2_UTF) != 0;
+
+  if (utf || (mb->poptions & PCRE2_UCP) != 0)
+    {
+    PCRE2_SPTR endptr = p + length;
+
+    /* Match characters up to the end of the reference. NOTE: the number of
+    code units matched may differ, because in UTF-8 there are some characters
+    whose upper and lower case codes have different numbers of bytes. For
+    example, U+023A (2 bytes in UTF-8) is the upper case version of U+2C65 (3
+    bytes in UTF-8); a sequence of 3 of the former uses 6 bytes, as does a
+    sequence of two of the latter. It is important, therefore, to check the
+    length along the reference, not along the subject (earlier code did this
+    wrong). UCP without uses Unicode properties but without UTF encoding. */
+
+    while (p < endptr)
+      {
+      uint32_t c, d;
+      const ucd_record *ur;
+      if (eptr >= mb->end_subject) return 1;   /* Partial match */
+
+      if (utf)
+        {
+        GETCHARINC(c, eptr);
+        GETCHARINC(d, p);
+        }
+      else
+        {
+        c = *eptr++;
+        d = *p++;
+        }
+
+      ur = GET_UCD(d);
+      if (c != d && c != (uint32_t)((int)d + ur->other_case))
+        {
+        const uint32_t *pp = PRIV(ucd_caseless_sets) + ur->caseset;
+        for (;;)
+          {
+          if (c < *pp) return -1;  /* No match */
+          if (c == *pp++) break;
+          }
+        }
+      }
+    }
+  else
+#endif
+
+  /* Not in UTF or UCP mode */
+    {
+    for (; length > 0; length--)
+      {
+      uint32_t cc, cp;
+      if (eptr >= mb->end_subject) return 1;   /* Partial match */
+      cc = UCHAR21TEST(eptr);
+      cp = UCHAR21TEST(p);
+      if (TABLE_GET(cp, mb->lcc, cp) != TABLE_GET(cc, mb->lcc, cc))
+        return -1;  /* No match */
+      p++;
+      eptr++;
+      }
+    }
+  }
+
+/* In the caseful case, we can just compare the code units, whether or not we
+are in UTF and/or UCP mode. When partial matching, we have to do this unit by
+unit. */
+
+else
+  {
+  if (mb->partial != 0)
+    {
+    for (; length > 0; length--)
+      {
+      if (eptr >= mb->end_subject) return 1;   /* Partial match */
+      if (UCHAR21INCTEST(p) != UCHAR21INCTEST(eptr)) return -1;  /* No match */
+      }
+    }
+
+  /* Not partial matching */
+
+  else
+    {
+    if ((PCRE2_SIZE)(mb->end_subject - eptr) < length) return 1; /* Partial */
+    if (memcmp(p, eptr, CU2BYTES(length)) != 0) return -1;  /* No match */
+    eptr += length;
+    }
+  }
+
+*lengthptr = eptr - eptr_start;
+return 0;  /* Match */
+}
+
+
+
+/******************************************************************************
+*******************************************************************************
+                   "Recursion" in the match() function
+
+The original match() function was highly recursive, but this proved to be the
+source of a number of problems over the years, mostly because of the relatively
+small system stacks that are commonly found. As new features were added to
+patterns, various kludges were invented to reduce the amount of stack used,
+making the code hard to understand in places.
+
+A version did exist that used individual frames on the heap instead of calling
+match() recursively, but this ran substantially slower. The current version is
+a refactoring that uses a vector of frames to remember backtracking points.
+This runs no slower, and possibly even a bit faster than the original recursive
+implementation. An initial vector of size START_FRAMES_SIZE (enough for maybe
+50 frames) is allocated on the system stack. If this is not big enough, the
+heap is used for a larger vector.
+
+*******************************************************************************
+******************************************************************************/
+
+
+
+
+/*************************************************
+*       Macros for the match() function          *
+*************************************************/
+
+/* These macros pack up tests that are used for partial matching several times
+in the code. The second one is used when we already know we are past the end of
+the subject. We set the "hit end" flag if the pointer is at the end of the
+subject and either (a) the pointer is past the earliest inspected character
+(i.e. something has been matched, even if not part of the actual matched
+string), or (b) the pattern contains a lookbehind. These are the conditions for
+which adding more characters may allow the current match to continue.
+
+For hard partial matching, we immediately return a partial match. Otherwise,
+carrying on means that a complete match on the current subject will be sought.
+A partial match is returned only if no complete match can be found. */
+
+#define CHECK_PARTIAL()\
+  if (Feptr >= mb->end_subject) \
+    { \
+    SCHECK_PARTIAL(); \
+    }
+
+#define SCHECK_PARTIAL()\
+  if (mb->partial != 0 && \
+      (Feptr > mb->start_used_ptr || mb->allowemptypartial)) \
+    { \
+    mb->hitend = TRUE; \
+    if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; \
+    }
+
+
+/* These macros are used to implement backtracking. They simulate a recursive
+call to the match() function by means of a local vector of frames which
+remember the backtracking points. */
+
+#define RMATCH(ra,rb)\
+  {\
+  start_ecode = ra;\
+  Freturn_id = rb;\
+  goto MATCH_RECURSE;\
+  L_##rb:;\
+  }
+
+#define RRETURN(ra)\
+  {\
+  rrc = ra;\
+  goto RETURN_SWITCH;\
+  }
+
+
+
+/*************************************************
+*         Match from current position            *
+*************************************************/
+
+/* This function is called to run one match attempt at a single starting point
+in the subject.
+
+Performance note: It might be tempting to extract commonly used fields from the
+mb structure (e.g. end_subject) into individual variables to improve
+performance. Tests using gcc on a SPARC disproved this; in the first case, it
+made performance worse.
+
+Arguments:
+   start_eptr   starting character in subject
+   start_ecode  starting position in compiled code
+   ovector      pointer to the final output vector
+   oveccount    number of pairs in ovector
+   top_bracket  number of capturing parentheses in the pattern
+   frame_size   size of each backtracking frame
+   mb           pointer to "static" variables block
+
+Returns:        MATCH_MATCH if matched            )  these values are >= 0
+                MATCH_NOMATCH if failed to match  )
+                negative MATCH_xxx value for PRUNE, SKIP, etc
+                negative PCRE2_ERROR_xxx value if aborted by an error condition
+                (e.g. stopped by repeated call or depth limit)
+*/
+
+static int
+match(PCRE2_SPTR start_eptr, PCRE2_SPTR start_ecode, PCRE2_SIZE *ovector,
+  uint16_t oveccount, uint16_t top_bracket, PCRE2_SIZE frame_size,
+  match_block *mb)
+{
+/* Frame-handling variables */
+
+heapframe *F;           /* Current frame pointer */
+heapframe *N = NULL;    /* Temporary frame pointers */
+heapframe *P = NULL;
+heapframe *assert_accept_frame = NULL;  /* For passing back a frame with captures */
+PCRE2_SIZE frame_copy_size;     /* Amount to copy when creating a new frame */
+
+/* Local variables that do not need to be preserved over calls to RRMATCH(). */
+
+PCRE2_SPTR bracode;     /* Temp pointer to start of group */
+PCRE2_SIZE offset;      /* Used for group offsets */
+PCRE2_SIZE length;      /* Used for various length calculations */
+
+int rrc;                /* Return from functions & backtracking "recursions" */
+#ifdef SUPPORT_UNICODE
+int proptype;           /* Type of character property */
+#endif
+
+uint32_t i;             /* Used for local loops */
+uint32_t fc;            /* Character values */
+uint32_t number;        /* Used for group and other numbers */
+uint32_t reptype = 0;   /* Type of repetition (0 to avoid compiler warning) */
+uint32_t group_frame_type;  /* Specifies type for new group frames */
+
+BOOL condition;         /* Used in conditional groups */
+BOOL cur_is_word;       /* Used in "word" tests */
+BOOL prev_is_word;      /* Used in "word" tests */
+
+/* UTF and UCP flags */
+
+#ifdef SUPPORT_UNICODE
+BOOL utf = (mb->poptions & PCRE2_UTF) != 0;
+BOOL ucp = (mb->poptions & PCRE2_UCP) != 0;
+#else
+BOOL utf = FALSE;  /* Required for convenience even when no Unicode support */
+#endif
+
+/* This is the length of the last part of a backtracking frame that must be
+copied when a new frame is created. */
+
+frame_copy_size = frame_size - offsetof(heapframe, eptr);
+
+/* Set up the first current frame at the start of the vector, and initialize
+fields that are not reset for new frames. */
+
+F = mb->match_frames;
+Frdepth = 0;                        /* "Recursion" depth */
+Fcapture_last = 0;                  /* Number of most recent capture */
+Fcurrent_recurse = RECURSE_UNSET;   /* Not pattern recursing. */
+Fstart_match = Feptr = start_eptr;  /* Current data pointer and start match */
+Fmark = NULL;                       /* Most recent mark */
+Foffset_top = 0;                    /* End of captures within the frame */
+Flast_group_offset = PCRE2_UNSET;   /* Saved frame of most recent group */
+group_frame_type = 0;               /* Not a start of group frame */
+goto NEW_FRAME;                     /* Start processing with this frame */
+
+/* Come back here when we want to create a new frame for remembering a
+backtracking point. */
+
+MATCH_RECURSE:
+
+/* Set up a new backtracking frame. If the vector is full, get a new one
+on the heap, doubling the size, but constrained by the heap limit. */
+
+N = (heapframe *)((char *)F + frame_size);
+if (N >= mb->match_frames_top)
+  {
+  PCRE2_SIZE newsize = mb->frame_vector_size * 2;
+  heapframe *new;
+
+  if ((newsize / 1024) > mb->heap_limit)
+    {
+    PCRE2_SIZE maxsize = ((mb->heap_limit * 1024)/frame_size) * frame_size;
+    if (mb->frame_vector_size >= maxsize) return PCRE2_ERROR_HEAPLIMIT;
+    newsize = maxsize;
+    }
+
+  new = mb->memctl.malloc(newsize, mb->memctl.memory_data);
+  if (new == NULL) return PCRE2_ERROR_NOMEMORY;
+  memcpy(new, mb->match_frames, mb->frame_vector_size);
+
+  F = (heapframe *)((char *)new + ((char *)F - (char *)mb->match_frames));
+  N = (heapframe *)((char *)F + frame_size);
+
+  if (mb->match_frames != mb->stack_frames)
+    mb->memctl.free(mb->match_frames, mb->memctl.memory_data);
+  mb->match_frames = new;
+  mb->match_frames_top = (heapframe *)((char *)mb->match_frames + newsize);
+  mb->frame_vector_size = newsize;
+  }
+
+#ifdef DEBUG_SHOW_RMATCH
+fprintf(stderr, "++ RMATCH %2d frame=%d", Freturn_id, Frdepth + 1);
+if (group_frame_type != 0)
+  {
+  fprintf(stderr, " type=%x ", group_frame_type);
+  switch (GF_IDMASK(group_frame_type))
+    {
+    case GF_CAPTURE:
+    fprintf(stderr, "capture=%d", GF_DATAMASK(group_frame_type));
+    break;
+
+    case GF_NOCAPTURE:
+    fprintf(stderr, "nocapture op=%d", GF_DATAMASK(group_frame_type));
+    break;
+
+    case GF_CONDASSERT:
+    fprintf(stderr, "condassert op=%d", GF_DATAMASK(group_frame_type));
+    break;
+
+    case GF_RECURSE:
+    fprintf(stderr, "recurse=%d", GF_DATAMASK(group_frame_type));
+    break;
+
+    default:
+    fprintf(stderr, "*** unknown ***");
+    break;
+    }
+  }
+fprintf(stderr, "\n");
+#endif
+
+/* Copy those fields that must be copied into the new frame, increase the
+"recursion" depth (i.e. the new frame's index) and then make the new frame
+current. */
+
+memcpy((char *)N + offsetof(heapframe, eptr),
+       (char *)F + offsetof(heapframe, eptr),
+       frame_copy_size);
+
+N->rdepth = Frdepth + 1;
+F = N;
+
+/* Carry on processing with a new frame. */
+
+NEW_FRAME:
+Fgroup_frame_type = group_frame_type;
+Fecode = start_ecode;      /* Starting code pointer */
+Fback_frame = frame_size;  /* Default is go back one frame */
+
+/* If this is a special type of group frame, remember its offset for quick
+access at the end of the group. If this is a recursion, set a new current
+recursion value. */
+
+if (group_frame_type != 0)
+  {
+  Flast_group_offset = (char *)F - (char *)mb->match_frames;
+  if (GF_IDMASK(group_frame_type) == GF_RECURSE)
+    Fcurrent_recurse = GF_DATAMASK(group_frame_type);
+  group_frame_type = 0;
+  }
+
+
+/* ========================================================================= */
+/* This is the main processing loop. First check that we haven't recorded too
+many backtracks (search tree is too large), or that we haven't exceeded the
+recursive depth limit (used too many backtracking frames). If not, process the
+opcodes. */
+
+if (mb->match_call_count++ >= mb->match_limit) return PCRE2_ERROR_MATCHLIMIT;
+if (Frdepth >= mb->match_limit_depth) return PCRE2_ERROR_DEPTHLIMIT;
+
+for (;;)
+  {
+#ifdef DEBUG_SHOW_OPS
+fprintf(stderr, "++ op=%d\n", *Fecode);
+#endif
+
+  Fop = (uint8_t)(*Fecode);  /* Cast needed for 16-bit and 32-bit modes */
+  switch(Fop)
+    {
+    /* ===================================================================== */
+    /* Before OP_ACCEPT there may be any number of OP_CLOSE opcodes, to close
+    any currently open capturing brackets. Unlike reaching the end of a group,
+    where we know the starting frame is at the top of the chained frames, in
+    this case we have to search back for the relevant frame in case other types
+    of group that use chained frames have intervened. Multiple OP_CLOSEs always
+    come innermost first, which matches the chain order. We can ignore this in
+    a recursion, because captures are not passed out of recursions. */
+
+    case OP_CLOSE:
+    if (Fcurrent_recurse == RECURSE_UNSET)
+      {
+      number = GET2(Fecode, 1);
+      offset = Flast_group_offset;
+      for(;;)
+        {
+        if (offset == PCRE2_UNSET) return PCRE2_ERROR_INTERNAL;
+        N = (heapframe *)((char *)mb->match_frames + offset);
+        P = (heapframe *)((char *)N - frame_size);
+        if (N->group_frame_type == (GF_CAPTURE | number)) break;
+        offset = P->last_group_offset;
+        }
+      offset = (number << 1) - 2;
+      Fcapture_last = number;
+      Fovector[offset] = P->eptr - mb->start_subject;
+      Fovector[offset+1] = Feptr - mb->start_subject;
+      if (offset >= Foffset_top) Foffset_top = offset + 2;
+      }
+    Fecode += PRIV(OP_lengths)[*Fecode];
+    break;
+
+
+    /* ===================================================================== */
+    /* Real or forced end of the pattern, assertion, or recursion. In an
+    assertion ACCEPT, update the last used pointer and remember the current
+    frame so that the captures and mark can be fished out of it. */
+
+    case OP_ASSERT_ACCEPT:
+    if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr;
+    assert_accept_frame = F;
+    RRETURN(MATCH_ACCEPT);
+
+    /* If recursing, we have to find the most recent recursion. */
+
+    case OP_ACCEPT:
+    case OP_END:
+
+    /* Handle end of a recursion. */
+
+    if (Fcurrent_recurse != RECURSE_UNSET)
+      {
+      offset = Flast_group_offset;
+      for(;;)
+        {
+        if (offset == PCRE2_UNSET) return PCRE2_ERROR_INTERNAL;
+        N = (heapframe *)((char *)mb->match_frames + offset);
+        P = (heapframe *)((char *)N - frame_size);
+        if (GF_IDMASK(N->group_frame_type) == GF_RECURSE) break;
+        offset = P->last_group_offset;
+        }
+
+      /* N is now the frame of the recursion; the previous frame is at the
+      OP_RECURSE position. Go back there, copying the current subject position
+      and mark, and move on past the OP_RECURSE. */
+
+      P->eptr = Feptr;
+      P->mark = Fmark;
+      F = P;
+      Fecode += 1 + LINK_SIZE;
+      continue;
+      }
+
+    /* Not a recursion. Fail for an empty string match if either PCRE2_NOTEMPTY
+    is set, or if PCRE2_NOTEMPTY_ATSTART is set and we have matched at the
+    start of the subject. In both cases, backtracking will then try other
+    alternatives, if any. */
+
+    if (Feptr == Fstart_match &&
+         ((mb->moptions & PCRE2_NOTEMPTY) != 0 ||
+           ((mb->moptions & PCRE2_NOTEMPTY_ATSTART) != 0 &&
+             Fstart_match == mb->start_subject + mb->start_offset)))
+      RRETURN(MATCH_NOMATCH);
+
+    /* Also fail if PCRE2_ENDANCHORED is set and the end of the match is not
+    the end of the subject. After (*ACCEPT) we fail the entire match (at this
+    position) but backtrack on reaching the end of the pattern. */
+
+    if (Feptr < mb->end_subject &&
+        ((mb->moptions | mb->poptions) & PCRE2_ENDANCHORED) != 0)
+      {
+      if (Fop == OP_END) RRETURN(MATCH_NOMATCH);
+      return MATCH_NOMATCH;
+      }
+
+    /* We have a successful match of the whole pattern. Record the result and
+    then do a direct return from the function. If there is space in the offset
+    vector, set any pairs that follow the highest-numbered captured string but
+    are less than the number of capturing groups in the pattern to PCRE2_UNSET.
+    It is documented that this happens. "Gaps" are set to PCRE2_UNSET
+    dynamically. It is only those at the end that need setting here. */
+
+    mb->end_match_ptr = Feptr;           /* Record where we ended */
+    mb->end_offset_top = Foffset_top;    /* and how many extracts were taken */
+    mb->mark = Fmark;                    /* and the last success mark */
+    if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr;
+
+    ovector[0] = Fstart_match - mb->start_subject;
+    ovector[1] = Feptr - mb->start_subject;
+
+    /* Set i to the smaller of the sizes of the external and frame ovectors. */
+
+    i = 2 * ((top_bracket + 1 > oveccount)? oveccount : top_bracket + 1);
+    memcpy(ovector + 2, Fovector, (i - 2) * sizeof(PCRE2_SIZE));
+    while (--i >= Foffset_top + 2) ovector[i] = PCRE2_UNSET;
+    return MATCH_MATCH;  /* Note: NOT RRETURN */
+
+
+    /*===================================================================== */
+    /* Match any single character type except newline; have to take care with
+    CRLF newlines and partial matching. */
+
+    case OP_ANY:
+    if (IS_NEWLINE(Feptr)) RRETURN(MATCH_NOMATCH);
+    if (mb->partial != 0 &&
+        Feptr == mb->end_subject - 1 &&
+        NLBLOCK->nltype == NLTYPE_FIXED &&
+        NLBLOCK->nllen == 2 &&
+        UCHAR21TEST(Feptr) == NLBLOCK->nl[0])
+      {
+      mb->hitend = TRUE;
+      if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+      }
+    /* Fall through */
+
+    /* Match any single character whatsoever. */
+
+    case OP_ALLANY:
+    if (Feptr >= mb->end_subject)  /* DO NOT merge the Feptr++ here; it must */
+      {                            /* not be updated before SCHECK_PARTIAL. */
+      SCHECK_PARTIAL();
+      RRETURN(MATCH_NOMATCH);
+      }
+    Feptr++;
+#ifdef SUPPORT_UNICODE
+    if (utf) ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++);
+#endif
+    Fecode++;
+    break;
+
+
+    /* ===================================================================== */
+    /* Match a single code unit, even in UTF mode. This opcode really does
+    match any code unit, even newline. (It really should be called ANYCODEUNIT,
+    of course - the byte name is from pre-16 bit days.) */
+
+    case OP_ANYBYTE:
+    if (Feptr >= mb->end_subject)   /* DO NOT merge the Feptr++ here; it must */
+      {                             /* not be updated before SCHECK_PARTIAL. */
+      SCHECK_PARTIAL();
+      RRETURN(MATCH_NOMATCH);
+      }
+    Feptr++;
+    Fecode++;
+    break;
+
+
+    /* ===================================================================== */
+    /* Match a single character, casefully */
+
+    case OP_CHAR:
+#ifdef SUPPORT_UNICODE
+    if (utf)
+      {
+      Flength = 1;
+      Fecode++;
+      GETCHARLEN(fc, Fecode, Flength);
+      if (Flength > (PCRE2_SIZE)(mb->end_subject - Feptr))
+        {
+        CHECK_PARTIAL();             /* Not SCHECK_PARTIAL() */
+        RRETURN(MATCH_NOMATCH);
+        }
+      for (; Flength > 0; Flength--)
+        {
+        if (*Fecode++ != UCHAR21INC(Feptr)) RRETURN(MATCH_NOMATCH);
+        }
+      }
+    else
+#endif
+
+    /* Not UTF mode */
+      {
+      if (mb->end_subject - Feptr < 1)
+        {
+        SCHECK_PARTIAL();            /* This one can use SCHECK_PARTIAL() */
+        RRETURN(MATCH_NOMATCH);
+        }
+      if (Fecode[1] != *Feptr++) RRETURN(MATCH_NOMATCH);
+      Fecode += 2;
+      }
+    break;
+
+
+    /* ===================================================================== */
+    /* Match a single character, caselessly. If we are at the end of the
+    subject, give up immediately. We get here only when the pattern character
+    has at most one other case. Characters with more than two cases are coded
+    as OP_PROP with the pseudo-property PT_CLIST. */
+
+    case OP_CHARI:
+    if (Feptr >= mb->end_subject)
+      {
+      SCHECK_PARTIAL();
+      RRETURN(MATCH_NOMATCH);
+      }
+
+#ifdef SUPPORT_UNICODE
+    if (utf)
+      {
+      Flength = 1;
+      Fecode++;
+      GETCHARLEN(fc, Fecode, Flength);
+
+      /* If the pattern character's value is < 128, we know that its other case
+      (if any) is also < 128 (and therefore only one code unit long in all
+      code-unit widths), so we can use the fast lookup table. We checked above
+      that there is at least one character left in the subject. */
+
+      if (fc < 128)
+        {
+        uint32_t cc = UCHAR21(Feptr);
+        if (mb->lcc[fc] != TABLE_GET(cc, mb->lcc, cc)) RRETURN(MATCH_NOMATCH);
+        Fecode++;
+        Feptr++;
+        }
+
+      /* Otherwise we must pick up the subject character and use Unicode
+      property support to test its other case. Note that we cannot use the
+      value of "Flength" to check for sufficient bytes left, because the other
+      case of the character may have more or fewer code units. */
+
+      else
+        {
+        uint32_t dc;
+        GETCHARINC(dc, Feptr);
+        Fecode += Flength;
+        if (dc != fc && dc != UCD_OTHERCASE(fc)) RRETURN(MATCH_NOMATCH);
+        }
+      }
+
+    /* If UCP is set without UTF we must do the same as above, but with one
+    character per code unit. */
+
+    else if (ucp)
+      {
+      uint32_t cc = UCHAR21(Feptr);
+      fc = Fecode[1];
+      if (fc < 128)
+        {
+        if (mb->lcc[fc] != TABLE_GET(cc, mb->lcc, cc)) RRETURN(MATCH_NOMATCH);
+        }
+      else
+        {
+        if (cc != fc && cc != UCD_OTHERCASE(fc)) RRETURN(MATCH_NOMATCH);
+        }
+      Feptr++;
+      Fecode += 2;
+      }
+
+    else
+#endif   /* SUPPORT_UNICODE */
+
+    /* Not UTF or UCP mode; use the table for characters < 256. */
+      {
+      if (TABLE_GET(Fecode[1], mb->lcc, Fecode[1])
+          != TABLE_GET(*Feptr, mb->lcc, *Feptr)) RRETURN(MATCH_NOMATCH);
+      Feptr++;
+      Fecode += 2;
+      }
+    break;
+
+
+    /* ===================================================================== */
+    /* Match not a single character. */
+
+    case OP_NOT:
+    case OP_NOTI:
+    if (Feptr >= mb->end_subject)
+      {
+      SCHECK_PARTIAL();
+      RRETURN(MATCH_NOMATCH);
+      }
+
+#ifdef SUPPORT_UNICODE
+    if (utf)
+      {
+      uint32_t ch;
+      Fecode++;
+      GETCHARINC(ch, Fecode);
+      GETCHARINC(fc, Feptr);
+      if (ch == fc)
+        {
+        RRETURN(MATCH_NOMATCH);  /* Caseful match */
+        }
+      else if (Fop == OP_NOTI)   /* If caseless */
+        {
+        if (ch > 127)
+          ch = UCD_OTHERCASE(ch);
+        else
+          ch = (mb->fcc)[ch];
+        if (ch == fc) RRETURN(MATCH_NOMATCH);
+        }
+      }
+
+    /* UCP without UTF is as above, but with one character per code unit. */
+
+    else if (ucp)
+      {
+      uint32_t ch;
+      fc = UCHAR21INC(Feptr);
+      ch = Fecode[1];
+      Fecode += 2;
+
+      if (ch == fc)
+        {
+        RRETURN(MATCH_NOMATCH);  /* Caseful match */
+        }
+      else if (Fop == OP_NOTI)   /* If caseless */
+        {
+        if (ch > 127)
+          ch = UCD_OTHERCASE(ch);
+        else
+          ch = (mb->fcc)[ch];
+        if (ch == fc) RRETURN(MATCH_NOMATCH);
+        }
+      }
+
+    else
+#endif  /* SUPPORT_UNICODE */
+
+    /* Neither UTF nor UCP is set */
+
+      {
+      uint32_t ch = Fecode[1];
+      fc = UCHAR21INC(Feptr);
+      if (ch == fc || (Fop == OP_NOTI && TABLE_GET(ch, mb->fcc, ch) == fc))
+        RRETURN(MATCH_NOMATCH);
+      Fecode += 2;
+      }
+    break;
+
+
+    /* ===================================================================== */
+    /* Match a single character repeatedly. */
+
+#define Loclength    F->temp_size
+#define Lstart_eptr  F->temp_sptr[0]
+#define Lcharptr     F->temp_sptr[1]
+#define Lmin         F->temp_32[0]
+#define Lmax         F->temp_32[1]
+#define Lc           F->temp_32[2]
+#define Loc          F->temp_32[3]
+
+    case OP_EXACT:
+    case OP_EXACTI:
+    Lmin = Lmax = GET2(Fecode, 1);
+    Fecode += 1 + IMM2_SIZE;
+    goto REPEATCHAR;
+
+    case OP_POSUPTO:
+    case OP_POSUPTOI:
+    reptype = REPTYPE_POS;
+    Lmin = 0;
+    Lmax = GET2(Fecode, 1);
+    Fecode += 1 + IMM2_SIZE;
+    goto REPEATCHAR;
+
+    case OP_UPTO:
+    case OP_UPTOI:
+    reptype = REPTYPE_MAX;
+    Lmin = 0;
+    Lmax = GET2(Fecode, 1);
+    Fecode += 1 + IMM2_SIZE;
+    goto REPEATCHAR;
+
+    case OP_MINUPTO:
+    case OP_MINUPTOI:
+    reptype = REPTYPE_MIN;
+    Lmin = 0;
+    Lmax = GET2(Fecode, 1);
+    Fecode += 1 + IMM2_SIZE;
+    goto REPEATCHAR;
+
+    case OP_POSSTAR:
+    case OP_POSSTARI:
+    reptype = REPTYPE_POS;
+    Lmin = 0;
+    Lmax = UINT32_MAX;
+    Fecode++;
+    goto REPEATCHAR;
+
+    case OP_POSPLUS:
+    case OP_POSPLUSI:
+    reptype = REPTYPE_POS;
+    Lmin = 1;
+    Lmax = UINT32_MAX;
+    Fecode++;
+    goto REPEATCHAR;
+
+    case OP_POSQUERY:
+    case OP_POSQUERYI:
+    reptype = REPTYPE_POS;
+    Lmin = 0;
+    Lmax = 1;
+    Fecode++;
+    goto REPEATCHAR;
+
+    case OP_STAR:
+    case OP_STARI:
+    case OP_MINSTAR:
+    case OP_MINSTARI:
+    case OP_PLUS:
+    case OP_PLUSI:
+    case OP_MINPLUS:
+    case OP_MINPLUSI:
+    case OP_QUERY:
+    case OP_QUERYI:
+    case OP_MINQUERY:
+    case OP_MINQUERYI:
+    fc = *Fecode++ - ((Fop < OP_STARI)? OP_STAR : OP_STARI);
+    Lmin = rep_min[fc];
+    Lmax = rep_max[fc];
+    reptype = rep_typ[fc];
+
+    /* Common code for all repeated single-character matches. We first check
+    for the minimum number of characters. If the minimum equals the maximum, we
+    are done. Otherwise, if minimizing, check the rest of the pattern for a
+    match; if there isn't one, advance up to the maximum, one character at a
+    time.
+
+    If maximizing, advance up to the maximum number of matching characters,
+    until Feptr is past the end of the maximum run. If possessive, we are
+    then done (no backing up). Otherwise, match at this position; anything
+    other than no match is immediately returned. For nomatch, back up one
+    character, unless we are matching \R and the last thing matched was
+    \r\n, in which case, back up two code units until we reach the first
+    optional character position.
+
+    The various UTF/non-UTF and caseful/caseless cases are handled separately,
+    for speed. */
+
+    REPEATCHAR:
+#ifdef SUPPORT_UNICODE
+    if (utf)
+      {
+      Flength = 1;
+      Lcharptr = Fecode;
+      GETCHARLEN(fc, Fecode, Flength);
+      Fecode += Flength;
+
+      /* Handle multi-code-unit character matching, caseful and caseless. */
+
+      if (Flength > 1)
+        {
+        uint32_t othercase;
+
+        if (Fop >= OP_STARI &&     /* Caseless */
+            (othercase = UCD_OTHERCASE(fc)) != fc)
+          Loclength = PRIV(ord2utf)(othercase, Foccu);
+        else Loclength = 0;
+
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr <= mb->end_subject - Flength &&
+            memcmp(Feptr, Lcharptr, CU2BYTES(Flength)) == 0) Feptr += Flength;
+          else if (Loclength > 0 &&
+                   Feptr <= mb->end_subject - Loclength &&
+                   memcmp(Feptr, Foccu, CU2BYTES(Loclength)) == 0)
+            Feptr += Loclength;
+          else
+            {
+            CHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          }
+
+        if (Lmin == Lmax) continue;
+
+        if (reptype == REPTYPE_MIN)
+          {
+          for (;;)
+            {
+            RMATCH(Fecode, RM202);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+            if (Feptr <= mb->end_subject - Flength &&
+              memcmp(Feptr, Lcharptr, CU2BYTES(Flength)) == 0) Feptr += Flength;
+            else if (Loclength > 0 &&
+                     Feptr <= mb->end_subject - Loclength &&
+                     memcmp(Feptr, Foccu, CU2BYTES(Loclength)) == 0)
+              Feptr += Loclength;
+            else
+              {
+              CHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            }
+          /* Control never gets here */
+          }
+
+        else  /* Maximize */
+          {
+          Lstart_eptr = Feptr;
+          for (i = Lmin; i < Lmax; i++)
+            {
+            if (Feptr <= mb->end_subject - Flength &&
+                memcmp(Feptr, Lcharptr, CU2BYTES(Flength)) == 0)
+              Feptr += Flength;
+            else if (Loclength > 0 &&
+                     Feptr <= mb->end_subject - Loclength &&
+                     memcmp(Feptr, Foccu, CU2BYTES(Loclength)) == 0)
+              Feptr += Loclength;
+            else
+              {
+              CHECK_PARTIAL();
+              break;
+              }
+            }
+
+          /* After \C in UTF mode, Lstart_eptr might be in the middle of a
+          Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't
+          go too far. */
+
+          if (reptype != REPTYPE_POS) for(;;)
+            {
+            if (Feptr <= Lstart_eptr) break;
+            RMATCH(Fecode, RM203);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            Feptr--;
+            BACKCHAR(Feptr);
+            }
+          }
+        break;   /* End of repeated wide character handling */
+        }
+
+      /* Length of UTF character is 1. Put it into the preserved variable and
+      fall through to the non-UTF code. */
+
+      Lc = fc;
+      }
+    else
+#endif  /* SUPPORT_UNICODE */
+
+    /* When not in UTF mode, load a single-code-unit character. Then proceed as
+    above, using Unicode casing if either UTF or UCP is set. */
+
+    Lc = *Fecode++;
+
+    /* Caseless comparison */
+
+    if (Fop >= OP_STARI)
+      {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#ifdef SUPPORT_UNICODE
+      if (ucp && !utf && Lc > 127) Loc = UCD_OTHERCASE(Lc);
+      else
+#endif  /* SUPPORT_UNICODE */
+      /* Lc will be < 128 in UTF-8 mode. */
+      Loc = mb->fcc[Lc];
+#else /* 16-bit & 32-bit */
+#ifdef SUPPORT_UNICODE
+      if ((utf || ucp) && Lc > 127) Loc = UCD_OTHERCASE(Lc);
+      else
+#endif  /* SUPPORT_UNICODE */
+      Loc = TABLE_GET(Lc, mb->fcc, Lc);
+#endif  /* PCRE2_CODE_UNIT_WIDTH == 8 */
+
+      for (i = 1; i <= Lmin; i++)
+        {
+        uint32_t cc;                 /* Faster than PCRE2_UCHAR */
+        if (Feptr >= mb->end_subject)
+          {
+          SCHECK_PARTIAL();
+          RRETURN(MATCH_NOMATCH);
+          }
+        cc = UCHAR21TEST(Feptr);
+        if (Lc != cc && Loc != cc) RRETURN(MATCH_NOMATCH);
+        Feptr++;
+        }
+      if (Lmin == Lmax) continue;
+
+      if (reptype == REPTYPE_MIN)
+        {
+        for (;;)
+          {
+          uint32_t cc;               /* Faster than PCRE2_UCHAR */
+          RMATCH(Fecode, RM25);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          cc = UCHAR21TEST(Feptr);
+          if (Lc != cc && Loc != cc) RRETURN(MATCH_NOMATCH);
+          Feptr++;
+          }
+        /* Control never gets here */
+        }
+
+      else  /* Maximize */
+        {
+        Lstart_eptr = Feptr;
+        for (i = Lmin; i < Lmax; i++)
+          {
+          uint32_t cc;               /* Faster than PCRE2_UCHAR */
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            break;
+            }
+          cc = UCHAR21TEST(Feptr);
+          if (Lc != cc && Loc != cc) break;
+          Feptr++;
+          }
+        if (reptype != REPTYPE_POS) for (;;)
+          {
+          if (Feptr == Lstart_eptr) break;
+          RMATCH(Fecode, RM26);
+          Feptr--;
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          }
+        }
+      }
+
+    /* Caseful comparisons (includes all multi-byte characters) */
+
+    else
+      {
+      for (i = 1; i <= Lmin; i++)
+        {
+        if (Feptr >= mb->end_subject)
+          {
+          SCHECK_PARTIAL();
+          RRETURN(MATCH_NOMATCH);
+          }
+        if (Lc != UCHAR21INCTEST(Feptr)) RRETURN(MATCH_NOMATCH);
+        }
+
+      if (Lmin == Lmax) continue;
+
+      if (reptype == REPTYPE_MIN)
+        {
+        for (;;)
+          {
+          RMATCH(Fecode, RM27);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          if (Lc != UCHAR21INCTEST(Feptr)) RRETURN(MATCH_NOMATCH);
+          }
+        /* Control never gets here */
+        }
+      else  /* Maximize */
+        {
+        Lstart_eptr = Feptr;
+        for (i = Lmin; i < Lmax; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            break;
+            }
+
+          if (Lc != UCHAR21TEST(Feptr)) break;
+          Feptr++;
+          }
+
+        if (reptype != REPTYPE_POS) for (;;)
+          {
+          if (Feptr <= Lstart_eptr) break;
+          RMATCH(Fecode, RM28);
+          Feptr--;
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          }
+        }
+      }
+    break;
+
+#undef Loclength
+#undef Lstart_eptr
+#undef Lcharptr
+#undef Lmin
+#undef Lmax
+#undef Lc
+#undef Loc
+
+
+    /* ===================================================================== */
+    /* Match a negated single one-byte character repeatedly. This is almost a
+    repeat of the code for a repeated single character, but I haven't found a
+    nice way of commoning these up that doesn't require a test of the
+    positive/negative option for each character match. Maybe that wouldn't add
+    very much to the time taken, but character matching *is* what this is all
+    about... */
+
+#define Lstart_eptr  F->temp_sptr[0]
+#define Lmin         F->temp_32[0]
+#define Lmax         F->temp_32[1]
+#define Lc           F->temp_32[2]
+#define Loc          F->temp_32[3]
+
+    case OP_NOTEXACT:
+    case OP_NOTEXACTI:
+    Lmin = Lmax = GET2(Fecode, 1);
+    Fecode += 1 + IMM2_SIZE;
+    goto REPEATNOTCHAR;
+
+    case OP_NOTUPTO:
+    case OP_NOTUPTOI:
+    Lmin = 0;
+    Lmax = GET2(Fecode, 1);
+    reptype = REPTYPE_MAX;
+    Fecode += 1 + IMM2_SIZE;
+    goto REPEATNOTCHAR;
+
+    case OP_NOTMINUPTO:
+    case OP_NOTMINUPTOI:
+    Lmin = 0;
+    Lmax = GET2(Fecode, 1);
+    reptype = REPTYPE_MIN;
+    Fecode += 1 + IMM2_SIZE;
+    goto REPEATNOTCHAR;
+
+    case OP_NOTPOSSTAR:
+    case OP_NOTPOSSTARI:
+    reptype = REPTYPE_POS;
+    Lmin = 0;
+    Lmax = UINT32_MAX;
+    Fecode++;
+    goto REPEATNOTCHAR;
+
+    case OP_NOTPOSPLUS:
+    case OP_NOTPOSPLUSI:
+    reptype = REPTYPE_POS;
+    Lmin = 1;
+    Lmax = UINT32_MAX;
+    Fecode++;
+    goto REPEATNOTCHAR;
+
+    case OP_NOTPOSQUERY:
+    case OP_NOTPOSQUERYI:
+    reptype = REPTYPE_POS;
+    Lmin = 0;
+    Lmax = 1;
+    Fecode++;
+    goto REPEATNOTCHAR;
+
+    case OP_NOTPOSUPTO:
+    case OP_NOTPOSUPTOI:
+    reptype = REPTYPE_POS;
+    Lmin = 0;
+    Lmax = GET2(Fecode, 1);
+    Fecode += 1 + IMM2_SIZE;
+    goto REPEATNOTCHAR;
+
+    case OP_NOTSTAR:
+    case OP_NOTSTARI:
+    case OP_NOTMINSTAR:
+    case OP_NOTMINSTARI:
+    case OP_NOTPLUS:
+    case OP_NOTPLUSI:
+    case OP_NOTMINPLUS:
+    case OP_NOTMINPLUSI:
+    case OP_NOTQUERY:
+    case OP_NOTQUERYI:
+    case OP_NOTMINQUERY:
+    case OP_NOTMINQUERYI:
+    fc = *Fecode++ - ((Fop >= OP_NOTSTARI)? OP_NOTSTARI: OP_NOTSTAR);
+    Lmin = rep_min[fc];
+    Lmax = rep_max[fc];
+    reptype = rep_typ[fc];
+
+    /* Common code for all repeated single-character non-matches. */
+
+    REPEATNOTCHAR:
+    GETCHARINCTEST(Lc, Fecode);
+
+    /* The code is duplicated for the caseless and caseful cases, for speed,
+    since matching characters is likely to be quite common. First, ensure the
+    minimum number of matches are present. If Lmin = Lmax, we are done.
+    Otherwise, if minimizing, keep trying the rest of the expression and
+    advancing one matching character if failing, up to the maximum.
+    Alternatively, if maximizing, find the maximum number of characters and
+    work backwards. */
+
+    if (Fop >= OP_NOTSTARI)     /* Caseless */
+      {
+#ifdef SUPPORT_UNICODE
+      if ((utf || ucp) && Lc > 127)
+        Loc = UCD_OTHERCASE(Lc);
+      else
+#endif /* SUPPORT_UNICODE */
+
+      Loc = TABLE_GET(Lc, mb->fcc, Lc);  /* Other case from table */
+
+#ifdef SUPPORT_UNICODE
+      if (utf)
+        {
+        uint32_t d;
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          GETCHARINC(d, Feptr);
+          if (Lc == d || Loc == d) RRETURN(MATCH_NOMATCH);
+          }
+        }
+      else
+#endif  /* SUPPORT_UNICODE */
+
+      /* Not UTF mode */
+        {
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          if (Lc == *Feptr || Loc == *Feptr) RRETURN(MATCH_NOMATCH);
+          Feptr++;
+          }
+        }
+
+      if (Lmin == Lmax) continue;  /* Finished for exact count */
+
+      if (reptype == REPTYPE_MIN)
+        {
+#ifdef SUPPORT_UNICODE
+        if (utf)
+          {
+          uint32_t d;
+          for (;;)
+            {
+            RMATCH(Fecode, RM204);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINC(d, Feptr);
+            if (Lc == d || Loc == d) RRETURN(MATCH_NOMATCH);
+            }
+          }
+        else
+#endif  /*SUPPORT_UNICODE */
+
+        /* Not UTF mode */
+          {
+          for (;;)
+            {
+            RMATCH(Fecode, RM29);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            if (Lc == *Feptr || Loc == *Feptr) RRETURN(MATCH_NOMATCH);
+            Feptr++;
+            }
+          }
+        /* Control never gets here */
+        }
+
+      /* Maximize case */
+
+      else
+        {
+        Lstart_eptr = Feptr;
+
+#ifdef SUPPORT_UNICODE
+        if (utf)
+          {
+          uint32_t d;
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLEN(d, Feptr, len);
+            if (Lc == d || Loc == d) break;
+            Feptr += len;
+            }
+
+          /* After \C in UTF mode, Lstart_eptr might be in the middle of a
+          Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't
+          go too far. */
+
+          if (reptype != REPTYPE_POS) for(;;)
+            {
+            if (Feptr <= Lstart_eptr) break;
+            RMATCH(Fecode, RM205);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            Feptr--;
+            BACKCHAR(Feptr);
+            }
+          }
+        else
+#endif  /* SUPPORT_UNICODE */
+
+        /* Not UTF mode */
+          {
+          for (i = Lmin; i < Lmax; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            if (Lc == *Feptr || Loc == *Feptr) break;
+            Feptr++;
+            }
+          if (reptype != REPTYPE_POS) for (;;)
+            {
+            if (Feptr == Lstart_eptr) break;
+            RMATCH(Fecode, RM30);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            Feptr--;
+            }
+          }
+        }
+      }
+
+    /* Caseful comparisons */
+
+    else
+      {
+#ifdef SUPPORT_UNICODE
+      if (utf)
+        {
+        uint32_t d;
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          GETCHARINC(d, Feptr);
+          if (Lc == d) RRETURN(MATCH_NOMATCH);
+          }
+        }
+      else
+#endif
+      /* Not UTF mode */
+        {
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          if (Lc == *Feptr++) RRETURN(MATCH_NOMATCH);
+          }
+        }
+
+      if (Lmin == Lmax) continue;
+
+      if (reptype == REPTYPE_MIN)
+        {
+#ifdef SUPPORT_UNICODE
+        if (utf)
+          {
+          uint32_t d;
+          for (;;)
+            {
+            RMATCH(Fecode, RM206);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINC(d, Feptr);
+            if (Lc == d) RRETURN(MATCH_NOMATCH);
+            }
+          }
+        else
+#endif
+        /* Not UTF mode */
+          {
+          for (;;)
+            {
+            RMATCH(Fecode, RM31);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            if (Lc == *Feptr++) RRETURN(MATCH_NOMATCH);
+            }
+          }
+        /* Control never gets here */
+        }
+
+      /* Maximize case */
+
+      else
+        {
+        Lstart_eptr = Feptr;
+
+#ifdef SUPPORT_UNICODE
+        if (utf)
+          {
+          uint32_t d;
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLEN(d, Feptr, len);
+            if (Lc == d) break;
+            Feptr += len;
+            }
+
+          /* After \C in UTF mode, Lstart_eptr might be in the middle of a
+          Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't
+          go too far. */
+
+          if (reptype != REPTYPE_POS) for(;;)
+            {
+            if (Feptr <= Lstart_eptr) break;
+            RMATCH(Fecode, RM207);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            Feptr--;
+            BACKCHAR(Feptr);
+            }
+          }
+        else
+#endif
+        /* Not UTF mode */
+          {
+          for (i = Lmin; i < Lmax; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            if (Lc == *Feptr) break;
+            Feptr++;
+            }
+          if (reptype != REPTYPE_POS) for (;;)
+            {
+            if (Feptr == Lstart_eptr) break;
+            RMATCH(Fecode, RM32);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            Feptr--;
+            }
+          }
+        }
+      }
+    break;
+
+#undef Lstart_eptr
+#undef Lmin
+#undef Lmax
+#undef Lc
+#undef Loc
+
+
+    /* ===================================================================== */
+    /* Match a bit-mapped character class, possibly repeatedly. These opcodes
+    are used when all the characters in the class have values in the range
+    0-255, and either the matching is caseful, or the characters are in the
+    range 0-127 when UTF processing is enabled. The only difference between
+    OP_CLASS and OP_NCLASS occurs when a data character outside the range is
+    encountered. */
+
+#define Lmin               F->temp_32[0]
+#define Lmax               F->temp_32[1]
+#define Lstart_eptr        F->temp_sptr[0]
+#define Lbyte_map_address  F->temp_sptr[1]
+#define Lbyte_map          ((unsigned char *)Lbyte_map_address)
+
+    case OP_NCLASS:
+    case OP_CLASS:
+      {
+      Lbyte_map_address = Fecode + 1;           /* Save for matching */
+      Fecode += 1 + (32 / sizeof(PCRE2_UCHAR)); /* Advance past the item */
+
+      /* Look past the end of the item to see if there is repeat information
+      following. Then obey similar code to character type repeats. */
+
+      switch (*Fecode)
+        {
+        case OP_CRSTAR:
+        case OP_CRMINSTAR:
+        case OP_CRPLUS:
+        case OP_CRMINPLUS:
+        case OP_CRQUERY:
+        case OP_CRMINQUERY:
+        case OP_CRPOSSTAR:
+        case OP_CRPOSPLUS:
+        case OP_CRPOSQUERY:
+        fc = *Fecode++ - OP_CRSTAR;
+        Lmin = rep_min[fc];
+        Lmax = rep_max[fc];
+        reptype = rep_typ[fc];
+        break;
+
+        case OP_CRRANGE:
+        case OP_CRMINRANGE:
+        case OP_CRPOSRANGE:
+        Lmin = GET2(Fecode, 1);
+        Lmax = GET2(Fecode, 1 + IMM2_SIZE);
+        if (Lmax == 0) Lmax = UINT32_MAX;       /* Max 0 => infinity */
+        reptype = rep_typ[*Fecode - OP_CRSTAR];
+        Fecode += 1 + 2 * IMM2_SIZE;
+        break;
+
+        default:               /* No repeat follows */
+        Lmin = Lmax = 1;
+        break;
+        }
+
+      /* First, ensure the minimum number of matches are present. */
+
+#ifdef SUPPORT_UNICODE
+      if (utf)
+        {
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          GETCHARINC(fc, Feptr);
+          if (fc > 255)
+            {
+            if (Fop == OP_CLASS) RRETURN(MATCH_NOMATCH);
+            }
+          else
+            if ((Lbyte_map[fc/8] & (1u << (fc&7))) == 0) RRETURN(MATCH_NOMATCH);
+          }
+        }
+      else
+#endif
+      /* Not UTF mode */
+        {
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          fc = *Feptr++;
+#if PCRE2_CODE_UNIT_WIDTH != 8
+          if (fc > 255)
+            {
+            if (Fop == OP_CLASS) RRETURN(MATCH_NOMATCH);
+            }
+          else
+#endif
+          if ((Lbyte_map[fc/8] & (1u << (fc&7))) == 0) RRETURN(MATCH_NOMATCH);
+          }
+        }
+
+      /* If Lmax == Lmin we are done. Continue with main loop. */
+
+      if (Lmin == Lmax) continue;
+
+      /* If minimizing, keep testing the rest of the expression and advancing
+      the pointer while it matches the class. */
+
+      if (reptype == REPTYPE_MIN)
+        {
+#ifdef SUPPORT_UNICODE
+        if (utf)
+          {
+          for (;;)
+            {
+            RMATCH(Fecode, RM200);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINC(fc, Feptr);
+            if (fc > 255)
+              {
+              if (Fop == OP_CLASS) RRETURN(MATCH_NOMATCH);
+              }
+            else
+              if ((Lbyte_map[fc/8] & (1u << (fc&7))) == 0) RRETURN(MATCH_NOMATCH);
+            }
+          }
+        else
+#endif
+        /* Not UTF mode */
+          {
+          for (;;)
+            {
+            RMATCH(Fecode, RM23);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            fc = *Feptr++;
+#if PCRE2_CODE_UNIT_WIDTH != 8
+            if (fc > 255)
+              {
+              if (Fop == OP_CLASS) RRETURN(MATCH_NOMATCH);
+              }
+            else
+#endif
+            if ((Lbyte_map[fc/8] & (1u << (fc&7))) == 0) RRETURN(MATCH_NOMATCH);
+            }
+          }
+        /* Control never gets here */
+        }
+
+      /* If maximizing, find the longest possible run, then work backwards. */
+
+      else
+        {
+        Lstart_eptr = Feptr;
+
+#ifdef SUPPORT_UNICODE
+        if (utf)
+          {
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLEN(fc, Feptr, len);
+            if (fc > 255)
+              {
+              if (Fop == OP_CLASS) break;
+              }
+            else
+              if ((Lbyte_map[fc/8] & (1u << (fc&7))) == 0) break;
+            Feptr += len;
+            }
+
+          if (reptype == REPTYPE_POS) continue;    /* No backtracking */
+
+          /* After \C in UTF mode, Lstart_eptr might be in the middle of a
+          Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't
+          go too far. */
+
+          for (;;)
+            {
+            RMATCH(Fecode, RM201);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Feptr-- <= Lstart_eptr) break;  /* Tried at original position */
+            BACKCHAR(Feptr);
+            }
+          }
+        else
+#endif
+          /* Not UTF mode */
+          {
+          for (i = Lmin; i < Lmax; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            fc = *Feptr;
+#if PCRE2_CODE_UNIT_WIDTH != 8
+            if (fc > 255)
+              {
+              if (Fop == OP_CLASS) break;
+              }
+            else
+#endif
+            if ((Lbyte_map[fc/8] & (1u << (fc&7))) == 0) break;
+            Feptr++;
+            }
+
+          if (reptype == REPTYPE_POS) continue;    /* No backtracking */
+
+          while (Feptr >= Lstart_eptr)
+            {
+            RMATCH(Fecode, RM24);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            Feptr--;
+            }
+          }
+
+        RRETURN(MATCH_NOMATCH);
+        }
+      }
+    /* Control never gets here */
+
+#undef Lbyte_map_address
+#undef Lbyte_map
+#undef Lstart_eptr
+#undef Lmin
+#undef Lmax
+
+
+    /* ===================================================================== */
+    /* Match an extended character class. In the 8-bit library, this opcode is
+    encountered only when UTF-8 mode mode is supported. In the 16-bit and
+    32-bit libraries, codepoints greater than 255 may be encountered even when
+    UTF is not supported. */
+
+#define Lstart_eptr  F->temp_sptr[0]
+#define Lxclass_data F->temp_sptr[1]
+#define Lmin         F->temp_32[0]
+#define Lmax         F->temp_32[1]
+
+#ifdef SUPPORT_WIDE_CHARS
+    case OP_XCLASS:
+      {
+      Lxclass_data = Fecode + 1 + LINK_SIZE;  /* Save for matching */
+      Fecode += GET(Fecode, 1);               /* Advance past the item */
+
+      switch (*Fecode)
+        {
+        case OP_CRSTAR:
+        case OP_CRMINSTAR:
+        case OP_CRPLUS:
+        case OP_CRMINPLUS:
+        case OP_CRQUERY:
+        case OP_CRMINQUERY:
+        case OP_CRPOSSTAR:
+        case OP_CRPOSPLUS:
+        case OP_CRPOSQUERY:
+        fc = *Fecode++ - OP_CRSTAR;
+        Lmin = rep_min[fc];
+        Lmax = rep_max[fc];
+        reptype = rep_typ[fc];
+        break;
+
+        case OP_CRRANGE:
+        case OP_CRMINRANGE:
+        case OP_CRPOSRANGE:
+        Lmin = GET2(Fecode, 1);
+        Lmax = GET2(Fecode, 1 + IMM2_SIZE);
+        if (Lmax == 0) Lmax = UINT32_MAX;  /* Max 0 => infinity */
+        reptype = rep_typ[*Fecode - OP_CRSTAR];
+        Fecode += 1 + 2 * IMM2_SIZE;
+        break;
+
+        default:               /* No repeat follows */
+        Lmin = Lmax = 1;
+        break;
+        }
+
+      /* First, ensure the minimum number of matches are present. */
+
+      for (i = 1; i <= Lmin; i++)
+        {
+        if (Feptr >= mb->end_subject)
+          {
+          SCHECK_PARTIAL();
+          RRETURN(MATCH_NOMATCH);
+          }
+        GETCHARINCTEST(fc, Feptr);
+        if (!PRIV(xclass)(fc, Lxclass_data, utf)) RRETURN(MATCH_NOMATCH);
+        }
+
+      /* If Lmax == Lmin we can just continue with the main loop. */
+
+      if (Lmin == Lmax) continue;
+
+      /* If minimizing, keep testing the rest of the expression and advancing
+      the pointer while it matches the class. */
+
+      if (reptype == REPTYPE_MIN)
+        {
+        for (;;)
+          {
+          RMATCH(Fecode, RM100);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          GETCHARINCTEST(fc, Feptr);
+          if (!PRIV(xclass)(fc, Lxclass_data, utf)) RRETURN(MATCH_NOMATCH);
+          }
+        /* Control never gets here */
+        }
+
+      /* If maximizing, find the longest possible run, then work backwards. */
+
+      else
+        {
+        Lstart_eptr = Feptr;
+        for (i = Lmin; i < Lmax; i++)
+          {
+          int len = 1;
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            break;
+            }
+#ifdef SUPPORT_UNICODE
+          GETCHARLENTEST(fc, Feptr, len);
+#else
+          fc = *Feptr;
+#endif
+          if (!PRIV(xclass)(fc, Lxclass_data, utf)) break;
+          Feptr += len;
+          }
+
+        if (reptype == REPTYPE_POS) continue;    /* No backtracking */
+
+        /* After \C in UTF mode, Lstart_eptr might be in the middle of a
+        Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't
+        go too far. */
+
+        for(;;)
+          {
+          RMATCH(Fecode, RM101);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (Feptr-- <= Lstart_eptr) break;  /* Tried at original position */
+#ifdef SUPPORT_UNICODE
+          if (utf) BACKCHAR(Feptr);
+#endif
+          }
+        RRETURN(MATCH_NOMATCH);
+        }
+
+      /* Control never gets here */
+      }
+#endif  /* SUPPORT_WIDE_CHARS: end of XCLASS */
+
+#undef Lstart_eptr
+#undef Lxclass_data
+#undef Lmin
+#undef Lmax
+
+
+    /* ===================================================================== */
+    /* Match various character types when PCRE2_UCP is not set. These opcodes
+    are not generated when PCRE2_UCP is set - instead appropriate property
+    tests are compiled. */
+
+    case OP_NOT_DIGIT:
+    if (Feptr >= mb->end_subject)
+      {
+      SCHECK_PARTIAL();
+      RRETURN(MATCH_NOMATCH);
+      }
+    GETCHARINCTEST(fc, Feptr);
+    if (CHMAX_255(fc) && (mb->ctypes[fc] & ctype_digit) != 0)
+      RRETURN(MATCH_NOMATCH);
+    Fecode++;
+    break;
+
+    case OP_DIGIT:
+    if (Feptr >= mb->end_subject)
+      {
+      SCHECK_PARTIAL();
+      RRETURN(MATCH_NOMATCH);
+      }
+    GETCHARINCTEST(fc, Feptr);
+    if (!CHMAX_255(fc) || (mb->ctypes[fc] & ctype_digit) == 0)
+      RRETURN(MATCH_NOMATCH);
+    Fecode++;
+    break;
+
+    case OP_NOT_WHITESPACE:
+    if (Feptr >= mb->end_subject)
+      {
+      SCHECK_PARTIAL();
+      RRETURN(MATCH_NOMATCH);
+      }
+    GETCHARINCTEST(fc, Feptr);
+    if (CHMAX_255(fc) && (mb->ctypes[fc] & ctype_space) != 0)
+      RRETURN(MATCH_NOMATCH);
+    Fecode++;
+    break;
+
+    case OP_WHITESPACE:
+    if (Feptr >= mb->end_subject)
+      {
+      SCHECK_PARTIAL();
+      RRETURN(MATCH_NOMATCH);
+      }
+    GETCHARINCTEST(fc, Feptr);
+    if (!CHMAX_255(fc) || (mb->ctypes[fc] & ctype_space) == 0)
+      RRETURN(MATCH_NOMATCH);
+    Fecode++;
+    break;
+
+    case OP_NOT_WORDCHAR:
+    if (Feptr >= mb->end_subject)
+      {
+      SCHECK_PARTIAL();
+      RRETURN(MATCH_NOMATCH);
+      }
+    GETCHARINCTEST(fc, Feptr);
+    if (CHMAX_255(fc) && (mb->ctypes[fc] & ctype_word) != 0)
+      RRETURN(MATCH_NOMATCH);
+    Fecode++;
+    break;
+
+    case OP_WORDCHAR:
+    if (Feptr >= mb->end_subject)
+      {
+      SCHECK_PARTIAL();
+      RRETURN(MATCH_NOMATCH);
+      }
+    GETCHARINCTEST(fc, Feptr);
+    if (!CHMAX_255(fc) || (mb->ctypes[fc] & ctype_word) == 0)
+      RRETURN(MATCH_NOMATCH);
+    Fecode++;
+    break;
+
+    case OP_ANYNL:
+    if (Feptr >= mb->end_subject)
+      {
+      SCHECK_PARTIAL();
+      RRETURN(MATCH_NOMATCH);
+      }
+    GETCHARINCTEST(fc, Feptr);
+    switch(fc)
+      {
+      default: RRETURN(MATCH_NOMATCH);
+
+      case CHAR_CR:
+      if (Feptr >= mb->end_subject)
+        {
+        SCHECK_PARTIAL();
+        }
+      else if (UCHAR21TEST(Feptr) == CHAR_LF) Feptr++;
+      break;
+
+      case CHAR_LF:
+      break;
+
+      case CHAR_VT:
+      case CHAR_FF:
+      case CHAR_NEL:
+#ifndef EBCDIC
+      case 0x2028:
+      case 0x2029:
+#endif  /* Not EBCDIC */
+      if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH);
+      break;
+      }
+    Fecode++;
+    break;
+
+    case OP_NOT_HSPACE:
+    if (Feptr >= mb->end_subject)
+      {
+      SCHECK_PARTIAL();
+      RRETURN(MATCH_NOMATCH);
+      }
+    GETCHARINCTEST(fc, Feptr);
+    switch(fc)
+      {
+      HSPACE_CASES: RRETURN(MATCH_NOMATCH);  /* Byte and multibyte cases */
+      default: break;
+      }
+    Fecode++;
+    break;
+
+    case OP_HSPACE:
+    if (Feptr >= mb->end_subject)
+      {
+      SCHECK_PARTIAL();
+      RRETURN(MATCH_NOMATCH);
+      }
+    GETCHARINCTEST(fc, Feptr);
+    switch(fc)
+      {
+      HSPACE_CASES: break;  /* Byte and multibyte cases */
+      default: RRETURN(MATCH_NOMATCH);
+      }
+    Fecode++;
+    break;
+
+    case OP_NOT_VSPACE:
+    if (Feptr >= mb->end_subject)
+      {
+      SCHECK_PARTIAL();
+      RRETURN(MATCH_NOMATCH);
+      }
+    GETCHARINCTEST(fc, Feptr);
+    switch(fc)
+      {
+      VSPACE_CASES: RRETURN(MATCH_NOMATCH);
+      default: break;
+      }
+    Fecode++;
+    break;
+
+    case OP_VSPACE:
+    if (Feptr >= mb->end_subject)
+      {
+      SCHECK_PARTIAL();
+      RRETURN(MATCH_NOMATCH);
+      }
+    GETCHARINCTEST(fc, Feptr);
+    switch(fc)
+      {
+      VSPACE_CASES: break;
+      default: RRETURN(MATCH_NOMATCH);
+      }
+    Fecode++;
+    break;
+
+
+#ifdef SUPPORT_UNICODE
+
+    /* ===================================================================== */
+    /* Check the next character by Unicode property. We will get here only
+    if the support is in the binary; otherwise a compile-time error occurs. */
+
+    case OP_PROP:
+    case OP_NOTPROP:
+    if (Feptr >= mb->end_subject)
+      {
+      SCHECK_PARTIAL();
+      RRETURN(MATCH_NOMATCH);
+      }
+    GETCHARINCTEST(fc, Feptr);
+      {
+      const uint32_t *cp;
+      const ucd_record *prop = GET_UCD(fc);
+
+      switch(Fecode[1])
+        {
+        case PT_ANY:
+        if (Fop == OP_NOTPROP) RRETURN(MATCH_NOMATCH);
+        break;
+
+        case PT_LAMP:
+        if ((prop->chartype == ucp_Lu ||
+             prop->chartype == ucp_Ll ||
+             prop->chartype == ucp_Lt) == (Fop == OP_NOTPROP))
+          RRETURN(MATCH_NOMATCH);
+        break;
+
+        case PT_GC:
+        if ((Fecode[2] != PRIV(ucp_gentype)[prop->chartype]) == (Fop == OP_PROP))
+          RRETURN(MATCH_NOMATCH);
+        break;
+
+        case PT_PC:
+        if ((Fecode[2] != prop->chartype) == (Fop == OP_PROP))
+          RRETURN(MATCH_NOMATCH);
+        break;
+
+        case PT_SC:
+        if ((Fecode[2] != prop->script) == (Fop == OP_PROP))
+          RRETURN(MATCH_NOMATCH);
+        break;
+
+        /* These are specials */
+
+        case PT_ALNUM:
+        if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+             PRIV(ucp_gentype)[prop->chartype] == ucp_N) == (Fop == OP_NOTPROP))
+          RRETURN(MATCH_NOMATCH);
+        break;
+
+        /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+        which means that Perl space and POSIX space are now identical. PCRE
+        was changed at release 8.34. */
+
+        case PT_SPACE:    /* Perl space */
+        case PT_PXSPACE:  /* POSIX space */
+        switch(fc)
+          {
+          HSPACE_CASES:
+          VSPACE_CASES:
+          if (Fop == OP_NOTPROP) RRETURN(MATCH_NOMATCH);
+          break;
+
+          default:
+          if ((PRIV(ucp_gentype)[prop->chartype] == ucp_Z) ==
+            (Fop == OP_NOTPROP)) RRETURN(MATCH_NOMATCH);
+          break;
+          }
+        break;
+
+        case PT_WORD:
+        if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+             PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
+             fc == CHAR_UNDERSCORE) == (Fop == OP_NOTPROP))
+          RRETURN(MATCH_NOMATCH);
+        break;
+
+        case PT_CLIST:
+        cp = PRIV(ucd_caseless_sets) + Fecode[2];
+        for (;;)
+          {
+          if (fc < *cp)
+            { if (Fop == OP_PROP) { RRETURN(MATCH_NOMATCH); } else break; }
+          if (fc == *cp++)
+            { if (Fop == OP_PROP) break; else { RRETURN(MATCH_NOMATCH); } }
+          }
+        break;
+
+        case PT_UCNC:
+        if ((fc == CHAR_DOLLAR_SIGN || fc == CHAR_COMMERCIAL_AT ||
+             fc == CHAR_GRAVE_ACCENT || (fc >= 0xa0 && fc <= 0xd7ff) ||
+             fc >= 0xe000) == (Fop == OP_NOTPROP))
+          RRETURN(MATCH_NOMATCH);
+        break;
+
+        /* This should never occur */
+
+        default:
+        return PCRE2_ERROR_INTERNAL;
+        }
+
+      Fecode += 3;
+      }
+    break;
+
+
+    /* ===================================================================== */
+    /* Match an extended Unicode sequence. We will get here only if the support
+    is in the binary; otherwise a compile-time error occurs. */
+
+    case OP_EXTUNI:
+    if (Feptr >= mb->end_subject)
+      {
+      SCHECK_PARTIAL();
+      RRETURN(MATCH_NOMATCH);
+      }
+    else
+      {
+      GETCHARINCTEST(fc, Feptr);
+      Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject, utf,
+        NULL);
+      }
+    CHECK_PARTIAL();
+    Fecode++;
+    break;
+
+#endif  /* SUPPORT_UNICODE */
+
+
+    /* ===================================================================== */
+    /* Match a single character type repeatedly. Note that the property type
+    does not need to be in a stack frame as it is not used within an RMATCH()
+    loop. */
+
+#define Lstart_eptr  F->temp_sptr[0]
+#define Lmin         F->temp_32[0]
+#define Lmax         F->temp_32[1]
+#define Lctype       F->temp_32[2]
+#define Lpropvalue   F->temp_32[3]
+
+    case OP_TYPEEXACT:
+    Lmin = Lmax = GET2(Fecode, 1);
+    Fecode += 1 + IMM2_SIZE;
+    goto REPEATTYPE;
+
+    case OP_TYPEUPTO:
+    case OP_TYPEMINUPTO:
+    Lmin = 0;
+    Lmax = GET2(Fecode, 1);
+    reptype = (*Fecode == OP_TYPEMINUPTO)? REPTYPE_MIN : REPTYPE_MAX;
+    Fecode += 1 + IMM2_SIZE;
+    goto REPEATTYPE;
+
+    case OP_TYPEPOSSTAR:
+    reptype = REPTYPE_POS;
+    Lmin = 0;
+    Lmax = UINT32_MAX;
+    Fecode++;
+    goto REPEATTYPE;
+
+    case OP_TYPEPOSPLUS:
+    reptype = REPTYPE_POS;
+    Lmin = 1;
+    Lmax = UINT32_MAX;
+    Fecode++;
+    goto REPEATTYPE;
+
+    case OP_TYPEPOSQUERY:
+    reptype = REPTYPE_POS;
+    Lmin = 0;
+    Lmax = 1;
+    Fecode++;
+    goto REPEATTYPE;
+
+    case OP_TYPEPOSUPTO:
+    reptype = REPTYPE_POS;
+    Lmin = 0;
+    Lmax = GET2(Fecode, 1);
+    Fecode += 1 + IMM2_SIZE;
+    goto REPEATTYPE;
+
+    case OP_TYPESTAR:
+    case OP_TYPEMINSTAR:
+    case OP_TYPEPLUS:
+    case OP_TYPEMINPLUS:
+    case OP_TYPEQUERY:
+    case OP_TYPEMINQUERY:
+    fc = *Fecode++ - OP_TYPESTAR;
+    Lmin = rep_min[fc];
+    Lmax = rep_max[fc];
+    reptype = rep_typ[fc];
+
+    /* Common code for all repeated character type matches. */
+
+    REPEATTYPE:
+    Lctype = *Fecode++;      /* Code for the character type */
+
+#ifdef SUPPORT_UNICODE
+    if (Lctype == OP_PROP || Lctype == OP_NOTPROP)
+      {
+      proptype = *Fecode++;
+      Lpropvalue = *Fecode++;
+      }
+    else proptype = -1;
+#endif
+
+    /* First, ensure the minimum number of matches are present. Use inline
+    code for maximizing the speed, and do the type test once at the start
+    (i.e. keep it out of the loop). The code for UTF mode is separated out for
+    tidiness, except for Unicode property tests. */
+
+    if (Lmin > 0)
+      {
+#ifdef SUPPORT_UNICODE
+      if (proptype >= 0)  /* Property tests in all modes */
+        {
+        switch(proptype)
+          {
+          case PT_ANY:
+          if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH);
+          for (i = 1; i <= Lmin; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            }
+          break;
+
+          case PT_LAMP:
+          for (i = 1; i <= Lmin; i++)
+            {
+            int chartype;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            chartype = UCD_CHARTYPE(fc);
+            if ((chartype == ucp_Lu ||
+                 chartype == ucp_Ll ||
+                 chartype == ucp_Lt) == (Lctype == OP_NOTPROP))
+              RRETURN(MATCH_NOMATCH);
+            }
+          break;
+
+          case PT_GC:
+          for (i = 1; i <= Lmin; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            if ((UCD_CATEGORY(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+              RRETURN(MATCH_NOMATCH);
+            }
+          break;
+
+          case PT_PC:
+          for (i = 1; i <= Lmin; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            if ((UCD_CHARTYPE(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+              RRETURN(MATCH_NOMATCH);
+            }
+          break;
+
+          case PT_SC:
+          for (i = 1; i <= Lmin; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            if ((UCD_SCRIPT(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+              RRETURN(MATCH_NOMATCH);
+            }
+          break;
+
+          case PT_ALNUM:
+          for (i = 1; i <= Lmin; i++)
+            {
+            int category;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            category = UCD_CATEGORY(fc);
+            if ((category == ucp_L || category == ucp_N) == (Lctype == OP_NOTPROP))
+              RRETURN(MATCH_NOMATCH);
+            }
+          break;
+
+          /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+          which means that Perl space and POSIX space are now identical. PCRE
+          was changed at release 8.34. */
+
+          case PT_SPACE:    /* Perl space */
+          case PT_PXSPACE:  /* POSIX space */
+          for (i = 1; i <= Lmin; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            switch(fc)
+              {
+              HSPACE_CASES:
+              VSPACE_CASES:
+              if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH);
+              break;
+
+              default:
+              if ((UCD_CATEGORY(fc) == ucp_Z) == (Lctype == OP_NOTPROP))
+                RRETURN(MATCH_NOMATCH);
+              break;
+              }
+            }
+          break;
+
+          case PT_WORD:
+          for (i = 1; i <= Lmin; i++)
+            {
+            int category;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            category = UCD_CATEGORY(fc);
+            if ((category == ucp_L || category == ucp_N ||
+                fc == CHAR_UNDERSCORE) == (Lctype == OP_NOTPROP))
+              RRETURN(MATCH_NOMATCH);
+            }
+          break;
+
+          case PT_CLIST:
+          for (i = 1; i <= Lmin; i++)
+            {
+            const uint32_t *cp;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            cp = PRIV(ucd_caseless_sets) + Lpropvalue;
+            for (;;)
+              {
+              if (fc < *cp)
+                {
+                if (Lctype == OP_NOTPROP) break;
+                RRETURN(MATCH_NOMATCH);
+                }
+              if (fc == *cp++)
+                {
+                if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH);
+                break;
+                }
+              }
+            }
+          break;
+
+          case PT_UCNC:
+          for (i = 1; i <= Lmin; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            if ((fc == CHAR_DOLLAR_SIGN || fc == CHAR_COMMERCIAL_AT ||
+                 fc == CHAR_GRAVE_ACCENT || (fc >= 0xa0 && fc <= 0xd7ff) ||
+                 fc >= 0xe000) == (Lctype == OP_NOTPROP))
+              RRETURN(MATCH_NOMATCH);
+            }
+          break;
+
+          /* This should not occur */
+
+          default:
+          return PCRE2_ERROR_INTERNAL;
+          }
+        }
+
+      /* Match extended Unicode sequences. We will get here only if the
+      support is in the binary; otherwise a compile-time error occurs. */
+
+      else if (Lctype == OP_EXTUNI)
+        {
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          else
+            {
+            GETCHARINCTEST(fc, Feptr);
+            Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject,
+              mb->end_subject, utf, NULL);
+            }
+          CHECK_PARTIAL();
+          }
+        }
+      else
+#endif     /* SUPPORT_UNICODE */
+
+/* Handle all other cases in UTF mode */
+
+#ifdef SUPPORT_UNICODE
+      if (utf) switch(Lctype)
+        {
+        case OP_ANY:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          if (IS_NEWLINE(Feptr)) RRETURN(MATCH_NOMATCH);
+          if (mb->partial != 0 &&
+              Feptr + 1 >= mb->end_subject &&
+              NLBLOCK->nltype == NLTYPE_FIXED &&
+              NLBLOCK->nllen == 2 &&
+              UCHAR21(Feptr) == NLBLOCK->nl[0])
+            {
+            mb->hitend = TRUE;
+            if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+            }
+          Feptr++;
+          ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++);
+          }
+        break;
+
+        case OP_ALLANY:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          Feptr++;
+          ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++);
+          }
+        break;
+
+        case OP_ANYBYTE:
+        if (Feptr > mb->end_subject - Lmin) RRETURN(MATCH_NOMATCH);
+        Feptr += Lmin;
+        break;
+
+        case OP_ANYNL:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          GETCHARINC(fc, Feptr);
+          switch(fc)
+            {
+            default: RRETURN(MATCH_NOMATCH);
+
+            case CHAR_CR:
+            if (Feptr < mb->end_subject && UCHAR21(Feptr) == CHAR_LF) Feptr++;
+            break;
+
+            case CHAR_LF:
+            break;
+
+            case CHAR_VT:
+            case CHAR_FF:
+            case CHAR_NEL:
+#ifndef EBCDIC
+            case 0x2028:
+            case 0x2029:
+#endif  /* Not EBCDIC */
+            if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH);
+            break;
+            }
+          }
+        break;
+
+        case OP_NOT_HSPACE:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          GETCHARINC(fc, Feptr);
+          switch(fc)
+            {
+            HSPACE_CASES: RRETURN(MATCH_NOMATCH);
+            default: break;
+            }
+          }
+        break;
+
+        case OP_HSPACE:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          GETCHARINC(fc, Feptr);
+          switch(fc)
+            {
+            HSPACE_CASES: break;
+            default: RRETURN(MATCH_NOMATCH);
+            }
+          }
+        break;
+
+        case OP_NOT_VSPACE:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          GETCHARINC(fc, Feptr);
+          switch(fc)
+            {
+            VSPACE_CASES: RRETURN(MATCH_NOMATCH);
+            default: break;
+            }
+          }
+        break;
+
+        case OP_VSPACE:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          GETCHARINC(fc, Feptr);
+          switch(fc)
+            {
+            VSPACE_CASES: break;
+            default: RRETURN(MATCH_NOMATCH);
+            }
+          }
+        break;
+
+        case OP_NOT_DIGIT:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          GETCHARINC(fc, Feptr);
+          if (fc < 128 && (mb->ctypes[fc] & ctype_digit) != 0)
+            RRETURN(MATCH_NOMATCH);
+          }
+        break;
+
+        case OP_DIGIT:
+        for (i = 1; i <= Lmin; i++)
+          {
+          uint32_t cc;
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          cc = UCHAR21(Feptr);
+          if (cc >= 128 || (mb->ctypes[cc] & ctype_digit) == 0)
+            RRETURN(MATCH_NOMATCH);
+          Feptr++;
+          /* No need to skip more code units - we know it has only one. */
+          }
+        break;
+
+        case OP_NOT_WHITESPACE:
+        for (i = 1; i <= Lmin; i++)
+          {
+          uint32_t cc;
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          cc = UCHAR21(Feptr);
+          if (cc < 128 && (mb->ctypes[cc] & ctype_space) != 0)
+            RRETURN(MATCH_NOMATCH);
+          Feptr++;
+          ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++);
+          }
+        break;
+
+        case OP_WHITESPACE:
+        for (i = 1; i <= Lmin; i++)
+          {
+          uint32_t cc;
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          cc = UCHAR21(Feptr);
+          if (cc >= 128 || (mb->ctypes[cc] & ctype_space) == 0)
+            RRETURN(MATCH_NOMATCH);
+          Feptr++;
+          /* No need to skip more code units - we know it has only one. */
+          }
+        break;
+
+        case OP_NOT_WORDCHAR:
+        for (i = 1; i <= Lmin; i++)
+          {
+          uint32_t cc;
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          cc = UCHAR21(Feptr);
+          if (cc < 128 && (mb->ctypes[cc] & ctype_word) != 0)
+            RRETURN(MATCH_NOMATCH);
+          Feptr++;
+          ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++);
+          }
+        break;
+
+        case OP_WORDCHAR:
+        for (i = 1; i <= Lmin; i++)
+          {
+          uint32_t cc;
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          cc = UCHAR21(Feptr);
+          if (cc >= 128 || (mb->ctypes[cc] & ctype_word) == 0)
+            RRETURN(MATCH_NOMATCH);
+          Feptr++;
+          /* No need to skip more code units - we know it has only one. */
+          }
+        break;
+
+        default:
+        return PCRE2_ERROR_INTERNAL;
+        }  /* End switch(Lctype) */
+
+      else
+#endif     /* SUPPORT_UNICODE */
+
+      /* Code for the non-UTF case for minimum matching of operators other
+      than OP_PROP and OP_NOTPROP. */
+
+      switch(Lctype)
+        {
+        case OP_ANY:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          if (IS_NEWLINE(Feptr)) RRETURN(MATCH_NOMATCH);
+          if (mb->partial != 0 &&
+              Feptr + 1 >= mb->end_subject &&
+              NLBLOCK->nltype == NLTYPE_FIXED &&
+              NLBLOCK->nllen == 2 &&
+              *Feptr == NLBLOCK->nl[0])
+            {
+            mb->hitend = TRUE;
+            if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+            }
+          Feptr++;
+          }
+        break;
+
+        case OP_ALLANY:
+        if (Feptr > mb->end_subject - Lmin)
+          {
+          SCHECK_PARTIAL();
+          RRETURN(MATCH_NOMATCH);
+          }
+        Feptr += Lmin;
+        break;
+
+        /* This OP_ANYBYTE case will never be reached because \C gets turned
+        into OP_ALLANY in non-UTF mode. Cut out the code so that coverage
+        reports don't complain about it's never being used. */
+
+/*        case OP_ANYBYTE:
+*        if (Feptr > mb->end_subject - Lmin)
+*          {
+*          SCHECK_PARTIAL();
+*          RRETURN(MATCH_NOMATCH);
+*          }
+*        Feptr += Lmin;
+*        break;
+*/
+        case OP_ANYNL:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          switch(*Feptr++)
+            {
+            default: RRETURN(MATCH_NOMATCH);
+
+            case CHAR_CR:
+            if (Feptr < mb->end_subject && *Feptr == CHAR_LF) Feptr++;
+            break;
+
+            case CHAR_LF:
+            break;
+
+            case CHAR_VT:
+            case CHAR_FF:
+            case CHAR_NEL:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+            case 0x2028:
+            case 0x2029:
+#endif
+            if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH);
+            break;
+            }
+          }
+        break;
+
+        case OP_NOT_HSPACE:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          switch(*Feptr++)
+            {
+            default: break;
+            HSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+            HSPACE_MULTIBYTE_CASES:
+#endif
+            RRETURN(MATCH_NOMATCH);
+            }
+          }
+        break;
+
+        case OP_HSPACE:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          switch(*Feptr++)
+            {
+            default: RRETURN(MATCH_NOMATCH);
+            HSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+            HSPACE_MULTIBYTE_CASES:
+#endif
+            break;
+            }
+          }
+        break;
+
+        case OP_NOT_VSPACE:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          switch(*Feptr++)
+            {
+            VSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+            VSPACE_MULTIBYTE_CASES:
+#endif
+            RRETURN(MATCH_NOMATCH);
+            default: break;
+            }
+          }
+        break;
+
+        case OP_VSPACE:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          switch(*Feptr++)
+            {
+            default: RRETURN(MATCH_NOMATCH);
+            VSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+            VSPACE_MULTIBYTE_CASES:
+#endif
+            break;
+            }
+          }
+        break;
+
+        case OP_NOT_DIGIT:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_digit) != 0)
+            RRETURN(MATCH_NOMATCH);
+          Feptr++;
+          }
+        break;
+
+        case OP_DIGIT:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_digit) == 0)
+            RRETURN(MATCH_NOMATCH);
+          Feptr++;
+          }
+        break;
+
+        case OP_NOT_WHITESPACE:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_space) != 0)
+            RRETURN(MATCH_NOMATCH);
+          Feptr++;
+          }
+        break;
+
+        case OP_WHITESPACE:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_space) == 0)
+            RRETURN(MATCH_NOMATCH);
+          Feptr++;
+          }
+        break;
+
+        case OP_NOT_WORDCHAR:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_word) != 0)
+            RRETURN(MATCH_NOMATCH);
+          Feptr++;
+          }
+        break;
+
+        case OP_WORDCHAR:
+        for (i = 1; i <= Lmin; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_word) == 0)
+            RRETURN(MATCH_NOMATCH);
+          Feptr++;
+          }
+        break;
+
+        default:
+        return PCRE2_ERROR_INTERNAL;
+        }
+      }
+
+    /* If Lmin = Lmax we are done. Continue with the main loop. */
+
+    if (Lmin == Lmax) continue;
+
+    /* If minimizing, we have to test the rest of the pattern before each
+    subsequent match. */
+
+    if (reptype == REPTYPE_MIN)
+      {
+#ifdef SUPPORT_UNICODE
+      if (proptype >= 0)
+        {
+        switch(proptype)
+          {
+          case PT_ANY:
+          for (;;)
+            {
+            RMATCH(Fecode, RM208);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH);
+            }
+          /* Control never gets here */
+
+          case PT_LAMP:
+          for (;;)
+            {
+            int chartype;
+            RMATCH(Fecode, RM209);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            chartype = UCD_CHARTYPE(fc);
+            if ((chartype == ucp_Lu ||
+                 chartype == ucp_Ll ||
+                 chartype == ucp_Lt) == (Lctype == OP_NOTPROP))
+              RRETURN(MATCH_NOMATCH);
+            }
+          /* Control never gets here */
+
+          case PT_GC:
+          for (;;)
+            {
+            RMATCH(Fecode, RM210);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            if ((UCD_CATEGORY(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+              RRETURN(MATCH_NOMATCH);
+            }
+          /* Control never gets here */
+
+          case PT_PC:
+          for (;;)
+            {
+            RMATCH(Fecode, RM211);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            if ((UCD_CHARTYPE(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+              RRETURN(MATCH_NOMATCH);
+            }
+          /* Control never gets here */
+
+          case PT_SC:
+          for (;;)
+            {
+            RMATCH(Fecode, RM212);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            if ((UCD_SCRIPT(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+              RRETURN(MATCH_NOMATCH);
+            }
+          /* Control never gets here */
+
+          case PT_ALNUM:
+          for (;;)
+            {
+            int category;
+            RMATCH(Fecode, RM213);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            category = UCD_CATEGORY(fc);
+            if ((category == ucp_L || category == ucp_N) ==
+                (Lctype == OP_NOTPROP))
+              RRETURN(MATCH_NOMATCH);
+            }
+          /* Control never gets here */
+
+          /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+          which means that Perl space and POSIX space are now identical. PCRE
+          was changed at release 8.34. */
+
+          case PT_SPACE:    /* Perl space */
+          case PT_PXSPACE:  /* POSIX space */
+          for (;;)
+            {
+            RMATCH(Fecode, RM214);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            switch(fc)
+              {
+              HSPACE_CASES:
+              VSPACE_CASES:
+              if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH);
+              break;
+
+              default:
+              if ((UCD_CATEGORY(fc) == ucp_Z) == (Lctype == OP_NOTPROP))
+                RRETURN(MATCH_NOMATCH);
+              break;
+              }
+            }
+          /* Control never gets here */
+
+          case PT_WORD:
+          for (;;)
+            {
+            int category;
+            RMATCH(Fecode, RM215);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            category = UCD_CATEGORY(fc);
+            if ((category == ucp_L ||
+                 category == ucp_N ||
+                 fc == CHAR_UNDERSCORE) == (Lctype == OP_NOTPROP))
+              RRETURN(MATCH_NOMATCH);
+            }
+          /* Control never gets here */
+
+          case PT_CLIST:
+          for (;;)
+            {
+            const uint32_t *cp;
+            RMATCH(Fecode, RM216);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            cp = PRIV(ucd_caseless_sets) + Lpropvalue;
+            for (;;)
+              {
+              if (fc < *cp)
+                {
+                if (Lctype == OP_NOTPROP) break;
+                RRETURN(MATCH_NOMATCH);
+                }
+              if (fc == *cp++)
+                {
+                if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH);
+                break;
+                }
+              }
+            }
+          /* Control never gets here */
+
+          case PT_UCNC:
+          for (;;)
+            {
+            RMATCH(Fecode, RM217);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              RRETURN(MATCH_NOMATCH);
+              }
+            GETCHARINCTEST(fc, Feptr);
+            if ((fc == CHAR_DOLLAR_SIGN || fc == CHAR_COMMERCIAL_AT ||
+                 fc == CHAR_GRAVE_ACCENT || (fc >= 0xa0 && fc <= 0xd7ff) ||
+                 fc >= 0xe000) == (Lctype == OP_NOTPROP))
+              RRETURN(MATCH_NOMATCH);
+            }
+          /* Control never gets here */
+
+          /* This should never occur */
+          default:
+          return PCRE2_ERROR_INTERNAL;
+          }
+        }
+
+      /* Match extended Unicode sequences. We will get here only if the
+      support is in the binary; otherwise a compile-time error occurs. */
+
+      else if (Lctype == OP_EXTUNI)
+        {
+        for (;;)
+          {
+          RMATCH(Fecode, RM218);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          else
+            {
+            GETCHARINCTEST(fc, Feptr);
+            Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject,
+              utf, NULL);
+            }
+          CHECK_PARTIAL();
+          }
+        }
+      else
+#endif     /* SUPPORT_UNICODE */
+
+      /* UTF mode for non-property testing character types. */
+
+#ifdef SUPPORT_UNICODE
+      if (utf)
+        {
+        for (;;)
+          {
+          RMATCH(Fecode, RM219);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          if (Lctype == OP_ANY && IS_NEWLINE(Feptr)) RRETURN(MATCH_NOMATCH);
+          GETCHARINC(fc, Feptr);
+          switch(Lctype)
+            {
+            case OP_ANY:               /* This is the non-NL case */
+            if (mb->partial != 0 &&    /* Take care with CRLF partial */
+                Feptr >= mb->end_subject &&
+                NLBLOCK->nltype == NLTYPE_FIXED &&
+                NLBLOCK->nllen == 2 &&
+                fc == NLBLOCK->nl[0])
+              {
+              mb->hitend = TRUE;
+              if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+              }
+            break;
+
+            case OP_ALLANY:
+            case OP_ANYBYTE:
+            break;
+
+            case OP_ANYNL:
+            switch(fc)
+              {
+              default: RRETURN(MATCH_NOMATCH);
+
+              case CHAR_CR:
+              if (Feptr < mb->end_subject && UCHAR21(Feptr) == CHAR_LF) Feptr++;
+              break;
+
+              case CHAR_LF:
+              break;
+
+              case CHAR_VT:
+              case CHAR_FF:
+              case CHAR_NEL:
+#ifndef EBCDIC
+              case 0x2028:
+              case 0x2029:
+#endif  /* Not EBCDIC */
+              if (mb->bsr_convention == PCRE2_BSR_ANYCRLF)
+                RRETURN(MATCH_NOMATCH);
+              break;
+              }
+            break;
+
+            case OP_NOT_HSPACE:
+            switch(fc)
+              {
+              HSPACE_CASES: RRETURN(MATCH_NOMATCH);
+              default: break;
+              }
+            break;
+
+            case OP_HSPACE:
+            switch(fc)
+              {
+              HSPACE_CASES: break;
+              default: RRETURN(MATCH_NOMATCH);
+              }
+            break;
+
+            case OP_NOT_VSPACE:
+            switch(fc)
+              {
+              VSPACE_CASES: RRETURN(MATCH_NOMATCH);
+              default: break;
+              }
+            break;
+
+            case OP_VSPACE:
+            switch(fc)
+              {
+              VSPACE_CASES: break;
+              default: RRETURN(MATCH_NOMATCH);
+              }
+            break;
+
+            case OP_NOT_DIGIT:
+            if (fc < 256 && (mb->ctypes[fc] & ctype_digit) != 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_DIGIT:
+            if (fc >= 256 || (mb->ctypes[fc] & ctype_digit) == 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_NOT_WHITESPACE:
+            if (fc < 256 && (mb->ctypes[fc] & ctype_space) != 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_WHITESPACE:
+            if (fc >= 256 || (mb->ctypes[fc] & ctype_space) == 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_NOT_WORDCHAR:
+            if (fc < 256 && (mb->ctypes[fc] & ctype_word) != 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_WORDCHAR:
+            if (fc >= 256 || (mb->ctypes[fc] & ctype_word) == 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            default:
+            return PCRE2_ERROR_INTERNAL;
+            }
+          }
+        }
+      else
+#endif  /* SUPPORT_UNICODE */
+
+      /* Not UTF mode */
+        {
+        for (;;)
+          {
+          RMATCH(Fecode, RM33);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            RRETURN(MATCH_NOMATCH);
+            }
+          if (Lctype == OP_ANY && IS_NEWLINE(Feptr))
+            RRETURN(MATCH_NOMATCH);
+          fc = *Feptr++;
+          switch(Lctype)
+            {
+            case OP_ANY:               /* This is the non-NL case */
+            if (mb->partial != 0 &&    /* Take care with CRLF partial */
+                Feptr >= mb->end_subject &&
+                NLBLOCK->nltype == NLTYPE_FIXED &&
+                NLBLOCK->nllen == 2 &&
+                fc == NLBLOCK->nl[0])
+              {
+              mb->hitend = TRUE;
+              if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+              }
+            break;
+
+            case OP_ALLANY:
+            case OP_ANYBYTE:
+            break;
+
+            case OP_ANYNL:
+            switch(fc)
+              {
+              default: RRETURN(MATCH_NOMATCH);
+
+              case CHAR_CR:
+              if (Feptr < mb->end_subject && *Feptr == CHAR_LF) Feptr++;
+              break;
+
+              case CHAR_LF:
+              break;
+
+              case CHAR_VT:
+              case CHAR_FF:
+              case CHAR_NEL:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+              case 0x2028:
+              case 0x2029:
+#endif
+              if (mb->bsr_convention == PCRE2_BSR_ANYCRLF)
+                RRETURN(MATCH_NOMATCH);
+              break;
+              }
+            break;
+
+            case OP_NOT_HSPACE:
+            switch(fc)
+              {
+              default: break;
+              HSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+              HSPACE_MULTIBYTE_CASES:
+#endif
+              RRETURN(MATCH_NOMATCH);
+              }
+            break;
+
+            case OP_HSPACE:
+            switch(fc)
+              {
+              default: RRETURN(MATCH_NOMATCH);
+              HSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+              HSPACE_MULTIBYTE_CASES:
+#endif
+              break;
+              }
+            break;
+
+            case OP_NOT_VSPACE:
+            switch(fc)
+              {
+              default: break;
+              VSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+              VSPACE_MULTIBYTE_CASES:
+#endif
+              RRETURN(MATCH_NOMATCH);
+              }
+            break;
+
+            case OP_VSPACE:
+            switch(fc)
+              {
+              default: RRETURN(MATCH_NOMATCH);
+              VSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+              VSPACE_MULTIBYTE_CASES:
+#endif
+              break;
+              }
+            break;
+
+            case OP_NOT_DIGIT:
+            if (MAX_255(fc) && (mb->ctypes[fc] & ctype_digit) != 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_DIGIT:
+            if (!MAX_255(fc) || (mb->ctypes[fc] & ctype_digit) == 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_NOT_WHITESPACE:
+            if (MAX_255(fc) && (mb->ctypes[fc] & ctype_space) != 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_WHITESPACE:
+            if (!MAX_255(fc) || (mb->ctypes[fc] & ctype_space) == 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_NOT_WORDCHAR:
+            if (MAX_255(fc) && (mb->ctypes[fc] & ctype_word) != 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_WORDCHAR:
+            if (!MAX_255(fc) || (mb->ctypes[fc] & ctype_word) == 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            default:
+            return PCRE2_ERROR_INTERNAL;
+            }
+          }
+        }
+      /* Control never gets here */
+      }
+
+    /* If maximizing, it is worth using inline code for speed, doing the type
+    test once at the start (i.e. keep it out of the loop). */
+
+    else
+      {
+      Lstart_eptr = Feptr;  /* Remember where we started */
+
+#ifdef SUPPORT_UNICODE
+      if (proptype >= 0)
+        {
+        switch(proptype)
+          {
+          case PT_ANY:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLENTEST(fc, Feptr, len);
+            if (Lctype == OP_NOTPROP) break;
+            Feptr+= len;
+            }
+          break;
+
+          case PT_LAMP:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int chartype;
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLENTEST(fc, Feptr, len);
+            chartype = UCD_CHARTYPE(fc);
+            if ((chartype == ucp_Lu ||
+                 chartype == ucp_Ll ||
+                 chartype == ucp_Lt) == (Lctype == OP_NOTPROP))
+              break;
+            Feptr+= len;
+            }
+          break;
+
+          case PT_GC:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLENTEST(fc, Feptr, len);
+            if ((UCD_CATEGORY(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+              break;
+            Feptr+= len;
+            }
+          break;
+
+          case PT_PC:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLENTEST(fc, Feptr, len);
+            if ((UCD_CHARTYPE(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+              break;
+            Feptr+= len;
+            }
+          break;
+
+          case PT_SC:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLENTEST(fc, Feptr, len);
+            if ((UCD_SCRIPT(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+              break;
+            Feptr+= len;
+            }
+          break;
+
+          case PT_ALNUM:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int category;
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLENTEST(fc, Feptr, len);
+            category = UCD_CATEGORY(fc);
+            if ((category == ucp_L || category == ucp_N) ==
+                (Lctype == OP_NOTPROP))
+              break;
+            Feptr+= len;
+            }
+          break;
+
+          /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+          which means that Perl space and POSIX space are now identical. PCRE
+          was changed at release 8.34. */
+
+          case PT_SPACE:    /* Perl space */
+          case PT_PXSPACE:  /* POSIX space */
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLENTEST(fc, Feptr, len);
+            switch(fc)
+              {
+              HSPACE_CASES:
+              VSPACE_CASES:
+              if (Lctype == OP_NOTPROP) goto ENDLOOP99;  /* Break the loop */
+              break;
+
+              default:
+              if ((UCD_CATEGORY(fc) == ucp_Z) == (Lctype == OP_NOTPROP))
+                goto ENDLOOP99;   /* Break the loop */
+              break;
+              }
+            Feptr+= len;
+            }
+          ENDLOOP99:
+          break;
+
+          case PT_WORD:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int category;
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLENTEST(fc, Feptr, len);
+            category = UCD_CATEGORY(fc);
+            if ((category == ucp_L || category == ucp_N ||
+                 fc == CHAR_UNDERSCORE) == (Lctype == OP_NOTPROP))
+              break;
+            Feptr+= len;
+            }
+          break;
+
+          case PT_CLIST:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            const uint32_t *cp;
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLENTEST(fc, Feptr, len);
+            cp = PRIV(ucd_caseless_sets) + Lpropvalue;
+            for (;;)
+              {
+              if (fc < *cp)
+                { if (Lctype == OP_NOTPROP) break; else goto GOT_MAX; }
+              if (fc == *cp++)
+                { if (Lctype == OP_NOTPROP) goto GOT_MAX; else break; }
+              }
+            Feptr += len;
+            }
+          GOT_MAX:
+          break;
+
+          case PT_UCNC:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLENTEST(fc, Feptr, len);
+            if ((fc == CHAR_DOLLAR_SIGN || fc == CHAR_COMMERCIAL_AT ||
+                 fc == CHAR_GRAVE_ACCENT || (fc >= 0xa0 && fc <= 0xd7ff) ||
+                 fc >= 0xe000) == (Lctype == OP_NOTPROP))
+              break;
+            Feptr += len;
+            }
+          break;
+
+          default:
+          return PCRE2_ERROR_INTERNAL;
+          }
+
+        /* Feptr is now past the end of the maximum run */
+
+        if (reptype == REPTYPE_POS) continue;    /* No backtracking */
+
+        /* After \C in UTF mode, Lstart_eptr might be in the middle of a
+        Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't
+        go too far. */
+
+        for(;;)
+          {
+          if (Feptr <= Lstart_eptr) break;
+          RMATCH(Fecode, RM222);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          Feptr--;
+          if (utf) BACKCHAR(Feptr);
+          }
+        }
+
+      /* Match extended Unicode grapheme clusters. We will get here only if the
+      support is in the binary; otherwise a compile-time error occurs. */
+
+      else if (Lctype == OP_EXTUNI)
+        {
+        for (i = Lmin; i < Lmax; i++)
+          {
+          if (Feptr >= mb->end_subject)
+            {
+            SCHECK_PARTIAL();
+            break;
+            }
+          else
+            {
+            GETCHARINCTEST(fc, Feptr);
+            Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject,
+              utf, NULL);
+            }
+          CHECK_PARTIAL();
+          }
+
+        /* Feptr is now past the end of the maximum run */
+
+        if (reptype == REPTYPE_POS) continue;    /* No backtracking */
+
+        /* We use <= Lstart_eptr rather than == Lstart_eptr to detect the start
+        of the run while backtracking because the use of \C in UTF mode can
+        cause BACKCHAR to move back past Lstart_eptr. This is just palliative;
+        the use of \C in UTF mode is fraught with danger. */
+
+        for(;;)
+          {
+          int lgb, rgb;
+          PCRE2_SPTR fptr;
+
+          if (Feptr <= Lstart_eptr) break;   /* At start of char run */
+          RMATCH(Fecode, RM220);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+
+          /* Backtracking over an extended grapheme cluster involves inspecting
+          the previous two characters (if present) to see if a break is
+          permitted between them. */
+
+          Feptr--;
+          if (!utf) fc = *Feptr; else
+            {
+            BACKCHAR(Feptr);
+            GETCHAR(fc, Feptr);
+            }
+          rgb = UCD_GRAPHBREAK(fc);
+
+          for (;;)
+            {
+            if (Feptr <= Lstart_eptr) break;   /* At start of char run */
+            fptr = Feptr - 1;
+            if (!utf) fc = *fptr; else
+              {
+              BACKCHAR(fptr);
+              GETCHAR(fc, fptr);
+              }
+            lgb = UCD_GRAPHBREAK(fc);
+            if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break;
+            Feptr = fptr;
+            rgb = lgb;
+            }
+          }
+        }
+
+      else
+#endif   /* SUPPORT_UNICODE */
+
+#ifdef SUPPORT_UNICODE
+      if (utf)
+        {
+        switch(Lctype)
+          {
+          case OP_ANY:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            if (IS_NEWLINE(Feptr)) break;
+            if (mb->partial != 0 &&    /* Take care with CRLF partial */
+                Feptr + 1 >= mb->end_subject &&
+                NLBLOCK->nltype == NLTYPE_FIXED &&
+                NLBLOCK->nllen == 2 &&
+                UCHAR21(Feptr) == NLBLOCK->nl[0])
+              {
+              mb->hitend = TRUE;
+              if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+              }
+            Feptr++;
+            ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++);
+            }
+          break;
+
+          case OP_ALLANY:
+          if (Lmax < UINT32_MAX)
+            {
+            for (i = Lmin; i < Lmax; i++)
+              {
+              if (Feptr >= mb->end_subject)
+                {
+                SCHECK_PARTIAL();
+                break;
+                }
+              Feptr++;
+              ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++);
+              }
+            }
+          else
+            {
+            Feptr = mb->end_subject;   /* Unlimited UTF-8 repeat */
+            SCHECK_PARTIAL();
+            }
+          break;
+
+          /* The "byte" (i.e. "code unit") case is the same as non-UTF */
+
+          case OP_ANYBYTE:
+          fc = Lmax - Lmin;
+          if (fc > (uint32_t)(mb->end_subject - Feptr))
+            {
+            Feptr = mb->end_subject;
+            SCHECK_PARTIAL();
+            }
+          else Feptr += fc;
+          break;
+
+          case OP_ANYNL:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLEN(fc, Feptr, len);
+            if (fc == CHAR_CR)
+              {
+              if (++Feptr >= mb->end_subject) break;
+              if (UCHAR21(Feptr) == CHAR_LF) Feptr++;
+              }
+            else
+              {
+              if (fc != CHAR_LF &&
+                  (mb->bsr_convention == PCRE2_BSR_ANYCRLF ||
+                   (fc != CHAR_VT && fc != CHAR_FF && fc != CHAR_NEL
+#ifndef EBCDIC
+                    && fc != 0x2028 && fc != 0x2029
+#endif  /* Not EBCDIC */
+                    )))
+                break;
+              Feptr += len;
+              }
+            }
+          break;
+
+          case OP_NOT_HSPACE:
+          case OP_HSPACE:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            BOOL gotspace;
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLEN(fc, Feptr, len);
+            switch(fc)
+              {
+              HSPACE_CASES: gotspace = TRUE; break;
+              default: gotspace = FALSE; break;
+              }
+            if (gotspace == (Lctype == OP_NOT_HSPACE)) break;
+            Feptr += len;
+            }
+          break;
+
+          case OP_NOT_VSPACE:
+          case OP_VSPACE:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            BOOL gotspace;
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLEN(fc, Feptr, len);
+            switch(fc)
+              {
+              VSPACE_CASES: gotspace = TRUE; break;
+              default: gotspace = FALSE; break;
+              }
+            if (gotspace == (Lctype == OP_NOT_VSPACE)) break;
+            Feptr += len;
+            }
+          break;
+
+          case OP_NOT_DIGIT:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLEN(fc, Feptr, len);
+            if (fc < 256 && (mb->ctypes[fc] & ctype_digit) != 0) break;
+            Feptr+= len;
+            }
+          break;
+
+          case OP_DIGIT:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLEN(fc, Feptr, len);
+            if (fc >= 256 ||(mb->ctypes[fc] & ctype_digit) == 0) break;
+            Feptr+= len;
+            }
+          break;
+
+          case OP_NOT_WHITESPACE:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLEN(fc, Feptr, len);
+            if (fc < 256 && (mb->ctypes[fc] & ctype_space) != 0) break;
+            Feptr+= len;
+            }
+          break;
+
+          case OP_WHITESPACE:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLEN(fc, Feptr, len);
+            if (fc >= 256 ||(mb->ctypes[fc] & ctype_space) == 0) break;
+            Feptr+= len;
+            }
+          break;
+
+          case OP_NOT_WORDCHAR:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLEN(fc, Feptr, len);
+            if (fc < 256 && (mb->ctypes[fc] & ctype_word) != 0) break;
+            Feptr+= len;
+            }
+          break;
+
+          case OP_WORDCHAR:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            int len = 1;
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            GETCHARLEN(fc, Feptr, len);
+            if (fc >= 256 || (mb->ctypes[fc] & ctype_word) == 0) break;
+            Feptr+= len;
+            }
+          break;
+
+          default:
+          return PCRE2_ERROR_INTERNAL;
+          }
+
+        if (reptype == REPTYPE_POS) continue;    /* No backtracking */
+
+        /* After \C in UTF mode, Lstart_eptr might be in the middle of a
+        Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't go
+        too far. */
+
+        for(;;)
+          {
+          if (Feptr <= Lstart_eptr) break;
+          RMATCH(Fecode, RM221);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          Feptr--;
+          BACKCHAR(Feptr);
+          if (Lctype == OP_ANYNL && Feptr > Lstart_eptr &&
+              UCHAR21(Feptr) == CHAR_NL && UCHAR21(Feptr - 1) == CHAR_CR)
+            Feptr--;
+          }
+        }
+      else
+#endif  /* SUPPORT_UNICODE */
+
+      /* Not UTF mode */
+        {
+        switch(Lctype)
+          {
+          case OP_ANY:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            if (IS_NEWLINE(Feptr)) break;
+            if (mb->partial != 0 &&    /* Take care with CRLF partial */
+                Feptr + 1 >= mb->end_subject &&
+                NLBLOCK->nltype == NLTYPE_FIXED &&
+                NLBLOCK->nllen == 2 &&
+                *Feptr == NLBLOCK->nl[0])
+              {
+              mb->hitend = TRUE;
+              if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+              }
+            Feptr++;
+            }
+          break;
+
+          case OP_ALLANY:
+          case OP_ANYBYTE:
+          fc = Lmax - Lmin;
+          if (fc > (uint32_t)(mb->end_subject - Feptr))
+            {
+            Feptr = mb->end_subject;
+            SCHECK_PARTIAL();
+            }
+          else Feptr += fc;
+          break;
+
+          case OP_ANYNL:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            fc = *Feptr;
+            if (fc == CHAR_CR)
+              {
+              if (++Feptr >= mb->end_subject) break;
+              if (*Feptr == CHAR_LF) Feptr++;
+              }
+            else
+              {
+              if (fc != CHAR_LF && (mb->bsr_convention == PCRE2_BSR_ANYCRLF ||
+                 (fc != CHAR_VT && fc != CHAR_FF && fc != CHAR_NEL
+#if PCRE2_CODE_UNIT_WIDTH != 8
+                 && fc != 0x2028 && fc != 0x2029
+#endif
+                 ))) break;
+              Feptr++;
+              }
+            }
+          break;
+
+          case OP_NOT_HSPACE:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            switch(*Feptr)
+              {
+              default: Feptr++; break;
+              HSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+              HSPACE_MULTIBYTE_CASES:
+#endif
+              goto ENDLOOP00;
+              }
+            }
+          ENDLOOP00:
+          break;
+
+          case OP_HSPACE:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            switch(*Feptr)
+              {
+              default: goto ENDLOOP01;
+              HSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+              HSPACE_MULTIBYTE_CASES:
+#endif
+              Feptr++; break;
+              }
+            }
+          ENDLOOP01:
+          break;
+
+          case OP_NOT_VSPACE:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            switch(*Feptr)
+              {
+              default: Feptr++; break;
+              VSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+              VSPACE_MULTIBYTE_CASES:
+#endif
+              goto ENDLOOP02;
+              }
+            }
+          ENDLOOP02:
+          break;
+
+          case OP_VSPACE:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            switch(*Feptr)
+              {
+              default: goto ENDLOOP03;
+              VSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+              VSPACE_MULTIBYTE_CASES:
+#endif
+              Feptr++; break;
+              }
+            }
+          ENDLOOP03:
+          break;
+
+          case OP_NOT_DIGIT:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_digit) != 0)
+              break;
+            Feptr++;
+            }
+          break;
+
+          case OP_DIGIT:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_digit) == 0)
+              break;
+            Feptr++;
+            }
+          break;
+
+          case OP_NOT_WHITESPACE:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_space) != 0)
+              break;
+            Feptr++;
+            }
+          break;
+
+          case OP_WHITESPACE:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_space) == 0)
+              break;
+            Feptr++;
+            }
+          break;
+
+          case OP_NOT_WORDCHAR:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_word) != 0)
+              break;
+            Feptr++;
+            }
+          break;
+
+          case OP_WORDCHAR:
+          for (i = Lmin; i < Lmax; i++)
+            {
+            if (Feptr >= mb->end_subject)
+              {
+              SCHECK_PARTIAL();
+              break;
+              }
+            if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_word) == 0)
+              break;
+            Feptr++;
+            }
+          break;
+
+          default:
+          return PCRE2_ERROR_INTERNAL;
+          }
+
+        if (reptype == REPTYPE_POS) continue;    /* No backtracking */
+
+        for (;;)
+          {
+          if (Feptr == Lstart_eptr) break;
+          RMATCH(Fecode, RM34);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          Feptr--;
+          if (Lctype == OP_ANYNL && Feptr > Lstart_eptr && *Feptr == CHAR_LF &&
+              Feptr[-1] == CHAR_CR) Feptr--;
+          }
+        }
+      }
+    break;  /* End of repeat character type processing */
+
+#undef Lstart_eptr
+#undef Lmin
+#undef Lmax
+#undef Lctype
+#undef Lpropvalue
+
+
+    /* ===================================================================== */
+    /* Match a back reference, possibly repeatedly. Look past the end of the
+    item to see if there is repeat information following. The OP_REF and
+    OP_REFI opcodes are used for a reference to a numbered group or to a
+    non-duplicated named group. For a duplicated named group, OP_DNREF and
+    OP_DNREFI are used. In this case we must scan the list of groups to which
+    the name refers, and use the first one that is set. */
+
+#define Lmin      F->temp_32[0]
+#define Lmax      F->temp_32[1]
+#define Lcaseless F->temp_32[2]
+#define Lstart    F->temp_sptr[0]
+#define Loffset   F->temp_size
+
+    case OP_DNREF:
+    case OP_DNREFI:
+    Lcaseless = (Fop == OP_DNREFI);
+      {
+      int count = GET2(Fecode, 1+IMM2_SIZE);
+      PCRE2_SPTR slot = mb->name_table + GET2(Fecode, 1) * mb->name_entry_size;
+      Fecode += 1 + 2*IMM2_SIZE;
+
+      while (count-- > 0)
+        {
+        Loffset = (GET2(slot, 0) << 1) - 2;
+        if (Loffset < Foffset_top && Fovector[Loffset] != PCRE2_UNSET) break;
+        slot += mb->name_entry_size;
+        }
+      }
+    goto REF_REPEAT;
+
+    case OP_REF:
+    case OP_REFI:
+    Lcaseless = (Fop == OP_REFI);
+    Loffset = (GET2(Fecode, 1) << 1) - 2;
+    Fecode += 1 + IMM2_SIZE;
+
+    /* Set up for repetition, or handle the non-repeated case. The maximum and
+    minimum must be in the heap frame, but as they are short-term values, we
+    use temporary fields. */
+
+    REF_REPEAT:
+    switch (*Fecode)
+      {
+      case OP_CRSTAR:
+      case OP_CRMINSTAR:
+      case OP_CRPLUS:
+      case OP_CRMINPLUS:
+      case OP_CRQUERY:
+      case OP_CRMINQUERY:
+      fc = *Fecode++ - OP_CRSTAR;
+      Lmin = rep_min[fc];
+      Lmax = rep_max[fc];
+      reptype = rep_typ[fc];
+      break;
+
+      case OP_CRRANGE:
+      case OP_CRMINRANGE:
+      Lmin = GET2(Fecode, 1);
+      Lmax = GET2(Fecode, 1 + IMM2_SIZE);
+      reptype = rep_typ[*Fecode - OP_CRSTAR];
+      if (Lmax == 0) Lmax = UINT32_MAX;  /* Max 0 => infinity */
+      Fecode += 1 + 2 * IMM2_SIZE;
+      break;
+
+      default:                  /* No repeat follows */
+        {
+        rrc = match_ref(Loffset, Lcaseless, F, mb, &length);
+        if (rrc != 0)
+          {
+          if (rrc > 0) Feptr = mb->end_subject;   /* Partial match */
+          CHECK_PARTIAL();
+          RRETURN(MATCH_NOMATCH);
+          }
+        }
+      Feptr += length;
+      continue;              /* With the main loop */
+      }
+
+    /* Handle repeated back references. If a set group has length zero, just
+    continue with the main loop, because it matches however many times. For an
+    unset reference, if the minimum is zero, we can also just continue. We can
+    also continue if PCRE2_MATCH_UNSET_BACKREF is set, because this makes unset
+    group behave as a zero-length group. For any other unset cases, carrying
+    on will result in NOMATCH. */
+
+    if (Loffset < Foffset_top && Fovector[Loffset] != PCRE2_UNSET)
+      {
+      if (Fovector[Loffset] == Fovector[Loffset + 1]) continue;
+      }
+    else  /* Group is not set */
+      {
+      if (Lmin == 0 || (mb->poptions & PCRE2_MATCH_UNSET_BACKREF) != 0)
+        continue;
+      }
+
+    /* First, ensure the minimum number of matches are present. */
+
+    for (i = 1; i <= Lmin; i++)
+      {
+      PCRE2_SIZE slength;
+      rrc = match_ref(Loffset, Lcaseless, F, mb, &slength);
+      if (rrc != 0)
+        {
+        if (rrc > 0) Feptr = mb->end_subject;   /* Partial match */
+        CHECK_PARTIAL();
+        RRETURN(MATCH_NOMATCH);
+        }
+      Feptr += slength;
+      }
+
+    /* If min = max, we are done. They are not both allowed to be zero. */
+
+    if (Lmin == Lmax) continue;
+
+    /* If minimizing, keep trying and advancing the pointer. */
+
+    if (reptype == REPTYPE_MIN)
+      {
+      for (;;)
+        {
+        PCRE2_SIZE slength;
+        RMATCH(Fecode, RM20);
+        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+        if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+        rrc = match_ref(Loffset, Lcaseless, F, mb, &slength);
+        if (rrc != 0)
+          {
+          if (rrc > 0) Feptr = mb->end_subject;   /* Partial match */
+          CHECK_PARTIAL();
+          RRETURN(MATCH_NOMATCH);
+          }
+        Feptr += slength;
+        }
+      /* Control never gets here */
+      }
+
+    /* If maximizing, find the longest string and work backwards, as long as
+    the matched lengths for each iteration are the same. */
+
+    else
+      {
+      BOOL samelengths = TRUE;
+      Lstart = Feptr;     /* Starting position */
+      Flength = Fovector[Loffset+1] - Fovector[Loffset];
+
+      for (i = Lmin; i < Lmax; i++)
+        {
+        PCRE2_SIZE slength;
+        rrc = match_ref(Loffset, Lcaseless, F, mb, &slength);
+        if (rrc != 0)
+          {
+          /* Can't use CHECK_PARTIAL because we don't want to update Feptr in
+          the soft partial matching case. */
+
+          if (rrc > 0 && mb->partial != 0 &&
+              mb->end_subject > mb->start_used_ptr)
+            {
+            mb->hitend = TRUE;
+            if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+            }
+          break;
+          }
+
+        if (slength != Flength) samelengths = FALSE;
+        Feptr += slength;
+        }
+
+      /* If the length matched for each repetition is the same as the length of
+      the captured group, we can easily work backwards. This is the normal
+      case. However, in caseless UTF-8 mode there are pairs of case-equivalent
+      characters whose lengths (in terms of code units) differ. However, this
+      is very rare, so we handle it by re-matching fewer and fewer times. */
+
+      if (samelengths)
+        {
+        while (Feptr >= Lstart)
+          {
+          RMATCH(Fecode, RM21);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          Feptr -= Flength;
+          }
+        }
+
+      /* The rare case of non-matching lengths. Re-scan the repetition for each
+      iteration. We know that match_ref() will succeed every time. */
+
+      else
+        {
+        Lmax = i;
+        for (;;)
+          {
+          RMATCH(Fecode, RM22);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (Feptr == Lstart) break; /* Failed after minimal repetition */
+          Feptr = Lstart;
+          Lmax--;
+          for (i = Lmin; i < Lmax; i++)
+            {
+            PCRE2_SIZE slength;
+            (void)match_ref(Loffset, Lcaseless, F, mb, &slength);
+            Feptr += slength;
+            }
+          }
+        }
+
+      RRETURN(MATCH_NOMATCH);
+      }
+    /* Control never gets here */
+
+#undef Lcaseless
+#undef Lmin
+#undef Lmax
+#undef Lstart
+#undef Loffset
+
+
+
+/* ========================================================================= */
+/*           Opcodes for the start of various parenthesized items            */
+/* ========================================================================= */
+
+    /* In all cases, if the result of RMATCH() is MATCH_THEN, check whether the
+    (*THEN) is within the current branch by comparing the address of OP_THEN
+    that is passed back with the end of the branch. If (*THEN) is within the
+    current branch, and the branch is one of two or more alternatives (it
+    either starts or ends with OP_ALT), we have reached the limit of THEN's
+    action, so convert the return code to NOMATCH, which will cause normal
+    backtracking to happen from now on. Otherwise, THEN is passed back to an
+    outer alternative. This implements Perl's treatment of parenthesized
+    groups, where a group not containing | does not affect the current
+    alternative, that is, (X) is NOT the same as (X|(*F)). */
+
+
+    /* ===================================================================== */
+    /* BRAZERO, BRAMINZERO and SKIPZERO occur just before a non-possessive
+    bracket group, indicating that it may occur zero times. It may repeat
+    infinitely, or not at all - i.e. it could be ()* or ()? or even (){0} in
+    the pattern. Brackets with fixed upper repeat limits are compiled as a
+    number of copies, with the optional ones preceded by BRAZERO or BRAMINZERO.
+    Possessive groups with possible zero repeats are preceded by BRAPOSZERO. */
+
+#define Lnext_ecode F->temp_sptr[0]
+
+    case OP_BRAZERO:
+    Lnext_ecode = Fecode + 1;
+    RMATCH(Lnext_ecode, RM9);
+    if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+    do Lnext_ecode += GET(Lnext_ecode, 1); while (*Lnext_ecode == OP_ALT);
+    Fecode = Lnext_ecode + 1 + LINK_SIZE;
+    break;
+
+    case OP_BRAMINZERO:
+    Lnext_ecode = Fecode + 1;
+    do Lnext_ecode += GET(Lnext_ecode, 1); while (*Lnext_ecode == OP_ALT);
+    RMATCH(Lnext_ecode + 1 + LINK_SIZE, RM10);
+    if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+    Fecode++;
+    break;
+
+#undef Lnext_ecode
+
+    case OP_SKIPZERO:
+    Fecode++;
+    do Fecode += GET(Fecode,1); while (*Fecode == OP_ALT);
+    Fecode += 1 + LINK_SIZE;
+    break;
+
+
+    /* ===================================================================== */
+    /* Handle possessive brackets with an unlimited repeat. The end of these
+    brackets will always be OP_KETRPOS, which returns MATCH_KETRPOS without
+    going further in the pattern. */
+
+#define Lframe_type    F->temp_32[0]
+#define Lmatched_once  F->temp_32[1]
+#define Lzero_allowed  F->temp_32[2]
+#define Lstart_eptr    F->temp_sptr[0]
+#define Lstart_group   F->temp_sptr[1]
+
+    case OP_BRAPOSZERO:
+    Lzero_allowed = TRUE;                /* Zero repeat is allowed */
+    Fecode += 1;
+    if (*Fecode == OP_CBRAPOS || *Fecode == OP_SCBRAPOS)
+      goto POSSESSIVE_CAPTURE;
+    goto POSSESSIVE_NON_CAPTURE;
+
+    case OP_BRAPOS:
+    case OP_SBRAPOS:
+    Lzero_allowed = FALSE;               /* Zero repeat not allowed */
+
+    POSSESSIVE_NON_CAPTURE:
+    Lframe_type = GF_NOCAPTURE;          /* Remembered frame type */
+    goto POSSESSIVE_GROUP;
+
+    case OP_CBRAPOS:
+    case OP_SCBRAPOS:
+    Lzero_allowed = FALSE;               /* Zero repeat not allowed */
+
+    POSSESSIVE_CAPTURE:
+    number = GET2(Fecode, 1+LINK_SIZE);
+    Lframe_type = GF_CAPTURE | number;   /* Remembered frame type */
+
+    POSSESSIVE_GROUP:
+    Lmatched_once = FALSE;               /* Never matched */
+    Lstart_group = Fecode;               /* Start of this group */
+
+    for (;;)
+      {
+      Lstart_eptr = Feptr;               /* Position at group start */
+      group_frame_type = Lframe_type;
+      RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM8);
+      if (rrc == MATCH_KETRPOS)
+        {
+        Lmatched_once = TRUE;            /* Matched at least once */
+        if (Feptr == Lstart_eptr)        /* Empty match; skip to end */
+          {
+          do Fecode += GET(Fecode, 1); while (*Fecode == OP_ALT);
+          break;
+          }
+
+        Fecode = Lstart_group;
+        continue;
+        }
+
+      /* See comment above about handling THEN. */
+
+      if (rrc == MATCH_THEN)
+        {
+        PCRE2_SPTR next_ecode = Fecode + GET(Fecode,1);
+        if (mb->verb_ecode_ptr < next_ecode &&
+            (*Fecode == OP_ALT || *next_ecode == OP_ALT))
+          rrc = MATCH_NOMATCH;
+        }
+
+      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+      Fecode += GET(Fecode, 1);
+      if (*Fecode != OP_ALT) break;
+      }
+
+    /* Success if matched something or zero repeat allowed */
+
+    if (Lmatched_once || Lzero_allowed)
+      {
+      Fecode += 1 + LINK_SIZE;
+      break;
+      }
+
+    RRETURN(MATCH_NOMATCH);
+
+#undef Lmatched_once
+#undef Lzero_allowed
+#undef Lframe_type
+#undef Lstart_eptr
+#undef Lstart_group
+
+
+    /* ===================================================================== */
+    /* Handle non-capturing brackets that cannot match an empty string. When we
+    get to the final alternative within the brackets, as long as there are no
+    THEN's in the pattern, we can optimize by not recording a new backtracking
+    point. (Ideally we should test for a THEN within this group, but we don't
+    have that information.) Don't do this if we are at the very top level,
+    however, because that would make handling assertions and once-only brackets
+    messier when there is nothing to go back to. */
+
+#define Lframe_type F->temp_32[0]     /* Set for all that use GROUPLOOP */
+#define Lnext_branch F->temp_sptr[0]  /* Used only in OP_BRA handling */
+
+    case OP_BRA:
+    if (mb->hasthen || Frdepth == 0)
+      {
+      Lframe_type = 0;
+      goto GROUPLOOP;
+      }
+
+    for (;;)
+      {
+      Lnext_branch = Fecode + GET(Fecode, 1);
+      if (*Lnext_branch != OP_ALT) break;
+
+      /* This is never the final branch. We do not need to test for MATCH_THEN
+      here because this code is not used when there is a THEN in the pattern. */
+
+      RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM1);
+      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+      Fecode = Lnext_branch;
+      }
+
+    /* Hit the start of the final branch. Continue at this level. */
+
+    Fecode += PRIV(OP_lengths)[*Fecode];
+    break;
+
+#undef Lnext_branch
+
+
+    /* ===================================================================== */
+    /* Handle a capturing bracket, other than those that are possessive with an
+    unlimited repeat. */
+
+    case OP_CBRA:
+    case OP_SCBRA:
+    Lframe_type = GF_CAPTURE | GET2(Fecode, 1+LINK_SIZE);
+    goto GROUPLOOP;
+
+
+    /* ===================================================================== */
+    /* Atomic groups and non-capturing brackets that can match an empty string
+    must record a backtracking point and also set up a chained frame. */
+
+    case OP_ONCE:
+    case OP_SCRIPT_RUN:
+    case OP_SBRA:
+    Lframe_type = GF_NOCAPTURE | Fop;
+
+    GROUPLOOP:
+    for (;;)
+      {
+      group_frame_type = Lframe_type;
+      RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM2);
+      if (rrc == MATCH_THEN)
+        {
+        PCRE2_SPTR next_ecode = Fecode + GET(Fecode,1);
+        if (mb->verb_ecode_ptr < next_ecode &&
+            (*Fecode == OP_ALT || *next_ecode == OP_ALT))
+          rrc = MATCH_NOMATCH;
+        }
+      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+      Fecode += GET(Fecode, 1);
+      if (*Fecode != OP_ALT) RRETURN(MATCH_NOMATCH);
+      }
+    /* Control never reaches here. */
+
+#undef Lframe_type
+
+
+    /* ===================================================================== */
+    /* Recursion either matches the current regex, or some subexpression. The
+    offset data is the offset to the starting bracket from the start of the
+    whole pattern. (This is so that it works from duplicated subpatterns.) */
+
+#define Lframe_type F->temp_32[0]
+#define Lstart_branch F->temp_sptr[0]
+
+    case OP_RECURSE:
+    bracode = mb->start_code + GET(Fecode, 1);
+    number = (bracode == mb->start_code)? 0 : GET2(bracode, 1 + LINK_SIZE);
+
+    /* If we are already in a recursion, check for repeating the same one
+    without advancing the subject pointer. This should catch convoluted mutual
+    recursions. (Some simple cases are caught at compile time.) */
+
+    if (Fcurrent_recurse != RECURSE_UNSET)
+      {
+      offset = Flast_group_offset;
+      while (offset != PCRE2_UNSET)
+        {
+        N = (heapframe *)((char *)mb->match_frames + offset);
+        P = (heapframe *)((char *)N - frame_size);
+        if (N->group_frame_type == (GF_RECURSE | number))
+          {
+          if (Feptr == P->eptr) return PCRE2_ERROR_RECURSELOOP;
+          break;
+          }
+        offset = P->last_group_offset;
+        }
+      }
+
+    /* Now run the recursion, branch by branch. */
+
+    Lstart_branch = bracode;
+    Lframe_type = GF_RECURSE | number;
+
+    for (;;)
+      {
+      PCRE2_SPTR next_ecode;
+
+      group_frame_type = Lframe_type;
+      RMATCH(Lstart_branch + PRIV(OP_lengths)[*Lstart_branch], RM11);
+      next_ecode = Lstart_branch + GET(Lstart_branch,1);
+
+      /* Handle backtracking verbs, which are defined in a range that can
+      easily be tested for. PCRE does not allow THEN, SKIP, PRUNE or COMMIT to
+      escape beyond a recursion; they cause a NOMATCH for the entire recursion.
+
+      When one of these verbs triggers, the current recursion group number is
+      recorded. If it matches the recursion we are processing, the verb
+      happened within the recursion and we must deal with it. Otherwise it must
+      have happened after the recursion completed, and so has to be passed
+      back. See comment above about handling THEN. */
+
+      if (rrc >= MATCH_BACKTRACK_MIN && rrc <= MATCH_BACKTRACK_MAX &&
+          mb->verb_current_recurse == (Lframe_type ^ GF_RECURSE))
+        {
+        if (rrc == MATCH_THEN && mb->verb_ecode_ptr < next_ecode &&
+            (*Lstart_branch == OP_ALT || *next_ecode == OP_ALT))
+          rrc = MATCH_NOMATCH;
+        else RRETURN(MATCH_NOMATCH);
+        }
+
+      /* Note that carrying on after (*ACCEPT) in a recursion is handled in the
+      OP_ACCEPT code. Nothing needs to be done here. */
+
+      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+      Lstart_branch = next_ecode;
+      if (*Lstart_branch != OP_ALT) RRETURN(MATCH_NOMATCH);
+      }
+    /* Control never reaches here. */
+
+#undef Lframe_type
+#undef Lstart_branch
+
+
+    /* ===================================================================== */
+    /* Positive assertions are like other groups except that PCRE doesn't allow
+    the effect of (*THEN) to escape beyond an assertion; it is therefore
+    treated as NOMATCH. (*ACCEPT) is treated as successful assertion, with its
+    captures and mark retained. Any other return is an error. */
+
+#define Lframe_type  F->temp_32[0]
+
+    case OP_ASSERT:
+    case OP_ASSERTBACK:
+    case OP_ASSERT_NA:
+    case OP_ASSERTBACK_NA:
+    Lframe_type = GF_NOCAPTURE | Fop;
+    for (;;)
+      {
+      group_frame_type = Lframe_type;
+      RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM3);
+      if (rrc == MATCH_ACCEPT)
+        {
+        memcpy(Fovector,
+              (char *)assert_accept_frame + offsetof(heapframe, ovector),
+              assert_accept_frame->offset_top * sizeof(PCRE2_SIZE));
+        Foffset_top = assert_accept_frame->offset_top;
+        Fmark = assert_accept_frame->mark;
+        break;
+        }
+      if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc);
+      Fecode += GET(Fecode, 1);
+      if (*Fecode != OP_ALT) RRETURN(MATCH_NOMATCH);
+      }
+
+    do Fecode += GET(Fecode, 1); while (*Fecode == OP_ALT);
+    Fecode += 1 + LINK_SIZE;
+    break;
+
+#undef Lframe_type
+
+
+    /* ===================================================================== */
+    /* Handle negative assertions. Loop for each non-matching branch as for
+    positive assertions. */
+
+#define Lframe_type  F->temp_32[0]
+
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK_NOT:
+    Lframe_type  = GF_NOCAPTURE | Fop;
+
+    for (;;)
+      {
+      group_frame_type = Lframe_type;
+      RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM4);
+      switch(rrc)
+        {
+        case MATCH_ACCEPT:   /* Assertion matched, therefore it fails. */
+        case MATCH_MATCH:
+        RRETURN (MATCH_NOMATCH);
+
+        case MATCH_NOMATCH:  /* Branch failed, try next if present. */
+        case MATCH_THEN:
+        Fecode += GET(Fecode, 1);
+        if (*Fecode != OP_ALT) goto ASSERT_NOT_FAILED;
+        break;
+
+        case MATCH_COMMIT:   /* Assertion forced to fail, therefore continue. */
+        case MATCH_SKIP:
+        case MATCH_PRUNE:
+        do Fecode += GET(Fecode, 1); while (*Fecode == OP_ALT);
+        goto ASSERT_NOT_FAILED;
+
+        default:             /* Pass back any other return */
+        RRETURN(rrc);
+        }
+      }
+
+    /* None of the branches have matched or there was a backtrack to (*COMMIT),
+    (*SKIP), (*PRUNE), or (*THEN) in the last branch. This is success for a
+    negative assertion, so carry on. */
+
+    ASSERT_NOT_FAILED:
+    Fecode += 1 + LINK_SIZE;
+    break;
+
+#undef Lframe_type
+
+
+    /* ===================================================================== */
+    /* The callout item calls an external function, if one is provided, passing
+    details of the match so far. This is mainly for debugging, though the
+    function is able to force a failure. */
+
+    case OP_CALLOUT:
+    case OP_CALLOUT_STR:
+    rrc = do_callout(F, mb, &length);
+    if (rrc > 0) RRETURN(MATCH_NOMATCH);
+    if (rrc < 0) RRETURN(rrc);
+    Fecode += length;
+    break;
+
+
+    /* ===================================================================== */
+    /* Conditional group: compilation checked that there are no more than two
+    branches. If the condition is false, skipping the first branch takes us
+    past the end of the item if there is only one branch, but that's exactly
+    what we want. */
+
+    case OP_COND:
+    case OP_SCOND:
+
+    /* The variable Flength will be added to Fecode when the condition is
+    false, to get to the second branch. Setting it to the offset to the ALT or
+    KET, then incrementing Fecode achieves this effect. However, if the second
+    branch is non-existent, we must point to the KET so that the end of the
+    group is correctly processed. We now have Fecode pointing to the condition
+    or callout. */
+
+    Flength = GET(Fecode, 1);    /* Offset to the second branch */
+    if (Fecode[Flength] != OP_ALT) Flength -= 1 + LINK_SIZE;
+    Fecode += 1 + LINK_SIZE;     /* From this opcode */
+
+    /* Because of the way auto-callout works during compile, a callout item is
+    inserted between OP_COND and an assertion condition. Such a callout can
+    also be inserted manually. */
+
+    if (*Fecode == OP_CALLOUT || *Fecode == OP_CALLOUT_STR)
+      {
+      rrc = do_callout(F, mb, &length);
+      if (rrc > 0) RRETURN(MATCH_NOMATCH);
+      if (rrc < 0) RRETURN(rrc);
+
+      /* Advance Fecode past the callout, so it now points to the condition. We
+      must adjust Flength so that the value of Fecode+Flength is unchanged. */
+
+      Fecode += length;
+      Flength -= length;
+      }
+
+    /* Test the various possible conditions */
+
+    condition = FALSE;
+    switch(*Fecode)
+      {
+      case OP_RREF:                  /* Group recursion test */
+      if (Fcurrent_recurse != RECURSE_UNSET)
+        {
+        number = GET2(Fecode, 1);
+        condition = (number == RREF_ANY || number == Fcurrent_recurse);
+        }
+      break;
+
+      case OP_DNRREF:       /* Duplicate named group recursion test */
+      if (Fcurrent_recurse != RECURSE_UNSET)
+        {
+        int count = GET2(Fecode, 1 + IMM2_SIZE);
+        PCRE2_SPTR slot = mb->name_table + GET2(Fecode, 1) * mb->name_entry_size;
+        while (count-- > 0)
+          {
+          number = GET2(slot, 0);
+          condition = number == Fcurrent_recurse;
+          if (condition) break;
+          slot += mb->name_entry_size;
+          }
+        }
+      break;
+
+      case OP_CREF:                         /* Numbered group used test */
+      offset = (GET2(Fecode, 1) << 1) - 2;  /* Doubled ref number */
+      condition = offset < Foffset_top && Fovector[offset] != PCRE2_UNSET;
+      break;
+
+      case OP_DNCREF:      /* Duplicate named group used test */
+        {
+        int count = GET2(Fecode, 1 + IMM2_SIZE);
+        PCRE2_SPTR slot = mb->name_table + GET2(Fecode, 1) * mb->name_entry_size;
+        while (count-- > 0)
+          {
+          offset = (GET2(slot, 0) << 1) - 2;
+          condition = offset < Foffset_top && Fovector[offset] != PCRE2_UNSET;
+          if (condition) break;
+          slot += mb->name_entry_size;
+          }
+        }
+      break;
+
+      case OP_FALSE:
+      case OP_FAIL:   /* The assertion (?!) becomes OP_FAIL */
+      break;
+
+      case OP_TRUE:
+      condition = TRUE;
+      break;
+
+      /* The condition is an assertion. Run code similar to the assertion code
+      above. */
+
+#define Lpositive      F->temp_32[0]
+#define Lstart_branch  F->temp_sptr[0]
+
+      default:
+      Lpositive = (*Fecode == OP_ASSERT || *Fecode == OP_ASSERTBACK);
+      Lstart_branch = Fecode;
+
+      for (;;)
+        {
+        group_frame_type = GF_CONDASSERT | *Fecode;
+        RMATCH(Lstart_branch + PRIV(OP_lengths)[*Lstart_branch], RM5);
+
+        switch(rrc)
+          {
+          case MATCH_ACCEPT:  /* Save captures */
+          memcpy(Fovector,
+                (char *)assert_accept_frame + offsetof(heapframe, ovector),
+                assert_accept_frame->offset_top * sizeof(PCRE2_SIZE));
+          Foffset_top = assert_accept_frame->offset_top;
+
+          /* Fall through */
+          /* In the case of a match, the captures have already been put into
+          the current frame. */
+
+          case MATCH_MATCH:
+          condition = Lpositive;   /* TRUE for positive assertion */
+          break;
+
+          /* PCRE doesn't allow the effect of (*THEN) to escape beyond an
+          assertion; it is therefore always treated as NOMATCH. */
+
+          case MATCH_NOMATCH:
+          case MATCH_THEN:
+          Lstart_branch += GET(Lstart_branch, 1);
+          if (*Lstart_branch == OP_ALT) continue;  /* Try next branch */
+          condition = !Lpositive;  /* TRUE for negative assertion */
+          break;
+
+          /* These force no match without checking other branches. */
+
+          case MATCH_COMMIT:
+          case MATCH_SKIP:
+          case MATCH_PRUNE:
+          condition = !Lpositive;
+          break;
+
+          default:
+          RRETURN(rrc);
+          }
+        break;  /* Out of the branch loop */
+        }
+
+      /* If the condition is true, find the end of the assertion so that
+      advancing past it gets us to the start of the first branch. */
+
+      if (condition)
+        {
+        do Fecode += GET(Fecode, 1); while (*Fecode == OP_ALT);
+        }
+      break;  /* End of assertion condition */
+      }
+
+#undef Lpositive
+#undef Lstart_branch
+
+    /* Choose branch according to the condition. */
+
+    Fecode += condition? PRIV(OP_lengths)[*Fecode] : Flength;
+
+    /* If the opcode is OP_SCOND it means we are at a repeated conditional
+    group that might match an empty string. We must therefore descend a level
+    so that the start is remembered for checking. For OP_COND we can just
+    continue at this level. */
+
+    if (Fop == OP_SCOND)
+      {
+      group_frame_type  = GF_NOCAPTURE | Fop;
+      RMATCH(Fecode, RM35);
+      RRETURN(rrc);
+      }
+    break;
+
+
+
+/* ========================================================================= */
+/*                  End of start of parenthesis opcodes                      */
+/* ========================================================================= */
+
+
+    /* ===================================================================== */
+    /* Move the subject pointer back. This occurs only at the start of each
+    branch of a lookbehind assertion. If we are too close to the start to move
+    back, fail. When working with UTF-8 we move back a number of characters,
+    not bytes. */
+
+    case OP_REVERSE:
+    number = GET(Fecode, 1);
+#ifdef SUPPORT_UNICODE
+    if (utf)
+      {
+      while (number-- > 0)
+        {
+        if (Feptr <= mb->check_subject) RRETURN(MATCH_NOMATCH);
+        Feptr--;
+        BACKCHAR(Feptr);
+        }
+      }
+    else
+#endif
+
+    /* No UTF-8 support, or not in UTF-8 mode: count is code unit count */
+
+      {
+      if ((ptrdiff_t)number > Feptr - mb->start_subject) RRETURN(MATCH_NOMATCH);
+      Feptr -= number;
+      }
+
+    /* Save the earliest consulted character, then skip to next opcode */
+
+    if (Feptr < mb->start_used_ptr) mb->start_used_ptr = Feptr;
+    Fecode += 1 + LINK_SIZE;
+    break;
+
+
+    /* ===================================================================== */
+    /* An alternation is the end of a branch; scan along to find the end of the
+    bracketed group. */
+
+    case OP_ALT:
+    do Fecode += GET(Fecode,1); while (*Fecode == OP_ALT);
+    break;
+
+
+    /* ===================================================================== */
+    /* The end of a parenthesized group. For all but OP_BRA and OP_COND, the
+    starting frame was added to the chained frames in order to remember the
+    starting subject position for the group. */
+
+    case OP_KET:
+    case OP_KETRMIN:
+    case OP_KETRMAX:
+    case OP_KETRPOS:
+
+    bracode = Fecode - GET(Fecode, 1);
+
+    /* Point N to the frame at the start of the most recent group.
+    Remember the subject pointer at the start of the group. */
+
+    if (*bracode != OP_BRA && *bracode != OP_COND)
+      {
+      N = (heapframe *)((char *)mb->match_frames + Flast_group_offset);
+      P = (heapframe *)((char *)N - frame_size);
+      Flast_group_offset = P->last_group_offset;
+
+#ifdef DEBUG_SHOW_RMATCH
+      fprintf(stderr, "++ KET for frame=%d type=%x prev char offset=%lu\n",
+        N->rdepth, N->group_frame_type,
+        (char *)P->eptr - (char *)mb->start_subject);
+#endif
+
+      /* If we are at the end of an assertion that is a condition, return a
+      match, discarding any intermediate backtracking points. Copy back the
+      mark setting and the captures into the frame before N so that they are
+      set on return. Doing this for all assertions, both positive and negative,
+      seems to match what Perl does. */
+
+      if (GF_IDMASK(N->group_frame_type) == GF_CONDASSERT)
+        {
+        memcpy((char *)P + offsetof(heapframe, ovector), Fovector,
+          Foffset_top * sizeof(PCRE2_SIZE));
+        P->offset_top = Foffset_top;
+        P->mark = Fmark;
+        Fback_frame = (char *)F - (char *)P;
+        RRETURN(MATCH_MATCH);
+        }
+      }
+    else P = NULL;   /* Indicates starting frame not recorded */
+
+    /* The group was not a conditional assertion. */
+
+    switch (*bracode)
+      {
+      case OP_BRA:    /* No need to do anything for these */
+      case OP_COND:
+      case OP_SCOND:
+      break;
+
+      /* Non-atomic positive assertions are like OP_BRA, except that the
+      subject pointer must be put back to where it was at the start of the
+      assertion. */
+
+      case OP_ASSERT_NA:
+      case OP_ASSERTBACK_NA:
+      if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr;
+      Feptr = P->eptr;
+      break;
+
+      /* Atomic positive assertions are like OP_ONCE, except that in addition
+      the subject pointer must be put back to where it was at the start of the
+      assertion. */
+
+      case OP_ASSERT:
+      case OP_ASSERTBACK:
+      if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr;
+      Feptr = P->eptr;
+      /* Fall through */
+
+      /* For an atomic group, discard internal backtracking points. We must
+      also ensure that any remaining branches within the top-level of the group
+      are not tried. Do this by adjusting the code pointer within the backtrack
+      frame so that it points to the final branch. */
+
+      case OP_ONCE:
+      Fback_frame = ((char *)F - (char *)P);
+      for (;;)
+        {
+        uint32_t y = GET(P->ecode,1);
+        if ((P->ecode)[y] != OP_ALT) break;
+        P->ecode += y;
+        }
+      break;
+
+      /* A matching negative assertion returns MATCH, which is turned into
+      NOMATCH at the assertion level. */
+
+      case OP_ASSERT_NOT:
+      case OP_ASSERTBACK_NOT:
+      RRETURN(MATCH_MATCH);
+
+      /* At the end of a script run, apply the script-checking rules. This code
+      will never by exercised if Unicode support it not compiled, because in
+      that environment script runs cause an error at compile time. */
+
+      case OP_SCRIPT_RUN:
+      if (!PRIV(script_run)(P->eptr, Feptr, utf)) RRETURN(MATCH_NOMATCH);
+      break;
+
+      /* Whole-pattern recursion is coded as a recurse into group 0, so it
+      won't be picked up here. Instead, we catch it when the OP_END is reached.
+      Other recursion is handled here. */
+
+      case OP_CBRA:
+      case OP_CBRAPOS:
+      case OP_SCBRA:
+      case OP_SCBRAPOS:
+      number = GET2(bracode, 1+LINK_SIZE);
+
+      /* Handle a recursively called group. We reinstate the previous set of
+      captures and then carry on after the recursion call. */
+
+      if (Fcurrent_recurse == number)
+        {
+        P = (heapframe *)((char *)N - frame_size);
+        memcpy((char *)F + offsetof(heapframe, ovector), P->ovector,
+          P->offset_top * sizeof(PCRE2_SIZE));
+        Foffset_top = P->offset_top;
+        Fcapture_last = P->capture_last;
+        Fcurrent_recurse = P->current_recurse;
+        Fecode = P->ecode + 1 + LINK_SIZE;
+        continue;  /* With next opcode */
+        }
+
+      /* Deal with actual capturing. */
+
+      offset = (number << 1) - 2;
+      Fcapture_last = number;
+      Fovector[offset] = P->eptr - mb->start_subject;
+      Fovector[offset+1] = Feptr - mb->start_subject;
+      if (offset >= Foffset_top) Foffset_top = offset + 2;
+      break;
+      }  /* End actions relating to the starting opcode */
+
+    /* OP_KETRPOS is a possessive repeating ket. Remember the current position,
+    and return the MATCH_KETRPOS. This makes it possible to do the repeats one
+    at a time from the outer level. This must precede the empty string test -
+    in this case that test is done at the outer level. */
+
+    if (*Fecode == OP_KETRPOS)
+      {
+      memcpy((char *)P + offsetof(heapframe, eptr),
+             (char *)F + offsetof(heapframe, eptr),
+             frame_copy_size);
+      RRETURN(MATCH_KETRPOS);
+      }
+
+    /* Handle the different kinds of closing brackets. A non-repeating ket
+    needs no special action, just continuing at this level. This also happens
+    for the repeating kets if the group matched no characters, in order to
+    forcibly break infinite loops. Otherwise, the repeating kets try the rest
+    of the pattern or restart from the preceding bracket, in the appropriate
+    order. */
+
+    if (Fop != OP_KET && (P == NULL || Feptr != P->eptr))
+      {
+      if (Fop == OP_KETRMIN)
+        {
+        RMATCH(Fecode + 1 + LINK_SIZE, RM6);
+        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+        Fecode -= GET(Fecode, 1);
+        break;   /* End of ket processing */
+        }
+
+      /* Repeat the maximum number of times (KETRMAX) */
+
+      RMATCH(bracode, RM7);
+      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+      }
+
+    /* Carry on at this level for a non-repeating ket, or after matching an
+    empty string, or after repeating for a maximum number of times. */
+
+    Fecode += 1 + LINK_SIZE;
+    break;
+
+
+    /* ===================================================================== */
+    /* Start and end of line assertions, not multiline mode. */
+
+    case OP_CIRC:   /* Start of line, unless PCRE2_NOTBOL is set. */
+    if (Feptr != mb->start_subject || (mb->moptions & PCRE2_NOTBOL) != 0)
+      RRETURN(MATCH_NOMATCH);
+    Fecode++;
+    break;
+
+    case OP_SOD:    /* Unconditional start of subject */
+    if (Feptr != mb->start_subject) RRETURN(MATCH_NOMATCH);
+    Fecode++;
+    break;
+
+    /* When PCRE2_NOTEOL is unset, assert before the subject end, or a
+    terminating newline unless PCRE2_DOLLAR_ENDONLY is set. */
+
+    case OP_DOLL:
+    if ((mb->moptions & PCRE2_NOTEOL) != 0) RRETURN(MATCH_NOMATCH);
+    if ((mb->poptions & PCRE2_DOLLAR_ENDONLY) == 0) goto ASSERT_NL_OR_EOS;
+
+    /* Fall through */
+    /* Unconditional end of subject assertion (\z) */
+
+    case OP_EOD:
+    if (Feptr < mb->end_subject) RRETURN(MATCH_NOMATCH);
+    if (mb->partial != 0)
+      {
+      mb->hitend = TRUE;
+      if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+      }
+    Fecode++;
+    break;
+
+    /* End of subject or ending \n assertion (\Z) */
+
+    case OP_EODN:
+    ASSERT_NL_OR_EOS:
+    if (Feptr < mb->end_subject &&
+        (!IS_NEWLINE(Feptr) || Feptr != mb->end_subject - mb->nllen))
+      {
+      if (mb->partial != 0 &&
+          Feptr + 1 >= mb->end_subject &&
+          NLBLOCK->nltype == NLTYPE_FIXED &&
+          NLBLOCK->nllen == 2 &&
+          UCHAR21TEST(Feptr) == NLBLOCK->nl[0])
+        {
+        mb->hitend = TRUE;
+        if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+        }
+      RRETURN(MATCH_NOMATCH);
+      }
+
+    /* Either at end of string or \n before end. */
+
+    if (mb->partial != 0)
+      {
+      mb->hitend = TRUE;
+      if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+      }
+    Fecode++;
+    break;
+
+
+    /* ===================================================================== */
+    /* Start and end of line assertions, multiline mode. */
+
+    /* Start of subject unless notbol, or after any newline except for one at
+    the very end, unless PCRE2_ALT_CIRCUMFLEX is set. */
+
+    case OP_CIRCM:
+    if ((mb->moptions & PCRE2_NOTBOL) != 0 && Feptr == mb->start_subject)
+      RRETURN(MATCH_NOMATCH);
+    if (Feptr != mb->start_subject &&
+        ((Feptr == mb->end_subject &&
+           (mb->poptions & PCRE2_ALT_CIRCUMFLEX) == 0) ||
+         !WAS_NEWLINE(Feptr)))
+      RRETURN(MATCH_NOMATCH);
+    Fecode++;
+    break;
+
+    /* Assert before any newline, or before end of subject unless noteol is
+    set. */
+
+    case OP_DOLLM:
+    if (Feptr < mb->end_subject)
+      {
+      if (!IS_NEWLINE(Feptr))
+        {
+        if (mb->partial != 0 &&
+            Feptr + 1 >= mb->end_subject &&
+            NLBLOCK->nltype == NLTYPE_FIXED &&
+            NLBLOCK->nllen == 2 &&
+            UCHAR21TEST(Feptr) == NLBLOCK->nl[0])
+          {
+          mb->hitend = TRUE;
+          if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+          }
+        RRETURN(MATCH_NOMATCH);
+        }
+      }
+    else
+      {
+      if ((mb->moptions & PCRE2_NOTEOL) != 0) RRETURN(MATCH_NOMATCH);
+      SCHECK_PARTIAL();
+      }
+    Fecode++;
+    break;
+
+
+    /* ===================================================================== */
+    /* Start of match assertion */
+
+    case OP_SOM:
+    if (Feptr != mb->start_subject + mb->start_offset) RRETURN(MATCH_NOMATCH);
+    Fecode++;
+    break;
+
+
+    /* ===================================================================== */
+    /* Reset the start of match point */
+
+    case OP_SET_SOM:
+    Fstart_match = Feptr;
+    Fecode++;
+    break;
+
+
+    /* ===================================================================== */
+    /* Word boundary assertions. Find out if the previous and current
+    characters are "word" characters. It takes a bit more work in UTF mode.
+    Characters > 255 are assumed to be "non-word" characters when PCRE2_UCP is
+    not set. When it is set, use Unicode properties if available, even when not
+    in UTF mode. Remember the earliest and latest consulted characters. */
+
+    case OP_NOT_WORD_BOUNDARY:
+    case OP_WORD_BOUNDARY:
+    if (Feptr == mb->check_subject) prev_is_word = FALSE; else
+      {
+      PCRE2_SPTR lastptr = Feptr - 1;
+#ifdef SUPPORT_UNICODE
+      if (utf)
+        {
+        BACKCHAR(lastptr);
+        GETCHAR(fc, lastptr);
+        }
+      else
+#endif  /* SUPPORT_UNICODE */
+      fc = *lastptr;
+      if (lastptr < mb->start_used_ptr) mb->start_used_ptr = lastptr;
+#ifdef SUPPORT_UNICODE
+      if ((mb->poptions & PCRE2_UCP) != 0)
+        {
+        if (fc == '_') prev_is_word = TRUE; else
+          {
+          int cat = UCD_CATEGORY(fc);
+          prev_is_word = (cat == ucp_L || cat == ucp_N);
+          }
+        }
+      else
+#endif  /* SUPPORT_UNICODE */
+      prev_is_word = CHMAX_255(fc) && (mb->ctypes[fc] & ctype_word) != 0;
+      }
+
+    /* Get status of next character */
+
+    if (Feptr >= mb->end_subject)
+      {
+      SCHECK_PARTIAL();
+      cur_is_word = FALSE;
+      }
+    else
+      {
+      PCRE2_SPTR nextptr = Feptr + 1;
+#ifdef SUPPORT_UNICODE
+      if (utf)
+        {
+        FORWARDCHARTEST(nextptr, mb->end_subject);
+        GETCHAR(fc, Feptr);
+        }
+      else
+#endif  /* SUPPORT_UNICODE */
+      fc = *Feptr;
+      if (nextptr > mb->last_used_ptr) mb->last_used_ptr = nextptr;
+#ifdef SUPPORT_UNICODE
+      if ((mb->poptions & PCRE2_UCP) != 0)
+        {
+        if (fc == '_') cur_is_word = TRUE; else
+          {
+          int cat = UCD_CATEGORY(fc);
+          cur_is_word = (cat == ucp_L || cat == ucp_N);
+          }
+        }
+      else
+#endif  /* SUPPORT_UNICODE */
+      cur_is_word = CHMAX_255(fc) && (mb->ctypes[fc] & ctype_word) != 0;
+      }
+
+    /* Now see if the situation is what we want */
+
+    if ((*Fecode++ == OP_WORD_BOUNDARY)?
+         cur_is_word == prev_is_word : cur_is_word != prev_is_word)
+      RRETURN(MATCH_NOMATCH);
+    break;
+
+
+    /* ===================================================================== */
+    /* Backtracking (*VERB)s, with and without arguments. Note that if the
+    pattern is successfully matched, we do not come back from RMATCH. */
+
+    case OP_MARK:
+    Fmark = mb->nomatch_mark = Fecode + 2;
+    RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM12);
+
+    /* A return of MATCH_SKIP_ARG means that matching failed at SKIP with an
+    argument, and we must check whether that argument matches this MARK's
+    argument. It is passed back in mb->verb_skip_ptr. If it does match, we
+    return MATCH_SKIP with mb->verb_skip_ptr now pointing to the subject
+    position that corresponds to this mark. Otherwise, pass back the return
+    code unaltered. */
+
+    if (rrc == MATCH_SKIP_ARG &&
+             PRIV(strcmp)(Fecode + 2, mb->verb_skip_ptr) == 0)
+      {
+      mb->verb_skip_ptr = Feptr;   /* Pass back current position */
+      RRETURN(MATCH_SKIP);
+      }
+    RRETURN(rrc);
+
+    case OP_FAIL:
+    RRETURN(MATCH_NOMATCH);
+
+    /* Record the current recursing group number in mb->verb_current_recurse
+    when a backtracking return such as MATCH_COMMIT is given. This enables the
+    recurse processing to catch verbs from within the recursion. */
+
+    case OP_COMMIT:
+    RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM13);
+    if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+    mb->verb_current_recurse = Fcurrent_recurse;
+    RRETURN(MATCH_COMMIT);
+
+    case OP_COMMIT_ARG:
+    Fmark = mb->nomatch_mark = Fecode + 2;
+    RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM36);
+    if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+    mb->verb_current_recurse = Fcurrent_recurse;
+    RRETURN(MATCH_COMMIT);
+
+    case OP_PRUNE:
+    RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM14);
+    if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+    mb->verb_current_recurse = Fcurrent_recurse;
+    RRETURN(MATCH_PRUNE);
+
+    case OP_PRUNE_ARG:
+    Fmark = mb->nomatch_mark = Fecode + 2;
+    RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM15);
+    if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+    mb->verb_current_recurse = Fcurrent_recurse;
+    RRETURN(MATCH_PRUNE);
+
+    case OP_SKIP:
+    RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM16);
+    if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+    mb->verb_skip_ptr = Feptr;   /* Pass back current position */
+    mb->verb_current_recurse = Fcurrent_recurse;
+    RRETURN(MATCH_SKIP);
+
+    /* Note that, for Perl compatibility, SKIP with an argument does NOT set
+    nomatch_mark. When a pattern match ends with a SKIP_ARG for which there was
+    not a matching mark, we have to re-run the match, ignoring the SKIP_ARG
+    that failed and any that precede it (either they also failed, or were not
+    triggered). To do this, we maintain a count of executed SKIP_ARGs. If a
+    SKIP_ARG gets to top level, the match is re-run with mb->ignore_skip_arg
+    set to the count of the one that failed. */
+
+    case OP_SKIP_ARG:
+    mb->skip_arg_count++;
+    if (mb->skip_arg_count <= mb->ignore_skip_arg)
+      {
+      Fecode += PRIV(OP_lengths)[*Fecode] + Fecode[1];
+      break;
+      }
+    RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM17);
+    if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+
+    /* Pass back the current skip name and return the special MATCH_SKIP_ARG
+    return code. This will either be caught by a matching MARK, or get to the
+    top, where it causes a rematch with mb->ignore_skip_arg set to the value of
+    mb->skip_arg_count. */
+
+    mb->verb_skip_ptr = Fecode + 2;
+    mb->verb_current_recurse = Fcurrent_recurse;
+    RRETURN(MATCH_SKIP_ARG);
+
+    /* For THEN (and THEN_ARG) we pass back the address of the opcode, so that
+    the branch in which it occurs can be determined. */
+
+    case OP_THEN:
+    RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM18);
+    if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+    mb->verb_ecode_ptr = Fecode;
+    mb->verb_current_recurse = Fcurrent_recurse;
+    RRETURN(MATCH_THEN);
+
+    case OP_THEN_ARG:
+    Fmark = mb->nomatch_mark = Fecode + 2;
+    RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM19);
+    if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+    mb->verb_ecode_ptr = Fecode;
+    mb->verb_current_recurse = Fcurrent_recurse;
+    RRETURN(MATCH_THEN);
+
+
+    /* ===================================================================== */
+    /* There's been some horrible disaster. Arrival here can only mean there is
+    something seriously wrong in the code above or the OP_xxx definitions. */
+
+    default:
+    return PCRE2_ERROR_INTERNAL;
+    }
+
+  /* Do not insert any code in here without much thought; it is assumed
+  that "continue" in the code above comes out to here to repeat the main
+  loop. */
+
+  }  /* End of main loop */
+/* Control never reaches here */
+
+
+/* ========================================================================= */
+/* The RRETURN() macro jumps here. The number that is saved in Freturn_id
+indicates which label we actually want to return to. The value in Frdepth is
+the index number of the frame in the vector. The return value has been placed
+in rrc. */
+
+#define LBL(val) case val: goto L_RM##val;
+
+RETURN_SWITCH:
+if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr;
+if (Frdepth == 0) return rrc;                     /* Exit from the top level */
+F = (heapframe *)((char *)F - Fback_frame);       /* Backtrack */
+mb->cb->callout_flags |= PCRE2_CALLOUT_BACKTRACK; /* Note for callouts */
+
+#ifdef DEBUG_SHOW_RMATCH
+fprintf(stderr, "++ RETURN %d to %d\n", rrc, Freturn_id);
+#endif
+
+switch (Freturn_id)
+  {
+  LBL( 1) LBL( 2) LBL( 3) LBL( 4) LBL( 5) LBL( 6) LBL( 7) LBL( 8)
+  LBL( 9) LBL(10) LBL(11) LBL(12) LBL(13) LBL(14) LBL(15) LBL(16)
+  LBL(17) LBL(18) LBL(19) LBL(20) LBL(21) LBL(22) LBL(23) LBL(24)
+  LBL(25) LBL(26) LBL(27) LBL(28) LBL(29) LBL(30) LBL(31) LBL(32)
+  LBL(33) LBL(34) LBL(35) LBL(36)
+
+#ifdef SUPPORT_WIDE_CHARS
+  LBL(100) LBL(101)
+#endif
+
+#ifdef SUPPORT_UNICODE
+  LBL(200) LBL(201) LBL(202) LBL(203) LBL(204) LBL(205) LBL(206)
+  LBL(207) LBL(208) LBL(209) LBL(210) LBL(211) LBL(212) LBL(213)
+  LBL(214) LBL(215) LBL(216) LBL(217) LBL(218) LBL(219) LBL(220)
+  LBL(221) LBL(222)
+#endif
+
+  default:
+  return PCRE2_ERROR_INTERNAL;
+  }
+#undef LBL
+}
+
+
+/*************************************************
+*           Match a Regular Expression           *
+*************************************************/
+
+/* This function applies a compiled pattern to a subject string and picks out
+portions of the string if it matches. Two elements in the vector are set for
+each substring: the offsets to the start and end of the substring.
+
+Arguments:
+  code            points to the compiled expression
+  subject         points to the subject string
+  length          length of subject string (may contain binary zeros)
+  start_offset    where to start in the subject string
+  options         option bits
+  match_data      points to a match_data block
+  mcontext        points a PCRE2 context
+
+Returns:          > 0 => success; value is the number of ovector pairs filled
+                  = 0 => success, but ovector is not big enough
+                  = -1 => failed to match (PCRE2_ERROR_NOMATCH)
+                  = -2 => partial match (PCRE2_ERROR_PARTIAL)
+                  < -2 => some kind of unexpected problem
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length,
+  PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data,
+  pcre2_match_context *mcontext)
+{
+int rc;
+int was_zero_terminated = 0;
+const uint8_t *start_bits = NULL;
+const pcre2_real_code *re = (const pcre2_real_code *)code;
+
+BOOL anchored;
+BOOL firstline;
+BOOL has_first_cu = FALSE;
+BOOL has_req_cu = FALSE;
+BOOL startline;
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+BOOL memchr_not_found_first_cu;
+BOOL memchr_not_found_first_cu2;
+#endif
+
+PCRE2_UCHAR first_cu = 0;
+PCRE2_UCHAR first_cu2 = 0;
+PCRE2_UCHAR req_cu = 0;
+PCRE2_UCHAR req_cu2 = 0;
+
+PCRE2_SPTR bumpalong_limit;
+PCRE2_SPTR end_subject;
+PCRE2_SPTR true_end_subject;
+PCRE2_SPTR start_match = subject + start_offset;
+PCRE2_SPTR req_cu_ptr = start_match - 1;
+PCRE2_SPTR start_partial;
+PCRE2_SPTR match_partial;
+
+#ifdef SUPPORT_JIT
+BOOL use_jit;
+#endif
+
+/* This flag is needed even when Unicode is not supported for convenience
+(it is used by the IS_NEWLINE macro). */
+
+BOOL utf = FALSE;
+
+#ifdef SUPPORT_UNICODE
+BOOL ucp = FALSE;
+BOOL allow_invalid;
+uint32_t fragment_options = 0;
+#ifdef SUPPORT_JIT
+BOOL jit_checked_utf = FALSE;
+#endif
+#endif  /* SUPPORT_UNICODE */
+
+PCRE2_SIZE frame_size;
+
+/* We need to have mb as a pointer to a match block, because the IS_NEWLINE
+macro is used below, and it expects NLBLOCK to be defined as a pointer. */
+
+pcre2_callout_block cb;
+match_block actual_match_block;
+match_block *mb = &actual_match_block;
+
+/* Allocate an initial vector of backtracking frames on the stack. If this
+proves to be too small, it is replaced by a larger one on the heap. To get a
+vector of the size required that is aligned for pointers, allocate it as a
+vector of pointers. */
+
+PCRE2_SPTR stack_frames_vector[START_FRAMES_SIZE/sizeof(PCRE2_SPTR)]
+    PCRE2_KEEP_UNINITIALIZED;
+mb->stack_frames = (heapframe *)stack_frames_vector;
+
+/* A length equal to PCRE2_ZERO_TERMINATED implies a zero-terminated
+subject string. */
+
+if (length == PCRE2_ZERO_TERMINATED)
+  {
+  length = PRIV(strlen)(subject);
+  was_zero_terminated = 1;
+  }
+true_end_subject = end_subject = subject + length;
+
+/* Plausibility checks */
+
+if ((options & ~PUBLIC_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION;
+if (code == NULL || subject == NULL || match_data == NULL)
+  return PCRE2_ERROR_NULL;
+if (start_offset > length) return PCRE2_ERROR_BADOFFSET;
+
+/* Check that the first field in the block is the magic number. */
+
+if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
+
+/* Check the code unit width. */
+
+if ((re->flags & PCRE2_MODE_MASK) != PCRE2_CODE_UNIT_WIDTH/8)
+  return PCRE2_ERROR_BADMODE;
+
+/* PCRE2_NOTEMPTY and PCRE2_NOTEMPTY_ATSTART are match-time flags in the
+options variable for this function. Users of PCRE2 who are not calling the
+function directly would like to have a way of setting these flags, in the same
+way that they can set pcre2_compile() flags like PCRE2_NO_AUTOPOSSESS with
+constructions like (*NO_AUTOPOSSESS). To enable this, (*NOTEMPTY) and
+(*NOTEMPTY_ATSTART) set bits in the pattern's "flag" function which we now
+transfer to the options for this function. The bits are guaranteed to be
+adjacent, but do not have the same values. This bit of Boolean trickery assumes
+that the match-time bits are not more significant than the flag bits. If by
+accident this is not the case, a compile-time division by zero error will
+occur. */
+
+#define FF (PCRE2_NOTEMPTY_SET|PCRE2_NE_ATST_SET)
+#define OO (PCRE2_NOTEMPTY|PCRE2_NOTEMPTY_ATSTART)
+options |= (re->flags & FF) / ((FF & (~FF+1)) / (OO & (~OO+1)));
+#undef FF
+#undef OO
+
+/* If the pattern was successfully studied with JIT support, we will run the
+JIT executable instead of the rest of this function. Most options must be set
+at compile time for the JIT code to be usable. */
+
+#ifdef SUPPORT_JIT
+use_jit = (re->executable_jit != NULL &&
+          (options & ~PUBLIC_JIT_MATCH_OPTIONS) == 0);
+#endif
+
+/* Initialize UTF/UCP parameters. */
+
+#ifdef SUPPORT_UNICODE
+utf = (re->overall_options & PCRE2_UTF) != 0;
+allow_invalid = (re->overall_options & PCRE2_MATCH_INVALID_UTF) != 0;
+ucp = (re->overall_options & PCRE2_UCP) != 0;
+#endif  /* SUPPORT_UNICODE */
+
+/* Convert the partial matching flags into an integer. */
+
+mb->partial = ((options & PCRE2_PARTIAL_HARD) != 0)? 2 :
+              ((options & PCRE2_PARTIAL_SOFT) != 0)? 1 : 0;
+
+/* Partial matching and PCRE2_ENDANCHORED are currently not allowed at the same
+time. */
+
+if (mb->partial != 0 &&
+   ((re->overall_options | options) & PCRE2_ENDANCHORED) != 0)
+  return PCRE2_ERROR_BADOPTION;
+
+/* It is an error to set an offset limit without setting the flag at compile
+time. */
+
+if (mcontext != NULL && mcontext->offset_limit != PCRE2_UNSET &&
+     (re->overall_options & PCRE2_USE_OFFSET_LIMIT) == 0)
+  return PCRE2_ERROR_BADOFFSETLIMIT;
+
+/* If the match data block was previously used with PCRE2_COPY_MATCHED_SUBJECT,
+free the memory that was obtained. Set the field to NULL for no match cases. */
+
+if ((match_data->flags & PCRE2_MD_COPIED_SUBJECT) != 0)
+  {
+  match_data->memctl.free((void *)match_data->subject,
+    match_data->memctl.memory_data);
+  match_data->flags &= ~PCRE2_MD_COPIED_SUBJECT;
+  }
+match_data->subject = NULL;
+
+/* Zero the error offset in case the first code unit is invalid UTF. */
+
+match_data->startchar = 0;
+
+
+/* ============================= JIT matching ============================== */
+
+/* Prepare for JIT matching. Check a UTF string for validity unless no check is
+requested or invalid UTF can be handled. We check only the portion of the
+subject that might be be inspected during matching - from the offset minus the
+maximum lookbehind to the given length. This saves time when a small part of a
+large subject is being matched by the use of a starting offset. Note that the
+maximum lookbehind is a number of characters, not code units. */
+
+#ifdef SUPPORT_JIT
+if (use_jit)
+  {
+#ifdef SUPPORT_UNICODE
+  if (utf && (options & PCRE2_NO_UTF_CHECK) == 0 && !allow_invalid)
+    {
+#if PCRE2_CODE_UNIT_WIDTH != 32
+    unsigned int i;
+#endif
+
+    /* For 8-bit and 16-bit UTF, check that the first code unit is a valid
+    character start. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 32
+    if (start_match < end_subject && NOT_FIRSTCU(*start_match))
+      {
+      if (start_offset > 0) return PCRE2_ERROR_BADUTFOFFSET;
+#if PCRE2_CODE_UNIT_WIDTH == 8
+      return PCRE2_ERROR_UTF8_ERR20;  /* Isolated 0x80 byte */
+#else
+      return PCRE2_ERROR_UTF16_ERR3;  /* Isolated low surrogate */
+#endif
+      }
+#endif  /* WIDTH != 32 */
+
+    /* Move back by the maximum lookbehind, just in case it happens at the very
+    start of matching. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 32
+    for (i = re->max_lookbehind; i > 0 && start_match > subject; i--)
+      {
+      start_match--;
+      while (start_match > subject &&
+#if PCRE2_CODE_UNIT_WIDTH == 8
+      (*start_match & 0xc0) == 0x80)
+#else  /* 16-bit */
+      (*start_match & 0xfc00) == 0xdc00)
+#endif
+        start_match--;
+      }
+#else  /* PCRE2_CODE_UNIT_WIDTH != 32 */
+
+    /* In the 32-bit library, one code unit equals one character. However,
+    we cannot just subtract the lookbehind and then compare pointers, because
+    a very large lookbehind could create an invalid pointer. */
+
+    if (start_offset >= re->max_lookbehind)
+      start_match -= re->max_lookbehind;
+    else
+      start_match = subject;
+#endif  /* PCRE2_CODE_UNIT_WIDTH != 32 */
+
+    /* Validate the relevant portion of the subject. Adjust the offset of an
+    invalid code point to be an absolute offset in the whole string. */
+
+    match_data->rc = PRIV(valid_utf)(start_match,
+      length - (start_match - subject), &(match_data->startchar));
+    if (match_data->rc != 0)
+      {
+      match_data->startchar += start_match - subject;
+      return match_data->rc;
+      }
+    jit_checked_utf = TRUE;
+    }
+#endif  /* SUPPORT_UNICODE */
+
+  /* If JIT returns BADOPTION, which means that the selected complete or
+  partial matching mode was not compiled, fall through to the interpreter. */
+
+  rc = pcre2_jit_match(code, subject, length, start_offset, options,
+    match_data, mcontext);
+  if (rc != PCRE2_ERROR_JIT_BADOPTION)
+    {
+    if (rc >= 0 && (options & PCRE2_COPY_MATCHED_SUBJECT) != 0)
+      {
+      length = CU2BYTES(length + was_zero_terminated);
+      match_data->subject = match_data->memctl.malloc(length,
+        match_data->memctl.memory_data);
+      if (match_data->subject == NULL) return PCRE2_ERROR_NOMEMORY;
+      memcpy((void *)match_data->subject, subject, length);
+      match_data->flags |= PCRE2_MD_COPIED_SUBJECT;
+      }
+    return rc;
+    }
+  }
+#endif  /* SUPPORT_JIT */
+
+/* ========================= End of JIT matching ========================== */
+
+
+/* Proceed with non-JIT matching. The default is to allow lookbehinds to the
+start of the subject. A UTF check when there is a non-zero offset may change
+this. */
+
+mb->check_subject = subject;
+
+/* If a UTF subject string was not checked for validity in the JIT code above,
+check it here, and handle support for invalid UTF strings. The check above
+happens only when invalid UTF is not supported and PCRE2_NO_CHECK_UTF is unset.
+If we get here in those circumstances, it means the subject string is valid,
+but for some reason JIT matching was not successful. There is no need to check
+the subject again.
+
+We check only the portion of the subject that might be be inspected during
+matching - from the offset minus the maximum lookbehind to the given length.
+This saves time when a small part of a large subject is being matched by the
+use of a starting offset. Note that the maximum lookbehind is a number of
+characters, not code units.
+
+Note also that support for invalid UTF forces a check, overriding the setting
+of PCRE2_NO_CHECK_UTF. */
+
+#ifdef SUPPORT_UNICODE
+if (utf &&
+#ifdef SUPPORT_JIT
+    !jit_checked_utf &&
+#endif
+    ((options & PCRE2_NO_UTF_CHECK) == 0 || allow_invalid))
+  {
+#if PCRE2_CODE_UNIT_WIDTH != 32
+  BOOL skipped_bad_start = FALSE;
+#endif
+
+  /* For 8-bit and 16-bit UTF, check that the first code unit is a valid
+  character start. If we are handling invalid UTF, just skip over such code
+  units. Otherwise, give an appropriate error. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 32
+  if (allow_invalid)
+    {
+    while (start_match < end_subject && NOT_FIRSTCU(*start_match))
+      {
+      start_match++;
+      skipped_bad_start = TRUE;
+      }
+    }
+  else if (start_match < end_subject && NOT_FIRSTCU(*start_match))
+    {
+    if (start_offset > 0) return PCRE2_ERROR_BADUTFOFFSET;
+#if PCRE2_CODE_UNIT_WIDTH == 8
+    return PCRE2_ERROR_UTF8_ERR20;  /* Isolated 0x80 byte */
+#else
+    return PCRE2_ERROR_UTF16_ERR3;  /* Isolated low surrogate */
+#endif
+    }
+#endif  /* WIDTH != 32 */
+
+  /* The mb->check_subject field points to the start of UTF checking;
+  lookbehinds can go back no further than this. */
+
+  mb->check_subject = start_match;
+
+  /* Move back by the maximum lookbehind, just in case it happens at the very
+  start of matching, but don't do this if we skipped bad 8-bit or 16-bit code
+  units above. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 32
+  if (!skipped_bad_start)
+    {
+    unsigned int i;
+    for (i = re->max_lookbehind; i > 0 && mb->check_subject > subject; i--)
+      {
+      mb->check_subject--;
+      while (mb->check_subject > subject &&
+#if PCRE2_CODE_UNIT_WIDTH == 8
+      (*mb->check_subject & 0xc0) == 0x80)
+#else  /* 16-bit */
+      (*mb->check_subject & 0xfc00) == 0xdc00)
+#endif
+        mb->check_subject--;
+      }
+    }
+#else  /* PCRE2_CODE_UNIT_WIDTH != 32 */
+
+  /* In the 32-bit library, one code unit equals one character. However,
+  we cannot just subtract the lookbehind and then compare pointers, because
+  a very large lookbehind could create an invalid pointer. */
+
+  if (start_offset >= re->max_lookbehind)
+    mb->check_subject -= re->max_lookbehind;
+  else
+    mb->check_subject = subject;
+#endif  /* PCRE2_CODE_UNIT_WIDTH != 32 */
+
+  /* Validate the relevant portion of the subject. There's a loop in case we
+  encounter bad UTF in the characters preceding start_match which we are
+  scanning because of a lookbehind. */
+
+  for (;;)
+    {
+    match_data->rc = PRIV(valid_utf)(mb->check_subject,
+      length - (mb->check_subject - subject), &(match_data->startchar));
+
+    if (match_data->rc == 0) break;   /* Valid UTF string */
+
+    /* Invalid UTF string. Adjust the offset to be an absolute offset in the
+    whole string. If we are handling invalid UTF strings, set end_subject to
+    stop before the bad code unit, and set the options to "not end of line".
+    Otherwise return the error. */
+
+    match_data->startchar += mb->check_subject - subject;
+    if (!allow_invalid || match_data->rc > 0) return match_data->rc;
+    end_subject = subject + match_data->startchar;
+
+    /* If the end precedes start_match, it means there is invalid UTF in the
+    extra code units we reversed over because of a lookbehind. Advance past the
+    first bad code unit, and then skip invalid character starting code units in
+    8-bit and 16-bit modes, and try again. */
+
+    if (end_subject < start_match)
+      {
+      mb->check_subject = end_subject + 1;
+#if PCRE2_CODE_UNIT_WIDTH != 32
+      while (mb->check_subject < start_match && NOT_FIRSTCU(*mb->check_subject))
+        mb->check_subject++;
+#endif
+      }
+
+    /* Otherwise, set the not end of line option, and do the match. */
+
+    else
+      {
+      fragment_options = PCRE2_NOTEOL;
+      break;
+      }
+    }
+  }
+#endif  /* SUPPORT_UNICODE */
+
+/* A NULL match context means "use a default context", but we take the memory
+control functions from the pattern. */
+
+if (mcontext == NULL)
+  {
+  mcontext = (pcre2_match_context *)(&PRIV(default_match_context));
+  mb->memctl = re->memctl;
+  }
+else mb->memctl = mcontext->memctl;
+
+anchored = ((re->overall_options | options) & PCRE2_ANCHORED) != 0;
+firstline = (re->overall_options & PCRE2_FIRSTLINE) != 0;
+startline = (re->flags & PCRE2_STARTLINE) != 0;
+bumpalong_limit = (mcontext->offset_limit == PCRE2_UNSET)?
+  true_end_subject : subject + mcontext->offset_limit;
+
+/* Initialize and set up the fixed fields in the callout block, with a pointer
+in the match block. */
+
+mb->cb = &cb;
+cb.version = 2;
+cb.subject = subject;
+cb.subject_length = (PCRE2_SIZE)(end_subject - subject);
+cb.callout_flags = 0;
+
+/* Fill in the remaining fields in the match block, except for moptions, which
+gets set later. */
+
+mb->callout = mcontext->callout;
+mb->callout_data = mcontext->callout_data;
+
+mb->start_subject = subject;
+mb->start_offset = start_offset;
+mb->end_subject = end_subject;
+mb->hasthen = (re->flags & PCRE2_HASTHEN) != 0;
+mb->allowemptypartial = (re->max_lookbehind > 0) ||
+    (re->flags & PCRE2_MATCH_EMPTY) != 0;
+mb->poptions = re->overall_options;          /* Pattern options */
+mb->ignore_skip_arg = 0;
+mb->mark = mb->nomatch_mark = NULL;          /* In case never set */
+
+/* The name table is needed for finding all the numbers associated with a
+given name, for condition testing. The code follows the name table. */
+
+mb->name_table = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code));
+mb->name_count = re->name_count;
+mb->name_entry_size = re->name_entry_size;
+mb->start_code = mb->name_table + re->name_count * re->name_entry_size;
+
+/* Process the \R and newline settings. */
+
+mb->bsr_convention = re->bsr_convention;
+mb->nltype = NLTYPE_FIXED;
+switch(re->newline_convention)
+  {
+  case PCRE2_NEWLINE_CR:
+  mb->nllen = 1;
+  mb->nl[0] = CHAR_CR;
+  break;
+
+  case PCRE2_NEWLINE_LF:
+  mb->nllen = 1;
+  mb->nl[0] = CHAR_NL;
+  break;
+
+  case PCRE2_NEWLINE_NUL:
+  mb->nllen = 1;
+  mb->nl[0] = CHAR_NUL;
+  break;
+
+  case PCRE2_NEWLINE_CRLF:
+  mb->nllen = 2;
+  mb->nl[0] = CHAR_CR;
+  mb->nl[1] = CHAR_NL;
+  break;
+
+  case PCRE2_NEWLINE_ANY:
+  mb->nltype = NLTYPE_ANY;
+  break;
+
+  case PCRE2_NEWLINE_ANYCRLF:
+  mb->nltype = NLTYPE_ANYCRLF;
+  break;
+
+  default: return PCRE2_ERROR_INTERNAL;
+  }
+
+/* The backtracking frames have fixed data at the front, and a PCRE2_SIZE
+vector at the end, whose size depends on the number of capturing parentheses in
+the pattern. It is not used at all if there are no capturing parentheses.
+
+  frame_size             is the total size of each frame
+  mb->frame_vector_size  is the total usable size of the vector (rounded down
+                           to a whole number of frames)
+
+The last of these is changed within the match() function if the frame vector
+has to be expanded. We therefore put it into the match block so that it is
+correct when calling match() more than once for non-anchored patterns. */
+
+frame_size = offsetof(heapframe, ovector) +
+  re->top_bracket * 2 * sizeof(PCRE2_SIZE);
+
+/* Limits set in the pattern override the match context only if they are
+smaller. */
+
+mb->heap_limit = (mcontext->heap_limit < re->limit_heap)?
+  mcontext->heap_limit : re->limit_heap;
+
+mb->match_limit = (mcontext->match_limit < re->limit_match)?
+  mcontext->match_limit : re->limit_match;
+
+mb->match_limit_depth = (mcontext->depth_limit < re->limit_depth)?
+  mcontext->depth_limit : re->limit_depth;
+
+/* If a pattern has very many capturing parentheses, the frame size may be very
+large. Ensure that there are at least 10 available frames by getting an initial
+vector on the heap if necessary, except when the heap limit prevents this. Get
+fewer if possible. (The heap limit is in kibibytes.) */
+
+if (frame_size <= START_FRAMES_SIZE/10)
+  {
+  mb->match_frames = mb->stack_frames;   /* Initial frame vector on the stack */
+  mb->frame_vector_size = ((START_FRAMES_SIZE/frame_size) * frame_size);
+  }
+else
+  {
+  mb->frame_vector_size = frame_size * 10;
+  if ((mb->frame_vector_size / 1024) > mb->heap_limit)
+    {
+    if (frame_size > mb->heap_limit * 1024) return PCRE2_ERROR_HEAPLIMIT;
+    mb->frame_vector_size = ((mb->heap_limit * 1024)/frame_size) * frame_size;
+    }
+  mb->match_frames = mb->memctl.malloc(mb->frame_vector_size,
+    mb->memctl.memory_data);
+  if (mb->match_frames == NULL) return PCRE2_ERROR_NOMEMORY;
+  }
+
+mb->match_frames_top =
+  (heapframe *)((char *)mb->match_frames + mb->frame_vector_size);
+
+/* Write to the ovector within the first frame to mark every capture unset and
+to avoid uninitialized memory read errors when it is copied to a new frame. */
+
+memset((char *)(mb->match_frames) + offsetof(heapframe, ovector), 0xff,
+  re->top_bracket * 2 * sizeof(PCRE2_SIZE));
+
+/* Pointers to the individual character tables */
+
+mb->lcc = re->tables + lcc_offset;
+mb->fcc = re->tables + fcc_offset;
+mb->ctypes = re->tables + ctypes_offset;
+
+/* Set up the first code unit to match, if available. If there's no first code
+unit there may be a bitmap of possible first characters. */
+
+if ((re->flags & PCRE2_FIRSTSET) != 0)
+  {
+  has_first_cu = TRUE;
+  first_cu = first_cu2 = (PCRE2_UCHAR)(re->first_codeunit);
+  if ((re->flags & PCRE2_FIRSTCASELESS) != 0)
+    {
+    first_cu2 = TABLE_GET(first_cu, mb->fcc, first_cu);
+#ifdef SUPPORT_UNICODE
+#if PCRE2_CODE_UNIT_WIDTH == 8
+    if (first_cu > 127 && ucp && !utf) first_cu2 = UCD_OTHERCASE(first_cu);
+#else
+    if (first_cu > 127 && (utf || ucp)) first_cu2 = UCD_OTHERCASE(first_cu);
+#endif
+#endif  /* SUPPORT_UNICODE */
+    }
+  }
+else
+  if (!startline && (re->flags & PCRE2_FIRSTMAPSET) != 0)
+    start_bits = re->start_bitmap;
+
+/* There may also be a "last known required character" set. */
+
+if ((re->flags & PCRE2_LASTSET) != 0)
+  {
+  has_req_cu = TRUE;
+  req_cu = req_cu2 = (PCRE2_UCHAR)(re->last_codeunit);
+  if ((re->flags & PCRE2_LASTCASELESS) != 0)
+    {
+    req_cu2 = TABLE_GET(req_cu, mb->fcc, req_cu);
+#ifdef SUPPORT_UNICODE
+#if PCRE2_CODE_UNIT_WIDTH == 8
+    if (req_cu > 127 && ucp && !utf) req_cu2 = UCD_OTHERCASE(req_cu);
+#else
+    if (req_cu > 127 && (utf || ucp)) req_cu2 = UCD_OTHERCASE(req_cu);
+#endif
+#endif  /* SUPPORT_UNICODE */
+    }
+  }
+
+
+/* ==========================================================================*/
+
+/* Loop for handling unanchored repeated matching attempts; for anchored regexs
+the loop runs just once. */
+
+#ifdef SUPPORT_UNICODE
+FRAGMENT_RESTART:
+#endif
+
+start_partial = match_partial = NULL;
+mb->hitend = FALSE;
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+memchr_not_found_first_cu = FALSE;
+memchr_not_found_first_cu2 = FALSE;
+#endif
+
+for(;;)
+  {
+  PCRE2_SPTR new_start_match;
+
+  /* ----------------- Start of match optimizations ---------------- */
+
+  /* There are some optimizations that avoid running the match if a known
+  starting point is not found, or if a known later code unit is not present.
+  However, there is an option (settable at compile time) that disables these,
+  for testing and for ensuring that all callouts do actually occur. */
+
+  if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0)
+    {
+    /* If firstline is TRUE, the start of the match is constrained to the first
+    line of a multiline string. That is, the match must be before or at the
+    first newline following the start of matching. Temporarily adjust
+    end_subject so that we stop the scans for a first code unit at a newline.
+    If the match fails at the newline, later code breaks the loop. */
+
+    if (firstline)
+      {
+      PCRE2_SPTR t = start_match;
+#ifdef SUPPORT_UNICODE
+      if (utf)
+        {
+        while (t < end_subject && !IS_NEWLINE(t))
+          {
+          t++;
+          ACROSSCHAR(t < end_subject, t, t++);
+          }
+        }
+      else
+#endif
+      while (t < end_subject && !IS_NEWLINE(t)) t++;
+      end_subject = t;
+      }
+
+    /* Anchored: check the first code unit if one is recorded. This may seem
+    pointless but it can help in detecting a no match case without scanning for
+    the required code unit. */
+
+    if (anchored)
+      {
+      if (has_first_cu || start_bits != NULL)
+        {
+        BOOL ok = start_match < end_subject;
+        if (ok)
+          {
+          PCRE2_UCHAR c = UCHAR21TEST(start_match);
+          ok = has_first_cu && (c == first_cu || c == first_cu2);
+          if (!ok && start_bits != NULL)
+            {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+            if (c > 255) c = 255;
+#endif
+            ok = (start_bits[c/8] & (1u << (c&7))) != 0;
+            }
+          }
+        if (!ok)
+          {
+          rc = MATCH_NOMATCH;
+          break;
+          }
+        }
+      }
+
+    /* Not anchored. Advance to a unique first code unit if there is one. In
+    8-bit mode, the use of memchr() gives a big speed up, even though we have
+    to call it twice in caseless mode, in order to find the earliest occurrence
+    of the character in either of its cases. If a call to memchr() that
+    searches the rest of the subject fails to find one case, remember that in
+    order not to keep on repeating the search. This can make a huge difference
+    when the strings are very long and only one case is present. */
+
+    else
+      {
+      if (has_first_cu)
+        {
+        if (first_cu != first_cu2)  /* Caseless */
+          {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+          PCRE2_UCHAR smc;
+          while (start_match < end_subject &&
+                (smc = UCHAR21TEST(start_match)) != first_cu &&
+                  smc != first_cu2)
+            start_match++;
+
+#else  /* 8-bit code units */
+          PCRE2_SPTR pp1 = NULL;
+          PCRE2_SPTR pp2 = NULL;
+          PCRE2_SIZE cu2size = end_subject - start_match;
+
+          if (!memchr_not_found_first_cu)
+            {
+            pp1 = memchr(start_match, first_cu, end_subject - start_match);
+            if (pp1 == NULL) memchr_not_found_first_cu = TRUE;
+              else cu2size = pp1 - start_match;
+            }
+
+          /* If pp1 is not NULL, we have arranged to search only as far as pp1,
+          to see if the other case is earlier, so we can set "not found" only
+          when both searches have returned NULL. */
+
+          if (!memchr_not_found_first_cu2)
+            {
+            pp2 = memchr(start_match, first_cu2, cu2size);
+            memchr_not_found_first_cu2 = (pp2 == NULL && pp1 == NULL);
+            }
+
+          if (pp1 == NULL)
+            start_match = (pp2 == NULL)? end_subject : pp2;
+          else
+            start_match = (pp2 == NULL || pp1 < pp2)? pp1 : pp2;
+#endif
+          }
+
+        /* The caseful case */
+
+        else
+          {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+          while (start_match < end_subject && UCHAR21TEST(start_match) !=
+                 first_cu)
+            start_match++;
+#else
+          start_match = memchr(start_match, first_cu, end_subject - start_match);
+          if (start_match == NULL) start_match = end_subject;
+#endif
+          }
+
+        /* If we can't find the required first code unit, having reached the
+        true end of the subject, break the bumpalong loop, to force a match
+        failure, except when doing partial matching, when we let the next cycle
+        run at the end of the subject. To see why, consider the pattern
+        /(?<=abc)def/, which partially matches "abc", even though the string
+        does not contain the starting character "d". If we have not reached the
+        true end of the subject (PCRE2_FIRSTLINE caused end_subject to be
+        temporarily modified) we also let the cycle run, because the matching
+        string is legitimately allowed to start with the first code unit of a
+        newline. */
+
+        if (mb->partial == 0 && start_match >= mb->end_subject)
+          {
+          rc = MATCH_NOMATCH;
+          break;
+          }
+        }
+
+      /* If there's no first code unit, advance to just after a linebreak for a
+      multiline match if required. */
+
+      else if (startline)
+        {
+        if (start_match > mb->start_subject + start_offset)
+          {
+#ifdef SUPPORT_UNICODE
+          if (utf)
+            {
+            while (start_match < end_subject && !WAS_NEWLINE(start_match))
+              {
+              start_match++;
+              ACROSSCHAR(start_match < end_subject, start_match, start_match++);
+              }
+            }
+          else
+#endif
+          while (start_match < end_subject && !WAS_NEWLINE(start_match))
+            start_match++;
+
+          /* If we have just passed a CR and the newline option is ANY or
+          ANYCRLF, and we are now at a LF, advance the match position by one
+          more code unit. */
+
+          if (start_match[-1] == CHAR_CR &&
+               (mb->nltype == NLTYPE_ANY || mb->nltype == NLTYPE_ANYCRLF) &&
+               start_match < end_subject &&
+               UCHAR21TEST(start_match) == CHAR_NL)
+            start_match++;
+          }
+        }
+
+      /* If there's no first code unit or a requirement for a multiline line
+      start, advance to a non-unique first code unit if any have been
+      identified. The bitmap contains only 256 bits. When code units are 16 or
+      32 bits wide, all code units greater than 254 set the 255 bit. */
+
+      else if (start_bits != NULL)
+        {
+        while (start_match < end_subject)
+          {
+          uint32_t c = UCHAR21TEST(start_match);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+          if (c > 255) c = 255;
+#endif
+          if ((start_bits[c/8] & (1u << (c&7))) != 0) break;
+          start_match++;
+          }
+
+        /* See comment above in first_cu checking about the next few lines. */
+
+        if (mb->partial == 0 && start_match >= mb->end_subject)
+          {
+          rc = MATCH_NOMATCH;
+          break;
+          }
+        }
+      }   /* End first code unit handling */
+
+    /* Restore fudged end_subject */
+
+    end_subject = mb->end_subject;
+
+    /* The following two optimizations must be disabled for partial matching. */
+
+    if (mb->partial == 0)
+      {
+      PCRE2_SPTR p;
+
+      /* The minimum matching length is a lower bound; no string of that length
+      may actually match the pattern. Although the value is, strictly, in
+      characters, we treat it as code units to avoid spending too much time in
+      this optimization. */
+
+      if (end_subject - start_match < re->minlength)
+        {
+        rc = MATCH_NOMATCH;
+        break;
+        }
+
+      /* If req_cu is set, we know that that code unit must appear in the
+      subject for the (non-partial) match to succeed. If the first code unit is
+      set, req_cu must be later in the subject; otherwise the test starts at
+      the match point. This optimization can save a huge amount of backtracking
+      in patterns with nested unlimited repeats that aren't going to match.
+      Writing separate code for caseful/caseless versions makes it go faster,
+      as does using an autoincrement and backing off on a match. As in the case
+      of the first code unit, using memchr() in the 8-bit library gives a big
+      speed up. Unlike the first_cu check above, we do not need to call
+      memchr() twice in the caseless case because we only need to check for the
+      presence of the character in either case, not find the first occurrence.
+
+      The search can be skipped if the code unit was found later than the
+      current starting point in a previous iteration of the bumpalong loop.
+
+      HOWEVER: when the subject string is very, very long, searching to its end
+      can take a long time, and give bad performance on quite ordinary
+      anchored patterns. This showed up when somebody was matching something
+      like /^\d+C/ on a 32-megabyte string... so we don't do this when the
+      string is sufficiently long, but it's worth searching a lot more for
+      unanchored patterns. */
+
+      p = start_match + (has_first_cu? 1:0);
+      if (has_req_cu && p > req_cu_ptr)
+        {
+        PCRE2_SIZE check_length = end_subject - start_match;
+
+        if (check_length < REQ_CU_MAX ||
+              (!anchored && check_length < REQ_CU_MAX * 1000))
+          {
+          if (req_cu != req_cu2)  /* Caseless */
+            {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+            while (p < end_subject)
+              {
+              uint32_t pp = UCHAR21INCTEST(p);
+              if (pp == req_cu || pp == req_cu2) { p--; break; }
+              }
+#else  /* 8-bit code units */
+            PCRE2_SPTR pp = p;
+            p = memchr(pp, req_cu, end_subject - pp);
+            if (p == NULL)
+              {
+              p = memchr(pp, req_cu2, end_subject - pp);
+              if (p == NULL) p = end_subject;
+              }
+#endif /* PCRE2_CODE_UNIT_WIDTH != 8 */
+            }
+
+          /* The caseful case */
+
+          else
+            {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+            while (p < end_subject)
+              {
+              if (UCHAR21INCTEST(p) == req_cu) { p--; break; }
+              }
+
+#else  /* 8-bit code units */
+            p = memchr(p, req_cu, end_subject - p);
+            if (p == NULL) p = end_subject;
+#endif
+            }
+
+          /* If we can't find the required code unit, break the bumpalong loop,
+          forcing a match failure. */
+
+          if (p >= end_subject)
+            {
+            rc = MATCH_NOMATCH;
+            break;
+            }
+
+          /* If we have found the required code unit, save the point where we
+          found it, so that we don't search again next time round the bumpalong
+          loop if the start hasn't yet passed this code unit. */
+
+          req_cu_ptr = p;
+          }
+        }
+      }
+    }
+
+  /* ------------ End of start of match optimizations ------------ */
+
+  /* Give no match if we have passed the bumpalong limit. */
+
+  if (start_match > bumpalong_limit)
+    {
+    rc = MATCH_NOMATCH;
+    break;
+    }
+
+  /* OK, we can now run the match. If "hitend" is set afterwards, remember the
+  first starting point for which a partial match was found. */
+
+  cb.start_match = (PCRE2_SIZE)(start_match - subject);
+  cb.callout_flags |= PCRE2_CALLOUT_STARTMATCH;
+
+  mb->start_used_ptr = start_match;
+  mb->last_used_ptr = start_match;
+#ifdef SUPPORT_UNICODE
+  mb->moptions = options | fragment_options;
+#else
+  mb->moptions = options;
+#endif
+  mb->match_call_count = 0;
+  mb->end_offset_top = 0;
+  mb->skip_arg_count = 0;
+
+  rc = match(start_match, mb->start_code, match_data->ovector,
+    match_data->oveccount, re->top_bracket, frame_size, mb);
+
+  if (mb->hitend && start_partial == NULL)
+    {
+    start_partial = mb->start_used_ptr;
+    match_partial = start_match;
+    }
+
+  switch(rc)
+    {
+    /* If MATCH_SKIP_ARG reaches this level it means that a MARK that matched
+    the SKIP's arg was not found. In this circumstance, Perl ignores the SKIP
+    entirely. The only way we can do that is to re-do the match at the same
+    point, with a flag to force SKIP with an argument to be ignored. Just
+    treating this case as NOMATCH does not work because it does not check other
+    alternatives in patterns such as A(*SKIP:A)B|AC when the subject is AC. */
+
+    case MATCH_SKIP_ARG:
+    new_start_match = start_match;
+    mb->ignore_skip_arg = mb->skip_arg_count;
+    break;
+
+    /* SKIP passes back the next starting point explicitly, but if it is no
+    greater than the match we have just done, treat it as NOMATCH. */
+
+    case MATCH_SKIP:
+    if (mb->verb_skip_ptr > start_match)
+      {
+      new_start_match = mb->verb_skip_ptr;
+      break;
+      }
+    /* Fall through */
+
+    /* NOMATCH and PRUNE advance by one character. THEN at this level acts
+    exactly like PRUNE. Unset ignore SKIP-with-argument. */
+
+    case MATCH_NOMATCH:
+    case MATCH_PRUNE:
+    case MATCH_THEN:
+    mb->ignore_skip_arg = 0;
+    new_start_match = start_match + 1;
+#ifdef SUPPORT_UNICODE
+    if (utf)
+      ACROSSCHAR(new_start_match < end_subject, new_start_match,
+        new_start_match++);
+#endif
+    break;
+
+    /* COMMIT disables the bumpalong, but otherwise behaves as NOMATCH. */
+
+    case MATCH_COMMIT:
+    rc = MATCH_NOMATCH;
+    goto ENDLOOP;
+
+    /* Any other return is either a match, or some kind of error. */
+
+    default:
+    goto ENDLOOP;
+    }
+
+  /* Control reaches here for the various types of "no match at this point"
+  result. Reset the code to MATCH_NOMATCH for subsequent checking. */
+
+  rc = MATCH_NOMATCH;
+
+  /* If PCRE2_FIRSTLINE is set, the match must happen before or at the first
+  newline in the subject (though it may continue over the newline). Therefore,
+  if we have just failed to match, starting at a newline, do not continue. */
+
+  if (firstline && IS_NEWLINE(start_match)) break;
+
+  /* Advance to new matching position */
+
+  start_match = new_start_match;
+
+  /* Break the loop if the pattern is anchored or if we have passed the end of
+  the subject. */
+
+  if (anchored || start_match > end_subject) break;
+
+  /* If we have just passed a CR and we are now at a LF, and the pattern does
+  not contain any explicit matches for \r or \n, and the newline option is CRLF
+  or ANY or ANYCRLF, advance the match position by one more code unit. In
+  normal matching start_match will aways be greater than the first position at
+  this stage, but a failed *SKIP can cause a return at the same point, which is
+  why the first test exists. */
+
+  if (start_match > subject + start_offset &&
+      start_match[-1] == CHAR_CR &&
+      start_match < end_subject &&
+      *start_match == CHAR_NL &&
+      (re->flags & PCRE2_HASCRORLF) == 0 &&
+        (mb->nltype == NLTYPE_ANY ||
+         mb->nltype == NLTYPE_ANYCRLF ||
+         mb->nllen == 2))
+    start_match++;
+
+  mb->mark = NULL;   /* Reset for start of next match attempt */
+  }                  /* End of for(;;) "bumpalong" loop */
+
+/* ==========================================================================*/
+
+/* When we reach here, one of the following stopping conditions is true:
+
+(1) The match succeeded, either completely, or partially;
+
+(2) The pattern is anchored or the match was failed after (*COMMIT);
+
+(3) We are past the end of the subject or the bumpalong limit;
+
+(4) PCRE2_FIRSTLINE is set and we have failed to match at a newline, because
+    this option requests that a match occur at or before the first newline in
+    the subject.
+
+(5) Some kind of error occurred.
+
+*/
+
+ENDLOOP:
+
+/* If end_subject != true_end_subject, it means we are handling invalid UTF,
+and have just processed a non-terminal fragment. If this resulted in no match
+or a partial match we must carry on to the next fragment (a partial match is
+returned to the caller only at the very end of the subject). A loop is used to
+avoid trying to match against empty fragments; if the pattern can match an
+empty string it would have done so already. */
+
+#ifdef SUPPORT_UNICODE
+if (utf && end_subject != true_end_subject &&
+    (rc == MATCH_NOMATCH || rc == PCRE2_ERROR_PARTIAL))
+  {
+  for (;;)
+    {
+    /* Advance past the first bad code unit, and then skip invalid character
+    starting code units in 8-bit and 16-bit modes. */
+
+    start_match = end_subject + 1;
+    
+#if PCRE2_CODE_UNIT_WIDTH != 32
+    while (start_match < true_end_subject && NOT_FIRSTCU(*start_match))
+      start_match++;
+#endif
+
+    /* If we have hit the end of the subject, there isn't another non-empty
+    fragment, so give up. */
+
+    if (start_match >= true_end_subject)
+      {
+      rc = MATCH_NOMATCH;  /* In case it was partial */
+      break;
+      }
+
+    /* Check the rest of the subject */
+
+    mb->check_subject = start_match;
+    rc = PRIV(valid_utf)(start_match, length - (start_match - subject),
+      &(match_data->startchar));
+
+    /* The rest of the subject is valid UTF. */
+
+    if (rc == 0)
+      {
+      mb->end_subject = end_subject = true_end_subject;
+      fragment_options = PCRE2_NOTBOL;
+      goto FRAGMENT_RESTART;
+      }
+
+    /* A subsequent UTF error has been found; if the next fragment is
+    non-empty, set up to process it. Otherwise, let the loop advance. */
+
+    else if (rc < 0)
+      {
+      mb->end_subject = end_subject = start_match + match_data->startchar;
+      if (end_subject > start_match)
+        {
+        fragment_options = PCRE2_NOTBOL|PCRE2_NOTEOL;
+        goto FRAGMENT_RESTART;
+        }
+      }
+    }
+  }
+#endif  /* SUPPORT_UNICODE */
+
+/* Release an enlarged frame vector that is on the heap. */
+
+if (mb->match_frames != mb->stack_frames)
+  mb->memctl.free(mb->match_frames, mb->memctl.memory_data);
+
+/* Fill in fields that are always returned in the match data. */
+
+match_data->code = re;
+match_data->mark = mb->mark;
+match_data->matchedby = PCRE2_MATCHEDBY_INTERPRETER;
+
+/* Handle a fully successful match. Set the return code to the number of
+captured strings, or 0 if there were too many to fit into the ovector, and then
+set the remaining returned values before returning. Make a copy of the subject
+string if requested. */
+
+if (rc == MATCH_MATCH)
+  {
+  match_data->rc = ((int)mb->end_offset_top >= 2 * match_data->oveccount)?
+    0 : (int)mb->end_offset_top/2 + 1;
+  match_data->startchar = start_match - subject;
+  match_data->leftchar = mb->start_used_ptr - subject;
+  match_data->rightchar = ((mb->last_used_ptr > mb->end_match_ptr)?
+    mb->last_used_ptr : mb->end_match_ptr) - subject;
+  if ((options & PCRE2_COPY_MATCHED_SUBJECT) != 0)
+    {
+    length = CU2BYTES(length + was_zero_terminated);
+    match_data->subject = match_data->memctl.malloc(length,
+      match_data->memctl.memory_data);
+    if (match_data->subject == NULL) return PCRE2_ERROR_NOMEMORY;
+    memcpy((void *)match_data->subject, subject, length);
+    match_data->flags |= PCRE2_MD_COPIED_SUBJECT;
+    }
+  else match_data->subject = subject;
+  return match_data->rc;
+  }
+
+/* Control gets here if there has been a partial match, an error, or if the
+overall match attempt has failed at all permitted starting positions. Any mark
+data is in the nomatch_mark field. */
+
+match_data->mark = mb->nomatch_mark;
+
+/* For anything other than nomatch or partial match, just return the code. */
+
+if (rc != MATCH_NOMATCH && rc != PCRE2_ERROR_PARTIAL) match_data->rc = rc;
+
+/* Handle a partial match. If a "soft" partial match was requested, searching
+for a complete match will have continued, and the value of rc at this point
+will be MATCH_NOMATCH. For a "hard" partial match, it will already be
+PCRE2_ERROR_PARTIAL. */
+
+else if (match_partial != NULL)
+  {
+  match_data->subject = subject;
+  match_data->ovector[0] = match_partial - subject;
+  match_data->ovector[1] = end_subject - subject;
+  match_data->startchar = match_partial - subject;
+  match_data->leftchar = start_partial - subject;
+  match_data->rightchar = end_subject - subject;
+  match_data->rc = PCRE2_ERROR_PARTIAL;
+  }
+
+/* Else this is the classic nomatch case. */
+
+else match_data->rc = PCRE2_ERROR_NOMATCH;
+
+return match_data->rc;
+}
+
+/* End of pcre2_match.c */
diff --git a/src/c/pcre2/src/pcre2_match_data.c b/src/c/pcre2/src/pcre2_match_data.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_match_data.c
@@ -0,0 +1,166 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2019 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+
+/*************************************************
+*  Create a match data block given ovector size  *
+*************************************************/
+
+/* A minimum of 1 is imposed on the number of ovector pairs. */
+
+PCRE2_EXP_DEFN pcre2_match_data * PCRE2_CALL_CONVENTION
+pcre2_match_data_create(uint32_t oveccount, pcre2_general_context *gcontext)
+{
+pcre2_match_data *yield;
+if (oveccount < 1) oveccount = 1;
+yield = PRIV(memctl_malloc)(
+  offsetof(pcre2_match_data, ovector) + 2*oveccount*sizeof(PCRE2_SIZE),
+  (pcre2_memctl *)gcontext);
+if (yield == NULL) return NULL;
+yield->oveccount = oveccount;
+yield->flags = 0;
+return yield;
+}
+
+
+
+/*************************************************
+*  Create a match data block using pattern data  *
+*************************************************/
+
+/* If no context is supplied, use the memory allocator from the code. */
+
+PCRE2_EXP_DEFN pcre2_match_data * PCRE2_CALL_CONVENTION
+pcre2_match_data_create_from_pattern(const pcre2_code *code,
+  pcre2_general_context *gcontext)
+{
+if (gcontext == NULL) gcontext = (pcre2_general_context *)code;
+return pcre2_match_data_create(((pcre2_real_code *)code)->top_bracket + 1,
+  gcontext);
+}
+
+
+
+/*************************************************
+*            Free a match data block             *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_match_data_free(pcre2_match_data *match_data)
+{
+if (match_data != NULL)
+  {
+  if ((match_data->flags & PCRE2_MD_COPIED_SUBJECT) != 0)
+    match_data->memctl.free((void *)match_data->subject,
+      match_data->memctl.memory_data);
+  match_data->memctl.free(match_data, match_data->memctl.memory_data);
+  }
+}
+
+
+
+/*************************************************
+*         Get last mark in match                 *
+*************************************************/
+
+PCRE2_EXP_DEFN PCRE2_SPTR PCRE2_CALL_CONVENTION
+pcre2_get_mark(pcre2_match_data *match_data)
+{
+return match_data->mark;
+}
+
+
+
+/*************************************************
+*          Get pointer to ovector                *
+*************************************************/
+
+PCRE2_EXP_DEFN PCRE2_SIZE * PCRE2_CALL_CONVENTION
+pcre2_get_ovector_pointer(pcre2_match_data *match_data)
+{
+return match_data->ovector;
+}
+
+
+
+/*************************************************
+*          Get number of ovector slots           *
+*************************************************/
+
+PCRE2_EXP_DEFN uint32_t PCRE2_CALL_CONVENTION
+pcre2_get_ovector_count(pcre2_match_data *match_data)
+{
+return match_data->oveccount;
+}
+
+
+
+/*************************************************
+*         Get starting code unit in match        *
+*************************************************/
+
+PCRE2_EXP_DEFN PCRE2_SIZE PCRE2_CALL_CONVENTION
+pcre2_get_startchar(pcre2_match_data *match_data)
+{
+return match_data->startchar;
+}
+
+
+
+/*************************************************
+*         Get size of match data block           *
+*************************************************/
+
+PCRE2_EXP_DEFN PCRE2_SIZE PCRE2_CALL_CONVENTION
+pcre2_get_match_data_size(pcre2_match_data *match_data)
+{
+return offsetof(pcre2_match_data, ovector) +
+  2 * (match_data->oveccount) * sizeof(PCRE2_SIZE);
+}
+
+/* End of pcre2_match_data.c */
diff --git a/src/c/pcre2/src/pcre2_newline.c b/src/c/pcre2/src/pcre2_newline.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_newline.c
@@ -0,0 +1,243 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+         New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains internal functions for testing newlines when more than
+one kind of newline is to be recognized. When a newline is found, its length is
+returned. In principle, we could implement several newline "types", each
+referring to a different set of newline characters. At present, PCRE2 supports
+only NLTYPE_FIXED, which gets handled without these functions, NLTYPE_ANYCRLF,
+and NLTYPE_ANY. The full list of Unicode newline characters is taken from
+http://unicode.org/unicode/reports/tr18/. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+
+/*************************************************
+*      Check for newline at given position       *
+*************************************************/
+
+/* This function is called only via the IS_NEWLINE macro, which does so only
+when the newline type is NLTYPE_ANY or NLTYPE_ANYCRLF. The case of a fixed
+newline (NLTYPE_FIXED) is handled inline. It is guaranteed that the code unit
+pointed to by ptr is less than the end of the string.
+
+Arguments:
+  ptr          pointer to possible newline
+  type         the newline type
+  endptr       pointer to the end of the string
+  lenptr       where to return the length
+  utf          TRUE if in utf mode
+
+Returns:       TRUE or FALSE
+*/
+
+BOOL
+PRIV(is_newline)(PCRE2_SPTR ptr, uint32_t type, PCRE2_SPTR endptr,
+  uint32_t *lenptr, BOOL utf)
+{
+uint32_t c;
+
+#ifdef SUPPORT_UNICODE
+if (utf) { GETCHAR(c, ptr); } else c = *ptr;
+#else
+(void)utf;
+c = *ptr;
+#endif  /* SUPPORT_UNICODE */
+
+if (type == NLTYPE_ANYCRLF) switch(c)
+  {
+  case CHAR_LF:
+  *lenptr = 1;
+  return TRUE;
+
+  case CHAR_CR:
+  *lenptr = (ptr < endptr - 1 && ptr[1] == CHAR_LF)? 2 : 1;
+  return TRUE;
+
+  default:
+  return FALSE;
+  }
+
+/* NLTYPE_ANY */
+
+else switch(c)
+  {
+#ifdef EBCDIC
+  case CHAR_NEL:
+#endif
+  case CHAR_LF:
+  case CHAR_VT:
+  case CHAR_FF:
+  *lenptr = 1;
+  return TRUE;
+
+  case CHAR_CR:
+  *lenptr = (ptr < endptr - 1 && ptr[1] == CHAR_LF)? 2 : 1;
+  return TRUE;
+
+#ifndef EBCDIC
+#if PCRE2_CODE_UNIT_WIDTH == 8
+  case CHAR_NEL:
+  *lenptr = utf? 2 : 1;
+  return TRUE;
+
+  case 0x2028:   /* LS */
+  case 0x2029:   /* PS */
+  *lenptr = 3;
+  return TRUE;
+
+#else  /* 16-bit or 32-bit code units */
+  case CHAR_NEL:
+  case 0x2028:   /* LS */
+  case 0x2029:   /* PS */
+  *lenptr = 1;
+  return TRUE;
+#endif
+#endif /* Not EBCDIC */
+
+  default:
+  return FALSE;
+  }
+}
+
+
+
+/*************************************************
+*     Check for newline at previous position     *
+*************************************************/
+
+/* This function is called only via the WAS_NEWLINE macro, which does so only
+when the newline type is NLTYPE_ANY or NLTYPE_ANYCRLF. The case of a fixed
+newline (NLTYPE_FIXED) is handled inline. It is guaranteed that the initial
+value of ptr is greater than the start of the string that is being processed.
+
+Arguments:
+  ptr          pointer to possible newline
+  type         the newline type
+  startptr     pointer to the start of the string
+  lenptr       where to return the length
+  utf          TRUE if in utf mode
+
+Returns:       TRUE or FALSE
+*/
+
+BOOL
+PRIV(was_newline)(PCRE2_SPTR ptr, uint32_t type, PCRE2_SPTR startptr,
+  uint32_t *lenptr, BOOL utf)
+{
+uint32_t c;
+ptr--;
+
+#ifdef SUPPORT_UNICODE
+if (utf)
+  {
+  BACKCHAR(ptr);
+  GETCHAR(c, ptr);
+  }
+else c = *ptr;
+#else
+(void)utf;
+c = *ptr;
+#endif  /* SUPPORT_UNICODE */
+
+if (type == NLTYPE_ANYCRLF) switch(c)
+  {
+  case CHAR_LF:
+  *lenptr = (ptr > startptr && ptr[-1] == CHAR_CR)? 2 : 1;
+  return TRUE;
+
+  case CHAR_CR:
+  *lenptr = 1;
+  return TRUE;
+
+  default:
+  return FALSE;
+  }
+
+/* NLTYPE_ANY */
+
+else switch(c)
+  {
+  case CHAR_LF:
+  *lenptr = (ptr > startptr && ptr[-1] == CHAR_CR)? 2 : 1;
+  return TRUE;
+
+#ifdef EBCDIC
+  case CHAR_NEL:
+#endif
+  case CHAR_VT:
+  case CHAR_FF:
+  case CHAR_CR:
+  *lenptr = 1;
+  return TRUE;
+
+#ifndef EBCDIC
+#if PCRE2_CODE_UNIT_WIDTH == 8
+  case CHAR_NEL:
+  *lenptr = utf? 2 : 1;
+  return TRUE;
+
+  case 0x2028:   /* LS */
+  case 0x2029:   /* PS */
+  *lenptr = 3;
+  return TRUE;
+
+#else /* 16-bit or 32-bit code units */
+  case CHAR_NEL:
+  case 0x2028:   /* LS */
+  case 0x2029:   /* PS */
+  *lenptr = 1;
+  return TRUE;
+#endif
+#endif /* Not EBCDIC */
+
+  default:
+  return FALSE;
+  }
+}
+
+/* End of pcre2_newline.c */
diff --git a/src/c/pcre2/src/pcre2_ord2utf.c b/src/c/pcre2/src/pcre2_ord2utf.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_ord2utf.c
@@ -0,0 +1,120 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+         New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This file contains a function that converts a Unicode character code point
+into a UTF string. The behaviour is different for each code unit width. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+/* If SUPPORT_UNICODE is not defined, this function will never be called.
+Supply a dummy function because some compilers do not like empty source
+modules. */
+
+#ifndef SUPPORT_UNICODE
+unsigned int
+PRIV(ord2utf)(uint32_t cvalue, PCRE2_UCHAR *buffer)
+{
+(void)(cvalue);
+(void)(buffer);
+return 0;
+}
+#else  /* SUPPORT_UNICODE */
+
+
+/*************************************************
+*          Convert code point to UTF             *
+*************************************************/
+
+/*
+Arguments:
+  cvalue     the character value
+  buffer     pointer to buffer for result
+
+Returns:     number of code units placed in the buffer
+*/
+
+unsigned int
+PRIV(ord2utf)(uint32_t cvalue, PCRE2_UCHAR *buffer)
+{
+/* Convert to UTF-8 */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+int i, j;
+for (i = 0; i < PRIV(utf8_table1_size); i++)
+  if ((int)cvalue <= PRIV(utf8_table1)[i]) break;
+buffer += i;
+for (j = i; j > 0; j--)
+ {
+ *buffer-- = 0x80 | (cvalue & 0x3f);
+ cvalue >>= 6;
+ }
+*buffer = PRIV(utf8_table2)[i] | cvalue;
+return i + 1;
+
+/* Convert to UTF-16 */
+
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+if (cvalue <= 0xffff)
+  {
+  *buffer = (PCRE2_UCHAR)cvalue;
+  return 1;
+  }
+cvalue -= 0x10000;
+*buffer++ = 0xd800 | (cvalue >> 10);
+*buffer = 0xdc00 | (cvalue & 0x3ff);
+return 2;
+
+/* Convert to UTF-32 */
+
+#else
+*buffer = (PCRE2_UCHAR)cvalue;
+return 1;
+#endif
+}
+#endif  /* SUPPORT_UNICODE */
+
+/* End of pcre_ord2utf.c */
diff --git a/src/c/pcre2/src/pcre2_pattern_info.c b/src/c/pcre2/src/pcre2_pattern_info.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_pattern_info.c
@@ -0,0 +1,432 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+/*************************************************
+*        Return info about compiled pattern      *
+*************************************************/
+
+/*
+Arguments:
+  code          points to compiled code
+  what          what information is required
+  where         where to put the information; if NULL, return length
+
+Returns:        0 when data returned
+                > 0 when length requested
+                < 0 on error or unset value
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_pattern_info(const pcre2_code *code, uint32_t what, void *where)
+{
+const pcre2_real_code *re = (pcre2_real_code *)code;
+
+if (where == NULL)   /* Requests field length */
+  {
+  switch(what)
+    {
+    case PCRE2_INFO_ALLOPTIONS:
+    case PCRE2_INFO_ARGOPTIONS:
+    case PCRE2_INFO_BACKREFMAX:
+    case PCRE2_INFO_BSR:
+    case PCRE2_INFO_CAPTURECOUNT:
+    case PCRE2_INFO_DEPTHLIMIT:
+    case PCRE2_INFO_EXTRAOPTIONS:
+    case PCRE2_INFO_FIRSTCODETYPE:
+    case PCRE2_INFO_FIRSTCODEUNIT:
+    case PCRE2_INFO_HASBACKSLASHC:
+    case PCRE2_INFO_HASCRORLF:
+    case PCRE2_INFO_HEAPLIMIT:
+    case PCRE2_INFO_JCHANGED:
+    case PCRE2_INFO_LASTCODETYPE:
+    case PCRE2_INFO_LASTCODEUNIT:
+    case PCRE2_INFO_MATCHEMPTY:
+    case PCRE2_INFO_MATCHLIMIT:
+    case PCRE2_INFO_MAXLOOKBEHIND:
+    case PCRE2_INFO_MINLENGTH:
+    case PCRE2_INFO_NAMEENTRYSIZE:
+    case PCRE2_INFO_NAMECOUNT:
+    case PCRE2_INFO_NEWLINE:
+    return sizeof(uint32_t);
+
+    case PCRE2_INFO_FIRSTBITMAP:
+    return sizeof(const uint8_t *);
+
+    case PCRE2_INFO_JITSIZE:
+    case PCRE2_INFO_SIZE:
+    case PCRE2_INFO_FRAMESIZE:
+    return sizeof(size_t);
+
+    case PCRE2_INFO_NAMETABLE:
+    return sizeof(PCRE2_SPTR);
+    }
+  }
+
+if (re == NULL) return PCRE2_ERROR_NULL;
+
+/* Check that the first field in the block is the magic number. If it is not,
+return with PCRE2_ERROR_BADMAGIC. */
+
+if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
+
+/* Check that this pattern was compiled in the correct bit mode */
+
+if ((re->flags & (PCRE2_CODE_UNIT_WIDTH/8)) == 0) return PCRE2_ERROR_BADMODE;
+
+switch(what)
+  {
+  case PCRE2_INFO_ALLOPTIONS:
+  *((uint32_t *)where) = re->overall_options;
+  break;
+
+  case PCRE2_INFO_ARGOPTIONS:
+  *((uint32_t *)where) = re->compile_options;
+  break;
+
+  case PCRE2_INFO_BACKREFMAX:
+  *((uint32_t *)where) = re->top_backref;
+  break;
+
+  case PCRE2_INFO_BSR:
+  *((uint32_t *)where) = re->bsr_convention;
+  break;
+
+  case PCRE2_INFO_CAPTURECOUNT:
+  *((uint32_t *)where) = re->top_bracket;
+  break;
+
+  case PCRE2_INFO_DEPTHLIMIT:
+  *((uint32_t *)where) = re->limit_depth;
+  if (re->limit_depth == UINT32_MAX) return PCRE2_ERROR_UNSET;
+  break;
+
+  case PCRE2_INFO_EXTRAOPTIONS:
+  *((uint32_t *)where) = re->extra_options;
+  break;
+
+  case PCRE2_INFO_FIRSTCODETYPE:
+  *((uint32_t *)where) = ((re->flags & PCRE2_FIRSTSET) != 0)? 1 :
+                         ((re->flags & PCRE2_STARTLINE) != 0)? 2 : 0;
+  break;
+
+  case PCRE2_INFO_FIRSTCODEUNIT:
+  *((uint32_t *)where) = ((re->flags & PCRE2_FIRSTSET) != 0)?
+    re->first_codeunit : 0;
+  break;
+
+  case PCRE2_INFO_FIRSTBITMAP:
+  *((const uint8_t **)where) = ((re->flags & PCRE2_FIRSTMAPSET) != 0)?
+    &(re->start_bitmap[0]) : NULL;
+  break;
+
+  case PCRE2_INFO_FRAMESIZE:
+  *((size_t *)where) = offsetof(heapframe, ovector) +
+    re->top_bracket * 2 * sizeof(PCRE2_SIZE);
+  break;
+
+  case PCRE2_INFO_HASBACKSLASHC:
+  *((uint32_t *)where) = (re->flags & PCRE2_HASBKC) != 0;
+  break;
+
+  case PCRE2_INFO_HASCRORLF:
+  *((uint32_t *)where) = (re->flags & PCRE2_HASCRORLF) != 0;
+  break;
+
+  case PCRE2_INFO_HEAPLIMIT:
+  *((uint32_t *)where) = re->limit_heap;
+  if (re->limit_heap == UINT32_MAX) return PCRE2_ERROR_UNSET;
+  break;
+
+  case PCRE2_INFO_JCHANGED:
+  *((uint32_t *)where) = (re->flags & PCRE2_JCHANGED) != 0;
+  break;
+
+  case PCRE2_INFO_JITSIZE:
+#ifdef SUPPORT_JIT
+  *((size_t *)where) = (re->executable_jit != NULL)?
+    PRIV(jit_get_size)(re->executable_jit) : 0;
+#else
+  *((size_t *)where) = 0;
+#endif
+  break;
+
+  case PCRE2_INFO_LASTCODETYPE:
+  *((uint32_t *)where) = ((re->flags & PCRE2_LASTSET) != 0)? 1 : 0;
+  break;
+
+  case PCRE2_INFO_LASTCODEUNIT:
+  *((uint32_t *)where) = ((re->flags & PCRE2_LASTSET) != 0)?
+    re->last_codeunit : 0;
+  break;
+
+  case PCRE2_INFO_MATCHEMPTY:
+  *((uint32_t *)where) = (re->flags & PCRE2_MATCH_EMPTY) != 0;
+  break;
+
+  case PCRE2_INFO_MATCHLIMIT:
+  *((uint32_t *)where) = re->limit_match;
+  if (re->limit_match == UINT32_MAX) return PCRE2_ERROR_UNSET;
+  break;
+
+  case PCRE2_INFO_MAXLOOKBEHIND:
+  *((uint32_t *)where) = re->max_lookbehind;
+  break;
+
+  case PCRE2_INFO_MINLENGTH:
+  *((uint32_t *)where) = re->minlength;
+  break;
+
+  case PCRE2_INFO_NAMEENTRYSIZE:
+  *((uint32_t *)where) = re->name_entry_size;
+  break;
+
+  case PCRE2_INFO_NAMECOUNT:
+  *((uint32_t *)where) = re->name_count;
+  break;
+
+  case PCRE2_INFO_NAMETABLE:
+  *((PCRE2_SPTR *)where) = (PCRE2_SPTR)((char *)re + sizeof(pcre2_real_code));
+  break;
+
+  case PCRE2_INFO_NEWLINE:
+  *((uint32_t *)where) = re->newline_convention;
+  break;
+
+  case PCRE2_INFO_SIZE:
+  *((size_t *)where) = re->blocksize;
+  break;
+
+  default: return PCRE2_ERROR_BADOPTION;
+  }
+
+return 0;
+}
+
+
+
+/*************************************************
+*              Callout enumerator                *
+*************************************************/
+
+/*
+Arguments:
+  code          points to compiled code
+  callback      function called for each callout block
+  callout_data  user data passed to the callback
+
+Returns:        0 when successfully completed
+                < 0 on local error
+               != 0 for callback error
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_callout_enumerate(const pcre2_code *code,
+  int (*callback)(pcre2_callout_enumerate_block *, void *), void *callout_data)
+{
+pcre2_real_code *re = (pcre2_real_code *)code;
+pcre2_callout_enumerate_block cb;
+PCRE2_SPTR cc;
+#ifdef SUPPORT_UNICODE
+BOOL utf;
+#endif
+
+if (re == NULL) return PCRE2_ERROR_NULL;
+
+#ifdef SUPPORT_UNICODE
+utf = (re->overall_options & PCRE2_UTF) != 0;
+#endif
+
+/* Check that the first field in the block is the magic number. If it is not,
+return with PCRE2_ERROR_BADMAGIC. */
+
+if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
+
+/* Check that this pattern was compiled in the correct bit mode */
+
+if ((re->flags & (PCRE2_CODE_UNIT_WIDTH/8)) == 0) return PCRE2_ERROR_BADMODE;
+
+cb.version = 0;
+cc = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code))
+     + re->name_count * re->name_entry_size;
+
+while (TRUE)
+  {
+  int rc;
+  switch (*cc)
+    {
+    case OP_END:
+    return 0;
+
+    case OP_CHAR:
+    case OP_CHARI:
+    case OP_NOT:
+    case OP_NOTI:
+    case OP_STAR:
+    case OP_MINSTAR:
+    case OP_PLUS:
+    case OP_MINPLUS:
+    case OP_QUERY:
+    case OP_MINQUERY:
+    case OP_UPTO:
+    case OP_MINUPTO:
+    case OP_EXACT:
+    case OP_POSSTAR:
+    case OP_POSPLUS:
+    case OP_POSQUERY:
+    case OP_POSUPTO:
+    case OP_STARI:
+    case OP_MINSTARI:
+    case OP_PLUSI:
+    case OP_MINPLUSI:
+    case OP_QUERYI:
+    case OP_MINQUERYI:
+    case OP_UPTOI:
+    case OP_MINUPTOI:
+    case OP_EXACTI:
+    case OP_POSSTARI:
+    case OP_POSPLUSI:
+    case OP_POSQUERYI:
+    case OP_POSUPTOI:
+    case OP_NOTSTAR:
+    case OP_NOTMINSTAR:
+    case OP_NOTPLUS:
+    case OP_NOTMINPLUS:
+    case OP_NOTQUERY:
+    case OP_NOTMINQUERY:
+    case OP_NOTUPTO:
+    case OP_NOTMINUPTO:
+    case OP_NOTEXACT:
+    case OP_NOTPOSSTAR:
+    case OP_NOTPOSPLUS:
+    case OP_NOTPOSQUERY:
+    case OP_NOTPOSUPTO:
+    case OP_NOTSTARI:
+    case OP_NOTMINSTARI:
+    case OP_NOTPLUSI:
+    case OP_NOTMINPLUSI:
+    case OP_NOTQUERYI:
+    case OP_NOTMINQUERYI:
+    case OP_NOTUPTOI:
+    case OP_NOTMINUPTOI:
+    case OP_NOTEXACTI:
+    case OP_NOTPOSSTARI:
+    case OP_NOTPOSPLUSI:
+    case OP_NOTPOSQUERYI:
+    case OP_NOTPOSUPTOI:
+    cc += PRIV(OP_lengths)[*cc];
+#ifdef SUPPORT_UNICODE
+    if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+    break;
+
+    case OP_TYPESTAR:
+    case OP_TYPEMINSTAR:
+    case OP_TYPEPLUS:
+    case OP_TYPEMINPLUS:
+    case OP_TYPEQUERY:
+    case OP_TYPEMINQUERY:
+    case OP_TYPEUPTO:
+    case OP_TYPEMINUPTO:
+    case OP_TYPEEXACT:
+    case OP_TYPEPOSSTAR:
+    case OP_TYPEPOSPLUS:
+    case OP_TYPEPOSQUERY:
+    case OP_TYPEPOSUPTO:
+    cc += PRIV(OP_lengths)[*cc];
+#ifdef SUPPORT_UNICODE
+    if (cc[-1] == OP_PROP || cc[-1] == OP_NOTPROP) cc += 2;
+#endif
+    break;
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+    case OP_XCLASS:
+    cc += GET(cc, 1);
+    break;
+#endif
+
+    case OP_MARK:
+    case OP_COMMIT_ARG:
+    case OP_PRUNE_ARG:
+    case OP_SKIP_ARG:
+    case OP_THEN_ARG:
+    cc += PRIV(OP_lengths)[*cc] + cc[1];
+    break;
+
+    case OP_CALLOUT:
+    cb.pattern_position = GET(cc, 1);
+    cb.next_item_length = GET(cc, 1 + LINK_SIZE);
+    cb.callout_number = cc[1 + 2*LINK_SIZE];
+    cb.callout_string_offset = 0;
+    cb.callout_string_length = 0;
+    cb.callout_string = NULL;
+    rc = callback(&cb, callout_data);
+    if (rc != 0) return rc;
+    cc += PRIV(OP_lengths)[*cc];
+    break;
+
+    case OP_CALLOUT_STR:
+    cb.pattern_position = GET(cc, 1);
+    cb.next_item_length = GET(cc, 1 + LINK_SIZE);
+    cb.callout_number = 0;
+    cb.callout_string_offset = GET(cc, 1 + 3*LINK_SIZE);
+    cb.callout_string_length =
+      GET(cc, 1 + 2*LINK_SIZE) - (1 + 4*LINK_SIZE) - 2;
+    cb.callout_string = cc + (1 + 4*LINK_SIZE) + 1;
+    rc = callback(&cb, callout_data);
+    if (rc != 0) return rc;
+    cc += GET(cc, 1 + 2*LINK_SIZE);
+    break;
+
+    default:
+    cc += PRIV(OP_lengths)[*cc];
+    break;
+    }
+  }
+}
+
+/* End of pcre2_pattern_info.c */
diff --git a/src/c/pcre2/src/pcre2_printint.c b/src/c/pcre2/src/pcre2_printint.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_printint.c
@@ -0,0 +1,836 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2019 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains a PCRE private debugging function for printing out the
+internal form of a compiled regular expression, along with some supporting
+local functions. This source file is #included in pcre2test.c at each supported
+code unit width, with PCRE2_SUFFIX set appropriately, just like the functions
+that comprise the library. It can also optionally be included in
+pcre2_compile.c for detailed debugging in error situations. */
+
+
+/* Tables of operator names. The same 8-bit table is used for all code unit
+widths, so it must be defined only once. The list itself is defined in
+pcre2_internal.h, which is #included by pcre2test before this file. */
+
+#ifndef OP_LISTS_DEFINED
+static const char *OP_names[] = { OP_NAME_LIST };
+#define OP_LISTS_DEFINED
+#endif
+
+/* The functions and tables herein must all have mode-dependent names. */
+
+#define OP_lengths            PCRE2_SUFFIX(OP_lengths_)
+#define get_ucpname           PCRE2_SUFFIX(get_ucpname_)
+#define pcre2_printint        PCRE2_SUFFIX(pcre2_printint_)
+#define print_char            PCRE2_SUFFIX(print_char_)
+#define print_custring        PCRE2_SUFFIX(print_custring_)
+#define print_custring_bylen  PCRE2_SUFFIX(print_custring_bylen_)
+#define print_prop            PCRE2_SUFFIX(print_prop_)
+
+/* Table of sizes for the fixed-length opcodes. It's defined in a macro so that
+the definition is next to the definition of the opcodes in pcre2_internal.h.
+The contents of the table are, however, mode-dependent. */
+
+static const uint8_t OP_lengths[] = { OP_LENGTHS };
+
+
+
+/*************************************************
+*       Print one character from a string        *
+*************************************************/
+
+/* In UTF mode the character may occupy more than one code unit.
+
+Arguments:
+  f           file to write to
+  ptr         pointer to first code unit of the character
+  utf         TRUE if string is UTF (will be FALSE if UTF is not supported)
+
+Returns:      number of additional code units used
+*/
+
+static unsigned int
+print_char(FILE *f, PCRE2_SPTR ptr, BOOL utf)
+{
+uint32_t c = *ptr;
+BOOL one_code_unit = !utf;
+
+/* If UTF is supported and requested, check for a valid single code unit. */
+
+#ifdef SUPPORT_UNICODE
+if (utf)
+  {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+  one_code_unit = c < 0x80;
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+  one_code_unit = (c & 0xfc00) != 0xd800;
+#else
+  one_code_unit = (c & 0xfffff800u) != 0xd800u;
+#endif  /* CODE_UNIT_WIDTH */
+  }
+#endif  /* SUPPORT_UNICODE */
+
+/* Handle a valid one-code-unit character at any width. */
+
+if (one_code_unit)
+  {
+  if (PRINTABLE(c)) fprintf(f, "%c", (char)c);
+  else if (c < 0x80) fprintf(f, "\\x%02x", c);
+  else fprintf(f, "\\x{%02x}", c);
+  return 0;
+  }
+
+/* Code for invalid UTF code units and multi-unit UTF characters is different
+for each width. If UTF is not supported, control should never get here, but we
+need a return statement to keep the compiler happy. */
+
+#ifndef SUPPORT_UNICODE
+return 0;
+#else
+
+/* Malformed UTF-8 should occur only if the sanity check has been turned off.
+Rather than swallow random bytes, just stop if we hit a bad one. Print it with
+\X instead of \x as an indication. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+if ((c & 0xc0) != 0xc0)
+  {
+  fprintf(f, "\\X{%x}", c);       /* Invalid starting byte */
+  return 0;
+  }
+else
+  {
+  int i;
+  int a = PRIV(utf8_table4)[c & 0x3f];  /* Number of additional bytes */
+  int s = 6*a;
+  c = (c & PRIV(utf8_table3)[a]) << s;
+  for (i = 1; i <= a; i++)
+    {
+    if ((ptr[i] & 0xc0) != 0x80)
+      {
+      fprintf(f, "\\X{%x}", c);   /* Invalid secondary byte */
+      return i - 1;
+      }
+    s -= 6;
+    c |= (ptr[i] & 0x3f) << s;
+    }
+  fprintf(f, "\\x{%x}", c);
+  return a;
+}
+#endif  /* PCRE2_CODE_UNIT_WIDTH == 8 */
+
+/* UTF-16: rather than swallow a low surrogate, just stop if we hit a bad one.
+Print it with \X instead of \x as an indication. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 16
+if ((ptr[1] & 0xfc00) != 0xdc00)
+  {
+  fprintf(f, "\\X{%x}", c);
+  return 0;
+  }
+c = (((c & 0x3ff) << 10) | (ptr[1] & 0x3ff)) + 0x10000;
+fprintf(f, "\\x{%x}", c);
+return 1;
+#endif  /* PCRE2_CODE_UNIT_WIDTH == 16 */
+
+/* For UTF-32 we get here only for a malformed code unit, which should only
+occur if the sanity check has been turned off. Print it with \X instead of \x
+as an indication. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+fprintf(f, "\\X{%x}", c);
+return 0;
+#endif  /* PCRE2_CODE_UNIT_WIDTH == 32 */
+#endif  /* SUPPORT_UNICODE */
+}
+
+
+
+/*************************************************
+*     Print string as a list of code units       *
+*************************************************/
+
+/* These take no account of UTF as they always print each individual code unit.
+The string is zero-terminated for print_custring(); the length is given for
+print_custring_bylen().
+
+Arguments:
+  f          file to write to
+  ptr        point to the string
+  len        length for print_custring_bylen()
+
+Returns:     nothing
+*/
+
+static void
+print_custring(FILE *f, PCRE2_SPTR ptr)
+{
+while (*ptr != '\0')
+  {
+  uint32_t c = *ptr++;
+  if (PRINTABLE(c)) fprintf(f, "%c", c); else fprintf(f, "\\x{%x}", c);
+  }
+}
+
+static void
+print_custring_bylen(FILE *f, PCRE2_SPTR ptr, PCRE2_UCHAR len)
+{
+for (; len > 0; len--)
+  {
+  uint32_t c = *ptr++;
+  if (PRINTABLE(c)) fprintf(f, "%c", c); else fprintf(f, "\\x{%x}", c);
+  }
+}
+
+
+
+/*************************************************
+*          Find Unicode property name            *
+*************************************************/
+
+/* When there is no UTF/UCP support, the table of names does not exist. This
+function should not be called in such configurations, because a pattern that
+tries to use Unicode properties won't compile. Rather than put lots of #ifdefs
+into the main code, however, we just put one into this function. */
+
+static const char *
+get_ucpname(unsigned int ptype, unsigned int pvalue)
+{
+#ifdef SUPPORT_UNICODE
+int i;
+for (i = PRIV(utt_size) - 1; i >= 0; i--)
+  {
+  if (ptype == PRIV(utt)[i].type && pvalue == PRIV(utt)[i].value) break;
+  }
+return (i >= 0)? PRIV(utt_names) + PRIV(utt)[i].name_offset : "??";
+#else   /* No UTF support */
+(void)ptype;
+(void)pvalue;
+return "??";
+#endif  /* SUPPORT_UNICODE */
+}
+
+
+
+/*************************************************
+*       Print Unicode property value             *
+*************************************************/
+
+/* "Normal" properties can be printed from tables. The PT_CLIST property is a
+pseudo-property that contains a pointer to a list of case-equivalent
+characters.
+
+Arguments:
+  f            file to write to
+  code         pointer in the compiled code
+  before       text to print before
+  after        text to print after
+
+Returns:       nothing
+*/
+
+static void
+print_prop(FILE *f, PCRE2_SPTR code, const char *before, const char *after)
+{
+if (code[1] != PT_CLIST)
+  {
+  fprintf(f, "%s%s %s%s", before, OP_names[*code], get_ucpname(code[1],
+    code[2]), after);
+  }
+else
+  {
+  const char *not = (*code == OP_PROP)? "" : "not ";
+  const uint32_t *p = PRIV(ucd_caseless_sets) + code[2];
+  fprintf (f, "%s%sclist", before, not);
+  while (*p < NOTACHAR) fprintf(f, " %04x", *p++);
+  fprintf(f, "%s", after);
+  }
+}
+
+
+
+/*************************************************
+*            Print compiled pattern              *
+*************************************************/
+
+/* The print_lengths flag controls whether offsets and lengths of items are
+printed. Lenths can be turned off from pcre2test so that automatic tests on
+bytecode can be written that do not depend on the value of LINK_SIZE.
+
+Arguments:
+  re              a compiled pattern
+  f               the file to write to
+  print_lengths   show various lengths
+
+Returns:          nothing
+*/
+
+static void
+pcre2_printint(pcre2_code *re, FILE *f, BOOL print_lengths)
+{
+PCRE2_SPTR codestart, nametable, code;
+uint32_t nesize = re->name_entry_size;
+BOOL utf = (re->overall_options & PCRE2_UTF) != 0;
+
+nametable = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code));
+code = codestart = nametable + re->name_count * re->name_entry_size;
+
+for(;;)
+  {
+  PCRE2_SPTR ccode;
+  uint32_t c;
+  int i;
+  const char *flag = "  ";
+  unsigned int extra = 0;
+
+  if (print_lengths)
+    fprintf(f, "%3d ", (int)(code - codestart));
+  else
+    fprintf(f, "    ");
+
+  switch(*code)
+    {
+/* ========================================================================== */
+      /* These cases are never obeyed. This is a fudge that causes a compile-
+      time error if the vectors OP_names or OP_lengths, which are indexed
+      by opcode, are not the correct length. It seems to be the only way to do
+      such a check at compile time, as the sizeof() operator does not work in
+      the C preprocessor. */
+
+      case OP_TABLE_LENGTH:
+      case OP_TABLE_LENGTH +
+        ((sizeof(OP_names)/sizeof(const char *) == OP_TABLE_LENGTH) &&
+        (sizeof(OP_lengths) == OP_TABLE_LENGTH)):
+      return;
+/* ========================================================================== */
+
+    case OP_END:
+    fprintf(f, "    %s\n", OP_names[*code]);
+    fprintf(f, "------------------------------------------------------------------\n");
+    return;
+
+    case OP_CHAR:
+    fprintf(f, "    ");
+    do
+      {
+      code++;
+      code += 1 + print_char(f, code, utf);
+      }
+    while (*code == OP_CHAR);
+    fprintf(f, "\n");
+    continue;
+
+    case OP_CHARI:
+    fprintf(f, " /i ");
+    do
+      {
+      code++;
+      code += 1 + print_char(f, code, utf);
+      }
+    while (*code == OP_CHARI);
+    fprintf(f, "\n");
+    continue;
+
+    case OP_CBRA:
+    case OP_CBRAPOS:
+    case OP_SCBRA:
+    case OP_SCBRAPOS:
+    if (print_lengths) fprintf(f, "%3d ", GET(code, 1));
+      else fprintf(f, "    ");
+    fprintf(f, "%s %d", OP_names[*code], GET2(code, 1+LINK_SIZE));
+    break;
+
+    case OP_BRA:
+    case OP_BRAPOS:
+    case OP_SBRA:
+    case OP_SBRAPOS:
+    case OP_KETRMAX:
+    case OP_KETRMIN:
+    case OP_KETRPOS:
+    case OP_ALT:
+    case OP_KET:
+    case OP_ASSERT:
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK:
+    case OP_ASSERTBACK_NOT:
+    case OP_ASSERT_NA:
+    case OP_ASSERTBACK_NA:
+    case OP_ONCE:
+    case OP_SCRIPT_RUN:
+    case OP_COND:
+    case OP_SCOND:
+    case OP_REVERSE:
+    if (print_lengths) fprintf(f, "%3d ", GET(code, 1));
+      else fprintf(f, "    ");
+    fprintf(f, "%s", OP_names[*code]);
+    break;
+
+    case OP_CLOSE:
+    fprintf(f, "    %s %d", OP_names[*code], GET2(code, 1));
+    break;
+
+    case OP_CREF:
+    fprintf(f, "%3d %s", GET2(code,1), OP_names[*code]);
+    break;
+
+    case OP_DNCREF:
+      {
+      PCRE2_SPTR entry = nametable + (GET2(code, 1) * nesize) + IMM2_SIZE;
+      fprintf(f, " %s Cond ref <", flag);
+      print_custring(f, entry);
+      fprintf(f, ">%d", GET2(code, 1 + IMM2_SIZE));
+      }
+    break;
+
+    case OP_RREF:
+    c = GET2(code, 1);
+    if (c == RREF_ANY)
+      fprintf(f, "    Cond recurse any");
+    else
+      fprintf(f, "    Cond recurse %d", c);
+    break;
+
+    case OP_DNRREF:
+      {
+      PCRE2_SPTR entry = nametable + (GET2(code, 1) * nesize) + IMM2_SIZE;
+      fprintf(f, " %s Cond recurse <", flag);
+      print_custring(f, entry);
+      fprintf(f, ">%d", GET2(code, 1 + IMM2_SIZE));
+      }
+    break;
+
+    case OP_FALSE:
+    fprintf(f, "    Cond false");
+    break;
+
+    case OP_TRUE:
+    fprintf(f, "    Cond true");
+    break;
+
+    case OP_STARI:
+    case OP_MINSTARI:
+    case OP_POSSTARI:
+    case OP_PLUSI:
+    case OP_MINPLUSI:
+    case OP_POSPLUSI:
+    case OP_QUERYI:
+    case OP_MINQUERYI:
+    case OP_POSQUERYI:
+    flag = "/i";
+    /* Fall through */
+    case OP_STAR:
+    case OP_MINSTAR:
+    case OP_POSSTAR:
+    case OP_PLUS:
+    case OP_MINPLUS:
+    case OP_POSPLUS:
+    case OP_QUERY:
+    case OP_MINQUERY:
+    case OP_POSQUERY:
+    case OP_TYPESTAR:
+    case OP_TYPEMINSTAR:
+    case OP_TYPEPOSSTAR:
+    case OP_TYPEPLUS:
+    case OP_TYPEMINPLUS:
+    case OP_TYPEPOSPLUS:
+    case OP_TYPEQUERY:
+    case OP_TYPEMINQUERY:
+    case OP_TYPEPOSQUERY:
+    fprintf(f, " %s ", flag);
+
+    if (*code >= OP_TYPESTAR)
+      {
+      if (code[1] == OP_PROP || code[1] == OP_NOTPROP)
+        {
+        print_prop(f, code + 1, "", " ");
+        extra = 2;
+        }
+      else fprintf(f, "%s", OP_names[code[1]]);
+      }
+    else extra = print_char(f, code+1, utf);
+    fprintf(f, "%s", OP_names[*code]);
+    break;
+
+    case OP_EXACTI:
+    case OP_UPTOI:
+    case OP_MINUPTOI:
+    case OP_POSUPTOI:
+    flag = "/i";
+    /* Fall through */
+    case OP_EXACT:
+    case OP_UPTO:
+    case OP_MINUPTO:
+    case OP_POSUPTO:
+    fprintf(f, " %s ", flag);
+    extra = print_char(f, code + 1 + IMM2_SIZE, utf);
+    fprintf(f, "{");
+    if (*code != OP_EXACT && *code != OP_EXACTI) fprintf(f, "0,");
+    fprintf(f, "%d}", GET2(code,1));
+    if (*code == OP_MINUPTO || *code == OP_MINUPTOI) fprintf(f, "?");
+      else if (*code == OP_POSUPTO || *code == OP_POSUPTOI) fprintf(f, "+");
+    break;
+
+    case OP_TYPEEXACT:
+    case OP_TYPEUPTO:
+    case OP_TYPEMINUPTO:
+    case OP_TYPEPOSUPTO:
+    if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
+      {
+      print_prop(f, code + IMM2_SIZE + 1, "    ", " ");
+      extra = 2;
+      }
+    else fprintf(f, "    %s", OP_names[code[1 + IMM2_SIZE]]);
+    fprintf(f, "{");
+    if (*code != OP_TYPEEXACT) fprintf(f, "0,");
+    fprintf(f, "%d}", GET2(code,1));
+    if (*code == OP_TYPEMINUPTO) fprintf(f, "?");
+      else if (*code == OP_TYPEPOSUPTO) fprintf(f, "+");
+    break;
+
+    case OP_NOTI:
+    flag = "/i";
+    /* Fall through */
+    case OP_NOT:
+    fprintf(f, " %s [^", flag);
+    extra = print_char(f, code + 1, utf);
+    fprintf(f, "]");
+    break;
+
+    case OP_NOTSTARI:
+    case OP_NOTMINSTARI:
+    case OP_NOTPOSSTARI:
+    case OP_NOTPLUSI:
+    case OP_NOTMINPLUSI:
+    case OP_NOTPOSPLUSI:
+    case OP_NOTQUERYI:
+    case OP_NOTMINQUERYI:
+    case OP_NOTPOSQUERYI:
+    flag = "/i";
+    /* Fall through */
+
+    case OP_NOTSTAR:
+    case OP_NOTMINSTAR:
+    case OP_NOTPOSSTAR:
+    case OP_NOTPLUS:
+    case OP_NOTMINPLUS:
+    case OP_NOTPOSPLUS:
+    case OP_NOTQUERY:
+    case OP_NOTMINQUERY:
+    case OP_NOTPOSQUERY:
+    fprintf(f, " %s [^", flag);
+    extra = print_char(f, code + 1, utf);
+    fprintf(f, "]%s", OP_names[*code]);
+    break;
+
+    case OP_NOTEXACTI:
+    case OP_NOTUPTOI:
+    case OP_NOTMINUPTOI:
+    case OP_NOTPOSUPTOI:
+    flag = "/i";
+    /* Fall through */
+
+    case OP_NOTEXACT:
+    case OP_NOTUPTO:
+    case OP_NOTMINUPTO:
+    case OP_NOTPOSUPTO:
+    fprintf(f, " %s [^", flag);
+    extra = print_char(f, code + 1 + IMM2_SIZE, utf);
+    fprintf(f, "]{");
+    if (*code != OP_NOTEXACT && *code != OP_NOTEXACTI) fprintf(f, "0,");
+    fprintf(f, "%d}", GET2(code,1));
+    if (*code == OP_NOTMINUPTO || *code == OP_NOTMINUPTOI) fprintf(f, "?");
+      else
+    if (*code == OP_NOTPOSUPTO || *code == OP_NOTPOSUPTOI) fprintf(f, "+");
+    break;
+
+    case OP_RECURSE:
+    if (print_lengths) fprintf(f, "%3d ", GET(code, 1));
+      else fprintf(f, "    ");
+    fprintf(f, "%s", OP_names[*code]);
+    break;
+
+    case OP_REFI:
+    flag = "/i";
+    /* Fall through */
+    case OP_REF:
+    fprintf(f, " %s \\%d", flag, GET2(code,1));
+    ccode = code + OP_lengths[*code];
+    goto CLASS_REF_REPEAT;
+
+    case OP_DNREFI:
+    flag = "/i";
+    /* Fall through */
+    case OP_DNREF:
+      {
+      PCRE2_SPTR entry = nametable + (GET2(code, 1) * nesize) + IMM2_SIZE;
+      fprintf(f, " %s \\k<", flag);
+      print_custring(f, entry);
+      fprintf(f, ">%d", GET2(code, 1 + IMM2_SIZE));
+      }
+    ccode = code + OP_lengths[*code];
+    goto CLASS_REF_REPEAT;
+
+    case OP_CALLOUT:
+    fprintf(f, "    %s %d %d %d", OP_names[*code], code[1 + 2*LINK_SIZE],
+      GET(code, 1), GET(code, 1 + LINK_SIZE));
+    break;
+
+    case OP_CALLOUT_STR:
+    c = code[1 + 4*LINK_SIZE];
+    fprintf(f, "    %s %c", OP_names[*code], c);
+    extra = GET(code, 1 + 2*LINK_SIZE);
+    print_custring_bylen(f, code + 2 + 4*LINK_SIZE, extra - 3 - 4*LINK_SIZE);
+    for (i = 0; PRIV(callout_start_delims)[i] != 0; i++)
+      if (c == PRIV(callout_start_delims)[i])
+        {
+        c = PRIV(callout_end_delims)[i];
+        break;
+        }
+    fprintf(f, "%c %d %d %d", c, GET(code, 1 + 3*LINK_SIZE), GET(code, 1),
+      GET(code, 1 + LINK_SIZE));
+    break;
+
+    case OP_PROP:
+    case OP_NOTPROP:
+    print_prop(f, code, "    ", "");
+    break;
+
+    /* OP_XCLASS cannot occur in 8-bit, non-UTF mode. However, there's no harm
+    in having this code always here, and it makes it less messy without all
+    those #ifdefs. */
+
+    case OP_CLASS:
+    case OP_NCLASS:
+    case OP_XCLASS:
+      {
+      unsigned int min, max;
+      BOOL printmap;
+      BOOL invertmap = FALSE;
+      uint8_t *map;
+      uint8_t inverted_map[32];
+
+      fprintf(f, "    [");
+
+      if (*code == OP_XCLASS)
+        {
+        extra = GET(code, 1);
+        ccode = code + LINK_SIZE + 1;
+        printmap = (*ccode & XCL_MAP) != 0;
+        if ((*ccode & XCL_NOT) != 0)
+          {
+          invertmap = (*ccode & XCL_HASPROP) == 0;
+          fprintf(f, "^");
+          }
+        ccode++;
+        }
+      else
+        {
+        printmap = TRUE;
+        ccode = code + 1;
+        }
+
+      /* Print a bit map */
+
+      if (printmap)
+        {
+        map = (uint8_t *)ccode;
+        if (invertmap)
+          {
+          /* Using 255 ^ instead of ~ avoids clang sanitize warning. */
+          for (i = 0; i < 32; i++) inverted_map[i] = 255 ^ map[i];
+          map = inverted_map;
+          }
+
+        for (i = 0; i < 256; i++)
+          {
+          if ((map[i/8] & (1u << (i&7))) != 0)
+            {
+            int j;
+            for (j = i+1; j < 256; j++)
+              if ((map[j/8] & (1u << (j&7))) == 0) break;
+            if (i == '-' || i == ']') fprintf(f, "\\");
+            if (PRINTABLE(i)) fprintf(f, "%c", i);
+              else fprintf(f, "\\x%02x", i);
+            if (--j > i)
+              {
+              if (j != i + 1) fprintf(f, "-");
+              if (j == '-' || j == ']') fprintf(f, "\\");
+              if (PRINTABLE(j)) fprintf(f, "%c", j);
+                else fprintf(f, "\\x%02x", j);
+              }
+            i = j;
+            }
+          }
+        ccode += 32 / sizeof(PCRE2_UCHAR);
+        }
+
+      /* For an XCLASS there is always some additional data */
+
+      if (*code == OP_XCLASS)
+        {
+        PCRE2_UCHAR ch;
+        while ((ch = *ccode++) != XCL_END)
+          {
+          BOOL not = FALSE;
+          const char *notch = "";
+
+          switch(ch)
+            {
+            case XCL_NOTPROP:
+            not = TRUE;
+            notch = "^";
+            /* Fall through */
+
+            case XCL_PROP:
+              {
+              unsigned int ptype = *ccode++;
+              unsigned int pvalue = *ccode++;
+
+              switch(ptype)
+                {
+                case PT_PXGRAPH:
+                fprintf(f, "[:%sgraph:]", notch);
+                break;
+
+                case PT_PXPRINT:
+                fprintf(f, "[:%sprint:]", notch);
+                break;
+
+                case PT_PXPUNCT:
+                fprintf(f, "[:%spunct:]", notch);
+                break;
+
+                default:
+                fprintf(f, "\\%c{%s}", (not? 'P':'p'),
+                  get_ucpname(ptype, pvalue));
+                break;
+                }
+              }
+            break;
+
+            default:
+            ccode += 1 + print_char(f, ccode, utf);
+            if (ch == XCL_RANGE)
+              {
+              fprintf(f, "-");
+              ccode += 1 + print_char(f, ccode, utf);
+              }
+            break;
+            }
+          }
+        }
+
+      /* Indicate a non-UTF class which was created by negation */
+
+      fprintf(f, "]%s", (*code == OP_NCLASS)? " (neg)" : "");
+
+      /* Handle repeats after a class or a back reference */
+
+      CLASS_REF_REPEAT:
+      switch(*ccode)
+        {
+        case OP_CRSTAR:
+        case OP_CRMINSTAR:
+        case OP_CRPLUS:
+        case OP_CRMINPLUS:
+        case OP_CRQUERY:
+        case OP_CRMINQUERY:
+        case OP_CRPOSSTAR:
+        case OP_CRPOSPLUS:
+        case OP_CRPOSQUERY:
+        fprintf(f, "%s", OP_names[*ccode]);
+        extra += OP_lengths[*ccode];
+        break;
+
+        case OP_CRRANGE:
+        case OP_CRMINRANGE:
+        case OP_CRPOSRANGE:
+        min = GET2(ccode,1);
+        max = GET2(ccode,1 + IMM2_SIZE);
+        if (max == 0) fprintf(f, "{%u,}", min);
+        else fprintf(f, "{%u,%u}", min, max);
+        if (*ccode == OP_CRMINRANGE) fprintf(f, "?");
+        else if (*ccode == OP_CRPOSRANGE) fprintf(f, "+");
+        extra += OP_lengths[*ccode];
+        break;
+
+        /* Do nothing if it's not a repeat; this code stops picky compilers
+        warning about the lack of a default code path. */
+
+        default:
+        break;
+        }
+      }
+    break;
+
+    case OP_MARK:
+    case OP_COMMIT_ARG:
+    case OP_PRUNE_ARG:
+    case OP_SKIP_ARG:
+    case OP_THEN_ARG:
+    fprintf(f, "    %s ", OP_names[*code]);
+    print_custring_bylen(f, code + 2, code[1]);
+    extra += code[1];
+    break;
+
+    case OP_THEN:
+    fprintf(f, "    %s", OP_names[*code]);
+    break;
+
+    case OP_CIRCM:
+    case OP_DOLLM:
+    flag = "/m";
+    /* Fall through */
+
+    /* Anything else is just an item with no data, but possibly a flag. */
+
+    default:
+    fprintf(f, " %s %s", flag, OP_names[*code]);
+    break;
+    }
+
+  code += OP_lengths[*code] + extra;
+  fprintf(f, "\n");
+  }
+}
+
+/* End of pcre2_printint.c */
diff --git a/src/c/pcre2/src/pcre2_script_run.c b/src/c/pcre2/src/pcre2_script_run.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_script_run.c
@@ -0,0 +1,441 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains the function for checking a script run. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+/*************************************************
+*                Check script run                *
+*************************************************/
+
+/* A script run is conceptually a sequence of characters all in the same
+Unicode script. However, it isn't quite that simple. There are special rules
+for scripts that are commonly used together, and also special rules for digits.
+This function implements the appropriate checks, which is possible only when
+PCRE2 is compiled with Unicode support. The function returns TRUE if there is
+no Unicode support; however, it should never be called in that circumstance
+because an error is given by pcre2_compile() if a script run is called for in a
+version of PCRE2 compiled without Unicode support.
+
+Arguments:
+  pgr       point to the first character
+  endptr    point after the last character
+  utf       TRUE if in UTF mode
+
+Returns:    TRUE if this is a valid script run
+*/
+
+/* These dummy values must be less than the negation of the largest offset in
+the PRIV(ucd_script_sets) vector, which is held in a 16-bit field in UCD
+records (and is only likely to be a few hundred). */
+
+#define SCRIPT_UNSET        (-99999)
+#define SCRIPT_HANPENDING   (-99998)
+#define SCRIPT_HANHIRAKATA  (-99997)
+#define SCRIPT_HANBOPOMOFO  (-99996)
+#define SCRIPT_HANHANGUL    (-99995)
+#define SCRIPT_LIST         (-99994)
+
+#define INTERSECTION_LIST_SIZE 50
+
+BOOL
+PRIV(script_run)(PCRE2_SPTR ptr, PCRE2_SPTR endptr, BOOL utf)
+{
+#ifdef SUPPORT_UNICODE
+int require_script = SCRIPT_UNSET;
+uint8_t intersection_list[INTERSECTION_LIST_SIZE];
+const uint8_t *require_list = NULL;
+uint32_t require_digitset = 0;
+uint32_t c;
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+(void)utf;    /* Avoid compiler warning */
+#endif
+
+/* Any string containing fewer than 2 characters is a valid script run. */
+
+if (ptr >= endptr) return TRUE;
+GETCHARINCTEST(c, ptr);
+if (ptr >= endptr) return TRUE;
+
+/* Scan strings of two or more characters, checking the Unicode characteristics
+of each code point. We make use of the Script Extensions property. There is
+special code for scripts that can be combined with characters from the Han
+Chinese script. This may be used in conjunction with four other scripts in
+these combinations:
+
+. Han with Hiragana and Katakana is allowed (for Japanese).
+. Han with Bopomofo is allowed (for Taiwanese Mandarin).
+. Han with Hangul is allowed (for Korean).
+
+If the first significant character's script is one of the four, the required
+script type is immediately known. However, if the first significant
+character's script is Han, we have to keep checking for a non-Han character.
+Hence the SCRIPT_HANPENDING state. */
+
+for (;;)
+  {
+  const ucd_record *ucd = GET_UCD(c);
+  int32_t scriptx = ucd->scriptx;
+
+  /* If the script extension is Unknown, the string is not a valid script run.
+  Such characters can only form script runs of length one. */
+
+  if (scriptx == ucp_Unknown) return FALSE;
+
+  /* A character whose script extension is Inherited is always accepted with
+  any script, and plays no further part in this testing. A character whose
+  script is Common is always accepted, but must still be tested for a digit
+  below. The scriptx value at this point is non-zero, because zero is
+  ucp_Unknown, tested for above. */
+
+  if (scriptx != ucp_Inherited)
+    {
+    if (scriptx != ucp_Common)
+      {
+      /* If the script extension value is positive, the character is not a mark
+      that can be used with many scripts. In the simple case we either set or
+      compare with the required script. However, handling the scripts that can
+      combine with Han are more complicated, as is the case when the previous
+      characters have been man-script marks. */
+
+      if (scriptx > 0)
+        {
+        switch(require_script)
+          {
+          /* Either the first significant character (require_script unset) or
+          after only Han characters. */
+
+          case SCRIPT_UNSET:
+          case SCRIPT_HANPENDING:
+          switch(scriptx)
+            {
+            case ucp_Han:
+            require_script = SCRIPT_HANPENDING;
+            break;
+
+            case ucp_Hiragana:
+            case ucp_Katakana:
+            require_script = SCRIPT_HANHIRAKATA;
+            break;
+
+            case ucp_Bopomofo:
+            require_script = SCRIPT_HANBOPOMOFO;
+            break;
+
+            case ucp_Hangul:
+            require_script = SCRIPT_HANHANGUL;
+            break;
+
+            /* Not a Han-related script. If expecting one, fail. Otherise set
+            the requirement to this script. */
+
+            default:
+            if (require_script == SCRIPT_HANPENDING) return FALSE;
+            require_script = scriptx;
+            break;
+            }
+          break;
+
+          /* Previously encountered one of the "with Han" scripts. Check that
+          this character is appropriate. */
+
+          case SCRIPT_HANHIRAKATA:
+          if (scriptx != ucp_Han && scriptx != ucp_Hiragana && 
+              scriptx != ucp_Katakana)
+            return FALSE;
+          break;
+
+          case SCRIPT_HANBOPOMOFO:
+          if (scriptx != ucp_Han && scriptx != ucp_Bopomofo) return FALSE;
+          break;
+
+          case SCRIPT_HANHANGUL:
+          if (scriptx != ucp_Han && scriptx != ucp_Hangul) return FALSE;
+          break;
+
+          /* We have a list of scripts to check that is derived from one or
+          more previous characters. This is either one of the lists in
+          ucd_script_sets[] (for one previous character) or the intersection of
+          several lists for multiple characters. */
+
+          case SCRIPT_LIST:
+            {
+            const uint8_t *list;
+            for (list = require_list; *list != 0; list++)
+              {
+              if (*list == scriptx) break;
+              }
+            if (*list == 0) return FALSE;
+            }
+
+          /* The rest of the string must be in this script, but we have to 
+          allow for the Han complications. */
+          
+          switch(scriptx)
+            {
+            case ucp_Han:
+            require_script = SCRIPT_HANPENDING;
+            break;
+
+            case ucp_Hiragana:
+            case ucp_Katakana:
+            require_script = SCRIPT_HANHIRAKATA;
+            break;
+
+            case ucp_Bopomofo:
+            require_script = SCRIPT_HANBOPOMOFO;
+            break;
+
+            case ucp_Hangul:
+            require_script = SCRIPT_HANHANGUL;
+            break;
+
+            default:
+            require_script = scriptx;
+            break;
+            }  
+          break;
+
+          /* This is the easy case when a single script is required. */
+
+          default:
+          if (scriptx != require_script) return FALSE;
+          break;
+          }
+        }  /* End of handing positive scriptx */
+
+      /* If scriptx is negative, this character is a mark-type character that
+      has a list of permitted scripts. */
+
+      else
+        {
+        uint32_t chspecial;
+        const uint8_t *clist, *rlist;
+        const uint8_t *list = PRIV(ucd_script_sets) - scriptx;
+        
+        switch(require_script)
+          {
+          case SCRIPT_UNSET:
+          require_list = PRIV(ucd_script_sets) - scriptx;
+          require_script = SCRIPT_LIST;
+          break;
+
+          /* An inspection of the Unicode 11.0.0 files shows that there are the
+          following types of Script Extension list that involve the Han,
+          Bopomofo, Hiragana, Katakana, and Hangul scripts:
+
+          . Bopomofo + Han
+          . Han + Hiragana + Katakana
+          . Hiragana + Katakana
+          . Bopopmofo + Hangul + Han + Hiragana + Katakana
+
+          The following code tries to make sense of this. */
+
+#define FOUND_BOPOMOFO 1
+#define FOUND_HIRAGANA 2
+#define FOUND_KATAKANA 4
+#define FOUND_HANGUL   8
+
+          case SCRIPT_HANPENDING:
+          chspecial = 0;
+          for (; *list != 0; list++)
+            {
+            switch (*list)
+              {
+              case ucp_Bopomofo: chspecial |= FOUND_BOPOMOFO; break;
+              case ucp_Hiragana: chspecial |= FOUND_HIRAGANA; break;
+              case ucp_Katakana: chspecial |= FOUND_KATAKANA; break;
+              case ucp_Hangul:   chspecial |= FOUND_HANGUL; break;
+              default: break;
+              }
+            }
+
+           if (chspecial == 0) return FALSE;
+
+           if (chspecial == FOUND_BOPOMOFO)
+             {
+             require_script = SCRIPT_HANBOPOMOFO;
+             }
+           else if (chspecial == (FOUND_HIRAGANA|FOUND_KATAKANA))
+             {
+             require_script = SCRIPT_HANHIRAKATA;
+             }
+
+          /* Otherwise it must be allowed with all of them, so remain in
+          the pending state. */
+
+          break;
+
+          case SCRIPT_HANHIRAKATA:
+          for (; *list != 0; list++)
+            {
+            if (*list == ucp_Hiragana || *list == ucp_Katakana) break;
+            }
+          if (*list == 0) return FALSE;
+          break;
+
+          case SCRIPT_HANBOPOMOFO:
+          for (; *list != 0; list++)
+            {
+            if (*list == ucp_Bopomofo) break;
+            }
+          if (*list == 0) return FALSE;
+          break;
+
+          case SCRIPT_HANHANGUL:
+          for (; *list != 0; list++)
+            {
+            if (*list == ucp_Hangul) break;
+            }
+          if (*list == 0) return FALSE;
+          break;
+
+          /* Previously encountered one or more characters that are allowed
+          with a list of scripts. Build the intersection of the required list
+          with this character's list in intersection_list[]. This code is
+          written so that it still works OK if the required list is already in
+          that vector. */
+
+          case SCRIPT_LIST:
+            {
+            int i = 0;
+            for (rlist = require_list; *rlist != 0; rlist++)
+              {
+              for (clist = list; *clist != 0; clist++)
+                {
+                if (*rlist == *clist)
+                  {
+                  intersection_list[i++] = *rlist;
+                  break;
+                  }
+                }
+              }
+            if (i == 0) return FALSE;  /* No scripts in common */
+
+            /* If there's just one script in common, we can set it as the
+            unique required script. Otherwise, terminate the intersection list
+            and make it the required list. */
+
+            if (i == 1)
+              {
+              require_script = intersection_list[0];
+              }
+            else
+              {
+              intersection_list[i] = 0;
+              require_list = intersection_list;
+              }
+            }
+          break;
+
+          /* The previously set required script is a single script, not
+          Han-related. Check that it is in this character's list. */
+
+          default:
+          for (; *list != 0; list++)
+            {
+            if (*list == require_script) break;
+            }
+          if (*list == 0) return FALSE;
+          break;
+          }
+        }  /* End of handling negative scriptx */
+      }    /* End of checking non-Common character */
+
+    /* The character is in an acceptable script. We must now ensure that all
+    decimal digits in the string come from the same set. Some scripts (e.g.
+    Common, Arabic) have more than one set of decimal digits. This code does
+    not allow mixing sets, even within the same script. The vector called
+    PRIV(ucd_digit_sets)[] contains, in its first element, the number of
+    following elements, and then, in ascending order, the code points of the
+    '9' characters in every set of 10 digits. Each set is identified by the
+    offset in the vector of its '9' character. An initial check of the first
+    value picks up ASCII digits quickly. Otherwise, a binary chop is used. */
+
+    if (ucd->chartype == ucp_Nd)
+      {
+      uint32_t digitset;
+
+      if (c <= PRIV(ucd_digit_sets)[1]) digitset = 1; else
+        {
+        int mid;
+        int bot = 1;
+        int top = PRIV(ucd_digit_sets)[0];
+        for (;;)
+          {
+          if (top <= bot + 1)    /* <= rather than == is paranoia */
+            {
+            digitset = top;
+            break;
+            }
+          mid = (top + bot) / 2;
+          if (c <= PRIV(ucd_digit_sets)[mid]) top = mid; else bot = mid;
+          }
+        }
+
+      /* A required value of 0 means "unset". */
+
+      if (require_digitset == 0) require_digitset = digitset;
+        else if (digitset != require_digitset) return FALSE;
+      }   /* End digit handling */
+    }     /* End checking non-Inherited character */
+
+  /* If we haven't yet got to the end, pick up the next character. */
+
+  if (ptr >= endptr) return TRUE;
+  GETCHARINCTEST(c, ptr);
+  }  /* End checking loop */
+
+#else   /* NOT SUPPORT_UNICODE */
+(void)ptr;
+(void)endptr;
+(void)utf;
+return TRUE;
+#endif  /* SUPPORT_UNICODE */
+}
+
+/* End of pcre2_script_run.c */
diff --git a/src/c/pcre2/src/pcre2_serialize.c b/src/c/pcre2/src/pcre2_serialize.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_serialize.c
@@ -0,0 +1,286 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2020 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains functions for serializing and deserializing
+a sequence of compiled codes. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "pcre2_internal.h"
+
+/* Magic number to provide a small check against being handed junk. */
+
+#define SERIALIZED_DATA_MAGIC 0x50523253u
+
+/* Deserialization is limited to the current PCRE version and
+character width. */
+
+#define SERIALIZED_DATA_VERSION \
+  ((PCRE2_MAJOR) | ((PCRE2_MINOR) << 16))
+
+#define SERIALIZED_DATA_CONFIG \
+  (sizeof(PCRE2_UCHAR) | ((sizeof(void*)) << 8) | ((sizeof(PCRE2_SIZE)) << 16))
+
+
+
+/*************************************************
+*           Serialize compiled patterns          *
+*************************************************/
+
+PCRE2_EXP_DEFN int32_t PCRE2_CALL_CONVENTION
+pcre2_serialize_encode(const pcre2_code **codes, int32_t number_of_codes,
+   uint8_t **serialized_bytes, PCRE2_SIZE *serialized_size,
+   pcre2_general_context *gcontext)
+{
+uint8_t *bytes;
+uint8_t *dst_bytes;
+int32_t i;
+PCRE2_SIZE total_size;
+const pcre2_real_code *re;
+const uint8_t *tables;
+pcre2_serialized_data *data;
+
+const pcre2_memctl *memctl = (gcontext != NULL) ?
+  &gcontext->memctl : &PRIV(default_compile_context).memctl;
+
+if (codes == NULL || serialized_bytes == NULL || serialized_size == NULL)
+  return PCRE2_ERROR_NULL;
+
+if (number_of_codes <= 0) return PCRE2_ERROR_BADDATA;
+
+/* Compute total size. */
+total_size = sizeof(pcre2_serialized_data) + TABLES_LENGTH;
+tables = NULL;
+
+for (i = 0; i < number_of_codes; i++)
+  {
+  if (codes[i] == NULL) return PCRE2_ERROR_NULL;
+  re = (const pcre2_real_code *)(codes[i]);
+  if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
+  if (tables == NULL)
+    tables = re->tables;
+  else if (tables != re->tables)
+    return PCRE2_ERROR_MIXEDTABLES;
+  total_size += re->blocksize;
+  }
+
+/* Initialize the byte stream. */
+bytes = memctl->malloc(total_size + sizeof(pcre2_memctl), memctl->memory_data);
+if (bytes == NULL) return PCRE2_ERROR_NOMEMORY;
+
+/* The controller is stored as a hidden parameter. */
+memcpy(bytes, memctl, sizeof(pcre2_memctl));
+bytes += sizeof(pcre2_memctl);
+
+data = (pcre2_serialized_data *)bytes;
+data->magic = SERIALIZED_DATA_MAGIC;
+data->version = SERIALIZED_DATA_VERSION;
+data->config = SERIALIZED_DATA_CONFIG;
+data->number_of_codes = number_of_codes;
+
+/* Copy all compiled code data. */
+dst_bytes = bytes + sizeof(pcre2_serialized_data);
+memcpy(dst_bytes, tables, TABLES_LENGTH);
+dst_bytes += TABLES_LENGTH;
+
+for (i = 0; i < number_of_codes; i++)
+  {
+  re = (const pcre2_real_code *)(codes[i]);
+  (void)memcpy(dst_bytes, (char *)re, re->blocksize);
+  
+  /* Certain fields in the compiled code block are re-set during 
+  deserialization. In order to ensure that the serialized data stream is always 
+  the same for the same pattern, set them to zero here. We can't assume the 
+  copy of the pattern is correctly aligned for accessing the fields as part of 
+  a structure. Note the use of sizeof(void *) in the second of these, to
+  specify the size of a pointer. If sizeof(uint8_t *) is used (tables is a 
+  pointer to uint8_t), gcc gives a warning because the first argument is also a 
+  pointer to uint8_t. Casting the first argument to (void *) can stop this, but 
+  it didn't stop Coverity giving the same complaint. */
+  
+  (void)memset(dst_bytes + offsetof(pcre2_real_code, memctl), 0, 
+    sizeof(pcre2_memctl));
+  (void)memset(dst_bytes + offsetof(pcre2_real_code, tables), 0, 
+    sizeof(void *));
+  (void)memset(dst_bytes + offsetof(pcre2_real_code, executable_jit), 0,
+    sizeof(void *));        
+ 
+  dst_bytes += re->blocksize;
+  }
+
+*serialized_bytes = bytes;
+*serialized_size = total_size;
+return number_of_codes;
+}
+
+
+/*************************************************
+*          Deserialize compiled patterns         *
+*************************************************/
+
+PCRE2_EXP_DEFN int32_t PCRE2_CALL_CONVENTION
+pcre2_serialize_decode(pcre2_code **codes, int32_t number_of_codes,
+   const uint8_t *bytes, pcre2_general_context *gcontext)
+{
+const pcre2_serialized_data *data = (const pcre2_serialized_data *)bytes;
+const pcre2_memctl *memctl = (gcontext != NULL) ?
+  &gcontext->memctl : &PRIV(default_compile_context).memctl;
+
+const uint8_t *src_bytes;
+pcre2_real_code *dst_re;
+uint8_t *tables;
+int32_t i, j;
+
+/* Sanity checks. */
+
+if (data == NULL || codes == NULL) return PCRE2_ERROR_NULL;
+if (number_of_codes <= 0) return PCRE2_ERROR_BADDATA;
+if (data->number_of_codes <= 0) return PCRE2_ERROR_BADSERIALIZEDDATA;
+if (data->magic != SERIALIZED_DATA_MAGIC) return PCRE2_ERROR_BADMAGIC;
+if (data->version != SERIALIZED_DATA_VERSION) return PCRE2_ERROR_BADMODE;
+if (data->config != SERIALIZED_DATA_CONFIG) return PCRE2_ERROR_BADMODE;
+
+if (number_of_codes > data->number_of_codes)
+  number_of_codes = data->number_of_codes;
+
+src_bytes = bytes + sizeof(pcre2_serialized_data);
+
+/* Decode tables. The reference count for the tables is stored immediately
+following them. */
+
+tables = memctl->malloc(TABLES_LENGTH + sizeof(PCRE2_SIZE), memctl->memory_data);
+if (tables == NULL) return PCRE2_ERROR_NOMEMORY;
+
+memcpy(tables, src_bytes, TABLES_LENGTH);
+*(PCRE2_SIZE *)(tables + TABLES_LENGTH) = number_of_codes;
+src_bytes += TABLES_LENGTH;
+
+/* Decode the byte stream. We must not try to read the size from the compiled
+code block in the stream, because it might be unaligned, which causes errors on
+hardware such as Sparc-64 that doesn't like unaligned memory accesses. The type
+of the blocksize field is given its own name to ensure that it is the same here
+as in the block. */
+
+for (i = 0; i < number_of_codes; i++)
+  {
+  CODE_BLOCKSIZE_TYPE blocksize;
+  memcpy(&blocksize, src_bytes + offsetof(pcre2_real_code, blocksize),
+    sizeof(CODE_BLOCKSIZE_TYPE));
+  if (blocksize <= sizeof(pcre2_real_code))
+    return PCRE2_ERROR_BADSERIALIZEDDATA;
+
+  /* The allocator provided by gcontext replaces the original one. */
+
+  dst_re = (pcre2_real_code *)PRIV(memctl_malloc)(blocksize,
+    (pcre2_memctl *)gcontext);
+  if (dst_re == NULL)
+    {
+    memctl->free(tables, memctl->memory_data);
+    for (j = 0; j < i; j++)
+      {
+      memctl->free(codes[j], memctl->memory_data);
+      codes[j] = NULL;
+      }
+    return PCRE2_ERROR_NOMEMORY;
+    }
+
+  /* The new allocator must be preserved. */
+
+  memcpy(((uint8_t *)dst_re) + sizeof(pcre2_memctl),
+    src_bytes + sizeof(pcre2_memctl), blocksize - sizeof(pcre2_memctl));
+  if (dst_re->magic_number != MAGIC_NUMBER ||
+      dst_re->name_entry_size > MAX_NAME_SIZE + IMM2_SIZE + 1 ||
+      dst_re->name_count > MAX_NAME_COUNT)
+    {   
+    memctl->free(dst_re, memctl->memory_data); 
+    return PCRE2_ERROR_BADSERIALIZEDDATA;
+    } 
+
+  /* At the moment only one table is supported. */
+
+  dst_re->tables = tables;
+  dst_re->executable_jit = NULL;
+  dst_re->flags |= PCRE2_DEREF_TABLES;
+
+  codes[i] = dst_re;
+  src_bytes += blocksize;
+  }
+
+return number_of_codes;
+}
+
+
+/*************************************************
+*    Get the number of serialized patterns       *
+*************************************************/
+
+PCRE2_EXP_DEFN int32_t PCRE2_CALL_CONVENTION
+pcre2_serialize_get_number_of_codes(const uint8_t *bytes)
+{
+const pcre2_serialized_data *data = (const pcre2_serialized_data *)bytes;
+
+if (data == NULL) return PCRE2_ERROR_NULL;
+if (data->magic != SERIALIZED_DATA_MAGIC) return PCRE2_ERROR_BADMAGIC;
+if (data->version != SERIALIZED_DATA_VERSION) return PCRE2_ERROR_BADMODE;
+if (data->config != SERIALIZED_DATA_CONFIG) return PCRE2_ERROR_BADMODE;
+
+return data->number_of_codes;
+}
+
+
+/*************************************************
+*            Free the allocated stream           *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_serialize_free(uint8_t *bytes)
+{
+if (bytes != NULL)
+  {
+  pcre2_memctl *memctl = (pcre2_memctl *)(bytes - sizeof(pcre2_memctl));
+  memctl->free(memctl, memctl->memory_data);
+  }
+}
+
+/* End of pcre2_serialize.c */
diff --git a/src/c/pcre2/src/pcre2_string_utils.c b/src/c/pcre2/src/pcre2_string_utils.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_string_utils.c
@@ -0,0 +1,237 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains internal functions for comparing and finding the length
+of strings. These are used instead of strcmp() etc because the standard
+functions work only on 8-bit data. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+/*************************************************
+*    Emulated memmove() for systems without it   *
+*************************************************/
+
+/* This function can make use of bcopy() if it is available. Otherwise do it by
+steam, as there some non-Unix environments that lack both memmove() and
+bcopy(). */
+
+#if !defined(VPCOMPAT) && !defined(HAVE_MEMMOVE)
+void *
+PRIV(memmove)(void *d, const void *s, size_t n)
+{
+#ifdef HAVE_BCOPY
+bcopy(s, d, n);
+return d;
+#else
+size_t i;
+unsigned char *dest = (unsigned char *)d;
+const unsigned char *src = (const unsigned char *)s;
+if (dest > src)
+  {
+  dest += n;
+  src += n;
+  for (i = 0; i < n; ++i) *(--dest) = *(--src);
+  return (void *)dest;
+  }
+else
+  {
+  for (i = 0; i < n; ++i) *dest++ = *src++;
+  return (void *)(dest - n);
+  }
+#endif   /* not HAVE_BCOPY */
+}
+#endif   /* not VPCOMPAT && not HAVE_MEMMOVE */
+
+
+/*************************************************
+*    Compare two zero-terminated PCRE2 strings   *
+*************************************************/
+
+/*
+Arguments:
+  str1        first string
+  str2        second string
+
+Returns:      0, 1, or -1
+*/
+
+int
+PRIV(strcmp)(PCRE2_SPTR str1, PCRE2_SPTR str2)
+{
+PCRE2_UCHAR c1, c2;
+while (*str1 != '\0' || *str2 != '\0')
+  {
+  c1 = *str1++;
+  c2 = *str2++;
+  if (c1 != c2) return ((c1 > c2) << 1) - 1;
+  }
+return 0;
+}
+
+
+/*************************************************
+*  Compare zero-terminated PCRE2 & 8-bit strings *
+*************************************************/
+
+/* As the 8-bit string is almost always a literal, its type is specified as
+const char *.
+
+Arguments:
+  str1        first string
+  str2        second string
+
+Returns:      0, 1, or -1
+*/
+
+int
+PRIV(strcmp_c8)(PCRE2_SPTR str1, const char *str2)
+{
+PCRE2_UCHAR c1, c2;
+while (*str1 != '\0' || *str2 != '\0')
+  {
+  c1 = *str1++;
+  c2 = *str2++;
+  if (c1 != c2) return ((c1 > c2) << 1) - 1;
+  }
+return 0;
+}
+
+
+/*************************************************
+*    Compare two PCRE2 strings, given a length   *
+*************************************************/
+
+/*
+Arguments:
+  str1        first string
+  str2        second string
+  len         the length
+
+Returns:      0, 1, or -1
+*/
+
+int
+PRIV(strncmp)(PCRE2_SPTR str1, PCRE2_SPTR str2, size_t len)
+{
+PCRE2_UCHAR c1, c2;
+for (; len > 0; len--)
+  {
+  c1 = *str1++;
+  c2 = *str2++;
+  if (c1 != c2) return ((c1 > c2) << 1) - 1;
+  }
+return 0;
+}
+
+
+/*************************************************
+* Compare PCRE2 string to 8-bit string by length *
+*************************************************/
+
+/* As the 8-bit string is almost always a literal, its type is specified as
+const char *.
+
+Arguments:
+  str1        first string
+  str2        second string
+  len         the length
+
+Returns:      0, 1, or -1
+*/
+
+int
+PRIV(strncmp_c8)(PCRE2_SPTR str1, const char *str2, size_t len)
+{
+PCRE2_UCHAR c1, c2;
+for (; len > 0; len--)
+  {
+  c1 = *str1++;
+  c2 = *str2++;
+  if (c1 != c2) return ((c1 > c2) << 1) - 1;
+  }
+return 0;
+}
+
+
+/*************************************************
+*        Find the length of a PCRE2 string       *
+*************************************************/
+
+/*
+Argument:    the string
+Returns:     the length
+*/
+
+PCRE2_SIZE
+PRIV(strlen)(PCRE2_SPTR str)
+{
+PCRE2_SIZE c = 0;
+while (*str++ != 0) c++;
+return c;
+}
+
+
+/*************************************************
+* Copy 8-bit 0-terminated string to PCRE2 string *
+*************************************************/
+
+/* Arguments:
+  str1     buffer to receive the string
+  str2     8-bit string to be copied
+
+Returns:   the number of code units used (excluding trailing zero)
+*/
+
+PCRE2_SIZE
+PRIV(strcpy_c8)(PCRE2_UCHAR *str1, const char *str2)
+{
+PCRE2_UCHAR *t = str1;
+while (*str2 != 0) *t++ = *str2++;
+*t = 0;
+return t - str1;
+}
+
+/* End of pcre2_string_utils.c */
diff --git a/src/c/pcre2/src/pcre2_study.c b/src/c/pcre2/src/pcre2_study.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_study.c
@@ -0,0 +1,1825 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2020 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains functions for scanning a compiled pattern and
+collecting data (e.g. minimum matching length). */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+/* The maximum remembered capturing brackets minimum. */
+
+#define MAX_CACHE_BACKREF 128
+
+/* Set a bit in the starting code unit bit map. */
+
+#define SET_BIT(c) re->start_bitmap[(c)/8] |= (1u << ((c)&7))
+
+/* Returns from set_start_bits() */
+
+enum { SSB_FAIL, SSB_DONE, SSB_CONTINUE, SSB_UNKNOWN, SSB_TOODEEP };
+
+
+/*************************************************
+*   Find the minimum subject length for a group  *
+*************************************************/
+
+/* Scan a parenthesized group and compute the minimum length of subject that
+is needed to match it. This is a lower bound; it does not mean there is a
+string of that length that matches. In UTF mode, the result is in characters
+rather than code units. The field in a compiled pattern for storing the minimum
+length is 16-bits long (on the grounds that anything longer than that is
+pathological), so we give up when we reach that amount. This also means that
+integer overflow for really crazy patterns cannot happen.
+
+Backreference minimum lengths are cached to speed up multiple references. This
+function is called only when the highest back reference in the pattern is less
+than or equal to MAX_CACHE_BACKREF, which is one less than the size of the
+caching vector. The zeroth element contains the number of the highest set
+value.
+
+Arguments:
+  re              compiled pattern block
+  code            pointer to start of group (the bracket)
+  startcode       pointer to start of the whole pattern's code
+  utf             UTF flag
+  recurses        chain of recurse_check to catch mutual recursion
+  countptr        pointer to call count (to catch over complexity)
+  backref_cache   vector for caching back references.
+
+This function is no longer called when the pattern contains (*ACCEPT); however,
+the old code for returning -1 is retained, just in case.
+
+Returns:   the minimum length
+           -1 \C in UTF-8 mode
+              or (*ACCEPT)
+              or pattern too complicated
+           -2 internal error (missing capturing bracket)
+           -3 internal error (opcode not listed)
+*/
+
+static int
+find_minlength(const pcre2_real_code *re, PCRE2_SPTR code,
+  PCRE2_SPTR startcode, BOOL utf, recurse_check *recurses, int *countptr,
+  int *backref_cache)
+{
+int length = -1;
+int branchlength = 0;
+int prev_cap_recno = -1;
+int prev_cap_d = 0;
+int prev_recurse_recno = -1;
+int prev_recurse_d = 0;
+uint32_t once_fudge = 0;
+BOOL had_recurse = FALSE;
+BOOL dupcapused = (re->flags & PCRE2_DUPCAPUSED) != 0;
+PCRE2_SPTR nextbranch = code + GET(code, 1);
+PCRE2_UCHAR *cc = (PCRE2_UCHAR *)code + 1 + LINK_SIZE;
+recurse_check this_recurse;
+
+/* If this is a "could be empty" group, its minimum length is 0. */
+
+if (*code >= OP_SBRA && *code <= OP_SCOND) return 0;
+
+/* Skip over capturing bracket number */
+
+if (*code == OP_CBRA || *code == OP_CBRAPOS) cc += IMM2_SIZE;
+
+/* A large and/or complex regex can take too long to process. */
+
+if ((*countptr)++ > 1000) return -1;
+
+/* Scan along the opcodes for this branch. If we get to the end of the branch,
+check the length against that of the other branches. If the accumulated length
+passes 16-bits, reset to that value and skip the rest of the branch. */
+
+for (;;)
+  {
+  int d, min, recno;
+  PCRE2_UCHAR op, *cs, *ce;
+
+  if (branchlength >= UINT16_MAX)
+    {
+    branchlength = UINT16_MAX;
+    cc = (PCRE2_UCHAR *)nextbranch;
+    }
+
+  op = *cc;
+  switch (op)
+    {
+    case OP_COND:
+    case OP_SCOND:
+
+    /* If there is only one branch in a condition, the implied branch has zero
+    length, so we don't add anything. This covers the DEFINE "condition"
+    automatically. If there are two branches we can treat it the same as any
+    other non-capturing subpattern. */
+
+    cs = cc + GET(cc, 1);
+    if (*cs != OP_ALT)
+      {
+      cc = cs + 1 + LINK_SIZE;
+      break;
+      }
+    goto PROCESS_NON_CAPTURE;
+
+    case OP_BRA:
+    /* There's a special case of OP_BRA, when it is wrapped round a repeated
+    OP_RECURSE. We'd like to process the latter at this level so that
+    remembering the value works for repeated cases. So we do nothing, but
+    set a fudge value to skip over the OP_KET after the recurse. */
+
+    if (cc[1+LINK_SIZE] == OP_RECURSE && cc[2*(1+LINK_SIZE)] == OP_KET)
+      {
+      once_fudge = 1 + LINK_SIZE;
+      cc += 1 + LINK_SIZE;
+      break;
+      }
+    /* Fall through */
+
+    case OP_ONCE:
+    case OP_SCRIPT_RUN:
+    case OP_SBRA:
+    case OP_BRAPOS:
+    case OP_SBRAPOS:
+    PROCESS_NON_CAPTURE:
+    d = find_minlength(re, cc, startcode, utf, recurses, countptr,
+      backref_cache);
+    if (d < 0) return d;
+    branchlength += d;
+    do cc += GET(cc, 1); while (*cc == OP_ALT);
+    cc += 1 + LINK_SIZE;
+    break;
+
+    /* To save time for repeated capturing subpatterns, we remember the
+    length of the previous one. Unfortunately we can't do the same for
+    the unnumbered ones above. Nor can we do this if (?| is present in the
+    pattern because captures with the same number are not then identical. */
+
+    case OP_CBRA:
+    case OP_SCBRA:
+    case OP_CBRAPOS:
+    case OP_SCBRAPOS:
+    recno = (int)GET2(cc, 1+LINK_SIZE);
+    if (dupcapused || recno != prev_cap_recno)
+      {
+      prev_cap_recno = recno;
+      prev_cap_d = find_minlength(re, cc, startcode, utf, recurses, countptr,
+        backref_cache);
+      if (prev_cap_d < 0) return prev_cap_d;
+      }
+    branchlength += prev_cap_d;
+    do cc += GET(cc, 1); while (*cc == OP_ALT);
+    cc += 1 + LINK_SIZE;
+    break;
+
+    /* ACCEPT makes things far too complicated; we have to give up. In fact,
+    from 10.34 onwards, if a pattern contains (*ACCEPT), this function is not
+    used. However, leave the code in place, just in case. */
+
+    case OP_ACCEPT:
+    case OP_ASSERT_ACCEPT:
+    return -1;
+
+    /* Reached end of a branch; if it's a ket it is the end of a nested
+    call. If it's ALT it is an alternation in a nested call. If it is END it's
+    the end of the outer call. All can be handled by the same code. If the
+    length of any branch is zero, there is no need to scan any subsequent
+    branches. */
+
+    case OP_ALT:
+    case OP_KET:
+    case OP_KETRMAX:
+    case OP_KETRMIN:
+    case OP_KETRPOS:
+    case OP_END:
+    if (length < 0 || (!had_recurse && branchlength < length))
+      length = branchlength;
+    if (op != OP_ALT || length == 0) return length;
+    nextbranch = cc + GET(cc, 1);
+    cc += 1 + LINK_SIZE;
+    branchlength = 0;
+    had_recurse = FALSE;
+    break;
+
+    /* Skip over assertive subpatterns */
+
+    case OP_ASSERT:
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK:
+    case OP_ASSERTBACK_NOT:
+    case OP_ASSERT_NA:
+    case OP_ASSERTBACK_NA:
+    do cc += GET(cc, 1); while (*cc == OP_ALT);
+    /* Fall through */
+
+    /* Skip over things that don't match chars */
+
+    case OP_REVERSE:
+    case OP_CREF:
+    case OP_DNCREF:
+    case OP_RREF:
+    case OP_DNRREF:
+    case OP_FALSE:
+    case OP_TRUE:
+    case OP_CALLOUT:
+    case OP_SOD:
+    case OP_SOM:
+    case OP_EOD:
+    case OP_EODN:
+    case OP_CIRC:
+    case OP_CIRCM:
+    case OP_DOLL:
+    case OP_DOLLM:
+    case OP_NOT_WORD_BOUNDARY:
+    case OP_WORD_BOUNDARY:
+    cc += PRIV(OP_lengths)[*cc];
+    break;
+
+    case OP_CALLOUT_STR:
+    cc += GET(cc, 1 + 2*LINK_SIZE);
+    break;
+
+    /* Skip over a subpattern that has a {0} or {0,x} quantifier */
+
+    case OP_BRAZERO:
+    case OP_BRAMINZERO:
+    case OP_BRAPOSZERO:
+    case OP_SKIPZERO:
+    cc += PRIV(OP_lengths)[*cc];
+    do cc += GET(cc, 1); while (*cc == OP_ALT);
+    cc += 1 + LINK_SIZE;
+    break;
+
+    /* Handle literal characters and + repetitions */
+
+    case OP_CHAR:
+    case OP_CHARI:
+    case OP_NOT:
+    case OP_NOTI:
+    case OP_PLUS:
+    case OP_PLUSI:
+    case OP_MINPLUS:
+    case OP_MINPLUSI:
+    case OP_POSPLUS:
+    case OP_POSPLUSI:
+    case OP_NOTPLUS:
+    case OP_NOTPLUSI:
+    case OP_NOTMINPLUS:
+    case OP_NOTMINPLUSI:
+    case OP_NOTPOSPLUS:
+    case OP_NOTPOSPLUSI:
+    branchlength++;
+    cc += 2;
+#ifdef SUPPORT_UNICODE
+    if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+    break;
+
+    case OP_TYPEPLUS:
+    case OP_TYPEMINPLUS:
+    case OP_TYPEPOSPLUS:
+    branchlength++;
+    cc += (cc[1] == OP_PROP || cc[1] == OP_NOTPROP)? 4 : 2;
+    break;
+
+    /* Handle exact repetitions. The count is already in characters, but we
+    may need to skip over a multibyte character in UTF mode.  */
+
+    case OP_EXACT:
+    case OP_EXACTI:
+    case OP_NOTEXACT:
+    case OP_NOTEXACTI:
+    branchlength += GET2(cc,1);
+    cc += 2 + IMM2_SIZE;
+#ifdef SUPPORT_UNICODE
+    if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+    break;
+
+    case OP_TYPEEXACT:
+    branchlength += GET2(cc,1);
+    cc += 2 + IMM2_SIZE + ((cc[1 + IMM2_SIZE] == OP_PROP
+      || cc[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0);
+    break;
+
+    /* Handle single-char non-literal matchers */
+
+    case OP_PROP:
+    case OP_NOTPROP:
+    cc += 2;
+    /* Fall through */
+
+    case OP_NOT_DIGIT:
+    case OP_DIGIT:
+    case OP_NOT_WHITESPACE:
+    case OP_WHITESPACE:
+    case OP_NOT_WORDCHAR:
+    case OP_WORDCHAR:
+    case OP_ANY:
+    case OP_ALLANY:
+    case OP_EXTUNI:
+    case OP_HSPACE:
+    case OP_NOT_HSPACE:
+    case OP_VSPACE:
+    case OP_NOT_VSPACE:
+    branchlength++;
+    cc++;
+    break;
+
+    /* "Any newline" might match two characters, but it also might match just
+    one. */
+
+    case OP_ANYNL:
+    branchlength += 1;
+    cc++;
+    break;
+
+    /* The single-byte matcher means we can't proceed in UTF mode. (In
+    non-UTF mode \C will actually be turned into OP_ALLANY, so won't ever
+    appear, but leave the code, just in case.) */
+
+    case OP_ANYBYTE:
+#ifdef SUPPORT_UNICODE
+    if (utf) return -1;
+#endif
+    branchlength++;
+    cc++;
+    break;
+
+    /* For repeated character types, we have to test for \p and \P, which have
+    an extra two bytes of parameters. */
+
+    case OP_TYPESTAR:
+    case OP_TYPEMINSTAR:
+    case OP_TYPEQUERY:
+    case OP_TYPEMINQUERY:
+    case OP_TYPEPOSSTAR:
+    case OP_TYPEPOSQUERY:
+    if (cc[1] == OP_PROP || cc[1] == OP_NOTPROP) cc += 2;
+    cc += PRIV(OP_lengths)[op];
+    break;
+
+    case OP_TYPEUPTO:
+    case OP_TYPEMINUPTO:
+    case OP_TYPEPOSUPTO:
+    if (cc[1 + IMM2_SIZE] == OP_PROP
+      || cc[1 + IMM2_SIZE] == OP_NOTPROP) cc += 2;
+    cc += PRIV(OP_lengths)[op];
+    break;
+
+    /* Check a class for variable quantification */
+
+    case OP_CLASS:
+    case OP_NCLASS:
+#ifdef SUPPORT_WIDE_CHARS
+    case OP_XCLASS:
+    /* The original code caused an unsigned overflow in 64 bit systems,
+    so now we use a conditional statement. */
+    if (op == OP_XCLASS)
+      cc += GET(cc, 1);
+    else
+      cc += PRIV(OP_lengths)[OP_CLASS];
+#else
+    cc += PRIV(OP_lengths)[OP_CLASS];
+#endif
+
+    switch (*cc)
+      {
+      case OP_CRPLUS:
+      case OP_CRMINPLUS:
+      case OP_CRPOSPLUS:
+      branchlength++;
+      /* Fall through */
+
+      case OP_CRSTAR:
+      case OP_CRMINSTAR:
+      case OP_CRQUERY:
+      case OP_CRMINQUERY:
+      case OP_CRPOSSTAR:
+      case OP_CRPOSQUERY:
+      cc++;
+      break;
+
+      case OP_CRRANGE:
+      case OP_CRMINRANGE:
+      case OP_CRPOSRANGE:
+      branchlength += GET2(cc,1);
+      cc += 1 + 2 * IMM2_SIZE;
+      break;
+
+      default:
+      branchlength++;
+      break;
+      }
+    break;
+
+    /* Backreferences and subroutine calls (OP_RECURSE) are treated in the same
+    way: we find the minimum length for the subpattern. A recursion
+    (backreference or subroutine) causes an a flag to be set that causes the
+    length of this branch to be ignored. The logic is that a recursion can only
+    make sense if there is another alternative that stops the recursing. That
+    will provide the minimum length (when no recursion happens).
+
+    If PCRE2_MATCH_UNSET_BACKREF is set, a backreference to an unset bracket
+    matches an empty string (by default it causes a matching failure), so in
+    that case we must set the minimum length to zero.
+
+    For backreferenes, if duplicate numbers are present in the pattern we check
+    for a reference to a duplicate. If it is, we don't know which version will
+    be referenced, so we have to set the minimum length to zero. */
+
+    /* Duplicate named pattern back reference. */
+
+    case OP_DNREF:
+    case OP_DNREFI:
+    if (!dupcapused && (re->overall_options & PCRE2_MATCH_UNSET_BACKREF) == 0)
+      {
+      int count = GET2(cc, 1+IMM2_SIZE);
+      PCRE2_UCHAR *slot =
+        (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)) +
+          GET2(cc, 1) * re->name_entry_size;
+
+      d = INT_MAX;
+
+      /* Scan all groups with the same name; find the shortest. */
+
+      while (count-- > 0)
+        {
+        int dd, i;
+        recno = GET2(slot, 0);
+
+        if (recno <= backref_cache[0] && backref_cache[recno] >= 0)
+          dd = backref_cache[recno];
+        else
+          {
+          ce = cs = (PCRE2_UCHAR *)PRIV(find_bracket)(startcode, utf, recno);
+          if (cs == NULL) return -2;
+          do ce += GET(ce, 1); while (*ce == OP_ALT);
+
+          dd = 0;
+          if (!dupcapused ||
+              (PCRE2_UCHAR *)PRIV(find_bracket)(ce, utf, recno) == NULL)
+            {
+            if (cc > cs && cc < ce)    /* Simple recursion */
+              {
+              had_recurse = TRUE;
+              }
+            else
+              {
+              recurse_check *r = recurses;
+              for (r = recurses; r != NULL; r = r->prev)
+                if (r->group == cs) break;
+              if (r != NULL)           /* Mutual recursion */
+                {
+                had_recurse = TRUE;
+                }
+              else
+                {
+                this_recurse.prev = recurses;  /* No recursion */
+                this_recurse.group = cs;
+                dd = find_minlength(re, cs, startcode, utf, &this_recurse,
+                  countptr, backref_cache);
+                if (dd < 0) return dd;
+                }
+              }
+            }
+
+          backref_cache[recno] = dd;
+          for (i = backref_cache[0] + 1; i < recno; i++) backref_cache[i] = -1;
+          backref_cache[0] = recno;
+          }
+
+        if (dd < d) d = dd;
+        if (d <= 0) break;    /* No point looking at any more */
+        slot += re->name_entry_size;
+        }
+      }
+    else d = 0;
+    cc += 1 + 2*IMM2_SIZE;
+    goto REPEAT_BACK_REFERENCE;
+
+    /* Single back reference by number. References by name are converted to by
+    number when there is no duplication. */
+
+    case OP_REF:
+    case OP_REFI:
+    recno = GET2(cc, 1);
+    if (recno <= backref_cache[0] && backref_cache[recno] >= 0)
+      d = backref_cache[recno];
+    else
+      {
+      int i;
+      d = 0;
+
+      if ((re->overall_options & PCRE2_MATCH_UNSET_BACKREF) == 0)
+        {
+        ce = cs = (PCRE2_UCHAR *)PRIV(find_bracket)(startcode, utf, recno);
+        if (cs == NULL) return -2;
+        do ce += GET(ce, 1); while (*ce == OP_ALT);
+
+        if (!dupcapused ||
+            (PCRE2_UCHAR *)PRIV(find_bracket)(ce, utf, recno) == NULL)
+          {
+          if (cc > cs && cc < ce)    /* Simple recursion */
+            {
+            had_recurse = TRUE;
+            }
+          else
+            {
+            recurse_check *r = recurses;
+            for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break;
+            if (r != NULL)           /* Mutual recursion */
+              {
+              had_recurse = TRUE;
+              }
+            else                     /* No recursion */
+              {
+              this_recurse.prev = recurses;
+              this_recurse.group = cs;
+              d = find_minlength(re, cs, startcode, utf, &this_recurse, countptr,
+                backref_cache);
+              if (d < 0) return d;
+              }
+            }
+          }
+        }
+
+      backref_cache[recno] = d;
+      for (i = backref_cache[0] + 1; i < recno; i++) backref_cache[i] = -1;
+      backref_cache[0] = recno;
+      }
+
+    cc += 1 + IMM2_SIZE;
+
+    /* Handle repeated back references */
+
+    REPEAT_BACK_REFERENCE:
+    switch (*cc)
+      {
+      case OP_CRSTAR:
+      case OP_CRMINSTAR:
+      case OP_CRQUERY:
+      case OP_CRMINQUERY:
+      case OP_CRPOSSTAR:
+      case OP_CRPOSQUERY:
+      min = 0;
+      cc++;
+      break;
+
+      case OP_CRPLUS:
+      case OP_CRMINPLUS:
+      case OP_CRPOSPLUS:
+      min = 1;
+      cc++;
+      break;
+
+      case OP_CRRANGE:
+      case OP_CRMINRANGE:
+      case OP_CRPOSRANGE:
+      min = GET2(cc, 1);
+      cc += 1 + 2 * IMM2_SIZE;
+      break;
+
+      default:
+      min = 1;
+      break;
+      }
+
+     /* Take care not to overflow: (1) min and d are ints, so check that their
+     product is not greater than INT_MAX. (2) branchlength is limited to
+     UINT16_MAX (checked at the top of the loop). */
+
+    if ((d > 0 && (INT_MAX/d) < min) || UINT16_MAX - branchlength < min*d)
+      branchlength = UINT16_MAX;
+    else branchlength += min * d;
+    break;
+
+    /* Recursion always refers to the first occurrence of a subpattern with a
+    given number. Therefore, we can always make use of caching, even when the
+    pattern contains multiple subpatterns with the same number. */
+
+    case OP_RECURSE:
+    cs = ce = (PCRE2_UCHAR *)startcode + GET(cc, 1);
+    recno = GET2(cs, 1+LINK_SIZE);
+    if (recno == prev_recurse_recno)
+      {
+      branchlength += prev_recurse_d;
+      }
+    else
+      {
+      do ce += GET(ce, 1); while (*ce == OP_ALT);
+      if (cc > cs && cc < ce)    /* Simple recursion */
+        had_recurse = TRUE;
+      else
+        {
+        recurse_check *r = recurses;
+        for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break;
+        if (r != NULL)          /* Mutual recursion */
+          had_recurse = TRUE;
+        else
+          {
+          this_recurse.prev = recurses;
+          this_recurse.group = cs;
+          prev_recurse_d = find_minlength(re, cs, startcode, utf, &this_recurse,
+            countptr, backref_cache);
+          if (prev_recurse_d < 0) return prev_recurse_d;
+          prev_recurse_recno = recno;
+          branchlength += prev_recurse_d;
+          }
+        }
+      }
+    cc += 1 + LINK_SIZE + once_fudge;
+    once_fudge = 0;
+    break;
+
+    /* Anything else does not or need not match a character. We can get the
+    item's length from the table, but for those that can match zero occurrences
+    of a character, we must take special action for UTF-8 characters. As it
+    happens, the "NOT" versions of these opcodes are used at present only for
+    ASCII characters, so they could be omitted from this list. However, in
+    future that may change, so we include them here so as not to leave a
+    gotcha for a future maintainer. */
+
+    case OP_UPTO:
+    case OP_UPTOI:
+    case OP_NOTUPTO:
+    case OP_NOTUPTOI:
+    case OP_MINUPTO:
+    case OP_MINUPTOI:
+    case OP_NOTMINUPTO:
+    case OP_NOTMINUPTOI:
+    case OP_POSUPTO:
+    case OP_POSUPTOI:
+    case OP_NOTPOSUPTO:
+    case OP_NOTPOSUPTOI:
+
+    case OP_STAR:
+    case OP_STARI:
+    case OP_NOTSTAR:
+    case OP_NOTSTARI:
+    case OP_MINSTAR:
+    case OP_MINSTARI:
+    case OP_NOTMINSTAR:
+    case OP_NOTMINSTARI:
+    case OP_POSSTAR:
+    case OP_POSSTARI:
+    case OP_NOTPOSSTAR:
+    case OP_NOTPOSSTARI:
+
+    case OP_QUERY:
+    case OP_QUERYI:
+    case OP_NOTQUERY:
+    case OP_NOTQUERYI:
+    case OP_MINQUERY:
+    case OP_MINQUERYI:
+    case OP_NOTMINQUERY:
+    case OP_NOTMINQUERYI:
+    case OP_POSQUERY:
+    case OP_POSQUERYI:
+    case OP_NOTPOSQUERY:
+    case OP_NOTPOSQUERYI:
+
+    cc += PRIV(OP_lengths)[op];
+#ifdef SUPPORT_UNICODE
+    if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+    break;
+
+    /* Skip these, but we need to add in the name length. */
+
+    case OP_MARK:
+    case OP_COMMIT_ARG:
+    case OP_PRUNE_ARG:
+    case OP_SKIP_ARG:
+    case OP_THEN_ARG:
+    cc += PRIV(OP_lengths)[op] + cc[1];
+    break;
+
+    /* The remaining opcodes are just skipped over. */
+
+    case OP_CLOSE:
+    case OP_COMMIT:
+    case OP_FAIL:
+    case OP_PRUNE:
+    case OP_SET_SOM:
+    case OP_SKIP:
+    case OP_THEN:
+    cc += PRIV(OP_lengths)[op];
+    break;
+
+    /* This should not occur: we list all opcodes explicitly so that when
+    new ones get added they are properly considered. */
+
+    default:
+    return -3;
+    }
+  }
+/* Control never gets here */
+}
+
+
+
+/*************************************************
+*      Set a bit and maybe its alternate case    *
+*************************************************/
+
+/* Given a character, set its first code unit's bit in the table, and also the
+corresponding bit for the other version of a letter if we are caseless.
+
+Arguments:
+  re            points to the regex block
+  p             points to the first code unit of the character
+  caseless      TRUE if caseless
+  utf           TRUE for UTF mode
+  ucp           TRUE for UCP mode
+
+Returns:        pointer after the character
+*/
+
+static PCRE2_SPTR
+set_table_bit(pcre2_real_code *re, PCRE2_SPTR p, BOOL caseless, BOOL utf,
+  BOOL ucp)
+{
+uint32_t c = *p++;   /* First code unit */
+
+(void)utf;           /* Stop compiler warnings when UTF not supported */
+(void)ucp;
+
+/* In 16-bit and 32-bit modes, code units greater than 0xff set the bit for
+0xff. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+if (c > 0xff) SET_BIT(0xff); else
+#endif
+
+SET_BIT(c);
+
+/* In UTF-8 or UTF-16 mode, pick up the remaining code units in order to find
+the end of the character, even when caseless. */
+
+#ifdef SUPPORT_UNICODE
+if (utf)
+  {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+  if (c >= 0xc0) GETUTF8INC(c, p);
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+  if ((c & 0xfc00) == 0xd800) GETUTF16INC(c, p);
+#endif
+  }
+#endif  /* SUPPORT_UNICODE */
+
+/* If caseless, handle the other case of the character. */
+
+if (caseless)
+  {
+#ifdef SUPPORT_UNICODE
+  if (utf || ucp)
+    {
+    c = UCD_OTHERCASE(c);
+#if PCRE2_CODE_UNIT_WIDTH == 8
+    if (utf)
+      {
+      PCRE2_UCHAR buff[6];
+      (void)PRIV(ord2utf)(c, buff);
+      SET_BIT(buff[0]);
+      }
+    else if (c < 256) SET_BIT(c);
+#else  /* 16-bit or 32-bit mode */
+    if (c > 0xff) SET_BIT(0xff); else SET_BIT(c);
+#endif
+    }
+
+  else
+#endif  /* SUPPORT_UNICODE */
+
+  /* Not UTF or UCP */
+
+  if (MAX_255(c)) SET_BIT(re->tables[fcc_offset + c]);
+  }
+
+return p;
+}
+
+
+
+/*************************************************
+*     Set bits for a positive character type     *
+*************************************************/
+
+/* This function sets starting bits for a character type. In UTF-8 mode, we can
+only do a direct setting for bytes less than 128, as otherwise there can be
+confusion with bytes in the middle of UTF-8 characters. In a "traditional"
+environment, the tables will only recognize ASCII characters anyway, but in at
+least one Windows environment, some higher bytes bits were set in the tables.
+So we deal with that case by considering the UTF-8 encoding.
+
+Arguments:
+  re             the regex block
+  cbit type      the type of character wanted
+  table_limit    32 for non-UTF-8; 16 for UTF-8
+
+Returns:         nothing
+*/
+
+static void
+set_type_bits(pcre2_real_code *re, int cbit_type, unsigned int table_limit)
+{
+uint32_t c;
+for (c = 0; c < table_limit; c++)
+  re->start_bitmap[c] |= re->tables[c+cbits_offset+cbit_type];
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+if (table_limit == 32) return;
+for (c = 128; c < 256; c++)
+  {
+  if ((re->tables[cbits_offset + c/8] & (1u << (c&7))) != 0)
+    {
+    PCRE2_UCHAR buff[6];
+    (void)PRIV(ord2utf)(c, buff);
+    SET_BIT(buff[0]);
+    }
+  }
+#endif  /* UTF-8 */
+}
+
+
+/*************************************************
+*     Set bits for a negative character type     *
+*************************************************/
+
+/* This function sets starting bits for a negative character type such as \D.
+In UTF-8 mode, we can only do a direct setting for bytes less than 128, as
+otherwise there can be confusion with bytes in the middle of UTF-8 characters.
+Unlike in the positive case, where we can set appropriate starting bits for
+specific high-valued UTF-8 characters, in this case we have to set the bits for
+all high-valued characters. The lowest is 0xc2, but we overkill by starting at
+0xc0 (192) for simplicity.
+
+Arguments:
+  re             the regex block
+  cbit type      the type of character wanted
+  table_limit    32 for non-UTF-8; 16 for UTF-8
+
+Returns:         nothing
+*/
+
+static void
+set_nottype_bits(pcre2_real_code *re, int cbit_type, unsigned int table_limit)
+{
+uint32_t c;
+for (c = 0; c < table_limit; c++)
+  re->start_bitmap[c] |= ~(re->tables[c+cbits_offset+cbit_type]);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+if (table_limit != 32) for (c = 24; c < 32; c++) re->start_bitmap[c] = 0xff;
+#endif
+}
+
+
+
+/*************************************************
+*      Create bitmap of starting code units      *
+*************************************************/
+
+/* This function scans a compiled unanchored expression recursively and
+attempts to build a bitmap of the set of possible starting code units whose
+values are less than 256. In 16-bit and 32-bit mode, values above 255 all cause
+the 255 bit to be set. When calling set[_not]_type_bits() in UTF-8 (sic) mode
+we pass a value of 16 rather than 32 as the final argument. (See comments in
+those functions for the reason.)
+
+The SSB_CONTINUE return is useful for parenthesized groups in patterns such as
+(a*)b where the group provides some optional starting code units but scanning
+must continue at the outer level to find at least one mandatory code unit. At
+the outermost level, this function fails unless the result is SSB_DONE.
+
+We restrict recursion (for nested groups) to 1000 to avoid stack overflow
+issues.
+
+Arguments:
+  re           points to the compiled regex block
+  code         points to an expression
+  utf          TRUE if in UTF mode
+  ucp          TRUE if in UCP mode
+  depthptr     pointer to recurse depth
+
+Returns:       SSB_FAIL     => Failed to find any starting code units
+               SSB_DONE     => Found mandatory starting code units
+               SSB_CONTINUE => Found optional starting code units
+               SSB_UNKNOWN  => Hit an unrecognized opcode
+               SSB_TOODEEP  => Recursion is too deep
+*/
+
+static int
+set_start_bits(pcre2_real_code *re, PCRE2_SPTR code, BOOL utf, BOOL ucp,
+  int *depthptr)
+{
+uint32_t c;
+int yield = SSB_DONE;
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+int table_limit = utf? 16:32;
+#else
+int table_limit = 32;
+#endif
+
+*depthptr += 1;
+if (*depthptr > 1000) return SSB_TOODEEP;
+
+do
+  {
+  BOOL try_next = TRUE;
+  PCRE2_SPTR tcode = code + 1 + LINK_SIZE;
+
+  if (*code == OP_CBRA || *code == OP_SCBRA ||
+      *code == OP_CBRAPOS || *code == OP_SCBRAPOS) tcode += IMM2_SIZE;
+
+  while (try_next)    /* Loop for items in this branch */
+    {
+    int rc;
+    uint8_t *classmap = NULL;
+#ifdef SUPPORT_WIDE_CHARS
+    PCRE2_UCHAR xclassflags;
+#endif
+
+    switch(*tcode)
+      {
+      /* If we reach something we don't understand, it means a new opcode has
+      been created that hasn't been added to this function. Hopefully this
+      problem will be discovered during testing. */
+
+      default:
+      return SSB_UNKNOWN;
+
+      /* Fail for a valid opcode that implies no starting bits. */
+
+      case OP_ACCEPT:
+      case OP_ASSERT_ACCEPT:
+      case OP_ALLANY:
+      case OP_ANY:
+      case OP_ANYBYTE:
+      case OP_CIRCM:
+      case OP_CLOSE:
+      case OP_COMMIT:
+      case OP_COMMIT_ARG:
+      case OP_COND:
+      case OP_CREF:
+      case OP_FALSE:
+      case OP_TRUE:
+      case OP_DNCREF:
+      case OP_DNREF:
+      case OP_DNREFI:
+      case OP_DNRREF:
+      case OP_DOLL:
+      case OP_DOLLM:
+      case OP_END:
+      case OP_EOD:
+      case OP_EODN:
+      case OP_EXTUNI:
+      case OP_FAIL:
+      case OP_MARK:
+      case OP_NOT:
+      case OP_NOTEXACT:
+      case OP_NOTEXACTI:
+      case OP_NOTI:
+      case OP_NOTMINPLUS:
+      case OP_NOTMINPLUSI:
+      case OP_NOTMINQUERY:
+      case OP_NOTMINQUERYI:
+      case OP_NOTMINSTAR:
+      case OP_NOTMINSTARI:
+      case OP_NOTMINUPTO:
+      case OP_NOTMINUPTOI:
+      case OP_NOTPLUS:
+      case OP_NOTPLUSI:
+      case OP_NOTPOSPLUS:
+      case OP_NOTPOSPLUSI:
+      case OP_NOTPOSQUERY:
+      case OP_NOTPOSQUERYI:
+      case OP_NOTPOSSTAR:
+      case OP_NOTPOSSTARI:
+      case OP_NOTPOSUPTO:
+      case OP_NOTPOSUPTOI:
+      case OP_NOTPROP:
+      case OP_NOTQUERY:
+      case OP_NOTQUERYI:
+      case OP_NOTSTAR:
+      case OP_NOTSTARI:
+      case OP_NOTUPTO:
+      case OP_NOTUPTOI:
+      case OP_NOT_HSPACE:
+      case OP_NOT_VSPACE:
+      case OP_PRUNE:
+      case OP_PRUNE_ARG:
+      case OP_RECURSE:
+      case OP_REF:
+      case OP_REFI:
+      case OP_REVERSE:
+      case OP_RREF:
+      case OP_SCOND:
+      case OP_SET_SOM:
+      case OP_SKIP:
+      case OP_SKIP_ARG:
+      case OP_SOD:
+      case OP_SOM:
+      case OP_THEN:
+      case OP_THEN_ARG:
+      return SSB_FAIL;
+
+      /* OP_CIRC happens only at the start of an anchored branch (multiline ^
+      uses OP_CIRCM). Skip over it. */
+
+      case OP_CIRC:
+      tcode += PRIV(OP_lengths)[OP_CIRC];
+      break;
+
+      /* A "real" property test implies no starting bits, but the fake property
+      PT_CLIST identifies a list of characters. These lists are short, as they
+      are used for characters with more than one "other case", so there is no
+      point in recognizing them for OP_NOTPROP. */
+
+      case OP_PROP:
+      if (tcode[1] != PT_CLIST) return SSB_FAIL;
+        {
+        const uint32_t *p = PRIV(ucd_caseless_sets) + tcode[2];
+        while ((c = *p++) < NOTACHAR)
+          {
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+          if (utf)
+            {
+            PCRE2_UCHAR buff[6];
+            (void)PRIV(ord2utf)(c, buff);
+            c = buff[0];
+            }
+#endif
+          if (c > 0xff) SET_BIT(0xff); else SET_BIT(c);
+          }
+        }
+      try_next = FALSE;
+      break;
+
+      /* We can ignore word boundary tests. */
+
+      case OP_WORD_BOUNDARY:
+      case OP_NOT_WORD_BOUNDARY:
+      tcode++;
+      break;
+
+      /* If we hit a bracket or a positive lookahead assertion, recurse to set
+      bits from within the subpattern. If it can't find anything, we have to
+      give up. If it finds some mandatory character(s), we are done for this
+      branch. Otherwise, carry on scanning after the subpattern. */
+
+      case OP_BRA:
+      case OP_SBRA:
+      case OP_CBRA:
+      case OP_SCBRA:
+      case OP_BRAPOS:
+      case OP_SBRAPOS:
+      case OP_CBRAPOS:
+      case OP_SCBRAPOS:
+      case OP_ONCE:
+      case OP_SCRIPT_RUN:
+      case OP_ASSERT:
+      case OP_ASSERT_NA:
+      rc = set_start_bits(re, tcode, utf, ucp, depthptr);
+      if (rc == SSB_DONE)
+        {
+        try_next = FALSE;
+        }
+      else if (rc == SSB_CONTINUE)
+        {
+        do tcode += GET(tcode, 1); while (*tcode == OP_ALT);
+        tcode += 1 + LINK_SIZE;
+        }
+      else return rc;   /* FAIL, UNKNOWN, or TOODEEP */
+      break;
+
+      /* If we hit ALT or KET, it means we haven't found anything mandatory in
+      this branch, though we might have found something optional. For ALT, we
+      continue with the next alternative, but we have to arrange that the final
+      result from subpattern is SSB_CONTINUE rather than SSB_DONE. For KET,
+      return SSB_CONTINUE: if this is the top level, that indicates failure,
+      but after a nested subpattern, it causes scanning to continue. */
+
+      case OP_ALT:
+      yield = SSB_CONTINUE;
+      try_next = FALSE;
+      break;
+
+      case OP_KET:
+      case OP_KETRMAX:
+      case OP_KETRMIN:
+      case OP_KETRPOS:
+      return SSB_CONTINUE;
+
+      /* Skip over callout */
+
+      case OP_CALLOUT:
+      tcode += PRIV(OP_lengths)[OP_CALLOUT];
+      break;
+
+      case OP_CALLOUT_STR:
+      tcode += GET(tcode, 1 + 2*LINK_SIZE);
+      break;
+
+      /* Skip over lookbehind and negative lookahead assertions */
+
+      case OP_ASSERT_NOT:
+      case OP_ASSERTBACK:
+      case OP_ASSERTBACK_NOT:
+      case OP_ASSERTBACK_NA:
+      do tcode += GET(tcode, 1); while (*tcode == OP_ALT);
+      tcode += 1 + LINK_SIZE;
+      break;
+
+      /* BRAZERO does the bracket, but carries on. */
+
+      case OP_BRAZERO:
+      case OP_BRAMINZERO:
+      case OP_BRAPOSZERO:
+      rc = set_start_bits(re, ++tcode, utf, ucp, depthptr);
+      if (rc == SSB_FAIL || rc == SSB_UNKNOWN || rc == SSB_TOODEEP) return rc;
+      do tcode += GET(tcode,1); while (*tcode == OP_ALT);
+      tcode += 1 + LINK_SIZE;
+      break;
+
+      /* SKIPZERO skips the bracket. */
+
+      case OP_SKIPZERO:
+      tcode++;
+      do tcode += GET(tcode,1); while (*tcode == OP_ALT);
+      tcode += 1 + LINK_SIZE;
+      break;
+
+      /* Single-char * or ? sets the bit and tries the next item */
+
+      case OP_STAR:
+      case OP_MINSTAR:
+      case OP_POSSTAR:
+      case OP_QUERY:
+      case OP_MINQUERY:
+      case OP_POSQUERY:
+      tcode = set_table_bit(re, tcode + 1, FALSE, utf, ucp);
+      break;
+
+      case OP_STARI:
+      case OP_MINSTARI:
+      case OP_POSSTARI:
+      case OP_QUERYI:
+      case OP_MINQUERYI:
+      case OP_POSQUERYI:
+      tcode = set_table_bit(re, tcode + 1, TRUE, utf, ucp);
+      break;
+
+      /* Single-char upto sets the bit and tries the next */
+
+      case OP_UPTO:
+      case OP_MINUPTO:
+      case OP_POSUPTO:
+      tcode = set_table_bit(re, tcode + 1 + IMM2_SIZE, FALSE, utf, ucp);
+      break;
+
+      case OP_UPTOI:
+      case OP_MINUPTOI:
+      case OP_POSUPTOI:
+      tcode = set_table_bit(re, tcode + 1 + IMM2_SIZE, TRUE, utf, ucp);
+      break;
+
+      /* At least one single char sets the bit and stops */
+
+      case OP_EXACT:
+      tcode += IMM2_SIZE;
+      /* Fall through */
+      case OP_CHAR:
+      case OP_PLUS:
+      case OP_MINPLUS:
+      case OP_POSPLUS:
+      (void)set_table_bit(re, tcode + 1, FALSE, utf, ucp);
+      try_next = FALSE;
+      break;
+
+      case OP_EXACTI:
+      tcode += IMM2_SIZE;
+      /* Fall through */
+      case OP_CHARI:
+      case OP_PLUSI:
+      case OP_MINPLUSI:
+      case OP_POSPLUSI:
+      (void)set_table_bit(re, tcode + 1, TRUE, utf, ucp);
+      try_next = FALSE;
+      break;
+
+      /* Special spacing and line-terminating items. These recognize specific
+      lists of characters. The difference between VSPACE and ANYNL is that the
+      latter can match the two-character CRLF sequence, but that is not
+      relevant for finding the first character, so their code here is
+      identical. */
+
+      case OP_HSPACE:
+      SET_BIT(CHAR_HT);
+      SET_BIT(CHAR_SPACE);
+
+      /* For the 16-bit and 32-bit libraries (which can never be EBCDIC), set
+      the bits for 0xA0 and for code units >= 255, independently of UTF. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+      SET_BIT(0xA0);
+      SET_BIT(0xFF);
+#else
+      /* For the 8-bit library in UTF-8 mode, set the bits for the first code
+      units of horizontal space characters. */
+
+#ifdef SUPPORT_UNICODE
+      if (utf)
+        {
+        SET_BIT(0xC2);  /* For U+00A0 */
+        SET_BIT(0xE1);  /* For U+1680, U+180E */
+        SET_BIT(0xE2);  /* For U+2000 - U+200A, U+202F, U+205F */
+        SET_BIT(0xE3);  /* For U+3000 */
+        }
+      else
+#endif
+      /* For the 8-bit library not in UTF-8 mode, set the bit for 0xA0, unless
+      the code is EBCDIC. */
+        {
+#ifndef EBCDIC
+        SET_BIT(0xA0);
+#endif  /* Not EBCDIC */
+        }
+#endif  /* 8-bit support */
+
+      try_next = FALSE;
+      break;
+
+      case OP_ANYNL:
+      case OP_VSPACE:
+      SET_BIT(CHAR_LF);
+      SET_BIT(CHAR_VT);
+      SET_BIT(CHAR_FF);
+      SET_BIT(CHAR_CR);
+
+      /* For the 16-bit and 32-bit libraries (which can never be EBCDIC), set
+      the bits for NEL and for code units >= 255, independently of UTF. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+      SET_BIT(CHAR_NEL);
+      SET_BIT(0xFF);
+#else
+      /* For the 8-bit library in UTF-8 mode, set the bits for the first code
+      units of vertical space characters. */
+
+#ifdef SUPPORT_UNICODE
+      if (utf)
+        {
+        SET_BIT(0xC2);  /* For U+0085 (NEL) */
+        SET_BIT(0xE2);  /* For U+2028, U+2029 */
+        }
+      else
+#endif
+      /* For the 8-bit library not in UTF-8 mode, set the bit for NEL. */
+        {
+        SET_BIT(CHAR_NEL);
+        }
+#endif  /* 8-bit support */
+
+      try_next = FALSE;
+      break;
+
+      /* Single character types set the bits and stop. Note that if PCRE2_UCP
+      is set, we do not see these opcodes because \d etc are converted to
+      properties. Therefore, these apply in the case when only characters less
+      than 256 are recognized to match the types. */
+
+      case OP_NOT_DIGIT:
+      set_nottype_bits(re, cbit_digit, table_limit);
+      try_next = FALSE;
+      break;
+
+      case OP_DIGIT:
+      set_type_bits(re, cbit_digit, table_limit);
+      try_next = FALSE;
+      break;
+
+      case OP_NOT_WHITESPACE:
+      set_nottype_bits(re, cbit_space, table_limit);
+      try_next = FALSE;
+      break;
+
+      case OP_WHITESPACE:
+      set_type_bits(re, cbit_space, table_limit);
+      try_next = FALSE;
+      break;
+
+      case OP_NOT_WORDCHAR:
+      set_nottype_bits(re, cbit_word, table_limit);
+      try_next = FALSE;
+      break;
+
+      case OP_WORDCHAR:
+      set_type_bits(re, cbit_word, table_limit);
+      try_next = FALSE;
+      break;
+
+      /* One or more character type fudges the pointer and restarts, knowing
+      it will hit a single character type and stop there. */
+
+      case OP_TYPEPLUS:
+      case OP_TYPEMINPLUS:
+      case OP_TYPEPOSPLUS:
+      tcode++;
+      break;
+
+      case OP_TYPEEXACT:
+      tcode += 1 + IMM2_SIZE;
+      break;
+
+      /* Zero or more repeats of character types set the bits and then
+      try again. */
+
+      case OP_TYPEUPTO:
+      case OP_TYPEMINUPTO:
+      case OP_TYPEPOSUPTO:
+      tcode += IMM2_SIZE;  /* Fall through */
+
+      case OP_TYPESTAR:
+      case OP_TYPEMINSTAR:
+      case OP_TYPEPOSSTAR:
+      case OP_TYPEQUERY:
+      case OP_TYPEMINQUERY:
+      case OP_TYPEPOSQUERY:
+      switch(tcode[1])
+        {
+        default:
+        case OP_ANY:
+        case OP_ALLANY:
+        return SSB_FAIL;
+
+        case OP_HSPACE:
+        SET_BIT(CHAR_HT);
+        SET_BIT(CHAR_SPACE);
+
+        /* For the 16-bit and 32-bit libraries (which can never be EBCDIC), set
+        the bits for 0xA0 and for code units >= 255, independently of UTF. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+        SET_BIT(0xA0);
+        SET_BIT(0xFF);
+#else
+        /* For the 8-bit library in UTF-8 mode, set the bits for the first code
+        units of horizontal space characters. */
+
+#ifdef SUPPORT_UNICODE
+        if (utf)
+          {
+          SET_BIT(0xC2);  /* For U+00A0 */
+          SET_BIT(0xE1);  /* For U+1680, U+180E */
+          SET_BIT(0xE2);  /* For U+2000 - U+200A, U+202F, U+205F */
+          SET_BIT(0xE3);  /* For U+3000 */
+          }
+        else
+#endif
+        /* For the 8-bit library not in UTF-8 mode, set the bit for 0xA0, unless
+        the code is EBCDIC. */
+          {
+#ifndef EBCDIC
+          SET_BIT(0xA0);
+#endif  /* Not EBCDIC */
+          }
+#endif  /* 8-bit support */
+        break;
+
+        case OP_ANYNL:
+        case OP_VSPACE:
+        SET_BIT(CHAR_LF);
+        SET_BIT(CHAR_VT);
+        SET_BIT(CHAR_FF);
+        SET_BIT(CHAR_CR);
+
+        /* For the 16-bit and 32-bit libraries (which can never be EBCDIC), set
+        the bits for NEL and for code units >= 255, independently of UTF. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+        SET_BIT(CHAR_NEL);
+        SET_BIT(0xFF);
+#else
+        /* For the 8-bit library in UTF-8 mode, set the bits for the first code
+        units of vertical space characters. */
+
+#ifdef SUPPORT_UNICODE
+        if (utf)
+          {
+          SET_BIT(0xC2);  /* For U+0085 (NEL) */
+          SET_BIT(0xE2);  /* For U+2028, U+2029 */
+          }
+        else
+#endif
+        /* For the 8-bit library not in UTF-8 mode, set the bit for NEL. */
+          {
+          SET_BIT(CHAR_NEL);
+          }
+#endif  /* 8-bit support */
+        break;
+
+        case OP_NOT_DIGIT:
+        set_nottype_bits(re, cbit_digit, table_limit);
+        break;
+
+        case OP_DIGIT:
+        set_type_bits(re, cbit_digit, table_limit);
+        break;
+
+        case OP_NOT_WHITESPACE:
+        set_nottype_bits(re, cbit_space, table_limit);
+        break;
+
+        case OP_WHITESPACE:
+        set_type_bits(re, cbit_space, table_limit);
+        break;
+
+        case OP_NOT_WORDCHAR:
+        set_nottype_bits(re, cbit_word, table_limit);
+        break;
+
+        case OP_WORDCHAR:
+        set_type_bits(re, cbit_word, table_limit);
+        break;
+        }
+
+      tcode += 2;
+      break;
+
+      /* Extended class: if there are any property checks, or if this is a
+      negative XCLASS without a map, give up. If there are no property checks,
+      there must be wide characters on the XCLASS list, because otherwise an
+      XCLASS would not have been created. This means that code points >= 255
+      are potential starters. In the UTF-8 case we can scan them and set bits
+      for the relevant leading bytes. */
+
+#ifdef SUPPORT_WIDE_CHARS
+      case OP_XCLASS:
+      xclassflags = tcode[1 + LINK_SIZE];
+      if ((xclassflags & XCL_HASPROP) != 0 ||
+          (xclassflags & (XCL_MAP|XCL_NOT)) == XCL_NOT)
+        return SSB_FAIL;
+
+      /* We have a positive XCLASS or a negative one without a map. Set up the
+      map pointer if there is one, and fall through. */
+
+      classmap = ((xclassflags & XCL_MAP) == 0)? NULL :
+        (uint8_t *)(tcode + 1 + LINK_SIZE + 1);
+
+      /* In UTF-8 mode, scan the character list and set bits for leading bytes,
+      then jump to handle the map. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+      if (utf && (xclassflags & XCL_NOT) == 0)
+        {
+        PCRE2_UCHAR b, e;
+        PCRE2_SPTR p = tcode + 1 + LINK_SIZE + 1 + ((classmap == NULL)? 0:32);
+        tcode += GET(tcode, 1);
+
+        for (;;) switch (*p++)
+          {
+          case XCL_SINGLE:
+          b = *p++;
+          while ((*p & 0xc0) == 0x80) p++;
+          re->start_bitmap[b/8] |= (1u << (b&7));
+          break;
+
+          case XCL_RANGE:
+          b = *p++;
+          while ((*p & 0xc0) == 0x80) p++;
+          e = *p++;
+          while ((*p & 0xc0) == 0x80) p++;
+          for (; b <= e; b++)
+            re->start_bitmap[b/8] |= (1u << (b&7));
+          break;
+
+          case XCL_END:
+          goto HANDLE_CLASSMAP;
+
+          default:
+          return SSB_UNKNOWN;   /* Internal error, should not occur */
+          }
+        }
+#endif  /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 */
+#endif  /* SUPPORT_WIDE_CHARS */
+
+      /* It seems that the fall through comment must be outside the #ifdef if
+      it is to avoid the gcc compiler warning. */
+
+      /* Fall through */
+
+      /* Enter here for a negative non-XCLASS. In the 8-bit library, if we are
+      in UTF mode, any byte with a value >= 0xc4 is a potentially valid starter
+      because it starts a character with a value > 255. In 8-bit non-UTF mode,
+      there is no difference between CLASS and NCLASS. In all other wide
+      character modes, set the 0xFF bit to indicate code units >= 255. */
+
+      case OP_NCLASS:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+      if (utf)
+        {
+        re->start_bitmap[24] |= 0xf0;            /* Bits for 0xc4 - 0xc8 */
+        memset(re->start_bitmap+25, 0xff, 7);    /* Bits for 0xc9 - 0xff */
+        }
+#elif PCRE2_CODE_UNIT_WIDTH != 8
+      SET_BIT(0xFF);                             /* For characters >= 255 */
+#endif
+      /* Fall through */
+
+      /* Enter here for a positive non-XCLASS. If we have fallen through from
+      an XCLASS, classmap will already be set; just advance the code pointer.
+      Otherwise, set up classmap for a a non-XCLASS and advance past it. */
+
+      case OP_CLASS:
+      if (*tcode == OP_XCLASS) tcode += GET(tcode, 1); else
+        {
+        classmap = (uint8_t *)(++tcode);
+        tcode += 32 / sizeof(PCRE2_UCHAR);
+        }
+
+      /* When wide characters are supported, classmap may be NULL. In UTF-8
+      (sic) mode, the bits in a class bit map correspond to character values,
+      not to byte values. However, the bit map we are constructing is for byte
+      values. So we have to do a conversion for characters whose code point is
+      greater than 127. In fact, there are only two possible starting bytes for
+      characters in the range 128 - 255. */
+
+#if defined SUPPORT_WIDE_CHARS && PCRE2_CODE_UNIT_WIDTH == 8
+      HANDLE_CLASSMAP:
+#endif
+      if (classmap != NULL)
+        {
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+        if (utf)
+          {
+          for (c = 0; c < 16; c++) re->start_bitmap[c] |= classmap[c];
+          for (c = 128; c < 256; c++)
+            {
+            if ((classmap[c/8] & (1u << (c&7))) != 0)
+              {
+              int d = (c >> 6) | 0xc0;                 /* Set bit for this starter */
+              re->start_bitmap[d/8] |= (1u << (d&7));  /* and then skip on to the */
+              c = (c & 0xc0) + 0x40 - 1;               /* next relevant character. */
+              }
+            }
+          }
+        else
+#endif
+        /* In all modes except UTF-8, the two bit maps are compatible. */
+
+          {
+          for (c = 0; c < 32; c++) re->start_bitmap[c] |= classmap[c];
+          }
+        }
+
+      /* Act on what follows the class. For a zero minimum repeat, continue;
+      otherwise stop processing. */
+
+      switch (*tcode)
+        {
+        case OP_CRSTAR:
+        case OP_CRMINSTAR:
+        case OP_CRQUERY:
+        case OP_CRMINQUERY:
+        case OP_CRPOSSTAR:
+        case OP_CRPOSQUERY:
+        tcode++;
+        break;
+
+        case OP_CRRANGE:
+        case OP_CRMINRANGE:
+        case OP_CRPOSRANGE:
+        if (GET2(tcode, 1) == 0) tcode += 1 + 2 * IMM2_SIZE;
+          else try_next = FALSE;
+        break;
+
+        default:
+        try_next = FALSE;
+        break;
+        }
+      break; /* End of class handling case */
+      }      /* End of switch for opcodes */
+    }        /* End of try_next loop */
+
+  code += GET(code, 1);   /* Advance to next branch */
+  }
+while (*code == OP_ALT);
+
+return yield;
+}
+
+
+
+/*************************************************
+*          Study a compiled expression           *
+*************************************************/
+
+/* This function is handed a compiled expression that it must study to produce
+information that will speed up the matching.
+
+Argument:
+  re       points to the compiled expression
+
+Returns:   0 normally; non-zero should never normally occur
+           1 unknown opcode in set_start_bits
+           2 missing capturing bracket
+           3 unknown opcode in find_minlength
+*/
+
+int
+PRIV(study)(pcre2_real_code *re)
+{
+int count = 0;
+PCRE2_UCHAR *code;
+BOOL utf = (re->overall_options & PCRE2_UTF) != 0;
+BOOL ucp = (re->overall_options & PCRE2_UCP) != 0;
+
+/* Find start of compiled code */
+
+code = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)) +
+  re->name_entry_size * re->name_count;
+
+/* For a pattern that has a first code unit, or a multiline pattern that
+matches only at "line start", there is no point in seeking a list of starting
+code units. */
+
+if ((re->flags & (PCRE2_FIRSTSET|PCRE2_STARTLINE)) == 0)
+  {
+  int depth = 0;
+  int rc = set_start_bits(re, code, utf, ucp, &depth);
+  if (rc == SSB_UNKNOWN) return 1;
+
+  /* If a list of starting code units was set up, scan the list to see if only
+  one or two were listed. Having only one listed is rare because usually a
+  single starting code unit will have been recognized and PCRE2_FIRSTSET set.
+  If two are listed, see if they are caseless versions of the same character;
+  if so we can replace the list with a caseless first code unit. This gives
+  better performance and is plausibly worth doing for patterns such as [Ww]ord
+  or (word|WORD). */
+
+  if (rc == SSB_DONE)
+    {
+    int i;
+    int a = -1;
+    int b = -1;
+    uint8_t *p = re->start_bitmap;
+    uint32_t flags = PCRE2_FIRSTMAPSET;
+
+    for (i = 0; i < 256; p++, i += 8)
+      {
+      uint8_t x = *p;
+      if (x != 0)
+        {
+        int c;
+        uint8_t y = x & (~x + 1);   /* Least significant bit */
+        if (y != x) goto DONE;      /* More than one bit set */
+
+        /* In the 16-bit and 32-bit libraries, the bit for 0xff means "0xff and
+        all wide characters", so we cannot use it here. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+        if (i == 248 && x == 0x80) goto DONE;
+#endif
+
+        /* Compute the character value */
+
+        c = i;
+        switch (x)
+          {
+          case 1:   break;
+          case 2:   c += 1; break;  case 4:  c += 2; break;
+          case 8:   c += 3; break;  case 16: c += 4; break;
+          case 32:  c += 5; break;  case 64: c += 6; break;
+          case 128: c += 7; break;
+          }
+
+        /* c contains the code unit value, in the range 0-255. In 8-bit UTF
+        mode, only values < 128 can be used. In all the other cases, c is a
+        character value. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+        if (utf && c > 127) goto DONE;
+#endif
+        if (a < 0) a = c;   /* First one found, save in a */
+        else if (b < 0)     /* Second one found */
+          {
+          int d = TABLE_GET((unsigned int)c, re->tables + fcc_offset, c);
+
+#ifdef SUPPORT_UNICODE
+          if (utf || ucp)
+            {
+            if (UCD_CASESET(c) != 0) goto DONE;     /* Multiple case set */
+            if (c > 127) d = UCD_OTHERCASE(c);
+            }
+#endif  /* SUPPORT_UNICODE */
+
+          if (d != a) goto DONE;   /* Not the other case of a */
+          b = c;                   /* Save second in b */
+          }
+        else goto DONE;   /* More than two characters found */
+        }
+      }
+
+    /* Replace the start code unit bits with a first code unit, but only if it
+    is not the same as a required later code unit. This is because a search for
+    a required code unit starts after an explicit first code unit, but at a
+    code unit found from the bitmap. Patterns such as /a*a/ don't work
+    if both the start unit and required unit are the same. */
+
+    if (a >= 0 &&
+        (
+        (re->flags & PCRE2_LASTSET) == 0 ||
+          (
+          re->last_codeunit != (uint32_t)a &&
+          (b < 0 || re->last_codeunit != (uint32_t)b)
+          )
+        ))
+      {
+      re->first_codeunit = a;
+      flags = PCRE2_FIRSTSET;
+      if (b >= 0) flags |= PCRE2_FIRSTCASELESS;
+      }
+
+    DONE:
+    re->flags |= flags;
+    }
+  }
+
+/* Find the minimum length of subject string. If the pattern can match an empty
+string, the minimum length is already known. If the pattern contains (*ACCEPT)
+all bets are off, and we don't even try to find a minimum length. If there are
+more back references than the size of the vector we are going to cache them in,
+do nothing. A pattern that complicated will probably take a long time to
+analyze and may in any case turn out to be too complicated. Note that back
+reference minima are held as 16-bit numbers. */
+
+if ((re->flags & (PCRE2_MATCH_EMPTY|PCRE2_HASACCEPT)) == 0 &&
+     re->top_backref <= MAX_CACHE_BACKREF)
+  {
+  int min;
+  int backref_cache[MAX_CACHE_BACKREF+1];
+  backref_cache[0] = 0;    /* Highest one that is set */
+  min = find_minlength(re, code, code, utf, NULL, &count, backref_cache);
+  switch(min)
+    {
+    case -1:  /* \C in UTF mode or over-complex regex */
+    break;    /* Leave minlength unchanged (will be zero) */
+
+    case -2:
+    return 2; /* missing capturing bracket */
+
+    case -3:
+    return 3; /* unrecognized opcode */
+
+    default:
+    re->minlength = (min > UINT16_MAX)? UINT16_MAX : min;
+    break;
+    }
+  }
+
+return 0;
+}
+
+/* End of pcre2_study.c */
diff --git a/src/c/pcre2/src/pcre2_substitute.c b/src/c/pcre2/src/pcre2_substitute.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_substitute.c
@@ -0,0 +1,987 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2020 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+#define PTR_STACK_SIZE 20
+
+#define SUBSTITUTE_OPTIONS \
+  (PCRE2_SUBSTITUTE_EXTENDED|PCRE2_SUBSTITUTE_GLOBAL| \
+   PCRE2_SUBSTITUTE_LITERAL|PCRE2_SUBSTITUTE_MATCHED| \
+   PCRE2_SUBSTITUTE_OVERFLOW_LENGTH|PCRE2_SUBSTITUTE_REPLACEMENT_ONLY| \
+   PCRE2_SUBSTITUTE_UNKNOWN_UNSET|PCRE2_SUBSTITUTE_UNSET_EMPTY)
+
+
+
+/*************************************************
+*           Find end of substitute text          *
+*************************************************/
+
+/* In extended mode, we recognize ${name:+set text:unset text} and similar
+constructions. This requires the identification of unescaped : and }
+characters. This function scans for such. It must deal with nested ${
+constructions. The pointer to the text is updated, either to the required end
+character, or to where an error was detected.
+
+Arguments:
+  code      points to the compiled expression (for options)
+  ptrptr    points to the pointer to the start of the text (updated)
+  ptrend    end of the whole string
+  last      TRUE if the last expected string (only } recognized)
+
+Returns:    0 on success
+            negative error code on failure
+*/
+
+static int
+find_text_end(const pcre2_code *code, PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend,
+  BOOL last)
+{
+int rc = 0;
+uint32_t nestlevel = 0;
+BOOL literal = FALSE;
+PCRE2_SPTR ptr = *ptrptr;
+
+for (; ptr < ptrend; ptr++)
+  {
+  if (literal)
+    {
+    if (ptr[0] == CHAR_BACKSLASH && ptr < ptrend - 1 && ptr[1] == CHAR_E)
+      {
+      literal = FALSE;
+      ptr += 1;
+      }
+    }
+
+  else if (*ptr == CHAR_RIGHT_CURLY_BRACKET)
+    {
+    if (nestlevel == 0) goto EXIT;
+    nestlevel--;
+    }
+
+  else if (*ptr == CHAR_COLON && !last && nestlevel == 0) goto EXIT;
+
+  else if (*ptr == CHAR_DOLLAR_SIGN)
+    {
+    if (ptr < ptrend - 1 && ptr[1] == CHAR_LEFT_CURLY_BRACKET)
+      {
+      nestlevel++;
+      ptr += 1;
+      }
+    }
+
+  else if (*ptr == CHAR_BACKSLASH)
+    {
+    int erc;
+    int errorcode;
+    uint32_t ch;
+
+    if (ptr < ptrend - 1) switch (ptr[1])
+      {
+      case CHAR_L:
+      case CHAR_l:
+      case CHAR_U:
+      case CHAR_u:
+      ptr += 1;
+      continue;
+      }
+
+    ptr += 1;  /* Must point after \ */
+    erc = PRIV(check_escape)(&ptr, ptrend, &ch, &errorcode,
+      code->overall_options, code->extra_options, FALSE, NULL);
+    ptr -= 1;  /* Back to last code unit of escape */
+    if (errorcode != 0)
+      {
+      rc = errorcode;
+      goto EXIT;
+      }
+
+    switch(erc)
+      {
+      case 0:      /* Data character */
+      case ESC_E:  /* Isolated \E is ignored */
+      break;
+
+      case ESC_Q:
+      literal = TRUE;
+      break;
+
+      default:
+      rc = PCRE2_ERROR_BADREPESCAPE;
+      goto EXIT;
+      }
+    }
+  }
+
+rc = PCRE2_ERROR_REPMISSINGBRACE;   /* Terminator not found */
+
+EXIT:
+*ptrptr = ptr;
+return rc;
+}
+
+
+
+/*************************************************
+*              Match and substitute              *
+*************************************************/
+
+/* This function applies a compiled re to a subject string and creates a new
+string with substitutions. The first 7 arguments are the same as for
+pcre2_match(). Either string length may be PCRE2_ZERO_TERMINATED.
+
+Arguments:
+  code            points to the compiled expression
+  subject         points to the subject string
+  length          length of subject string (may contain binary zeros)
+  start_offset    where to start in the subject string
+  options         option bits
+  match_data      points to a match_data block, or is NULL
+  context         points a PCRE2 context
+  replacement     points to the replacement string
+  rlength         length of replacement string
+  buffer          where to put the substituted string
+  blength         points to length of buffer; updated to length of string
+
+Returns:          >= 0 number of substitutions made
+                  < 0 an error code
+                  PCRE2_ERROR_BADREPLACEMENT means invalid use of $
+*/
+
+/* This macro checks for space in the buffer before copying into it. On
+overflow, either give an error immediately, or keep on, accumulating the
+length. */
+
+#define CHECKMEMCPY(from,length) \
+  { \
+  if (!overflowed && lengthleft < length) \
+    { \
+    if ((suboptions & PCRE2_SUBSTITUTE_OVERFLOW_LENGTH) == 0) goto NOROOM; \
+    overflowed = TRUE; \
+    extra_needed = length - lengthleft; \
+    } \
+  else if (overflowed) \
+    { \
+    extra_needed += length; \
+    }  \
+  else \
+    {  \
+    memcpy(buffer + buff_offset, from, CU2BYTES(length)); \
+    buff_offset += length; \
+    lengthleft -= length; \
+    } \
+  }
+
+/* Here's the function */
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substitute(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length,
+  PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data,
+  pcre2_match_context *mcontext, PCRE2_SPTR replacement, PCRE2_SIZE rlength,
+  PCRE2_UCHAR *buffer, PCRE2_SIZE *blength)
+{
+int rc;
+int subs;
+int forcecase = 0;
+int forcecasereset = 0;
+uint32_t ovector_count;
+uint32_t goptions = 0;
+uint32_t suboptions;
+pcre2_match_data *internal_match_data = NULL;
+BOOL escaped_literal = FALSE;
+BOOL overflowed = FALSE;
+BOOL use_existing_match;
+BOOL replacement_only;
+#ifdef SUPPORT_UNICODE
+BOOL utf = (code->overall_options & PCRE2_UTF) != 0;
+BOOL ucp = (code->overall_options & PCRE2_UCP) != 0;
+#endif
+PCRE2_UCHAR temp[6];
+PCRE2_SPTR ptr;
+PCRE2_SPTR repend;
+PCRE2_SIZE extra_needed = 0;
+PCRE2_SIZE buff_offset, buff_length, lengthleft, fraglength;
+PCRE2_SIZE *ovector;
+PCRE2_SIZE ovecsave[3];
+pcre2_substitute_callout_block scb;
+
+/* General initialization */
+
+buff_offset = 0;
+lengthleft = buff_length = *blength;
+*blength = PCRE2_UNSET;
+ovecsave[0] = ovecsave[1] = ovecsave[2] = PCRE2_UNSET;
+
+/* Partial matching is not valid. This must come after setting *blength to
+PCRE2_UNSET, so as not to imply an offset in the replacement. */
+
+if ((options & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0)
+  return PCRE2_ERROR_BADOPTION;
+
+/* Check for using a match that has already happened. Note that the subject
+pointer in the match data may be NULL after a no-match. */
+
+use_existing_match = ((options & PCRE2_SUBSTITUTE_MATCHED) != 0);
+replacement_only = ((options & PCRE2_SUBSTITUTE_REPLACEMENT_ONLY) != 0);
+
+/* If starting from an existing match, there must be an externally provided
+match data block. We create an internal match_data block in two cases: (a) an
+external one is not supplied (and we are not starting from an existing match);
+(b) an existing match is to be used for the first substitution. In the latter
+case, we copy the existing match into the internal block. This ensures that no
+changes are made to the existing match data block. */
+
+if (match_data == NULL)
+  {
+  pcre2_general_context *gcontext;
+  if (use_existing_match) return PCRE2_ERROR_NULL;
+  gcontext = (mcontext == NULL)?
+    (pcre2_general_context *)code :
+    (pcre2_general_context *)mcontext;
+  match_data = internal_match_data =
+    pcre2_match_data_create_from_pattern(code, gcontext);
+  if (internal_match_data == NULL) return PCRE2_ERROR_NOMEMORY;
+  }
+
+else if (use_existing_match)
+  {
+  pcre2_general_context *gcontext = (mcontext == NULL)?
+    (pcre2_general_context *)code :
+    (pcre2_general_context *)mcontext;
+  int pairs = (code->top_bracket + 1 < match_data->oveccount)?
+    code->top_bracket + 1 : match_data->oveccount;
+  internal_match_data = pcre2_match_data_create(match_data->oveccount,
+    gcontext);
+  if (internal_match_data == NULL) return PCRE2_ERROR_NOMEMORY;
+  memcpy(internal_match_data, match_data, offsetof(pcre2_match_data, ovector)
+    + 2*pairs*sizeof(PCRE2_SIZE));
+  match_data = internal_match_data;
+  }
+
+/* Remember ovector details */
+
+ovector = pcre2_get_ovector_pointer(match_data);
+ovector_count = pcre2_get_ovector_count(match_data);
+
+/* Fixed things in the callout block */
+
+scb.version = 0;
+scb.input = subject;
+scb.output = (PCRE2_SPTR)buffer;
+scb.ovector = ovector;
+
+/* Find lengths of zero-terminated strings and the end of the replacement. */
+
+if (length == PCRE2_ZERO_TERMINATED) length = PRIV(strlen)(subject);
+if (rlength == PCRE2_ZERO_TERMINATED) rlength = PRIV(strlen)(replacement);
+repend = replacement + rlength;
+
+/* Check UTF replacement string if necessary. */
+
+#ifdef SUPPORT_UNICODE
+if (utf && (options & PCRE2_NO_UTF_CHECK) == 0)
+  {
+  rc = PRIV(valid_utf)(replacement, rlength, &(match_data->startchar));
+  if (rc != 0)
+    {
+    match_data->leftchar = 0;
+    goto EXIT;
+    }
+  }
+#endif  /* SUPPORT_UNICODE */
+
+/* Save the substitute options and remove them from the match options. */
+
+suboptions = options & SUBSTITUTE_OPTIONS;
+options &= ~SUBSTITUTE_OPTIONS;
+
+/* Error if the start match offset is greater than the length of the subject. */
+
+if (start_offset > length)
+  {
+  match_data->leftchar = 0;
+  rc = PCRE2_ERROR_BADOFFSET;
+  goto EXIT;
+  }
+
+/* Copy up to the start offset, unless only the replacement is required. */
+
+if (!replacement_only) CHECKMEMCPY(subject, start_offset);
+
+/* Loop for global substituting. If PCRE2_SUBSTITUTE_MATCHED is set, the first
+match is taken from the match_data that was passed in. */
+
+subs = 0;
+do
+  {
+  PCRE2_SPTR ptrstack[PTR_STACK_SIZE];
+  uint32_t ptrstackptr = 0;
+
+  if (use_existing_match)
+    {
+    rc = match_data->rc;
+    use_existing_match = FALSE;
+    }
+  else rc = pcre2_match(code, subject, length, start_offset, options|goptions,
+    match_data, mcontext);
+
+#ifdef SUPPORT_UNICODE
+  if (utf) options |= PCRE2_NO_UTF_CHECK;  /* Only need to check once */
+#endif
+
+  /* Any error other than no match returns the error code. No match when not
+  doing the special after-empty-match global rematch, or when at the end of the
+  subject, breaks the global loop. Otherwise, advance the starting point by one
+  character, copying it to the output, and try again. */
+
+  if (rc < 0)
+    {
+    PCRE2_SIZE save_start;
+
+    if (rc != PCRE2_ERROR_NOMATCH) goto EXIT;
+    if (goptions == 0 || start_offset >= length) break;
+
+    /* Advance by one code point. Then, if CRLF is a valid newline sequence and
+    we have advanced into the middle of it, advance one more code point. In
+    other words, do not start in the middle of CRLF, even if CR and LF on their
+    own are valid newlines. */
+
+    save_start = start_offset++;
+    if (subject[start_offset-1] == CHAR_CR &&
+        code->newline_convention != PCRE2_NEWLINE_CR &&
+        code->newline_convention != PCRE2_NEWLINE_LF &&
+        start_offset < length &&
+        subject[start_offset] == CHAR_LF)
+      start_offset++;
+
+    /* Otherwise, in UTF mode, advance past any secondary code points. */
+
+    else if ((code->overall_options & PCRE2_UTF) != 0)
+      {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+      while (start_offset < length && (subject[start_offset] & 0xc0) == 0x80)
+        start_offset++;
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+      while (start_offset < length &&
+            (subject[start_offset] & 0xfc00) == 0xdc00)
+        start_offset++;
+#endif
+      }
+
+    /* Copy what we have advanced past (unless not required), reset the special
+    global options, and continue to the next match. */
+
+    fraglength = start_offset - save_start;
+    if (!replacement_only) CHECKMEMCPY(subject + save_start, fraglength);
+    goptions = 0;
+    continue;
+    }
+
+  /* Handle a successful match. Matches that use \K to end before they start
+  or start before the current point in the subject are not supported. */
+
+  if (ovector[1] < ovector[0] || ovector[0] < start_offset)
+    {
+    rc = PCRE2_ERROR_BADSUBSPATTERN;
+    goto EXIT;
+    }
+
+  /* Check for the same match as previous. This is legitimate after matching an
+  empty string that starts after the initial match offset. We have tried again
+  at the match point in case the pattern is one like /(?<=\G.)/ which can never
+  match at its starting point, so running the match achieves the bumpalong. If
+  we do get the same (null) match at the original match point, it isn't such a
+  pattern, so we now do the empty string magic. In all other cases, a repeat
+  match should never occur. */
+
+  if (ovecsave[0] == ovector[0] && ovecsave[1] == ovector[1])
+    {
+    if (ovector[0] == ovector[1] && ovecsave[2] != start_offset)
+      {
+      goptions = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED;
+      ovecsave[2] = start_offset;
+      continue;    /* Back to the top of the loop */
+      }
+    rc = PCRE2_ERROR_INTERNAL_DUPMATCH;
+    goto EXIT;
+    }
+
+  /* Count substitutions with a paranoid check for integer overflow; surely no
+  real call to this function would ever hit this! */
+
+  if (subs == INT_MAX)
+    {
+    rc = PCRE2_ERROR_TOOMANYREPLACE;
+    goto EXIT;
+    }
+  subs++;
+
+  /* Copy the text leading up to the match (unless not required), and remember
+  where the insert begins and how many ovector pairs are set. */
+
+  if (rc == 0) rc = ovector_count;
+  fraglength = ovector[0] - start_offset;
+  if (!replacement_only) CHECKMEMCPY(subject + start_offset, fraglength);
+  scb.output_offsets[0] = buff_offset;
+  scb.oveccount = rc;
+
+  /* Process the replacement string. If the entire replacement is literal, just
+  copy it with length check. */
+
+  ptr = replacement;
+  if ((suboptions & PCRE2_SUBSTITUTE_LITERAL) != 0)
+    {
+    CHECKMEMCPY(ptr, rlength);
+    }
+
+  /* Within a non-literal replacement, which must be scanned character by
+  character, local literal mode can be set by \Q, but only in extended mode
+  when backslashes are being interpreted. In extended mode we must handle
+  nested substrings that are to be reprocessed. */
+
+  else for (;;)
+    {
+    uint32_t ch;
+    unsigned int chlen;
+
+    /* If at the end of a nested substring, pop the stack. */
+
+    if (ptr >= repend)
+      {
+      if (ptrstackptr == 0) break;       /* End of replacement string */
+      repend = ptrstack[--ptrstackptr];
+      ptr = ptrstack[--ptrstackptr];
+      continue;
+      }
+
+    /* Handle the next character */
+
+    if (escaped_literal)
+      {
+      if (ptr[0] == CHAR_BACKSLASH && ptr < repend - 1 && ptr[1] == CHAR_E)
+        {
+        escaped_literal = FALSE;
+        ptr += 2;
+        continue;
+        }
+      goto LOADLITERAL;
+      }
+
+    /* Not in literal mode. */
+
+    if (*ptr == CHAR_DOLLAR_SIGN)
+      {
+      int group, n;
+      uint32_t special = 0;
+      BOOL inparens;
+      BOOL star;
+      PCRE2_SIZE sublength;
+      PCRE2_SPTR text1_start = NULL;
+      PCRE2_SPTR text1_end = NULL;
+      PCRE2_SPTR text2_start = NULL;
+      PCRE2_SPTR text2_end = NULL;
+      PCRE2_UCHAR next;
+      PCRE2_UCHAR name[33];
+
+      if (++ptr >= repend) goto BAD;
+      if ((next = *ptr) == CHAR_DOLLAR_SIGN) goto LOADLITERAL;
+
+      group = -1;
+      n = 0;
+      inparens = FALSE;
+      star = FALSE;
+
+      if (next == CHAR_LEFT_CURLY_BRACKET)
+        {
+        if (++ptr >= repend) goto BAD;
+        next = *ptr;
+        inparens = TRUE;
+        }
+
+      if (next == CHAR_ASTERISK)
+        {
+        if (++ptr >= repend) goto BAD;
+        next = *ptr;
+        star = TRUE;
+        }
+
+      if (!star && next >= CHAR_0 && next <= CHAR_9)
+        {
+        group = next - CHAR_0;
+        while (++ptr < repend)
+          {
+          next = *ptr;
+          if (next < CHAR_0 || next > CHAR_9) break;
+          group = group * 10 + next - CHAR_0;
+
+          /* A check for a number greater than the hightest captured group
+          is sufficient here; no need for a separate overflow check. If unknown
+          groups are to be treated as unset, just skip over any remaining
+          digits and carry on. */
+
+          if (group > code->top_bracket)
+            {
+            if ((suboptions & PCRE2_SUBSTITUTE_UNKNOWN_UNSET) != 0)
+              {
+              while (++ptr < repend && *ptr >= CHAR_0 && *ptr <= CHAR_9);
+              break;
+              }
+            else
+              {
+              rc = PCRE2_ERROR_NOSUBSTRING;
+              goto PTREXIT;
+              }
+            }
+          }
+        }
+      else
+        {
+        const uint8_t *ctypes = code->tables + ctypes_offset;
+        while (MAX_255(next) && (ctypes[next] & ctype_word) != 0)
+          {
+          name[n++] = next;
+          if (n > 32) goto BAD;
+          if (++ptr >= repend) break;
+          next = *ptr;
+          }
+        if (n == 0) goto BAD;
+        name[n] = 0;
+        }
+
+      /* In extended mode we recognize ${name:+set text:unset text} and
+      ${name:-default text}. */
+
+      if (inparens)
+        {
+        if ((suboptions & PCRE2_SUBSTITUTE_EXTENDED) != 0 &&
+             !star && ptr < repend - 2 && next == CHAR_COLON)
+          {
+          special = *(++ptr);
+          if (special != CHAR_PLUS && special != CHAR_MINUS)
+            {
+            rc = PCRE2_ERROR_BADSUBSTITUTION;
+            goto PTREXIT;
+            }
+
+          text1_start = ++ptr;
+          rc = find_text_end(code, &ptr, repend, special == CHAR_MINUS);
+          if (rc != 0) goto PTREXIT;
+          text1_end = ptr;
+
+          if (special == CHAR_PLUS && *ptr == CHAR_COLON)
+            {
+            text2_start = ++ptr;
+            rc = find_text_end(code, &ptr, repend, TRUE);
+            if (rc != 0) goto PTREXIT;
+            text2_end = ptr;
+            }
+          }
+
+        else
+          {
+          if (ptr >= repend || *ptr != CHAR_RIGHT_CURLY_BRACKET)
+            {
+            rc = PCRE2_ERROR_REPMISSINGBRACE;
+            goto PTREXIT;
+            }
+          }
+
+        ptr++;
+        }
+
+      /* Have found a syntactically correct group number or name, or *name.
+      Only *MARK is currently recognized. */
+
+      if (star)
+        {
+        if (PRIV(strcmp_c8)(name, STRING_MARK) == 0)
+          {
+          PCRE2_SPTR mark = pcre2_get_mark(match_data);
+          if (mark != NULL)
+            {
+            PCRE2_SPTR mark_start = mark;
+            while (*mark != 0) mark++;
+            fraglength = mark - mark_start;
+            CHECKMEMCPY(mark_start, fraglength);
+            }
+          }
+        else goto BAD;
+        }
+
+      /* Substitute the contents of a group. We don't use substring_copy
+      functions any more, in order to support case forcing. */
+
+      else
+        {
+        PCRE2_SPTR subptr, subptrend;
+
+        /* Find a number for a named group. In case there are duplicate names,
+        search for the first one that is set. If the name is not found when
+        PCRE2_SUBSTITUTE_UNKNOWN_EMPTY is set, set the group number to a
+        non-existent group. */
+
+        if (group < 0)
+          {
+          PCRE2_SPTR first, last, entry;
+          rc = pcre2_substring_nametable_scan(code, name, &first, &last);
+          if (rc == PCRE2_ERROR_NOSUBSTRING &&
+              (suboptions & PCRE2_SUBSTITUTE_UNKNOWN_UNSET) != 0)
+            {
+            group = code->top_bracket + 1;
+            }
+          else
+            {
+            if (rc < 0) goto PTREXIT;
+            for (entry = first; entry <= last; entry += rc)
+              {
+              uint32_t ng = GET2(entry, 0);
+              if (ng < ovector_count)
+                {
+                if (group < 0) group = ng;          /* First in ovector */
+                if (ovector[ng*2] != PCRE2_UNSET)
+                  {
+                  group = ng;                       /* First that is set */
+                  break;
+                  }
+                }
+              }
+
+            /* If group is still negative, it means we did not find a group
+            that is in the ovector. Just set the first group. */
+
+            if (group < 0) group = GET2(first, 0);
+            }
+          }
+
+        /* We now have a group that is identified by number. Find the length of
+        the captured string. If a group in a non-special substitution is unset
+        when PCRE2_SUBSTITUTE_UNSET_EMPTY is set, substitute nothing. */
+
+        rc = pcre2_substring_length_bynumber(match_data, group, &sublength);
+        if (rc < 0)
+          {
+          if (rc == PCRE2_ERROR_NOSUBSTRING &&
+              (suboptions & PCRE2_SUBSTITUTE_UNKNOWN_UNSET) != 0)
+            {
+            rc = PCRE2_ERROR_UNSET;
+            }
+          if (rc != PCRE2_ERROR_UNSET) goto PTREXIT;  /* Non-unset errors */
+          if (special == 0)                           /* Plain substitution */
+            {
+            if ((suboptions & PCRE2_SUBSTITUTE_UNSET_EMPTY) != 0) continue;
+            goto PTREXIT;                             /* Else error */
+            }
+          }
+
+        /* If special is '+' we have a 'set' and possibly an 'unset' text,
+        both of which are reprocessed when used. If special is '-' we have a
+        default text for when the group is unset; it must be reprocessed. */
+
+        if (special != 0)
+          {
+          if (special == CHAR_MINUS)
+            {
+            if (rc == 0) goto LITERAL_SUBSTITUTE;
+            text2_start = text1_start;
+            text2_end = text1_end;
+            }
+
+          if (ptrstackptr >= PTR_STACK_SIZE) goto BAD;
+          ptrstack[ptrstackptr++] = ptr;
+          ptrstack[ptrstackptr++] = repend;
+
+          if (rc == 0)
+            {
+            ptr = text1_start;
+            repend = text1_end;
+            }
+          else
+            {
+            ptr = text2_start;
+            repend = text2_end;
+            }
+          continue;
+          }
+
+        /* Otherwise we have a literal substitution of a group's contents. */
+
+        LITERAL_SUBSTITUTE:
+        subptr = subject + ovector[group*2];
+        subptrend = subject + ovector[group*2 + 1];
+
+        /* Substitute a literal string, possibly forcing alphabetic case. */
+
+        while (subptr < subptrend)
+          {
+          GETCHARINCTEST(ch, subptr);
+          if (forcecase != 0)
+            {
+#ifdef SUPPORT_UNICODE
+            if (utf || ucp)
+              {
+              uint32_t type = UCD_CHARTYPE(ch);
+              if (PRIV(ucp_gentype)[type] == ucp_L &&
+                  type != ((forcecase > 0)? ucp_Lu : ucp_Ll))
+                ch = UCD_OTHERCASE(ch);
+              }
+            else
+#endif
+              {
+              if (((code->tables + cbits_offset +
+                  ((forcecase > 0)? cbit_upper:cbit_lower)
+                  )[ch/8] & (1u << (ch%8))) == 0)
+                ch = (code->tables + fcc_offset)[ch];
+              }
+            forcecase = forcecasereset;
+            }
+
+#ifdef SUPPORT_UNICODE
+          if (utf) chlen = PRIV(ord2utf)(ch, temp); else
+#endif
+            {
+            temp[0] = ch;
+            chlen = 1;
+            }
+          CHECKMEMCPY(temp, chlen);
+          }
+        }
+      }
+
+    /* Handle an escape sequence in extended mode. We can use check_escape()
+    to process \Q, \E, \c, \o, \x and \ followed by non-alphanumerics, but
+    the case-forcing escapes are not supported in pcre2_compile() so must be
+    recognized here. */
+
+    else if ((suboptions & PCRE2_SUBSTITUTE_EXTENDED) != 0 &&
+              *ptr == CHAR_BACKSLASH)
+      {
+      int errorcode;
+
+      if (ptr < repend - 1) switch (ptr[1])
+        {
+        case CHAR_L:
+        forcecase = forcecasereset = -1;
+        ptr += 2;
+        continue;
+
+        case CHAR_l:
+        forcecase = -1;
+        forcecasereset = 0;
+        ptr += 2;
+        continue;
+
+        case CHAR_U:
+        forcecase = forcecasereset = 1;
+        ptr += 2;
+        continue;
+
+        case CHAR_u:
+        forcecase = 1;
+        forcecasereset = 0;
+        ptr += 2;
+        continue;
+
+        default:
+        break;
+        }
+
+      ptr++;  /* Point after \ */
+      rc = PRIV(check_escape)(&ptr, repend, &ch, &errorcode,
+        code->overall_options, code->extra_options, FALSE, NULL);
+      if (errorcode != 0) goto BADESCAPE;
+
+      switch(rc)
+        {
+        case ESC_E:
+        forcecase = forcecasereset = 0;
+        continue;
+
+        case ESC_Q:
+        escaped_literal = TRUE;
+        continue;
+
+        case 0:      /* Data character */
+        goto LITERAL;
+
+        default:
+        goto BADESCAPE;
+        }
+      }
+
+    /* Handle a literal code unit */
+
+    else
+      {
+      LOADLITERAL:
+      GETCHARINCTEST(ch, ptr);    /* Get character value, increment pointer */
+
+      LITERAL:
+      if (forcecase != 0)
+        {
+#ifdef SUPPORT_UNICODE
+        if (utf || ucp)
+          {
+          uint32_t type = UCD_CHARTYPE(ch);
+          if (PRIV(ucp_gentype)[type] == ucp_L &&
+              type != ((forcecase > 0)? ucp_Lu : ucp_Ll))
+            ch = UCD_OTHERCASE(ch);
+          }
+        else
+#endif
+          {
+          if (((code->tables + cbits_offset +
+              ((forcecase > 0)? cbit_upper:cbit_lower)
+              )[ch/8] & (1u << (ch%8))) == 0)
+            ch = (code->tables + fcc_offset)[ch];
+          }
+        forcecase = forcecasereset;
+        }
+
+#ifdef SUPPORT_UNICODE
+      if (utf) chlen = PRIV(ord2utf)(ch, temp); else
+#endif
+        {
+        temp[0] = ch;
+        chlen = 1;
+        }
+      CHECKMEMCPY(temp, chlen);
+      } /* End handling a literal code unit */
+    }   /* End of loop for scanning the replacement. */
+
+  /* The replacement has been copied to the output, or its size has been
+  remembered. Do the callout if there is one and we have done an actual
+  replacement. */
+
+  if (!overflowed && mcontext != NULL && mcontext->substitute_callout != NULL)
+    {
+    scb.subscount = subs;
+    scb.output_offsets[1] = buff_offset;
+    rc = mcontext->substitute_callout(&scb, mcontext->substitute_callout_data);
+
+    /* A non-zero return means cancel this substitution. Instead, copy the
+    matched string fragment. */
+
+    if (rc != 0)
+      {
+      PCRE2_SIZE newlength = scb.output_offsets[1] - scb.output_offsets[0];
+      PCRE2_SIZE oldlength = ovector[1] - ovector[0];
+
+      buff_offset -= newlength;
+      lengthleft += newlength;
+      if (!replacement_only) CHECKMEMCPY(subject + ovector[0], oldlength);
+
+      /* A negative return means do not do any more. */
+
+      if (rc < 0) suboptions &= (~PCRE2_SUBSTITUTE_GLOBAL);
+      }
+    }
+
+  /* Save the details of this match. See above for how this data is used. If we
+  matched an empty string, do the magic for global matches. Update the start
+  offset to point to the rest of the subject string. If we re-used an existing
+  match for the first match, switch to the internal match data block. */
+
+  ovecsave[0] = ovector[0];
+  ovecsave[1] = ovector[1];
+  ovecsave[2] = start_offset;
+
+  goptions = (ovector[0] != ovector[1] || ovector[0] > start_offset)? 0 :
+    PCRE2_ANCHORED|PCRE2_NOTEMPTY_ATSTART;
+  start_offset = ovector[1];
+  } while ((suboptions & PCRE2_SUBSTITUTE_GLOBAL) != 0);  /* Repeat "do" loop */
+
+/* Copy the rest of the subject unless not required, and terminate the output
+with a binary zero. */
+
+if (!replacement_only)
+  {
+  fraglength = length - start_offset;
+  CHECKMEMCPY(subject + start_offset, fraglength);
+  }
+
+temp[0] = 0;
+CHECKMEMCPY(temp, 1);
+
+/* If overflowed is set it means the PCRE2_SUBSTITUTE_OVERFLOW_LENGTH is set,
+and matching has carried on after a full buffer, in order to compute the length
+needed. Otherwise, an overflow generates an immediate error return. */
+
+if (overflowed)
+  {
+  rc = PCRE2_ERROR_NOMEMORY;
+  *blength = buff_length + extra_needed;
+  }
+
+/* After a successful execution, return the number of substitutions and set the
+length of buffer used, excluding the trailing zero. */
+
+else
+  {
+  rc = subs;
+  *blength = buff_offset - 1;
+  }
+
+EXIT:
+if (internal_match_data != NULL) pcre2_match_data_free(internal_match_data);
+  else match_data->rc = rc;
+return rc;
+
+NOROOM:
+rc = PCRE2_ERROR_NOMEMORY;
+goto EXIT;
+
+BAD:
+rc = PCRE2_ERROR_BADREPLACEMENT;
+goto PTREXIT;
+
+BADESCAPE:
+rc = PCRE2_ERROR_BADREPESCAPE;
+
+PTREXIT:
+*blength = (PCRE2_SIZE)(ptr - replacement);
+goto EXIT;
+}
+
+/* End of pcre2_substitute.c */
diff --git a/src/c/pcre2/src/pcre2_substring.c b/src/c/pcre2/src/pcre2_substring.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_substring.c
@@ -0,0 +1,547 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+
+/*************************************************
+*   Copy named captured string to given buffer   *
+*************************************************/
+
+/* This function copies a single captured substring into a given buffer,
+identifying it by name. If the regex permits duplicate names, the first
+substring that is set is chosen.
+
+Arguments:
+  match_data     points to the match data
+  stringname     the name of the required substring
+  buffer         where to put the substring
+  sizeptr        the size of the buffer, updated to the size of the substring
+
+Returns:         if successful: zero
+                 if not successful, a negative error code:
+                   (1) an error from nametable_scan()
+                   (2) an error from copy_bynumber()
+                   (3) PCRE2_ERROR_UNAVAILABLE: no group is in ovector
+                   (4) PCRE2_ERROR_UNSET: all named groups in ovector are unset
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_copy_byname(pcre2_match_data *match_data, PCRE2_SPTR stringname,
+  PCRE2_UCHAR *buffer, PCRE2_SIZE *sizeptr)
+{
+PCRE2_SPTR first, last, entry;
+int failrc, entrysize;
+if (match_data->matchedby == PCRE2_MATCHEDBY_DFA_INTERPRETER)
+  return PCRE2_ERROR_DFA_UFUNC;
+entrysize = pcre2_substring_nametable_scan(match_data->code, stringname,
+  &first, &last);
+if (entrysize < 0) return entrysize;
+failrc = PCRE2_ERROR_UNAVAILABLE;
+for (entry = first; entry <= last; entry += entrysize)
+  {
+  uint32_t n = GET2(entry, 0);
+  if (n < match_data->oveccount)
+    {
+    if (match_data->ovector[n*2] != PCRE2_UNSET)
+      return pcre2_substring_copy_bynumber(match_data, n, buffer, sizeptr);
+    failrc = PCRE2_ERROR_UNSET;
+    }
+  }
+return failrc;
+}
+
+
+
+/*************************************************
+*  Copy numbered captured string to given buffer *
+*************************************************/
+
+/* This function copies a single captured substring into a given buffer,
+identifying it by number.
+
+Arguments:
+  match_data     points to the match data
+  stringnumber   the number of the required substring
+  buffer         where to put the substring
+  sizeptr        the size of the buffer, updated to the size of the substring
+
+Returns:         if successful: 0
+                 if not successful, a negative error code:
+                   PCRE2_ERROR_NOMEMORY: buffer too small
+                   PCRE2_ERROR_NOSUBSTRING: no such substring
+                   PCRE2_ERROR_UNAVAILABLE: ovector too small
+                   PCRE2_ERROR_UNSET: substring is not set
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_copy_bynumber(pcre2_match_data *match_data,
+  uint32_t stringnumber, PCRE2_UCHAR *buffer, PCRE2_SIZE *sizeptr)
+{
+int rc;
+PCRE2_SIZE size;
+rc = pcre2_substring_length_bynumber(match_data, stringnumber, &size);
+if (rc < 0) return rc;
+if (size + 1 > *sizeptr) return PCRE2_ERROR_NOMEMORY;
+memcpy(buffer, match_data->subject + match_data->ovector[stringnumber*2],
+  CU2BYTES(size));
+buffer[size] = 0;
+*sizeptr = size;
+return 0;
+}
+
+
+
+/*************************************************
+*          Extract named captured string         *
+*************************************************/
+
+/* This function copies a single captured substring, identified by name, into
+new memory. If the regex permits duplicate names, the first substring that is
+set is chosen.
+
+Arguments:
+  match_data     pointer to match_data
+  stringname     the name of the required substring
+  stringptr      where to put the pointer to the new memory
+  sizeptr        where to put the length of the substring
+
+Returns:         if successful: zero
+                 if not successful, a negative value:
+                   (1) an error from nametable_scan()
+                   (2) an error from get_bynumber()
+                   (3) PCRE2_ERROR_UNAVAILABLE: no group is in ovector
+                   (4) PCRE2_ERROR_UNSET: all named groups in ovector are unset
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_get_byname(pcre2_match_data *match_data,
+  PCRE2_SPTR stringname, PCRE2_UCHAR **stringptr, PCRE2_SIZE *sizeptr)
+{
+PCRE2_SPTR first, last, entry;
+int failrc, entrysize;
+if (match_data->matchedby == PCRE2_MATCHEDBY_DFA_INTERPRETER)
+  return PCRE2_ERROR_DFA_UFUNC;
+entrysize = pcre2_substring_nametable_scan(match_data->code, stringname,
+  &first, &last);
+if (entrysize < 0) return entrysize;
+failrc = PCRE2_ERROR_UNAVAILABLE;
+for (entry = first; entry <= last; entry += entrysize)
+  {
+  uint32_t n = GET2(entry, 0);
+  if (n < match_data->oveccount)
+    {
+    if (match_data->ovector[n*2] != PCRE2_UNSET)
+      return pcre2_substring_get_bynumber(match_data, n, stringptr, sizeptr);
+    failrc = PCRE2_ERROR_UNSET;
+    }
+  }
+return failrc;
+}
+
+
+
+/*************************************************
+*      Extract captured string to new memory     *
+*************************************************/
+
+/* This function copies a single captured substring into a piece of new
+memory.
+
+Arguments:
+  match_data     points to match data
+  stringnumber   the number of the required substring
+  stringptr      where to put a pointer to the new memory
+  sizeptr        where to put the size of the substring
+
+Returns:         if successful: 0
+                 if not successful, a negative error code:
+                   PCRE2_ERROR_NOMEMORY: failed to get memory
+                   PCRE2_ERROR_NOSUBSTRING: no such substring
+                   PCRE2_ERROR_UNAVAILABLE: ovector too small
+                   PCRE2_ERROR_UNSET: substring is not set
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_get_bynumber(pcre2_match_data *match_data,
+  uint32_t stringnumber, PCRE2_UCHAR **stringptr, PCRE2_SIZE *sizeptr)
+{
+int rc;
+PCRE2_SIZE size;
+PCRE2_UCHAR *yield;
+rc = pcre2_substring_length_bynumber(match_data, stringnumber, &size);
+if (rc < 0) return rc;
+yield = PRIV(memctl_malloc)(sizeof(pcre2_memctl) +
+  (size + 1)*PCRE2_CODE_UNIT_WIDTH, (pcre2_memctl *)match_data);
+if (yield == NULL) return PCRE2_ERROR_NOMEMORY;
+yield = (PCRE2_UCHAR *)(((char *)yield) + sizeof(pcre2_memctl));
+memcpy(yield, match_data->subject + match_data->ovector[stringnumber*2],
+  CU2BYTES(size));
+yield[size] = 0;
+*stringptr = yield;
+*sizeptr = size;
+return 0;
+}
+
+
+
+/*************************************************
+*       Free memory obtained by get_substring    *
+*************************************************/
+
+/*
+Argument:     the result of a previous pcre2_substring_get_byxxx()
+Returns:      nothing
+*/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_substring_free(PCRE2_UCHAR *string)
+{
+if (string != NULL)
+  {
+  pcre2_memctl *memctl = (pcre2_memctl *)((char *)string - sizeof(pcre2_memctl));
+  memctl->free(memctl, memctl->memory_data);
+  }
+}
+
+
+
+/*************************************************
+*         Get length of a named substring        *
+*************************************************/
+
+/* This function returns the length of a named captured substring. If the regex
+permits duplicate names, the first substring that is set is chosen.
+
+Arguments:
+  match_data      pointer to match data
+  stringname      the name of the required substring
+  sizeptr         where to put the length
+
+Returns:          0 if successful, else a negative error number
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_length_byname(pcre2_match_data *match_data,
+  PCRE2_SPTR stringname, PCRE2_SIZE *sizeptr)
+{
+PCRE2_SPTR first, last, entry;
+int failrc, entrysize;
+if (match_data->matchedby == PCRE2_MATCHEDBY_DFA_INTERPRETER)
+  return PCRE2_ERROR_DFA_UFUNC;
+entrysize = pcre2_substring_nametable_scan(match_data->code, stringname,
+  &first, &last);
+if (entrysize < 0) return entrysize;
+failrc = PCRE2_ERROR_UNAVAILABLE;
+for (entry = first; entry <= last; entry += entrysize)
+  {
+  uint32_t n = GET2(entry, 0);
+  if (n < match_data->oveccount)
+    {
+    if (match_data->ovector[n*2] != PCRE2_UNSET)
+      return pcre2_substring_length_bynumber(match_data, n, sizeptr);
+    failrc = PCRE2_ERROR_UNSET;
+    }
+  }
+return failrc;
+}
+
+
+
+/*************************************************
+*        Get length of a numbered substring      *
+*************************************************/
+
+/* This function returns the length of a captured substring. If the start is
+beyond the end (which can happen when \K is used in an assertion), it sets the
+length to zero.
+
+Arguments:
+  match_data      pointer to match data
+  stringnumber    the number of the required substring
+  sizeptr         where to put the length, if not NULL
+
+Returns:         if successful: 0
+                 if not successful, a negative error code:
+                   PCRE2_ERROR_NOSUBSTRING: no such substring
+                   PCRE2_ERROR_UNAVAILABLE: ovector is too small
+                   PCRE2_ERROR_UNSET: substring is not set
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_length_bynumber(pcre2_match_data *match_data,
+  uint32_t stringnumber, PCRE2_SIZE *sizeptr)
+{
+PCRE2_SIZE left, right;
+int count = match_data->rc;
+if (count == PCRE2_ERROR_PARTIAL)
+  {
+  if (stringnumber > 0) return PCRE2_ERROR_PARTIAL;
+  count = 0;
+  }
+else if (count < 0) return count;            /* Match failed */
+
+if (match_data->matchedby != PCRE2_MATCHEDBY_DFA_INTERPRETER)
+  {
+  if (stringnumber > match_data->code->top_bracket)
+    return PCRE2_ERROR_NOSUBSTRING;
+  if (stringnumber >= match_data->oveccount)
+    return PCRE2_ERROR_UNAVAILABLE;
+  if (match_data->ovector[stringnumber*2] == PCRE2_UNSET)
+    return PCRE2_ERROR_UNSET;
+  }
+else  /* Matched using pcre2_dfa_match() */
+  {
+  if (stringnumber >= match_data->oveccount) return PCRE2_ERROR_UNAVAILABLE;
+  if (count != 0 && stringnumber >= (uint32_t)count) return PCRE2_ERROR_UNSET;
+  }
+
+left = match_data->ovector[stringnumber*2];
+right = match_data->ovector[stringnumber*2+1];
+if (sizeptr != NULL) *sizeptr = (left > right)? 0 : right - left;
+return 0;
+}
+
+
+
+/*************************************************
+*    Extract all captured strings to new memory  *
+*************************************************/
+
+/* This function gets one chunk of memory and builds a list of pointers and all
+the captured substrings in it. A NULL pointer is put on the end of the list.
+The substrings are zero-terminated, but also, if the final argument is
+non-NULL, a list of lengths is also returned. This allows binary data to be
+handled.
+
+Arguments:
+  match_data     points to the match data
+  listptr        set to point to the list of pointers
+  lengthsptr     set to point to the list of lengths (may be NULL)
+
+Returns:         if successful: 0
+                 if not successful, a negative error code:
+                   PCRE2_ERROR_NOMEMORY: failed to get memory,
+                   or a match failure code
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_list_get(pcre2_match_data *match_data, PCRE2_UCHAR ***listptr,
+  PCRE2_SIZE **lengthsptr)
+{
+int i, count, count2;
+PCRE2_SIZE size;
+PCRE2_SIZE *lensp;
+pcre2_memctl *memp;
+PCRE2_UCHAR **listp;
+PCRE2_UCHAR *sp;
+PCRE2_SIZE *ovector;
+
+if ((count = match_data->rc) < 0) return count;   /* Match failed */
+if (count == 0) count = match_data->oveccount;    /* Ovector too small */
+
+count2 = 2*count;
+ovector = match_data->ovector;
+size = sizeof(pcre2_memctl) + sizeof(PCRE2_UCHAR *);      /* For final NULL */
+if (lengthsptr != NULL) size += sizeof(PCRE2_SIZE) * count;  /* For lengths */
+
+for (i = 0; i < count2; i += 2)
+  {
+  size += sizeof(PCRE2_UCHAR *) + CU2BYTES(1);
+  if (ovector[i+1] > ovector[i]) size += CU2BYTES(ovector[i+1] - ovector[i]);
+  }
+
+memp = PRIV(memctl_malloc)(size, (pcre2_memctl *)match_data);
+if (memp == NULL) return PCRE2_ERROR_NOMEMORY;
+
+*listptr = listp = (PCRE2_UCHAR **)((char *)memp + sizeof(pcre2_memctl));
+lensp = (PCRE2_SIZE *)((char *)listp + sizeof(PCRE2_UCHAR *) * (count + 1));
+
+if (lengthsptr == NULL)
+  {
+  sp = (PCRE2_UCHAR *)lensp;
+  lensp = NULL;
+  }
+else
+  {
+  *lengthsptr = lensp;
+  sp = (PCRE2_UCHAR *)((char *)lensp + sizeof(PCRE2_SIZE) * count);
+  }
+
+for (i = 0; i < count2; i += 2)
+  {
+  size = (ovector[i+1] > ovector[i])? (ovector[i+1] - ovector[i]) : 0;
+
+  /* Size == 0 includes the case when the capture is unset. Avoid adding
+  PCRE2_UNSET to match_data->subject because it overflows, even though with
+  zero size calling memcpy() is harmless. */
+
+  if (size != 0) memcpy(sp, match_data->subject + ovector[i], CU2BYTES(size));
+  *listp++ = sp;
+  if (lensp != NULL) *lensp++ = size;
+  sp += size;
+  *sp++ = 0;
+  }
+
+*listp = NULL;
+return 0;
+}
+
+
+
+/*************************************************
+*   Free memory obtained by substring_list_get   *
+*************************************************/
+
+/*
+Argument:     the result of a previous pcre2_substring_list_get()
+Returns:      nothing
+*/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_substring_list_free(PCRE2_SPTR *list)
+{
+if (list != NULL)
+  {
+  pcre2_memctl *memctl = (pcre2_memctl *)((char *)list - sizeof(pcre2_memctl));
+  memctl->free(memctl, memctl->memory_data);
+  }
+}
+
+
+
+/*************************************************
+*     Find (multiple) entries for named string   *
+*************************************************/
+
+/* This function scans the nametable for a given name, using binary chop. It
+returns either two pointers to the entries in the table, or, if no pointers are
+given, the number of a unique group with the given name. If duplicate names are
+permitted, and the name is not unique, an error is generated.
+
+Arguments:
+  code        the compiled regex
+  stringname  the name whose entries required
+  firstptr    where to put the pointer to the first entry
+  lastptr     where to put the pointer to the last entry
+
+Returns:      PCRE2_ERROR_NOSUBSTRING if the name is not found
+              otherwise, if firstptr and lastptr are NULL:
+                a group number for a unique substring
+                else PCRE2_ERROR_NOUNIQUESUBSTRING
+              otherwise:
+                the length of each entry, having set firstptr and lastptr
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_nametable_scan(const pcre2_code *code, PCRE2_SPTR stringname,
+  PCRE2_SPTR *firstptr, PCRE2_SPTR *lastptr)
+{
+uint16_t bot = 0;
+uint16_t top = code->name_count;
+uint16_t entrysize = code->name_entry_size;
+PCRE2_SPTR nametable = (PCRE2_SPTR)((char *)code + sizeof(pcre2_real_code));
+
+while (top > bot)
+  {
+  uint16_t mid = (top + bot) / 2;
+  PCRE2_SPTR entry = nametable + entrysize*mid;
+  int c = PRIV(strcmp)(stringname, entry + IMM2_SIZE);
+  if (c == 0)
+    {
+    PCRE2_SPTR first;
+    PCRE2_SPTR last;
+    PCRE2_SPTR lastentry;
+    lastentry = nametable + entrysize * (code->name_count - 1);
+    first = last = entry;
+    while (first > nametable)
+      {
+      if (PRIV(strcmp)(stringname, (first - entrysize + IMM2_SIZE)) != 0) break;
+      first -= entrysize;
+      }
+    while (last < lastentry)
+      {
+      if (PRIV(strcmp)(stringname, (last + entrysize + IMM2_SIZE)) != 0) break;
+      last += entrysize;
+      }
+    if (firstptr == NULL) return (first == last)?
+      (int)GET2(entry, 0) : PCRE2_ERROR_NOUNIQUESUBSTRING;
+    *firstptr = first;
+    *lastptr = last;
+    return entrysize;
+    }
+  if (c > 0) bot = mid + 1; else top = mid;
+  }
+
+return PCRE2_ERROR_NOSUBSTRING;
+}
+
+
+/*************************************************
+*           Find number for named string         *
+*************************************************/
+
+/* This function is a convenience wrapper for pcre2_substring_nametable_scan()
+when it is known that names are unique. If there are duplicate names, it is not
+defined which number is returned.
+
+Arguments:
+  code        the compiled regex
+  stringname  the name whose number is required
+
+Returns:      the number of the named parenthesis, or a negative number
+                PCRE2_ERROR_NOSUBSTRING if not found
+                PCRE2_ERROR_NOUNIQUESUBSTRING if not unique
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_number_from_name(const pcre2_code *code,
+  PCRE2_SPTR stringname)
+{
+return pcre2_substring_nametable_scan(code, stringname, NULL, NULL);
+}
+
+/* End of pcre2_substring.c */
diff --git a/src/c/pcre2/src/pcre2_tables.c b/src/c/pcre2/src/pcre2_tables.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_tables.c
@@ -0,0 +1,854 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2019 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains some fixed tables that are used by more than one of the
+PCRE2 code modules. The tables are also #included by the pcre2test program,
+which uses macros to change their names from _pcre2_xxx to xxxx, thereby
+avoiding name clashes with the library. In this case, PCRE2_PCRE2TEST is
+defined. */
+
+#ifndef PCRE2_PCRE2TEST           /* We're compiling the library */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "pcre2_internal.h"
+#endif /* PCRE2_PCRE2TEST */
+
+
+/* Table of sizes for the fixed-length opcodes. It's defined in a macro so that
+the definition is next to the definition of the opcodes in pcre2_internal.h.
+This is mode-dependent, so is skipped when this file is included by pcre2test. */
+
+#ifndef PCRE2_PCRE2TEST
+const uint8_t PRIV(OP_lengths)[] = { OP_LENGTHS };
+#endif
+
+/* Tables of horizontal and vertical whitespace characters, suitable for
+adding to classes. */
+
+const uint32_t PRIV(hspace_list)[] = { HSPACE_LIST };
+const uint32_t PRIV(vspace_list)[] = { VSPACE_LIST };
+
+/* These tables are the pairs of delimiters that are valid for callout string
+arguments. For each starting delimiter there must be a matching ending
+delimiter, which in fact is different only for bracket-like delimiters. */
+
+const uint32_t PRIV(callout_start_delims)[] = {
+  CHAR_GRAVE_ACCENT, CHAR_APOSTROPHE, CHAR_QUOTATION_MARK,
+  CHAR_CIRCUMFLEX_ACCENT, CHAR_PERCENT_SIGN, CHAR_NUMBER_SIGN,
+  CHAR_DOLLAR_SIGN, CHAR_LEFT_CURLY_BRACKET, 0 };
+
+const uint32_t PRIV(callout_end_delims[]) = {
+  CHAR_GRAVE_ACCENT, CHAR_APOSTROPHE, CHAR_QUOTATION_MARK,
+  CHAR_CIRCUMFLEX_ACCENT, CHAR_PERCENT_SIGN, CHAR_NUMBER_SIGN,
+  CHAR_DOLLAR_SIGN, CHAR_RIGHT_CURLY_BRACKET, 0 };
+
+
+/*************************************************
+*           Tables for UTF-8 support             *
+*************************************************/
+
+/* These tables are required by pcre2test in 16- or 32-bit mode, as well
+as for the library in 8-bit mode, because pcre2test uses UTF-8 internally for
+handling wide characters. */
+
+#if defined PCRE2_PCRE2TEST || \
+   (defined SUPPORT_UNICODE && \
+    defined PCRE2_CODE_UNIT_WIDTH && \
+    PCRE2_CODE_UNIT_WIDTH == 8)
+
+/* These are the breakpoints for different numbers of bytes in a UTF-8
+character. */
+
+const int PRIV(utf8_table1)[] =
+  { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff};
+
+const int PRIV(utf8_table1_size) = sizeof(PRIV(utf8_table1)) / sizeof(int);
+
+/* These are the indicator bits and the mask for the data bits to set in the
+first byte of a character, indexed by the number of additional bytes. */
+
+const int PRIV(utf8_table2)[] = { 0,    0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
+const int PRIV(utf8_table3)[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
+
+/* Table of the number of extra bytes, indexed by the first byte masked with
+0x3f. The highest number for a valid UTF-8 first byte is in fact 0x3d. */
+
+const uint8_t PRIV(utf8_table4)[] = {
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 };
+
+#endif /* UTF-8 support needed */
+
+
+#ifdef SUPPORT_UNICODE
+
+/* Table to translate from particular type value to the general value. */
+
+const uint32_t PRIV(ucp_gentype)[] = {
+  ucp_C, ucp_C, ucp_C, ucp_C, ucp_C,  /* Cc, Cf, Cn, Co, Cs */
+  ucp_L, ucp_L, ucp_L, ucp_L, ucp_L,  /* Ll, Lu, Lm, Lo, Lt */
+  ucp_M, ucp_M, ucp_M,                /* Mc, Me, Mn */
+  ucp_N, ucp_N, ucp_N,                /* Nd, Nl, No */
+  ucp_P, ucp_P, ucp_P, ucp_P, ucp_P,  /* Pc, Pd, Pe, Pf, Pi */
+  ucp_P, ucp_P,                       /* Ps, Po */
+  ucp_S, ucp_S, ucp_S, ucp_S,         /* Sc, Sk, Sm, So */
+  ucp_Z, ucp_Z, ucp_Z                 /* Zl, Zp, Zs */
+};
+
+/* This table encodes the rules for finding the end of an extended grapheme
+cluster. Every code point has a grapheme break property which is one of the
+ucp_gbXX values defined in pcre2_ucp.h. These changed between Unicode versions
+10 and 11. The 2-dimensional table is indexed by the properties of two adjacent
+code points. The left property selects a word from the table, and the right
+property selects a bit from that word like this:
+
+  PRIV(ucp_gbtable)[left-property] & (1u << right-property)
+
+The value is non-zero if a grapheme break is NOT permitted between the relevant
+two code points. The breaking rules are as follows:
+
+1. Break at the start and end of text (pretty obviously).
+
+2. Do not break between a CR and LF; otherwise, break before and after
+   controls.
+
+3. Do not break Hangul syllable sequences, the rules for which are:
+
+    L may be followed by L, V, LV or LVT
+    LV or V may be followed by V or T
+    LVT or T may be followed by T
+
+4. Do not break before extending characters or zero-width-joiner (ZWJ).
+
+The following rules are only for extended grapheme clusters (but that's what we
+are implementing).
+
+5. Do not break before SpacingMarks.
+
+6. Do not break after Prepend characters.
+
+7. Do not break within emoji modifier sequences or emoji zwj sequences. That
+   is, do not break between characters with the Extended_Pictographic property.
+   Extend and ZWJ characters are allowed between the characters; this cannot be
+   represented in this table, the code has to deal with it.
+
+8. Do not break within emoji flag sequences. That is, do not break between
+   regional indicator (RI) symbols if there are an odd number of RI characters
+   before the break point. This table encodes "join RI characters"; the code
+   has to deal with checking for previous adjoining RIs.
+
+9. Otherwise, break everywhere.
+*/
+
+#define ESZ (1<<ucp_gbExtend)|(1<<ucp_gbSpacingMark)|(1<<ucp_gbZWJ)
+
+const uint32_t PRIV(ucp_gbtable)[] = {
+   (1u<<ucp_gbLF),                                      /*  0 CR */
+   0,                                                   /*  1 LF */
+   0,                                                   /*  2 Control */
+   ESZ,                                                 /*  3 Extend */
+   ESZ|(1u<<ucp_gbPrepend)|                             /*  4 Prepend */
+       (1u<<ucp_gbL)|(1u<<ucp_gbV)|(1u<<ucp_gbT)|
+       (1u<<ucp_gbLV)|(1u<<ucp_gbLVT)|(1u<<ucp_gbOther)|
+       (1u<<ucp_gbRegionalIndicator),
+   ESZ,                                                 /*  5 SpacingMark */
+   ESZ|(1u<<ucp_gbL)|(1u<<ucp_gbV)|(1u<<ucp_gbLV)|      /*  6 L */
+       (1u<<ucp_gbLVT),
+   ESZ|(1u<<ucp_gbV)|(1u<<ucp_gbT),                     /*  7 V */
+   ESZ|(1u<<ucp_gbT),                                   /*  8 T */
+   ESZ|(1u<<ucp_gbV)|(1u<<ucp_gbT),                     /*  9 LV */
+   ESZ|(1u<<ucp_gbT),                                   /* 10 LVT */
+   (1u<<ucp_gbRegionalIndicator),                       /* 11 RegionalIndicator */
+   ESZ,                                                 /* 12 Other */
+   ESZ,                                                 /* 13 ZWJ */
+   ESZ|(1u<<ucp_gbExtended_Pictographic)                /* 14 Extended Pictographic */
+};
+
+#undef ESZ
+
+#ifdef SUPPORT_JIT
+/* This table reverses PRIV(ucp_gentype). We can save the cost
+of a memory load. */
+
+const int PRIV(ucp_typerange)[] = {
+  ucp_Cc, ucp_Cs,
+  ucp_Ll, ucp_Lu,
+  ucp_Mc, ucp_Mn,
+  ucp_Nd, ucp_No,
+  ucp_Pc, ucp_Ps,
+  ucp_Sc, ucp_So,
+  ucp_Zl, ucp_Zs,
+};
+#endif /* SUPPORT_JIT */
+
+/* The PRIV(utt)[] table below translates Unicode property names into type and
+code values. It is searched by binary chop, so must be in collating sequence of
+name. Originally, the table contained pointers to the name strings in the first
+field of each entry. However, that leads to a large number of relocations when
+a shared library is dynamically loaded. A significant reduction is made by
+putting all the names into a single, large string and then using offsets in the
+table itself. Maintenance is more error-prone, but frequent changes to this
+data are unlikely.
+
+July 2008: There is now a script called maint/GenerateUtt.py that can be used
+to generate this data automatically instead of maintaining it by hand.
+
+The script was updated in March 2009 to generate a new EBCDIC-compliant
+version. Like all other character and string literals that are compared against
+the regular expression pattern, we must use STR_ macros instead of literal
+strings to make sure that UTF-8 support works on EBCDIC platforms. */
+
+#define STRING_Adlam0 STR_A STR_d STR_l STR_a STR_m "\0"
+#define STRING_Ahom0 STR_A STR_h STR_o STR_m "\0"
+#define STRING_Anatolian_Hieroglyphs0 STR_A STR_n STR_a STR_t STR_o STR_l STR_i STR_a STR_n STR_UNDERSCORE STR_H STR_i STR_e STR_r STR_o STR_g STR_l STR_y STR_p STR_h STR_s "\0"
+#define STRING_Any0 STR_A STR_n STR_y "\0"
+#define STRING_Arabic0 STR_A STR_r STR_a STR_b STR_i STR_c "\0"
+#define STRING_Armenian0 STR_A STR_r STR_m STR_e STR_n STR_i STR_a STR_n "\0"
+#define STRING_Avestan0 STR_A STR_v STR_e STR_s STR_t STR_a STR_n "\0"
+#define STRING_Balinese0 STR_B STR_a STR_l STR_i STR_n STR_e STR_s STR_e "\0"
+#define STRING_Bamum0 STR_B STR_a STR_m STR_u STR_m "\0"
+#define STRING_Bassa_Vah0 STR_B STR_a STR_s STR_s STR_a STR_UNDERSCORE STR_V STR_a STR_h "\0"
+#define STRING_Batak0 STR_B STR_a STR_t STR_a STR_k "\0"
+#define STRING_Bengali0 STR_B STR_e STR_n STR_g STR_a STR_l STR_i "\0"
+#define STRING_Bhaiksuki0 STR_B STR_h STR_a STR_i STR_k STR_s STR_u STR_k STR_i "\0"
+#define STRING_Bopomofo0 STR_B STR_o STR_p STR_o STR_m STR_o STR_f STR_o "\0"
+#define STRING_Brahmi0 STR_B STR_r STR_a STR_h STR_m STR_i "\0"
+#define STRING_Braille0 STR_B STR_r STR_a STR_i STR_l STR_l STR_e "\0"
+#define STRING_Buginese0 STR_B STR_u STR_g STR_i STR_n STR_e STR_s STR_e "\0"
+#define STRING_Buhid0 STR_B STR_u STR_h STR_i STR_d "\0"
+#define STRING_C0 STR_C "\0"
+#define STRING_Canadian_Aboriginal0 STR_C STR_a STR_n STR_a STR_d STR_i STR_a STR_n STR_UNDERSCORE STR_A STR_b STR_o STR_r STR_i STR_g STR_i STR_n STR_a STR_l "\0"
+#define STRING_Carian0 STR_C STR_a STR_r STR_i STR_a STR_n "\0"
+#define STRING_Caucasian_Albanian0 STR_C STR_a STR_u STR_c STR_a STR_s STR_i STR_a STR_n STR_UNDERSCORE STR_A STR_l STR_b STR_a STR_n STR_i STR_a STR_n "\0"
+#define STRING_Cc0 STR_C STR_c "\0"
+#define STRING_Cf0 STR_C STR_f "\0"
+#define STRING_Chakma0 STR_C STR_h STR_a STR_k STR_m STR_a "\0"
+#define STRING_Cham0 STR_C STR_h STR_a STR_m "\0"
+#define STRING_Cherokee0 STR_C STR_h STR_e STR_r STR_o STR_k STR_e STR_e "\0"
+#define STRING_Chorasmian0 STR_C STR_h STR_o STR_r STR_a STR_s STR_m STR_i STR_a STR_n "\0"
+#define STRING_Cn0 STR_C STR_n "\0"
+#define STRING_Co0 STR_C STR_o "\0"
+#define STRING_Common0 STR_C STR_o STR_m STR_m STR_o STR_n "\0"
+#define STRING_Coptic0 STR_C STR_o STR_p STR_t STR_i STR_c "\0"
+#define STRING_Cs0 STR_C STR_s "\0"
+#define STRING_Cuneiform0 STR_C STR_u STR_n STR_e STR_i STR_f STR_o STR_r STR_m "\0"
+#define STRING_Cypriot0 STR_C STR_y STR_p STR_r STR_i STR_o STR_t "\0"
+#define STRING_Cyrillic0 STR_C STR_y STR_r STR_i STR_l STR_l STR_i STR_c "\0"
+#define STRING_Deseret0 STR_D STR_e STR_s STR_e STR_r STR_e STR_t "\0"
+#define STRING_Devanagari0 STR_D STR_e STR_v STR_a STR_n STR_a STR_g STR_a STR_r STR_i "\0"
+#define STRING_Dives_Akuru0 STR_D STR_i STR_v STR_e STR_s STR_UNDERSCORE STR_A STR_k STR_u STR_r STR_u "\0"
+#define STRING_Dogra0 STR_D STR_o STR_g STR_r STR_a "\0"
+#define STRING_Duployan0 STR_D STR_u STR_p STR_l STR_o STR_y STR_a STR_n "\0"
+#define STRING_Egyptian_Hieroglyphs0 STR_E STR_g STR_y STR_p STR_t STR_i STR_a STR_n STR_UNDERSCORE STR_H STR_i STR_e STR_r STR_o STR_g STR_l STR_y STR_p STR_h STR_s "\0"
+#define STRING_Elbasan0 STR_E STR_l STR_b STR_a STR_s STR_a STR_n "\0"
+#define STRING_Elymaic0 STR_E STR_l STR_y STR_m STR_a STR_i STR_c "\0"
+#define STRING_Ethiopic0 STR_E STR_t STR_h STR_i STR_o STR_p STR_i STR_c "\0"
+#define STRING_Georgian0 STR_G STR_e STR_o STR_r STR_g STR_i STR_a STR_n "\0"
+#define STRING_Glagolitic0 STR_G STR_l STR_a STR_g STR_o STR_l STR_i STR_t STR_i STR_c "\0"
+#define STRING_Gothic0 STR_G STR_o STR_t STR_h STR_i STR_c "\0"
+#define STRING_Grantha0 STR_G STR_r STR_a STR_n STR_t STR_h STR_a "\0"
+#define STRING_Greek0 STR_G STR_r STR_e STR_e STR_k "\0"
+#define STRING_Gujarati0 STR_G STR_u STR_j STR_a STR_r STR_a STR_t STR_i "\0"
+#define STRING_Gunjala_Gondi0 STR_G STR_u STR_n STR_j STR_a STR_l STR_a STR_UNDERSCORE STR_G STR_o STR_n STR_d STR_i "\0"
+#define STRING_Gurmukhi0 STR_G STR_u STR_r STR_m STR_u STR_k STR_h STR_i "\0"
+#define STRING_Han0 STR_H STR_a STR_n "\0"
+#define STRING_Hangul0 STR_H STR_a STR_n STR_g STR_u STR_l "\0"
+#define STRING_Hanifi_Rohingya0 STR_H STR_a STR_n STR_i STR_f STR_i STR_UNDERSCORE STR_R STR_o STR_h STR_i STR_n STR_g STR_y STR_a "\0"
+#define STRING_Hanunoo0 STR_H STR_a STR_n STR_u STR_n STR_o STR_o "\0"
+#define STRING_Hatran0 STR_H STR_a STR_t STR_r STR_a STR_n "\0"
+#define STRING_Hebrew0 STR_H STR_e STR_b STR_r STR_e STR_w "\0"
+#define STRING_Hiragana0 STR_H STR_i STR_r STR_a STR_g STR_a STR_n STR_a "\0"
+#define STRING_Imperial_Aramaic0 STR_I STR_m STR_p STR_e STR_r STR_i STR_a STR_l STR_UNDERSCORE STR_A STR_r STR_a STR_m STR_a STR_i STR_c "\0"
+#define STRING_Inherited0 STR_I STR_n STR_h STR_e STR_r STR_i STR_t STR_e STR_d "\0"
+#define STRING_Inscriptional_Pahlavi0 STR_I STR_n STR_s STR_c STR_r STR_i STR_p STR_t STR_i STR_o STR_n STR_a STR_l STR_UNDERSCORE STR_P STR_a STR_h STR_l STR_a STR_v STR_i "\0"
+#define STRING_Inscriptional_Parthian0 STR_I STR_n STR_s STR_c STR_r STR_i STR_p STR_t STR_i STR_o STR_n STR_a STR_l STR_UNDERSCORE STR_P STR_a STR_r STR_t STR_h STR_i STR_a STR_n "\0"
+#define STRING_Javanese0 STR_J STR_a STR_v STR_a STR_n STR_e STR_s STR_e "\0"
+#define STRING_Kaithi0 STR_K STR_a STR_i STR_t STR_h STR_i "\0"
+#define STRING_Kannada0 STR_K STR_a STR_n STR_n STR_a STR_d STR_a "\0"
+#define STRING_Katakana0 STR_K STR_a STR_t STR_a STR_k STR_a STR_n STR_a "\0"
+#define STRING_Kayah_Li0 STR_K STR_a STR_y STR_a STR_h STR_UNDERSCORE STR_L STR_i "\0"
+#define STRING_Kharoshthi0 STR_K STR_h STR_a STR_r STR_o STR_s STR_h STR_t STR_h STR_i "\0"
+#define STRING_Khitan_Small_Script0 STR_K STR_h STR_i STR_t STR_a STR_n STR_UNDERSCORE STR_S STR_m STR_a STR_l STR_l STR_UNDERSCORE STR_S STR_c STR_r STR_i STR_p STR_t "\0"
+#define STRING_Khmer0 STR_K STR_h STR_m STR_e STR_r "\0"
+#define STRING_Khojki0 STR_K STR_h STR_o STR_j STR_k STR_i "\0"
+#define STRING_Khudawadi0 STR_K STR_h STR_u STR_d STR_a STR_w STR_a STR_d STR_i "\0"
+#define STRING_L0 STR_L "\0"
+#define STRING_L_AMPERSAND0 STR_L STR_AMPERSAND "\0"
+#define STRING_Lao0 STR_L STR_a STR_o "\0"
+#define STRING_Latin0 STR_L STR_a STR_t STR_i STR_n "\0"
+#define STRING_Lepcha0 STR_L STR_e STR_p STR_c STR_h STR_a "\0"
+#define STRING_Limbu0 STR_L STR_i STR_m STR_b STR_u "\0"
+#define STRING_Linear_A0 STR_L STR_i STR_n STR_e STR_a STR_r STR_UNDERSCORE STR_A "\0"
+#define STRING_Linear_B0 STR_L STR_i STR_n STR_e STR_a STR_r STR_UNDERSCORE STR_B "\0"
+#define STRING_Lisu0 STR_L STR_i STR_s STR_u "\0"
+#define STRING_Ll0 STR_L STR_l "\0"
+#define STRING_Lm0 STR_L STR_m "\0"
+#define STRING_Lo0 STR_L STR_o "\0"
+#define STRING_Lt0 STR_L STR_t "\0"
+#define STRING_Lu0 STR_L STR_u "\0"
+#define STRING_Lycian0 STR_L STR_y STR_c STR_i STR_a STR_n "\0"
+#define STRING_Lydian0 STR_L STR_y STR_d STR_i STR_a STR_n "\0"
+#define STRING_M0 STR_M "\0"
+#define STRING_Mahajani0 STR_M STR_a STR_h STR_a STR_j STR_a STR_n STR_i "\0"
+#define STRING_Makasar0 STR_M STR_a STR_k STR_a STR_s STR_a STR_r "\0"
+#define STRING_Malayalam0 STR_M STR_a STR_l STR_a STR_y STR_a STR_l STR_a STR_m "\0"
+#define STRING_Mandaic0 STR_M STR_a STR_n STR_d STR_a STR_i STR_c "\0"
+#define STRING_Manichaean0 STR_M STR_a STR_n STR_i STR_c STR_h STR_a STR_e STR_a STR_n "\0"
+#define STRING_Marchen0 STR_M STR_a STR_r STR_c STR_h STR_e STR_n "\0"
+#define STRING_Masaram_Gondi0 STR_M STR_a STR_s STR_a STR_r STR_a STR_m STR_UNDERSCORE STR_G STR_o STR_n STR_d STR_i "\0"
+#define STRING_Mc0 STR_M STR_c "\0"
+#define STRING_Me0 STR_M STR_e "\0"
+#define STRING_Medefaidrin0 STR_M STR_e STR_d STR_e STR_f STR_a STR_i STR_d STR_r STR_i STR_n "\0"
+#define STRING_Meetei_Mayek0 STR_M STR_e STR_e STR_t STR_e STR_i STR_UNDERSCORE STR_M STR_a STR_y STR_e STR_k "\0"
+#define STRING_Mende_Kikakui0 STR_M STR_e STR_n STR_d STR_e STR_UNDERSCORE STR_K STR_i STR_k STR_a STR_k STR_u STR_i "\0"
+#define STRING_Meroitic_Cursive0 STR_M STR_e STR_r STR_o STR_i STR_t STR_i STR_c STR_UNDERSCORE STR_C STR_u STR_r STR_s STR_i STR_v STR_e "\0"
+#define STRING_Meroitic_Hieroglyphs0 STR_M STR_e STR_r STR_o STR_i STR_t STR_i STR_c STR_UNDERSCORE STR_H STR_i STR_e STR_r STR_o STR_g STR_l STR_y STR_p STR_h STR_s "\0"
+#define STRING_Miao0 STR_M STR_i STR_a STR_o "\0"
+#define STRING_Mn0 STR_M STR_n "\0"
+#define STRING_Modi0 STR_M STR_o STR_d STR_i "\0"
+#define STRING_Mongolian0 STR_M STR_o STR_n STR_g STR_o STR_l STR_i STR_a STR_n "\0"
+#define STRING_Mro0 STR_M STR_r STR_o "\0"
+#define STRING_Multani0 STR_M STR_u STR_l STR_t STR_a STR_n STR_i "\0"
+#define STRING_Myanmar0 STR_M STR_y STR_a STR_n STR_m STR_a STR_r "\0"
+#define STRING_N0 STR_N "\0"
+#define STRING_Nabataean0 STR_N STR_a STR_b STR_a STR_t STR_a STR_e STR_a STR_n "\0"
+#define STRING_Nandinagari0 STR_N STR_a STR_n STR_d STR_i STR_n STR_a STR_g STR_a STR_r STR_i "\0"
+#define STRING_Nd0 STR_N STR_d "\0"
+#define STRING_New_Tai_Lue0 STR_N STR_e STR_w STR_UNDERSCORE STR_T STR_a STR_i STR_UNDERSCORE STR_L STR_u STR_e "\0"
+#define STRING_Newa0 STR_N STR_e STR_w STR_a "\0"
+#define STRING_Nko0 STR_N STR_k STR_o "\0"
+#define STRING_Nl0 STR_N STR_l "\0"
+#define STRING_No0 STR_N STR_o "\0"
+#define STRING_Nushu0 STR_N STR_u STR_s STR_h STR_u "\0"
+#define STRING_Nyiakeng_Puachue_Hmong0 STR_N STR_y STR_i STR_a STR_k STR_e STR_n STR_g STR_UNDERSCORE STR_P STR_u STR_a STR_c STR_h STR_u STR_e STR_UNDERSCORE STR_H STR_m STR_o STR_n STR_g "\0"
+#define STRING_Ogham0 STR_O STR_g STR_h STR_a STR_m "\0"
+#define STRING_Ol_Chiki0 STR_O STR_l STR_UNDERSCORE STR_C STR_h STR_i STR_k STR_i "\0"
+#define STRING_Old_Hungarian0 STR_O STR_l STR_d STR_UNDERSCORE STR_H STR_u STR_n STR_g STR_a STR_r STR_i STR_a STR_n "\0"
+#define STRING_Old_Italic0 STR_O STR_l STR_d STR_UNDERSCORE STR_I STR_t STR_a STR_l STR_i STR_c "\0"
+#define STRING_Old_North_Arabian0 STR_O STR_l STR_d STR_UNDERSCORE STR_N STR_o STR_r STR_t STR_h STR_UNDERSCORE STR_A STR_r STR_a STR_b STR_i STR_a STR_n "\0"
+#define STRING_Old_Permic0 STR_O STR_l STR_d STR_UNDERSCORE STR_P STR_e STR_r STR_m STR_i STR_c "\0"
+#define STRING_Old_Persian0 STR_O STR_l STR_d STR_UNDERSCORE STR_P STR_e STR_r STR_s STR_i STR_a STR_n "\0"
+#define STRING_Old_Sogdian0 STR_O STR_l STR_d STR_UNDERSCORE STR_S STR_o STR_g STR_d STR_i STR_a STR_n "\0"
+#define STRING_Old_South_Arabian0 STR_O STR_l STR_d STR_UNDERSCORE STR_S STR_o STR_u STR_t STR_h STR_UNDERSCORE STR_A STR_r STR_a STR_b STR_i STR_a STR_n "\0"
+#define STRING_Old_Turkic0 STR_O STR_l STR_d STR_UNDERSCORE STR_T STR_u STR_r STR_k STR_i STR_c "\0"
+#define STRING_Oriya0 STR_O STR_r STR_i STR_y STR_a "\0"
+#define STRING_Osage0 STR_O STR_s STR_a STR_g STR_e "\0"
+#define STRING_Osmanya0 STR_O STR_s STR_m STR_a STR_n STR_y STR_a "\0"
+#define STRING_P0 STR_P "\0"
+#define STRING_Pahawh_Hmong0 STR_P STR_a STR_h STR_a STR_w STR_h STR_UNDERSCORE STR_H STR_m STR_o STR_n STR_g "\0"
+#define STRING_Palmyrene0 STR_P STR_a STR_l STR_m STR_y STR_r STR_e STR_n STR_e "\0"
+#define STRING_Pau_Cin_Hau0 STR_P STR_a STR_u STR_UNDERSCORE STR_C STR_i STR_n STR_UNDERSCORE STR_H STR_a STR_u "\0"
+#define STRING_Pc0 STR_P STR_c "\0"
+#define STRING_Pd0 STR_P STR_d "\0"
+#define STRING_Pe0 STR_P STR_e "\0"
+#define STRING_Pf0 STR_P STR_f "\0"
+#define STRING_Phags_Pa0 STR_P STR_h STR_a STR_g STR_s STR_UNDERSCORE STR_P STR_a "\0"
+#define STRING_Phoenician0 STR_P STR_h STR_o STR_e STR_n STR_i STR_c STR_i STR_a STR_n "\0"
+#define STRING_Pi0 STR_P STR_i "\0"
+#define STRING_Po0 STR_P STR_o "\0"
+#define STRING_Ps0 STR_P STR_s "\0"
+#define STRING_Psalter_Pahlavi0 STR_P STR_s STR_a STR_l STR_t STR_e STR_r STR_UNDERSCORE STR_P STR_a STR_h STR_l STR_a STR_v STR_i "\0"
+#define STRING_Rejang0 STR_R STR_e STR_j STR_a STR_n STR_g "\0"
+#define STRING_Runic0 STR_R STR_u STR_n STR_i STR_c "\0"
+#define STRING_S0 STR_S "\0"
+#define STRING_Samaritan0 STR_S STR_a STR_m STR_a STR_r STR_i STR_t STR_a STR_n "\0"
+#define STRING_Saurashtra0 STR_S STR_a STR_u STR_r STR_a STR_s STR_h STR_t STR_r STR_a "\0"
+#define STRING_Sc0 STR_S STR_c "\0"
+#define STRING_Sharada0 STR_S STR_h STR_a STR_r STR_a STR_d STR_a "\0"
+#define STRING_Shavian0 STR_S STR_h STR_a STR_v STR_i STR_a STR_n "\0"
+#define STRING_Siddham0 STR_S STR_i STR_d STR_d STR_h STR_a STR_m "\0"
+#define STRING_SignWriting0 STR_S STR_i STR_g STR_n STR_W STR_r STR_i STR_t STR_i STR_n STR_g "\0"
+#define STRING_Sinhala0 STR_S STR_i STR_n STR_h STR_a STR_l STR_a "\0"
+#define STRING_Sk0 STR_S STR_k "\0"
+#define STRING_Sm0 STR_S STR_m "\0"
+#define STRING_So0 STR_S STR_o "\0"
+#define STRING_Sogdian0 STR_S STR_o STR_g STR_d STR_i STR_a STR_n "\0"
+#define STRING_Sora_Sompeng0 STR_S STR_o STR_r STR_a STR_UNDERSCORE STR_S STR_o STR_m STR_p STR_e STR_n STR_g "\0"
+#define STRING_Soyombo0 STR_S STR_o STR_y STR_o STR_m STR_b STR_o "\0"
+#define STRING_Sundanese0 STR_S STR_u STR_n STR_d STR_a STR_n STR_e STR_s STR_e "\0"
+#define STRING_Syloti_Nagri0 STR_S STR_y STR_l STR_o STR_t STR_i STR_UNDERSCORE STR_N STR_a STR_g STR_r STR_i "\0"
+#define STRING_Syriac0 STR_S STR_y STR_r STR_i STR_a STR_c "\0"
+#define STRING_Tagalog0 STR_T STR_a STR_g STR_a STR_l STR_o STR_g "\0"
+#define STRING_Tagbanwa0 STR_T STR_a STR_g STR_b STR_a STR_n STR_w STR_a "\0"
+#define STRING_Tai_Le0 STR_T STR_a STR_i STR_UNDERSCORE STR_L STR_e "\0"
+#define STRING_Tai_Tham0 STR_T STR_a STR_i STR_UNDERSCORE STR_T STR_h STR_a STR_m "\0"
+#define STRING_Tai_Viet0 STR_T STR_a STR_i STR_UNDERSCORE STR_V STR_i STR_e STR_t "\0"
+#define STRING_Takri0 STR_T STR_a STR_k STR_r STR_i "\0"
+#define STRING_Tamil0 STR_T STR_a STR_m STR_i STR_l "\0"
+#define STRING_Tangut0 STR_T STR_a STR_n STR_g STR_u STR_t "\0"
+#define STRING_Telugu0 STR_T STR_e STR_l STR_u STR_g STR_u "\0"
+#define STRING_Thaana0 STR_T STR_h STR_a STR_a STR_n STR_a "\0"
+#define STRING_Thai0 STR_T STR_h STR_a STR_i "\0"
+#define STRING_Tibetan0 STR_T STR_i STR_b STR_e STR_t STR_a STR_n "\0"
+#define STRING_Tifinagh0 STR_T STR_i STR_f STR_i STR_n STR_a STR_g STR_h "\0"
+#define STRING_Tirhuta0 STR_T STR_i STR_r STR_h STR_u STR_t STR_a "\0"
+#define STRING_Ugaritic0 STR_U STR_g STR_a STR_r STR_i STR_t STR_i STR_c "\0"
+#define STRING_Unknown0 STR_U STR_n STR_k STR_n STR_o STR_w STR_n "\0"
+#define STRING_Vai0 STR_V STR_a STR_i "\0"
+#define STRING_Wancho0 STR_W STR_a STR_n STR_c STR_h STR_o "\0"
+#define STRING_Warang_Citi0 STR_W STR_a STR_r STR_a STR_n STR_g STR_UNDERSCORE STR_C STR_i STR_t STR_i "\0"
+#define STRING_Xan0 STR_X STR_a STR_n "\0"
+#define STRING_Xps0 STR_X STR_p STR_s "\0"
+#define STRING_Xsp0 STR_X STR_s STR_p "\0"
+#define STRING_Xuc0 STR_X STR_u STR_c "\0"
+#define STRING_Xwd0 STR_X STR_w STR_d "\0"
+#define STRING_Yezidi0 STR_Y STR_e STR_z STR_i STR_d STR_i "\0"
+#define STRING_Yi0 STR_Y STR_i "\0"
+#define STRING_Z0 STR_Z "\0"
+#define STRING_Zanabazar_Square0 STR_Z STR_a STR_n STR_a STR_b STR_a STR_z STR_a STR_r STR_UNDERSCORE STR_S STR_q STR_u STR_a STR_r STR_e "\0"
+#define STRING_Zl0 STR_Z STR_l "\0"
+#define STRING_Zp0 STR_Z STR_p "\0"
+#define STRING_Zs0 STR_Z STR_s "\0"
+
+const char PRIV(utt_names)[] =
+  STRING_Adlam0
+  STRING_Ahom0
+  STRING_Anatolian_Hieroglyphs0
+  STRING_Any0
+  STRING_Arabic0
+  STRING_Armenian0
+  STRING_Avestan0
+  STRING_Balinese0
+  STRING_Bamum0
+  STRING_Bassa_Vah0
+  STRING_Batak0
+  STRING_Bengali0
+  STRING_Bhaiksuki0
+  STRING_Bopomofo0
+  STRING_Brahmi0
+  STRING_Braille0
+  STRING_Buginese0
+  STRING_Buhid0
+  STRING_C0
+  STRING_Canadian_Aboriginal0
+  STRING_Carian0
+  STRING_Caucasian_Albanian0
+  STRING_Cc0
+  STRING_Cf0
+  STRING_Chakma0
+  STRING_Cham0
+  STRING_Cherokee0
+  STRING_Chorasmian0
+  STRING_Cn0
+  STRING_Co0
+  STRING_Common0
+  STRING_Coptic0
+  STRING_Cs0
+  STRING_Cuneiform0
+  STRING_Cypriot0
+  STRING_Cyrillic0
+  STRING_Deseret0
+  STRING_Devanagari0
+  STRING_Dives_Akuru0
+  STRING_Dogra0
+  STRING_Duployan0
+  STRING_Egyptian_Hieroglyphs0
+  STRING_Elbasan0
+  STRING_Elymaic0
+  STRING_Ethiopic0
+  STRING_Georgian0
+  STRING_Glagolitic0
+  STRING_Gothic0
+  STRING_Grantha0
+  STRING_Greek0
+  STRING_Gujarati0
+  STRING_Gunjala_Gondi0
+  STRING_Gurmukhi0
+  STRING_Han0
+  STRING_Hangul0
+  STRING_Hanifi_Rohingya0
+  STRING_Hanunoo0
+  STRING_Hatran0
+  STRING_Hebrew0
+  STRING_Hiragana0
+  STRING_Imperial_Aramaic0
+  STRING_Inherited0
+  STRING_Inscriptional_Pahlavi0
+  STRING_Inscriptional_Parthian0
+  STRING_Javanese0
+  STRING_Kaithi0
+  STRING_Kannada0
+  STRING_Katakana0
+  STRING_Kayah_Li0
+  STRING_Kharoshthi0
+  STRING_Khitan_Small_Script0
+  STRING_Khmer0
+  STRING_Khojki0
+  STRING_Khudawadi0
+  STRING_L0
+  STRING_L_AMPERSAND0
+  STRING_Lao0
+  STRING_Latin0
+  STRING_Lepcha0
+  STRING_Limbu0
+  STRING_Linear_A0
+  STRING_Linear_B0
+  STRING_Lisu0
+  STRING_Ll0
+  STRING_Lm0
+  STRING_Lo0
+  STRING_Lt0
+  STRING_Lu0
+  STRING_Lycian0
+  STRING_Lydian0
+  STRING_M0
+  STRING_Mahajani0
+  STRING_Makasar0
+  STRING_Malayalam0
+  STRING_Mandaic0
+  STRING_Manichaean0
+  STRING_Marchen0
+  STRING_Masaram_Gondi0
+  STRING_Mc0
+  STRING_Me0
+  STRING_Medefaidrin0
+  STRING_Meetei_Mayek0
+  STRING_Mende_Kikakui0
+  STRING_Meroitic_Cursive0
+  STRING_Meroitic_Hieroglyphs0
+  STRING_Miao0
+  STRING_Mn0
+  STRING_Modi0
+  STRING_Mongolian0
+  STRING_Mro0
+  STRING_Multani0
+  STRING_Myanmar0
+  STRING_N0
+  STRING_Nabataean0
+  STRING_Nandinagari0
+  STRING_Nd0
+  STRING_New_Tai_Lue0
+  STRING_Newa0
+  STRING_Nko0
+  STRING_Nl0
+  STRING_No0
+  STRING_Nushu0
+  STRING_Nyiakeng_Puachue_Hmong0
+  STRING_Ogham0
+  STRING_Ol_Chiki0
+  STRING_Old_Hungarian0
+  STRING_Old_Italic0
+  STRING_Old_North_Arabian0
+  STRING_Old_Permic0
+  STRING_Old_Persian0
+  STRING_Old_Sogdian0
+  STRING_Old_South_Arabian0
+  STRING_Old_Turkic0
+  STRING_Oriya0
+  STRING_Osage0
+  STRING_Osmanya0
+  STRING_P0
+  STRING_Pahawh_Hmong0
+  STRING_Palmyrene0
+  STRING_Pau_Cin_Hau0
+  STRING_Pc0
+  STRING_Pd0
+  STRING_Pe0
+  STRING_Pf0
+  STRING_Phags_Pa0
+  STRING_Phoenician0
+  STRING_Pi0
+  STRING_Po0
+  STRING_Ps0
+  STRING_Psalter_Pahlavi0
+  STRING_Rejang0
+  STRING_Runic0
+  STRING_S0
+  STRING_Samaritan0
+  STRING_Saurashtra0
+  STRING_Sc0
+  STRING_Sharada0
+  STRING_Shavian0
+  STRING_Siddham0
+  STRING_SignWriting0
+  STRING_Sinhala0
+  STRING_Sk0
+  STRING_Sm0
+  STRING_So0
+  STRING_Sogdian0
+  STRING_Sora_Sompeng0
+  STRING_Soyombo0
+  STRING_Sundanese0
+  STRING_Syloti_Nagri0
+  STRING_Syriac0
+  STRING_Tagalog0
+  STRING_Tagbanwa0
+  STRING_Tai_Le0
+  STRING_Tai_Tham0
+  STRING_Tai_Viet0
+  STRING_Takri0
+  STRING_Tamil0
+  STRING_Tangut0
+  STRING_Telugu0
+  STRING_Thaana0
+  STRING_Thai0
+  STRING_Tibetan0
+  STRING_Tifinagh0
+  STRING_Tirhuta0
+  STRING_Ugaritic0
+  STRING_Unknown0
+  STRING_Vai0
+  STRING_Wancho0
+  STRING_Warang_Citi0
+  STRING_Xan0
+  STRING_Xps0
+  STRING_Xsp0
+  STRING_Xuc0
+  STRING_Xwd0
+  STRING_Yezidi0
+  STRING_Yi0
+  STRING_Z0
+  STRING_Zanabazar_Square0
+  STRING_Zl0
+  STRING_Zp0
+  STRING_Zs0;
+
+const ucp_type_table PRIV(utt)[] = {
+  {   0, PT_SC, ucp_Adlam },
+  {   6, PT_SC, ucp_Ahom },
+  {  11, PT_SC, ucp_Anatolian_Hieroglyphs },
+  {  33, PT_ANY, 0 },
+  {  37, PT_SC, ucp_Arabic },
+  {  44, PT_SC, ucp_Armenian },
+  {  53, PT_SC, ucp_Avestan },
+  {  61, PT_SC, ucp_Balinese },
+  {  70, PT_SC, ucp_Bamum },
+  {  76, PT_SC, ucp_Bassa_Vah },
+  {  86, PT_SC, ucp_Batak },
+  {  92, PT_SC, ucp_Bengali },
+  { 100, PT_SC, ucp_Bhaiksuki },
+  { 110, PT_SC, ucp_Bopomofo },
+  { 119, PT_SC, ucp_Brahmi },
+  { 126, PT_SC, ucp_Braille },
+  { 134, PT_SC, ucp_Buginese },
+  { 143, PT_SC, ucp_Buhid },
+  { 149, PT_GC, ucp_C },
+  { 151, PT_SC, ucp_Canadian_Aboriginal },
+  { 171, PT_SC, ucp_Carian },
+  { 178, PT_SC, ucp_Caucasian_Albanian },
+  { 197, PT_PC, ucp_Cc },
+  { 200, PT_PC, ucp_Cf },
+  { 203, PT_SC, ucp_Chakma },
+  { 210, PT_SC, ucp_Cham },
+  { 215, PT_SC, ucp_Cherokee },
+  { 224, PT_SC, ucp_Chorasmian },
+  { 235, PT_PC, ucp_Cn },
+  { 238, PT_PC, ucp_Co },
+  { 241, PT_SC, ucp_Common },
+  { 248, PT_SC, ucp_Coptic },
+  { 255, PT_PC, ucp_Cs },
+  { 258, PT_SC, ucp_Cuneiform },
+  { 268, PT_SC, ucp_Cypriot },
+  { 276, PT_SC, ucp_Cyrillic },
+  { 285, PT_SC, ucp_Deseret },
+  { 293, PT_SC, ucp_Devanagari },
+  { 304, PT_SC, ucp_Dives_Akuru },
+  { 316, PT_SC, ucp_Dogra },
+  { 322, PT_SC, ucp_Duployan },
+  { 331, PT_SC, ucp_Egyptian_Hieroglyphs },
+  { 352, PT_SC, ucp_Elbasan },
+  { 360, PT_SC, ucp_Elymaic },
+  { 368, PT_SC, ucp_Ethiopic },
+  { 377, PT_SC, ucp_Georgian },
+  { 386, PT_SC, ucp_Glagolitic },
+  { 397, PT_SC, ucp_Gothic },
+  { 404, PT_SC, ucp_Grantha },
+  { 412, PT_SC, ucp_Greek },
+  { 418, PT_SC, ucp_Gujarati },
+  { 427, PT_SC, ucp_Gunjala_Gondi },
+  { 441, PT_SC, ucp_Gurmukhi },
+  { 450, PT_SC, ucp_Han },
+  { 454, PT_SC, ucp_Hangul },
+  { 461, PT_SC, ucp_Hanifi_Rohingya },
+  { 477, PT_SC, ucp_Hanunoo },
+  { 485, PT_SC, ucp_Hatran },
+  { 492, PT_SC, ucp_Hebrew },
+  { 499, PT_SC, ucp_Hiragana },
+  { 508, PT_SC, ucp_Imperial_Aramaic },
+  { 525, PT_SC, ucp_Inherited },
+  { 535, PT_SC, ucp_Inscriptional_Pahlavi },
+  { 557, PT_SC, ucp_Inscriptional_Parthian },
+  { 580, PT_SC, ucp_Javanese },
+  { 589, PT_SC, ucp_Kaithi },
+  { 596, PT_SC, ucp_Kannada },
+  { 604, PT_SC, ucp_Katakana },
+  { 613, PT_SC, ucp_Kayah_Li },
+  { 622, PT_SC, ucp_Kharoshthi },
+  { 633, PT_SC, ucp_Khitan_Small_Script },
+  { 653, PT_SC, ucp_Khmer },
+  { 659, PT_SC, ucp_Khojki },
+  { 666, PT_SC, ucp_Khudawadi },
+  { 676, PT_GC, ucp_L },
+  { 678, PT_LAMP, 0 },
+  { 681, PT_SC, ucp_Lao },
+  { 685, PT_SC, ucp_Latin },
+  { 691, PT_SC, ucp_Lepcha },
+  { 698, PT_SC, ucp_Limbu },
+  { 704, PT_SC, ucp_Linear_A },
+  { 713, PT_SC, ucp_Linear_B },
+  { 722, PT_SC, ucp_Lisu },
+  { 727, PT_PC, ucp_Ll },
+  { 730, PT_PC, ucp_Lm },
+  { 733, PT_PC, ucp_Lo },
+  { 736, PT_PC, ucp_Lt },
+  { 739, PT_PC, ucp_Lu },
+  { 742, PT_SC, ucp_Lycian },
+  { 749, PT_SC, ucp_Lydian },
+  { 756, PT_GC, ucp_M },
+  { 758, PT_SC, ucp_Mahajani },
+  { 767, PT_SC, ucp_Makasar },
+  { 775, PT_SC, ucp_Malayalam },
+  { 785, PT_SC, ucp_Mandaic },
+  { 793, PT_SC, ucp_Manichaean },
+  { 804, PT_SC, ucp_Marchen },
+  { 812, PT_SC, ucp_Masaram_Gondi },
+  { 826, PT_PC, ucp_Mc },
+  { 829, PT_PC, ucp_Me },
+  { 832, PT_SC, ucp_Medefaidrin },
+  { 844, PT_SC, ucp_Meetei_Mayek },
+  { 857, PT_SC, ucp_Mende_Kikakui },
+  { 871, PT_SC, ucp_Meroitic_Cursive },
+  { 888, PT_SC, ucp_Meroitic_Hieroglyphs },
+  { 909, PT_SC, ucp_Miao },
+  { 914, PT_PC, ucp_Mn },
+  { 917, PT_SC, ucp_Modi },
+  { 922, PT_SC, ucp_Mongolian },
+  { 932, PT_SC, ucp_Mro },
+  { 936, PT_SC, ucp_Multani },
+  { 944, PT_SC, ucp_Myanmar },
+  { 952, PT_GC, ucp_N },
+  { 954, PT_SC, ucp_Nabataean },
+  { 964, PT_SC, ucp_Nandinagari },
+  { 976, PT_PC, ucp_Nd },
+  { 979, PT_SC, ucp_New_Tai_Lue },
+  { 991, PT_SC, ucp_Newa },
+  { 996, PT_SC, ucp_Nko },
+  { 1000, PT_PC, ucp_Nl },
+  { 1003, PT_PC, ucp_No },
+  { 1006, PT_SC, ucp_Nushu },
+  { 1012, PT_SC, ucp_Nyiakeng_Puachue_Hmong },
+  { 1035, PT_SC, ucp_Ogham },
+  { 1041, PT_SC, ucp_Ol_Chiki },
+  { 1050, PT_SC, ucp_Old_Hungarian },
+  { 1064, PT_SC, ucp_Old_Italic },
+  { 1075, PT_SC, ucp_Old_North_Arabian },
+  { 1093, PT_SC, ucp_Old_Permic },
+  { 1104, PT_SC, ucp_Old_Persian },
+  { 1116, PT_SC, ucp_Old_Sogdian },
+  { 1128, PT_SC, ucp_Old_South_Arabian },
+  { 1146, PT_SC, ucp_Old_Turkic },
+  { 1157, PT_SC, ucp_Oriya },
+  { 1163, PT_SC, ucp_Osage },
+  { 1169, PT_SC, ucp_Osmanya },
+  { 1177, PT_GC, ucp_P },
+  { 1179, PT_SC, ucp_Pahawh_Hmong },
+  { 1192, PT_SC, ucp_Palmyrene },
+  { 1202, PT_SC, ucp_Pau_Cin_Hau },
+  { 1214, PT_PC, ucp_Pc },
+  { 1217, PT_PC, ucp_Pd },
+  { 1220, PT_PC, ucp_Pe },
+  { 1223, PT_PC, ucp_Pf },
+  { 1226, PT_SC, ucp_Phags_Pa },
+  { 1235, PT_SC, ucp_Phoenician },
+  { 1246, PT_PC, ucp_Pi },
+  { 1249, PT_PC, ucp_Po },
+  { 1252, PT_PC, ucp_Ps },
+  { 1255, PT_SC, ucp_Psalter_Pahlavi },
+  { 1271, PT_SC, ucp_Rejang },
+  { 1278, PT_SC, ucp_Runic },
+  { 1284, PT_GC, ucp_S },
+  { 1286, PT_SC, ucp_Samaritan },
+  { 1296, PT_SC, ucp_Saurashtra },
+  { 1307, PT_PC, ucp_Sc },
+  { 1310, PT_SC, ucp_Sharada },
+  { 1318, PT_SC, ucp_Shavian },
+  { 1326, PT_SC, ucp_Siddham },
+  { 1334, PT_SC, ucp_SignWriting },
+  { 1346, PT_SC, ucp_Sinhala },
+  { 1354, PT_PC, ucp_Sk },
+  { 1357, PT_PC, ucp_Sm },
+  { 1360, PT_PC, ucp_So },
+  { 1363, PT_SC, ucp_Sogdian },
+  { 1371, PT_SC, ucp_Sora_Sompeng },
+  { 1384, PT_SC, ucp_Soyombo },
+  { 1392, PT_SC, ucp_Sundanese },
+  { 1402, PT_SC, ucp_Syloti_Nagri },
+  { 1415, PT_SC, ucp_Syriac },
+  { 1422, PT_SC, ucp_Tagalog },
+  { 1430, PT_SC, ucp_Tagbanwa },
+  { 1439, PT_SC, ucp_Tai_Le },
+  { 1446, PT_SC, ucp_Tai_Tham },
+  { 1455, PT_SC, ucp_Tai_Viet },
+  { 1464, PT_SC, ucp_Takri },
+  { 1470, PT_SC, ucp_Tamil },
+  { 1476, PT_SC, ucp_Tangut },
+  { 1483, PT_SC, ucp_Telugu },
+  { 1490, PT_SC, ucp_Thaana },
+  { 1497, PT_SC, ucp_Thai },
+  { 1502, PT_SC, ucp_Tibetan },
+  { 1510, PT_SC, ucp_Tifinagh },
+  { 1519, PT_SC, ucp_Tirhuta },
+  { 1527, PT_SC, ucp_Ugaritic },
+  { 1536, PT_SC, ucp_Unknown },
+  { 1544, PT_SC, ucp_Vai },
+  { 1548, PT_SC, ucp_Wancho },
+  { 1555, PT_SC, ucp_Warang_Citi },
+  { 1567, PT_ALNUM, 0 },
+  { 1571, PT_PXSPACE, 0 },
+  { 1575, PT_SPACE, 0 },
+  { 1579, PT_UCNC, 0 },
+  { 1583, PT_WORD, 0 },
+  { 1587, PT_SC, ucp_Yezidi },
+  { 1594, PT_SC, ucp_Yi },
+  { 1597, PT_GC, ucp_Z },
+  { 1599, PT_SC, ucp_Zanabazar_Square },
+  { 1616, PT_PC, ucp_Zl },
+  { 1619, PT_PC, ucp_Zp },
+  { 1622, PT_PC, ucp_Zs }
+};
+
+const size_t PRIV(utt_size) = sizeof(PRIV(utt)) / sizeof(ucp_type_table);
+
+#endif /* SUPPORT_UNICODE */
+
+/* End of pcre2_tables.c */
diff --git a/src/c/pcre2/src/pcre2_ucd.c b/src/c/pcre2/src/pcre2_ucd.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_ucd.c
@@ -0,0 +1,4538 @@
+/* This module is generated by the maint/MultiStage2.py script.
+Do not modify it by hand. Instead modify the script and run it
+to regenerate this code.
+
+As well as being part of the PCRE2 library, this module is #included
+by the pcre2test program, which redefines the PRIV macro to change
+table names from _pcre2_xxx to xxxx, thereby avoiding name clashes
+with the library. At present, just one of these tables is actually
+needed. */
+
+#ifndef PCRE2_PCRE2TEST
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+#endif /* PCRE2_PCRE2TEST */
+
+/* Unicode character database. */
+/* This file was autogenerated by the MultiStage2.py script. */
+/* Total size: 101044 bytes, block size: 128. */
+
+/* The tables herein are needed only when UCP support is built,
+and in PCRE2 that happens automatically with UTF support.
+This module should not be referenced otherwise, so
+it should not matter whether it is compiled or not. However
+a comment was received about space saving - maybe the guy linked
+all the modules rather than using a library - so we include a
+condition to cut out the tables when not needed. But don't leave
+a totally empty module because some compilers barf at that.
+Instead, just supply some small dummy tables. */
+
+#ifndef SUPPORT_UNICODE
+const ucd_record PRIV(ucd_records)[] = {{0,0,0,0,0,0,0 }};
+const uint16_t PRIV(ucd_stage1)[] = {0};
+const uint16_t PRIV(ucd_stage2)[] = {0};
+const uint32_t PRIV(ucd_caseless_sets)[] = {0};
+#else
+
+const char *PRIV(unicode_version) = "13.0.0";
+
+/* If the 32-bit library is run in non-32-bit mode, character values
+greater than 0x10ffff may be encountered. For these we set up a
+special record. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+const ucd_record PRIV(dummy_ucd_record)[] = {{
+  ucp_Unknown,    /* script */
+  ucp_Cn,         /* type unassigned */
+  ucp_gbOther,    /* grapheme break property */
+  0,              /* case set */
+  0,              /* other case */
+  ucp_Unknown,    /* script extension */
+  0,              /* dummy filler */
+  }};
+#endif
+
+/* When recompiling tables with a new Unicode version, please check the
+types in this structure definition from pcre2_internal.h (the actual
+field names will be different):
+
+typedef struct {
+uint8_t property_0;
+uint8_t property_1;
+uint8_t property_2;
+uint8_t property_3;
+pcre_int32 property_4;
+pcre_int16 property_5;
+uint16_t property_6;
+} ucd_record;
+*/
+
+/* This table contains lists of characters that are caseless sets of
+more than one character. Each list is terminated by NOTACHAR. */
+
+const uint32_t PRIV(ucd_caseless_sets)[] = {
+  NOTACHAR,
+  0x0053,   0x0073,   0x017f,   NOTACHAR,
+  0x01c4,   0x01c5,   0x01c6,   NOTACHAR,
+  0x01c7,   0x01c8,   0x01c9,   NOTACHAR,
+  0x01ca,   0x01cb,   0x01cc,   NOTACHAR,
+  0x01f1,   0x01f2,   0x01f3,   NOTACHAR,
+  0x0345,   0x0399,   0x03b9,   0x1fbe,   NOTACHAR,
+  0x00b5,   0x039c,   0x03bc,   NOTACHAR,
+  0x03a3,   0x03c2,   0x03c3,   NOTACHAR,
+  0x0392,   0x03b2,   0x03d0,   NOTACHAR,
+  0x0398,   0x03b8,   0x03d1,   0x03f4,   NOTACHAR,
+  0x03a6,   0x03c6,   0x03d5,   NOTACHAR,
+  0x03a0,   0x03c0,   0x03d6,   NOTACHAR,
+  0x039a,   0x03ba,   0x03f0,   NOTACHAR,
+  0x03a1,   0x03c1,   0x03f1,   NOTACHAR,
+  0x0395,   0x03b5,   0x03f5,   NOTACHAR,
+  0x0412,   0x0432,   0x1c80,   NOTACHAR,
+  0x0414,   0x0434,   0x1c81,   NOTACHAR,
+  0x041e,   0x043e,   0x1c82,   NOTACHAR,
+  0x0421,   0x0441,   0x1c83,   NOTACHAR,
+  0x0422,   0x0442,   0x1c84,   0x1c85,   NOTACHAR,
+  0x042a,   0x044a,   0x1c86,   NOTACHAR,
+  0x0462,   0x0463,   0x1c87,   NOTACHAR,
+  0x1e60,   0x1e61,   0x1e9b,   NOTACHAR,
+  0x03a9,   0x03c9,   0x2126,   NOTACHAR,
+  0x004b,   0x006b,   0x212a,   NOTACHAR,
+  0x00c5,   0x00e5,   0x212b,   NOTACHAR,
+  0x1c88,   0xa64a,   0xa64b,   NOTACHAR,
+};
+
+/* When #included in pcre2test, we don't need the table of digit
+sets, nor the the large main UCD tables. */
+
+#ifndef PCRE2_PCRE2TEST
+
+/* This table lists the code points for the '9' characters in each
+set of decimal digits. It is used to ensure that all the digits in
+a script run come from the same set. */
+
+const uint32_t PRIV(ucd_digit_sets)[] = {
+  65,  /* Number of subsequent values */
+  0x00039, 0x00669, 0x006f9, 0x007c9, 0x0096f, 0x009ef, 0x00a6f, 0x00aef,
+  0x00b6f, 0x00bef, 0x00c6f, 0x00cef, 0x00d6f, 0x00def, 0x00e59, 0x00ed9,
+  0x00f29, 0x01049, 0x01099, 0x017e9, 0x01819, 0x0194f, 0x019d9, 0x01a89,
+  0x01a99, 0x01b59, 0x01bb9, 0x01c49, 0x01c59, 0x0a629, 0x0a8d9, 0x0a909,
+  0x0a9d9, 0x0a9f9, 0x0aa59, 0x0abf9, 0x0ff19, 0x104a9, 0x10d39, 0x1106f,
+  0x110f9, 0x1113f, 0x111d9, 0x112f9, 0x11459, 0x114d9, 0x11659, 0x116c9,
+  0x11739, 0x118e9, 0x11959, 0x11c59, 0x11d59, 0x11da9, 0x16a69, 0x16b59,
+  0x1d7d7, 0x1d7e1, 0x1d7eb, 0x1d7f5, 0x1d7ff, 0x1e149, 0x1e2f9, 0x1e959,
+  0x1fbf9,
+};
+
+/* This vector is a list of lists of scripts for the Script Extension
+property. Each sublist is zero-terminated. */
+
+const uint8_t PRIV(ucd_script_sets)[] = {
+  /*   0 */   0,
+  /*   1 */   1,  11,   0,
+  /*   4 */   1, 144,   0,
+  /*   7 */   1,  50,   0,
+  /*  10 */   1,  56,   0,
+  /*  13 */   3,  15,   0,
+  /*  16 */   4,  23,   0,
+  /*  19 */   6,  84,   0,
+  /*  22 */  12,  36,   0,
+  /*  25 */  13,  18,   0,
+  /*  28 */  13,  34,   0,
+  /*  31 */  13, 118,   0,
+  /*  34 */  13,  50,   0,
+  /*  37 */  15, 107,   0,
+  /*  40 */  15, 150,   0,
+  /*  43 */  15, 100,   0,
+  /*  46 */  15,  54,   0,
+  /*  49 */  17,  34,   0,
+  /*  52 */ 107,  54,   0,
+  /*  55 */  21, 108,   0,
+  /*  58 */  22, 129,   0,
+  /*  61 */  23,  34,   0,
+  /*  64 */  27,  30,   0,
+  /*  67 */  29, 150,   0,
+  /*  70 */  34,  38,   0,
+  /*  73 */  38,  65,   0,
+  /*  76 */   1,  50,  56,   0,
+  /*  80 */   1,  56, 156,   0,
+  /*  84 */   3,  96,  49,   0,
+  /*  88 */  96,  39,  53,   0,
+  /*  92 */  12, 110,  36,   0,
+  /*  96 */  15, 107,  29,   0,
+  /* 100 */  15, 107,  34,   0,
+  /* 104 */  23,  27,  30,   0,
+  /* 108 */  69,  34,  39,   0,
+  /* 112 */   3,  15, 107,  29,   0,
+  /* 117 */   7,  25,  52,  51,   0,
+  /* 122 */  15, 142,  85, 111,   0,
+  /* 127 */   1, 144,  50,  56, 156,   0,
+  /* 133 */   4,  24,  23,  27,  30,   0,
+  /* 139 */   4,  24,  23,  27,  30,  61,   0,
+  /* 146 */  15,  29,  37,  44,  54,  55,   0,
+  /* 153 */ 132,   1,  95, 112, 121, 144, 148,  50,   0,
+  /* 162 */   3,  15, 107,  29, 150,  44,  55, 124,   0,
+  /* 171 */  15, 142,  21,  22, 108,  85, 111, 114, 109, 102, 124,   0,
+  /* 183 */   3,  15, 107,  21,  22,  29,  34,  37,  44,  54,  55, 124,   0,
+  /* 196 */   3,  15, 107,  21,  22,  29,  34,  37,  44, 100,  54,  55, 124,   0,
+  /* 210 */  15, 142,  21,  22, 108,  29,  85, 111, 114, 150, 109, 102, 124,   0,
+  /* 224 */  15, 142,  21,  22, 108,  29,  85, 111,  37, 114, 150, 109, 102, 124,   0,
+  /* 239 */   3,  15, 142, 143, 138, 107,  21,  22,  29, 111,  37, 150,  44, 109,  48,  49, 102,  54,  55, 124,   0,
+  /* 260 */   3,  15, 142, 143, 138, 107,  21,  22,  29,  35, 111,  37, 150,  44, 109,  48,  49, 102,  54,  55, 124,   0,
+  /* 282 */
+};
+
+/* These are the main two-stage UCD tables. The fields in each record are:
+script (8 bits), character type (8 bits), grapheme break property (8 bits),
+offset to multichar other cases or zero (8 bits), offset to other case
+or zero (32 bits, signed), script extension (16 bits, signed), and a dummy
+16-bit field to make the whole thing a multiple of 4 bytes. */
+
+const ucd_record PRIV(ucd_records)[] = { /* 11700 bytes, record size 12 */
+  {    10,      0,      2,      0,      0,     10,    256, }, /*   0 */
+  {    10,      0,      2,      0,      0,     10,      0, }, /*   1 */
+  {    10,      0,      1,      0,      0,     10,      0, }, /*   2 */
+  {    10,      0,      0,      0,      0,     10,      0, }, /*   3 */
+  {    10,     29,     12,      0,      0,     10,      0, }, /*   4 */
+  {    10,     21,     12,      0,      0,     10,      0, }, /*   5 */
+  {    10,     23,     12,      0,      0,     10,      0, }, /*   6 */
+  {    10,     22,     12,      0,      0,     10,      0, }, /*   7 */
+  {    10,     18,     12,      0,      0,     10,      0, }, /*   8 */
+  {    10,     25,     12,      0,      0,     10,      0, }, /*   9 */
+  {    10,     17,     12,      0,      0,     10,      0, }, /*  10 */
+  {    10,     13,     12,      0,      0,     10,      0, }, /*  11 */
+  {    34,      9,     12,      0,     32,     34,      0, }, /*  12 */
+  {    34,      9,     12,    100,     32,     34,      0, }, /*  13 */
+  {    34,      9,     12,      1,     32,     34,      0, }, /*  14 */
+  {    10,     24,     12,      0,      0,     10,      0, }, /*  15 */
+  {    10,     16,     12,      0,      0,     10,      0, }, /*  16 */
+  {    34,      5,     12,      0,    -32,     34,      0, }, /*  17 */
+  {    34,      5,     12,    100,    -32,     34,      0, }, /*  18 */
+  {    34,      5,     12,      1,    -32,     34,      0, }, /*  19 */
+  {    10,     26,     12,      0,      0,     10,      0, }, /*  20 */
+  {    10,     26,     14,      0,      0,     10,      0, }, /*  21 */
+  {    34,      7,     12,      0,      0,     34,      0, }, /*  22 */
+  {    10,     20,     12,      0,      0,     10,      0, }, /*  23 */
+  {    10,      1,      2,      0,      0,     10,      0, }, /*  24 */
+  {    10,     15,     12,      0,      0,     10,      0, }, /*  25 */
+  {    10,      5,     12,     26,    775,     10,      0, }, /*  26 */
+  {    10,     19,     12,      0,      0,     10,      0, }, /*  27 */
+  {    34,      9,     12,    104,     32,     34,      0, }, /*  28 */
+  {    34,      5,     12,      0,   7615,     34,      0, }, /*  29 */
+  {    34,      5,     12,    104,    -32,     34,      0, }, /*  30 */
+  {    34,      5,     12,      0,    121,     34,      0, }, /*  31 */
+  {    34,      9,     12,      0,      1,     34,      0, }, /*  32 */
+  {    34,      5,     12,      0,     -1,     34,      0, }, /*  33 */
+  {    34,      9,     12,      0,      0,     34,      0, }, /*  34 */
+  {    34,      5,     12,      0,      0,     34,      0, }, /*  35 */
+  {    34,      9,     12,      0,   -121,     34,      0, }, /*  36 */
+  {    34,      5,     12,      1,   -268,     34,      0, }, /*  37 */
+  {    34,      5,     12,      0,    195,     34,      0, }, /*  38 */
+  {    34,      9,     12,      0,    210,     34,      0, }, /*  39 */
+  {    34,      9,     12,      0,    206,     34,      0, }, /*  40 */
+  {    34,      9,     12,      0,    205,     34,      0, }, /*  41 */
+  {    34,      9,     12,      0,     79,     34,      0, }, /*  42 */
+  {    34,      9,     12,      0,    202,     34,      0, }, /*  43 */
+  {    34,      9,     12,      0,    203,     34,      0, }, /*  44 */
+  {    34,      9,     12,      0,    207,     34,      0, }, /*  45 */
+  {    34,      5,     12,      0,     97,     34,      0, }, /*  46 */
+  {    34,      9,     12,      0,    211,     34,      0, }, /*  47 */
+  {    34,      9,     12,      0,    209,     34,      0, }, /*  48 */
+  {    34,      5,     12,      0,    163,     34,      0, }, /*  49 */
+  {    34,      9,     12,      0,    213,     34,      0, }, /*  50 */
+  {    34,      5,     12,      0,    130,     34,      0, }, /*  51 */
+  {    34,      9,     12,      0,    214,     34,      0, }, /*  52 */
+  {    34,      9,     12,      0,    218,     34,      0, }, /*  53 */
+  {    34,      9,     12,      0,    217,     34,      0, }, /*  54 */
+  {    34,      9,     12,      0,    219,     34,      0, }, /*  55 */
+  {    34,      5,     12,      0,     56,     34,      0, }, /*  56 */
+  {    34,      9,     12,      5,      2,     34,      0, }, /*  57 */
+  {    34,      8,     12,      5,      1,     34,      0, }, /*  58 */
+  {    34,      5,     12,      5,     -2,     34,      0, }, /*  59 */
+  {    34,      9,     12,      9,      2,     34,      0, }, /*  60 */
+  {    34,      8,     12,      9,      1,     34,      0, }, /*  61 */
+  {    34,      5,     12,      9,     -2,     34,      0, }, /*  62 */
+  {    34,      9,     12,     13,      2,     34,      0, }, /*  63 */
+  {    34,      8,     12,     13,      1,     34,      0, }, /*  64 */
+  {    34,      5,     12,     13,     -2,     34,      0, }, /*  65 */
+  {    34,      5,     12,      0,    -79,     34,      0, }, /*  66 */
+  {    34,      9,     12,     17,      2,     34,      0, }, /*  67 */
+  {    34,      8,     12,     17,      1,     34,      0, }, /*  68 */
+  {    34,      5,     12,     17,     -2,     34,      0, }, /*  69 */
+  {    34,      9,     12,      0,    -97,     34,      0, }, /*  70 */
+  {    34,      9,     12,      0,    -56,     34,      0, }, /*  71 */
+  {    34,      9,     12,      0,   -130,     34,      0, }, /*  72 */
+  {    34,      9,     12,      0,  10795,     34,      0, }, /*  73 */
+  {    34,      9,     12,      0,   -163,     34,      0, }, /*  74 */
+  {    34,      9,     12,      0,  10792,     34,      0, }, /*  75 */
+  {    34,      5,     12,      0,  10815,     34,      0, }, /*  76 */
+  {    34,      9,     12,      0,   -195,     34,      0, }, /*  77 */
+  {    34,      9,     12,      0,     69,     34,      0, }, /*  78 */
+  {    34,      9,     12,      0,     71,     34,      0, }, /*  79 */
+  {    34,      5,     12,      0,  10783,     34,      0, }, /*  80 */
+  {    34,      5,     12,      0,  10780,     34,      0, }, /*  81 */
+  {    34,      5,     12,      0,  10782,     34,      0, }, /*  82 */
+  {    34,      5,     12,      0,   -210,     34,      0, }, /*  83 */
+  {    34,      5,     12,      0,   -206,     34,      0, }, /*  84 */
+  {    34,      5,     12,      0,   -205,     34,      0, }, /*  85 */
+  {    34,      5,     12,      0,   -202,     34,      0, }, /*  86 */
+  {    34,      5,     12,      0,   -203,     34,      0, }, /*  87 */
+  {    34,      5,     12,      0,  42319,     34,      0, }, /*  88 */
+  {    34,      5,     12,      0,  42315,     34,      0, }, /*  89 */
+  {    34,      5,     12,      0,   -207,     34,      0, }, /*  90 */
+  {    34,      5,     12,      0,  42280,     34,      0, }, /*  91 */
+  {    34,      5,     12,      0,  42308,     34,      0, }, /*  92 */
+  {    34,      5,     12,      0,   -209,     34,      0, }, /*  93 */
+  {    34,      5,     12,      0,   -211,     34,      0, }, /*  94 */
+  {    34,      5,     12,      0,  10743,     34,      0, }, /*  95 */
+  {    34,      5,     12,      0,  42305,     34,      0, }, /*  96 */
+  {    34,      5,     12,      0,  10749,     34,      0, }, /*  97 */
+  {    34,      5,     12,      0,   -213,     34,      0, }, /*  98 */
+  {    34,      5,     12,      0,   -214,     34,      0, }, /*  99 */
+  {    34,      5,     12,      0,  10727,     34,      0, }, /* 100 */
+  {    34,      5,     12,      0,   -218,     34,      0, }, /* 101 */
+  {    34,      5,     12,      0,  42307,     34,      0, }, /* 102 */
+  {    34,      5,     12,      0,  42282,     34,      0, }, /* 103 */
+  {    34,      5,     12,      0,    -69,     34,      0, }, /* 104 */
+  {    34,      5,     12,      0,   -217,     34,      0, }, /* 105 */
+  {    34,      5,     12,      0,    -71,     34,      0, }, /* 106 */
+  {    34,      5,     12,      0,   -219,     34,      0, }, /* 107 */
+  {    34,      5,     12,      0,  42261,     34,      0, }, /* 108 */
+  {    34,      5,     12,      0,  42258,     34,      0, }, /* 109 */
+  {    34,      6,     12,      0,      0,     34,      0, }, /* 110 */
+  {    10,      6,     12,      0,      0,     10,      0, }, /* 111 */
+  {     4,     24,     12,      0,      0,      4,      0, }, /* 112 */
+  {    28,     12,      3,      0,      0,     28,      0, }, /* 113 */
+  {    28,     12,      3,      0,      0,     20,      0, }, /* 114 */
+  {    28,     12,      3,     21,    116,     20,      0, }, /* 115 */
+  {    28,     12,      3,      0,      0,     34,      0, }, /* 116 */
+  {    20,      9,     12,      0,      1,     20,      0, }, /* 117 */
+  {    20,      5,     12,      0,     -1,     20,      0, }, /* 118 */
+  {    20,     24,     12,      0,      0,     20,      0, }, /* 119 */
+  {     0,      2,     12,      0,      0,      0,      0, }, /* 120 */
+  {    20,      6,     12,      0,      0,     20,      0, }, /* 121 */
+  {    20,      5,     12,      0,    130,     20,      0, }, /* 122 */
+  {    20,      9,     12,      0,    116,     20,      0, }, /* 123 */
+  {    20,      9,     12,      0,     38,     20,      0, }, /* 124 */
+  {    20,      9,     12,      0,     37,     20,      0, }, /* 125 */
+  {    20,      9,     12,      0,     64,     20,      0, }, /* 126 */
+  {    20,      9,     12,      0,     63,     20,      0, }, /* 127 */
+  {    20,      5,     12,      0,      0,     20,      0, }, /* 128 */
+  {    20,      9,     12,      0,     32,     20,      0, }, /* 129 */
+  {    20,      9,     12,     34,     32,     20,      0, }, /* 130 */
+  {    20,      9,     12,     59,     32,     20,      0, }, /* 131 */
+  {    20,      9,     12,     38,     32,     20,      0, }, /* 132 */
+  {    20,      9,     12,     21,     32,     20,      0, }, /* 133 */
+  {    20,      9,     12,     51,     32,     20,      0, }, /* 134 */
+  {    20,      9,     12,     26,     32,     20,      0, }, /* 135 */
+  {    20,      9,     12,     47,     32,     20,      0, }, /* 136 */
+  {    20,      9,     12,     55,     32,     20,      0, }, /* 137 */
+  {    20,      9,     12,     30,     32,     20,      0, }, /* 138 */
+  {    20,      9,     12,     43,     32,     20,      0, }, /* 139 */
+  {    20,      9,     12,     96,     32,     20,      0, }, /* 140 */
+  {    20,      5,     12,      0,    -38,     20,      0, }, /* 141 */
+  {    20,      5,     12,      0,    -37,     20,      0, }, /* 142 */
+  {    20,      5,     12,      0,    -32,     20,      0, }, /* 143 */
+  {    20,      5,     12,     34,    -32,     20,      0, }, /* 144 */
+  {    20,      5,     12,     59,    -32,     20,      0, }, /* 145 */
+  {    20,      5,     12,     38,    -32,     20,      0, }, /* 146 */
+  {    20,      5,     12,     21,   -116,     20,      0, }, /* 147 */
+  {    20,      5,     12,     51,    -32,     20,      0, }, /* 148 */
+  {    20,      5,     12,     26,   -775,     20,      0, }, /* 149 */
+  {    20,      5,     12,     47,    -32,     20,      0, }, /* 150 */
+  {    20,      5,     12,     55,    -32,     20,      0, }, /* 151 */
+  {    20,      5,     12,     30,      1,     20,      0, }, /* 152 */
+  {    20,      5,     12,     30,    -32,     20,      0, }, /* 153 */
+  {    20,      5,     12,     43,    -32,     20,      0, }, /* 154 */
+  {    20,      5,     12,     96,    -32,     20,      0, }, /* 155 */
+  {    20,      5,     12,      0,    -64,     20,      0, }, /* 156 */
+  {    20,      5,     12,      0,    -63,     20,      0, }, /* 157 */
+  {    20,      9,     12,      0,      8,     20,      0, }, /* 158 */
+  {    20,      5,     12,     34,    -30,     20,      0, }, /* 159 */
+  {    20,      5,     12,     38,    -25,     20,      0, }, /* 160 */
+  {    20,      9,     12,      0,      0,     20,      0, }, /* 161 */
+  {    20,      5,     12,     43,    -15,     20,      0, }, /* 162 */
+  {    20,      5,     12,     47,    -22,     20,      0, }, /* 163 */
+  {    20,      5,     12,      0,     -8,     20,      0, }, /* 164 */
+  {    11,      9,     12,      0,      1,     11,      0, }, /* 165 */
+  {    11,      5,     12,      0,     -1,     11,      0, }, /* 166 */
+  {    20,      5,     12,     51,    -54,     20,      0, }, /* 167 */
+  {    20,      5,     12,     55,    -48,     20,      0, }, /* 168 */
+  {    20,      5,     12,      0,      7,     20,      0, }, /* 169 */
+  {    20,      5,     12,      0,   -116,     20,      0, }, /* 170 */
+  {    20,      9,     12,     38,    -60,     20,      0, }, /* 171 */
+  {    20,      5,     12,     59,    -64,     20,      0, }, /* 172 */
+  {    20,     25,     12,      0,      0,     20,      0, }, /* 173 */
+  {    20,      9,     12,      0,     -7,     20,      0, }, /* 174 */
+  {    20,      9,     12,      0,   -130,     20,      0, }, /* 175 */
+  {    13,      9,     12,      0,     80,     13,      0, }, /* 176 */
+  {    13,      9,     12,      0,     32,     13,      0, }, /* 177 */
+  {    13,      9,     12,     63,     32,     13,      0, }, /* 178 */
+  {    13,      9,     12,     67,     32,     13,      0, }, /* 179 */
+  {    13,      9,     12,     71,     32,     13,      0, }, /* 180 */
+  {    13,      9,     12,     75,     32,     13,      0, }, /* 181 */
+  {    13,      9,     12,     79,     32,     13,      0, }, /* 182 */
+  {    13,      9,     12,     84,     32,     13,      0, }, /* 183 */
+  {    13,      5,     12,      0,    -32,     13,      0, }, /* 184 */
+  {    13,      5,     12,     63,    -32,     13,      0, }, /* 185 */
+  {    13,      5,     12,     67,    -32,     13,      0, }, /* 186 */
+  {    13,      5,     12,     71,    -32,     13,      0, }, /* 187 */
+  {    13,      5,     12,     75,    -32,     13,      0, }, /* 188 */
+  {    13,      5,     12,     79,    -32,     13,      0, }, /* 189 */
+  {    13,      5,     12,     84,    -32,     13,      0, }, /* 190 */
+  {    13,      5,     12,      0,    -80,     13,      0, }, /* 191 */
+  {    13,      9,     12,      0,      1,     13,      0, }, /* 192 */
+  {    13,      5,     12,      0,     -1,     13,      0, }, /* 193 */
+  {    13,      9,     12,     88,      1,     13,      0, }, /* 194 */
+  {    13,      5,     12,     88,     -1,     13,      0, }, /* 195 */
+  {    13,     26,     12,      0,      0,     13,      0, }, /* 196 */
+  {    13,     12,      3,      0,      0,    -31,      0, }, /* 197 */
+  {    13,     12,      3,      0,      0,    -25,      0, }, /* 198 */
+  {    28,     12,      3,      0,      0,    -28,      0, }, /* 199 */
+  {    13,     11,      3,      0,      0,     13,      0, }, /* 200 */
+  {    13,      9,     12,      0,     15,     13,      0, }, /* 201 */
+  {    13,      5,     12,      0,    -15,     13,      0, }, /* 202 */
+  {     2,      9,     12,      0,     48,      2,      0, }, /* 203 */
+  {     2,      6,     12,      0,      0,      2,      0, }, /* 204 */
+  {     2,     21,     12,      0,      0,      2,      0, }, /* 205 */
+  {     2,      5,     12,      0,      0,      2,      0, }, /* 206 */
+  {     2,      5,     12,      0,    -48,      2,      0, }, /* 207 */
+  {     2,     17,     12,      0,      0,      2,      0, }, /* 208 */
+  {     2,     26,     12,      0,      0,      2,      0, }, /* 209 */
+  {     2,     23,     12,      0,      0,      2,      0, }, /* 210 */
+  {    26,     12,      3,      0,      0,     26,      0, }, /* 211 */
+  {    26,     17,     12,      0,      0,     26,      0, }, /* 212 */
+  {    26,     21,     12,      0,      0,     26,      0, }, /* 213 */
+  {    26,      7,     12,      0,      0,     26,      0, }, /* 214 */
+  {     1,      1,      4,      0,      0,      1,      0, }, /* 215 */
+  {    10,      1,      4,      0,      0,     10,      0, }, /* 216 */
+  {     1,     25,     12,      0,      0,      1,      0, }, /* 217 */
+  {     1,     21,     12,      0,      0,      1,      0, }, /* 218 */
+  {     1,     23,     12,      0,      0,      1,      0, }, /* 219 */
+  {    10,     21,     12,      0,      0,   -127,      0, }, /* 220 */
+  {     1,     26,     12,      0,      0,      1,      0, }, /* 221 */
+  {     1,     12,      3,      0,      0,      1,      0, }, /* 222 */
+  {     1,      1,      2,      0,      0,    -76,      0, }, /* 223 */
+  {     1,      7,     12,      0,      0,      1,      0, }, /* 224 */
+  {    10,      6,     12,      0,      0,   -153,      0, }, /* 225 */
+  {    28,     12,      3,      0,      0,     -7,      0, }, /* 226 */
+  {     1,     13,     12,      0,      0,    -80,      0, }, /* 227 */
+  {     1,     21,     12,      0,      0,     -4,      0, }, /* 228 */
+  {     1,      6,     12,      0,      0,      1,      0, }, /* 229 */
+  {     1,     13,     12,      0,      0,      1,      0, }, /* 230 */
+  {    50,     21,     12,      0,      0,     50,      0, }, /* 231 */
+  {    50,      1,      4,      0,      0,     50,      0, }, /* 232 */
+  {    50,      7,     12,      0,      0,     50,      0, }, /* 233 */
+  {    50,     12,      3,      0,      0,     50,      0, }, /* 234 */
+  {    56,      7,     12,      0,      0,     56,      0, }, /* 235 */
+  {    56,     12,      3,      0,      0,     56,      0, }, /* 236 */
+  {    64,     13,     12,      0,      0,     64,      0, }, /* 237 */
+  {    64,      7,     12,      0,      0,     64,      0, }, /* 238 */
+  {    64,     12,      3,      0,      0,     64,      0, }, /* 239 */
+  {    64,      6,     12,      0,      0,     64,      0, }, /* 240 */
+  {    64,     26,     12,      0,      0,     64,      0, }, /* 241 */
+  {    64,     21,     12,      0,      0,     64,      0, }, /* 242 */
+  {    64,     23,     12,      0,      0,     64,      0, }, /* 243 */
+  {    90,      7,     12,      0,      0,     90,      0, }, /* 244 */
+  {    90,     12,      3,      0,      0,     90,      0, }, /* 245 */
+  {    90,      6,     12,      0,      0,     90,      0, }, /* 246 */
+  {    90,     21,     12,      0,      0,     90,      0, }, /* 247 */
+  {    95,      7,     12,      0,      0,     95,      0, }, /* 248 */
+  {    95,     12,      3,      0,      0,     95,      0, }, /* 249 */
+  {    95,     21,     12,      0,      0,     95,      0, }, /* 250 */
+  {    15,     12,      3,      0,      0,     15,      0, }, /* 251 */
+  {    15,     10,      5,      0,      0,     15,      0, }, /* 252 */
+  {    15,      7,     12,      0,      0,     15,      0, }, /* 253 */
+  {    28,     12,      3,      0,      0,   -196,      0, }, /* 254 */
+  {    28,     12,      3,      0,      0,   -183,      0, }, /* 255 */
+  {    10,     21,     12,      0,      0,   -239,      0, }, /* 256 */
+  {    10,     21,     12,      0,      0,   -260,      0, }, /* 257 */
+  {    15,     13,     12,      0,      0,   -122,      0, }, /* 258 */
+  {    15,     21,     12,      0,      0,     15,      0, }, /* 259 */
+  {    15,      6,     12,      0,      0,     15,      0, }, /* 260 */
+  {     3,      7,     12,      0,      0,      3,      0, }, /* 261 */
+  {     3,     12,      3,      0,      0,      3,      0, }, /* 262 */
+  {     3,     10,      5,      0,      0,      3,      0, }, /* 263 */
+  {     3,     10,      3,      0,      0,      3,      0, }, /* 264 */
+  {     3,     13,     12,      0,      0,    -84,      0, }, /* 265 */
+  {     3,     23,     12,      0,      0,      3,      0, }, /* 266 */
+  {     3,     15,     12,      0,      0,      3,      0, }, /* 267 */
+  {     3,     26,     12,      0,      0,      3,      0, }, /* 268 */
+  {     3,     21,     12,      0,      0,      3,      0, }, /* 269 */
+  {    22,     12,      3,      0,      0,     22,      0, }, /* 270 */
+  {    22,     10,      5,      0,      0,     22,      0, }, /* 271 */
+  {    22,      7,     12,      0,      0,     22,      0, }, /* 272 */
+  {    22,     13,     12,      0,      0,    -58,      0, }, /* 273 */
+  {    22,     21,     12,      0,      0,     22,      0, }, /* 274 */
+  {    21,     12,      3,      0,      0,     21,      0, }, /* 275 */
+  {    21,     10,      5,      0,      0,     21,      0, }, /* 276 */
+  {    21,      7,     12,      0,      0,     21,      0, }, /* 277 */
+  {    21,     13,     12,      0,      0,    -55,      0, }, /* 278 */
+  {    21,     21,     12,      0,      0,     21,      0, }, /* 279 */
+  {    21,     23,     12,      0,      0,     21,      0, }, /* 280 */
+  {    44,     12,      3,      0,      0,     44,      0, }, /* 281 */
+  {    44,     10,      5,      0,      0,     44,      0, }, /* 282 */
+  {    44,      7,     12,      0,      0,     44,      0, }, /* 283 */
+  {    44,     10,      3,      0,      0,     44,      0, }, /* 284 */
+  {    44,     13,     12,      0,      0,     44,      0, }, /* 285 */
+  {    44,     26,     12,      0,      0,     44,      0, }, /* 286 */
+  {    44,     15,     12,      0,      0,     44,      0, }, /* 287 */
+  {    54,     12,      3,      0,      0,     54,      0, }, /* 288 */
+  {    54,      7,     12,      0,      0,     54,      0, }, /* 289 */
+  {    54,     10,      3,      0,      0,     54,      0, }, /* 290 */
+  {    54,     10,      5,      0,      0,     54,      0, }, /* 291 */
+  {    54,     13,     12,      0,      0,    -52,      0, }, /* 292 */
+  {    54,     15,     12,      0,      0,    -52,      0, }, /* 293 */
+  {    54,     26,     12,      0,      0,    -52,      0, }, /* 294 */
+  {    54,     26,     12,      0,      0,     54,      0, }, /* 295 */
+  {    54,     23,     12,      0,      0,     54,      0, }, /* 296 */
+  {    55,     12,      3,      0,      0,     55,      0, }, /* 297 */
+  {    55,     10,      5,      0,      0,     55,      0, }, /* 298 */
+  {    55,      7,     12,      0,      0,     55,      0, }, /* 299 */
+  {    55,     13,     12,      0,      0,     55,      0, }, /* 300 */
+  {    55,     21,     12,      0,      0,     55,      0, }, /* 301 */
+  {    55,     15,     12,      0,      0,     55,      0, }, /* 302 */
+  {    55,     26,     12,      0,      0,     55,      0, }, /* 303 */
+  {    29,      7,     12,      0,      0,     29,      0, }, /* 304 */
+  {    29,     12,      3,      0,      0,     29,      0, }, /* 305 */
+  {    29,     10,      5,      0,      0,     29,      0, }, /* 306 */
+  {    29,     21,     12,      0,      0,     29,      0, }, /* 307 */
+  {    29,     10,      3,      0,      0,     29,      0, }, /* 308 */
+  {    29,     13,     12,      0,      0,    -67,      0, }, /* 309 */
+  {    37,     12,      3,      0,      0,     37,      0, }, /* 310 */
+  {    37,     10,      5,      0,      0,     37,      0, }, /* 311 */
+  {    37,      7,     12,      0,      0,     37,      0, }, /* 312 */
+  {    37,     10,      3,      0,      0,     37,      0, }, /* 313 */
+  {    37,      7,      4,      0,      0,     37,      0, }, /* 314 */
+  {    37,     26,     12,      0,      0,     37,      0, }, /* 315 */
+  {    37,     15,     12,      0,      0,     37,      0, }, /* 316 */
+  {    37,     13,     12,      0,      0,     37,      0, }, /* 317 */
+  {    48,     12,      3,      0,      0,     48,      0, }, /* 318 */
+  {    48,     10,      5,      0,      0,     48,      0, }, /* 319 */
+  {    48,      7,     12,      0,      0,     48,      0, }, /* 320 */
+  {    48,     10,      3,      0,      0,     48,      0, }, /* 321 */
+  {    48,     13,     12,      0,      0,     48,      0, }, /* 322 */
+  {    48,     21,     12,      0,      0,     48,      0, }, /* 323 */
+  {    57,      7,     12,      0,      0,     57,      0, }, /* 324 */
+  {    57,     12,      3,      0,      0,     57,      0, }, /* 325 */
+  {    57,      7,      5,      0,      0,     57,      0, }, /* 326 */
+  {    57,      6,     12,      0,      0,     57,      0, }, /* 327 */
+  {    57,     21,     12,      0,      0,     57,      0, }, /* 328 */
+  {    57,     13,     12,      0,      0,     57,      0, }, /* 329 */
+  {    33,      7,     12,      0,      0,     33,      0, }, /* 330 */
+  {    33,     12,      3,      0,      0,     33,      0, }, /* 331 */
+  {    33,      7,      5,      0,      0,     33,      0, }, /* 332 */
+  {    33,      6,     12,      0,      0,     33,      0, }, /* 333 */
+  {    33,     13,     12,      0,      0,     33,      0, }, /* 334 */
+  {    58,      7,     12,      0,      0,     58,      0, }, /* 335 */
+  {    58,     26,     12,      0,      0,     58,      0, }, /* 336 */
+  {    58,     21,     12,      0,      0,     58,      0, }, /* 337 */
+  {    58,     12,      3,      0,      0,     58,      0, }, /* 338 */
+  {    58,     13,     12,      0,      0,     58,      0, }, /* 339 */
+  {    58,     15,     12,      0,      0,     58,      0, }, /* 340 */
+  {    58,     22,     12,      0,      0,     58,      0, }, /* 341 */
+  {    58,     18,     12,      0,      0,     58,      0, }, /* 342 */
+  {    58,     10,      5,      0,      0,     58,      0, }, /* 343 */
+  {    39,      7,     12,      0,      0,     39,      0, }, /* 344 */
+  {    39,     10,     12,      0,      0,     39,      0, }, /* 345 */
+  {    39,     12,      3,      0,      0,     39,      0, }, /* 346 */
+  {    39,     10,      5,      0,      0,     39,      0, }, /* 347 */
+  {    39,     13,     12,      0,      0,    -88,      0, }, /* 348 */
+  {    39,     21,     12,      0,      0,     39,      0, }, /* 349 */
+  {    39,     13,     12,      0,      0,     39,      0, }, /* 350 */
+  {    39,     26,     12,      0,      0,     39,      0, }, /* 351 */
+  {    17,      9,     12,      0,   7264,     17,      0, }, /* 352 */
+  {    17,      5,     12,      0,   3008,     17,      0, }, /* 353 */
+  {    10,     21,     12,      0,      0,    -49,      0, }, /* 354 */
+  {    17,      6,     12,      0,      0,     17,      0, }, /* 355 */
+  {    24,      7,      6,      0,      0,     24,      0, }, /* 356 */
+  {    24,      7,      7,      0,      0,     24,      0, }, /* 357 */
+  {    24,      7,      8,      0,      0,     24,      0, }, /* 358 */
+  {    16,      7,     12,      0,      0,     16,      0, }, /* 359 */
+  {    16,     12,      3,      0,      0,     16,      0, }, /* 360 */
+  {    16,     21,     12,      0,      0,     16,      0, }, /* 361 */
+  {    16,     15,     12,      0,      0,     16,      0, }, /* 362 */
+  {    16,     26,     12,      0,      0,     16,      0, }, /* 363 */
+  {     9,      9,     12,      0,  38864,      9,      0, }, /* 364 */
+  {     9,      9,     12,      0,      8,      9,      0, }, /* 365 */
+  {     9,      5,     12,      0,     -8,      9,      0, }, /* 366 */
+  {     8,     17,     12,      0,      0,      8,      0, }, /* 367 */
+  {     8,      7,     12,      0,      0,      8,      0, }, /* 368 */
+  {     8,     26,     12,      0,      0,      8,      0, }, /* 369 */
+  {     8,     21,     12,      0,      0,      8,      0, }, /* 370 */
+  {    41,     29,     12,      0,      0,     41,      0, }, /* 371 */
+  {    41,      7,     12,      0,      0,     41,      0, }, /* 372 */
+  {    41,     22,     12,      0,      0,     41,      0, }, /* 373 */
+  {    41,     18,     12,      0,      0,     41,      0, }, /* 374 */
+  {    46,      7,     12,      0,      0,     46,      0, }, /* 375 */
+  {    46,     14,     12,      0,      0,     46,      0, }, /* 376 */
+  {    51,      7,     12,      0,      0,     51,      0, }, /* 377 */
+  {    51,     12,      3,      0,      0,     51,      0, }, /* 378 */
+  {    25,      7,     12,      0,      0,     25,      0, }, /* 379 */
+  {    25,     12,      3,      0,      0,     25,      0, }, /* 380 */
+  {    10,     21,     12,      0,      0,   -117,      0, }, /* 381 */
+  {     7,      7,     12,      0,      0,      7,      0, }, /* 382 */
+  {     7,     12,      3,      0,      0,      7,      0, }, /* 383 */
+  {    52,      7,     12,      0,      0,     52,      0, }, /* 384 */
+  {    52,     12,      3,      0,      0,     52,      0, }, /* 385 */
+  {    32,      7,     12,      0,      0,     32,      0, }, /* 386 */
+  {    32,     12,      3,      0,      0,     32,      0, }, /* 387 */
+  {    32,     10,      5,      0,      0,     32,      0, }, /* 388 */
+  {    32,     21,     12,      0,      0,     32,      0, }, /* 389 */
+  {    32,      6,     12,      0,      0,     32,      0, }, /* 390 */
+  {    32,     23,     12,      0,      0,     32,      0, }, /* 391 */
+  {    32,     13,     12,      0,      0,     32,      0, }, /* 392 */
+  {    32,     15,     12,      0,      0,     32,      0, }, /* 393 */
+  {    38,     21,     12,      0,      0,     38,      0, }, /* 394 */
+  {    10,     21,     12,      0,      0,    -73,      0, }, /* 395 */
+  {    38,     17,     12,      0,      0,     38,      0, }, /* 396 */
+  {    38,     12,      3,      0,      0,     38,      0, }, /* 397 */
+  {    38,      1,      2,      0,      0,     38,      0, }, /* 398 */
+  {    38,     13,     12,      0,      0,     38,      0, }, /* 399 */
+  {    38,      7,     12,      0,      0,     38,      0, }, /* 400 */
+  {    38,      6,     12,      0,      0,     38,      0, }, /* 401 */
+  {    35,      7,     12,      0,      0,     35,      0, }, /* 402 */
+  {    35,     12,      3,      0,      0,     35,      0, }, /* 403 */
+  {    35,     10,      5,      0,      0,     35,      0, }, /* 404 */
+  {    35,     26,     12,      0,      0,     35,      0, }, /* 405 */
+  {    35,     21,     12,      0,      0,     35,      0, }, /* 406 */
+  {    35,     13,     12,      0,      0,     35,      0, }, /* 407 */
+  {    53,      7,     12,      0,      0,     53,      0, }, /* 408 */
+  {    40,      7,     12,      0,      0,     40,      0, }, /* 409 */
+  {    40,     13,     12,      0,      0,     40,      0, }, /* 410 */
+  {    40,     15,     12,      0,      0,     40,      0, }, /* 411 */
+  {    40,     26,     12,      0,      0,     40,      0, }, /* 412 */
+  {    32,     26,     12,      0,      0,     32,      0, }, /* 413 */
+  {     6,      7,     12,      0,      0,      6,      0, }, /* 414 */
+  {     6,     12,      3,      0,      0,      6,      0, }, /* 415 */
+  {     6,     10,      5,      0,      0,      6,      0, }, /* 416 */
+  {     6,     21,     12,      0,      0,      6,      0, }, /* 417 */
+  {    91,      7,     12,      0,      0,     91,      0, }, /* 418 */
+  {    91,     10,      5,      0,      0,     91,      0, }, /* 419 */
+  {    91,     12,      3,      0,      0,     91,      0, }, /* 420 */
+  {    91,     10,     12,      0,      0,     91,      0, }, /* 421 */
+  {    91,     13,     12,      0,      0,     91,      0, }, /* 422 */
+  {    91,     21,     12,      0,      0,     91,      0, }, /* 423 */
+  {    91,      6,     12,      0,      0,     91,      0, }, /* 424 */
+  {    28,     11,      3,      0,      0,     28,      0, }, /* 425 */
+  {    62,     12,      3,      0,      0,     62,      0, }, /* 426 */
+  {    62,     10,      5,      0,      0,     62,      0, }, /* 427 */
+  {    62,      7,     12,      0,      0,     62,      0, }, /* 428 */
+  {    62,     10,      3,      0,      0,     62,      0, }, /* 429 */
+  {    62,     13,     12,      0,      0,     62,      0, }, /* 430 */
+  {    62,     21,     12,      0,      0,     62,      0, }, /* 431 */
+  {    62,     26,     12,      0,      0,     62,      0, }, /* 432 */
+  {    76,     12,      3,      0,      0,     76,      0, }, /* 433 */
+  {    76,     10,      5,      0,      0,     76,      0, }, /* 434 */
+  {    76,      7,     12,      0,      0,     76,      0, }, /* 435 */
+  {    76,     13,     12,      0,      0,     76,      0, }, /* 436 */
+  {    93,      7,     12,      0,      0,     93,      0, }, /* 437 */
+  {    93,     12,      3,      0,      0,     93,      0, }, /* 438 */
+  {    93,     10,      5,      0,      0,     93,      0, }, /* 439 */
+  {    93,     21,     12,      0,      0,     93,      0, }, /* 440 */
+  {    70,      7,     12,      0,      0,     70,      0, }, /* 441 */
+  {    70,     10,      5,      0,      0,     70,      0, }, /* 442 */
+  {    70,     12,      3,      0,      0,     70,      0, }, /* 443 */
+  {    70,     21,     12,      0,      0,     70,      0, }, /* 444 */
+  {    70,     13,     12,      0,      0,     70,      0, }, /* 445 */
+  {    73,     13,     12,      0,      0,     73,      0, }, /* 446 */
+  {    73,      7,     12,      0,      0,     73,      0, }, /* 447 */
+  {    73,      6,     12,      0,      0,     73,      0, }, /* 448 */
+  {    73,     21,     12,      0,      0,     73,      0, }, /* 449 */
+  {    13,      5,     12,     63,  -6222,     13,      0, }, /* 450 */
+  {    13,      5,     12,     67,  -6221,     13,      0, }, /* 451 */
+  {    13,      5,     12,     71,  -6212,     13,      0, }, /* 452 */
+  {    13,      5,     12,     75,  -6210,     13,      0, }, /* 453 */
+  {    13,      5,     12,     79,  -6210,     13,      0, }, /* 454 */
+  {    13,      5,     12,     79,  -6211,     13,      0, }, /* 455 */
+  {    13,      5,     12,     84,  -6204,     13,      0, }, /* 456 */
+  {    13,      5,     12,     88,  -6180,     13,      0, }, /* 457 */
+  {    13,      5,     12,    108,  35267,     13,      0, }, /* 458 */
+  {    17,      9,     12,      0,  -3008,     17,      0, }, /* 459 */
+  {    76,     21,     12,      0,      0,     76,      0, }, /* 460 */
+  {    28,     12,      3,      0,      0,   -112,      0, }, /* 461 */
+  {    28,     12,      3,      0,      0,     15,      0, }, /* 462 */
+  {    10,     21,     12,      0,      0,    -37,      0, }, /* 463 */
+  {    28,     12,      3,      0,      0,    -13,      0, }, /* 464 */
+  {    28,     12,      3,      0,      0,    -43,      0, }, /* 465 */
+  {    28,     12,      3,      0,      0,   -146,      0, }, /* 466 */
+  {    10,     10,      5,      0,      0,    -13,      0, }, /* 467 */
+  {    10,      7,     12,      0,      0,    -40,      0, }, /* 468 */
+  {    10,      7,     12,      0,      0,    -13,      0, }, /* 469 */
+  {    10,      7,     12,      0,      0,     15,      0, }, /* 470 */
+  {    10,      7,     12,      0,      0,   -162,      0, }, /* 471 */
+  {    10,      7,     12,      0,      0,    -37,      0, }, /* 472 */
+  {    28,     12,      3,      0,      0,    -96,      0, }, /* 473 */
+  {    10,     10,      5,      0,      0,      3,      0, }, /* 474 */
+  {    28,     12,      3,      0,      0,    -37,      0, }, /* 475 */
+  {    10,      7,     12,      0,      0,    150,      0, }, /* 476 */
+  {    13,      5,     12,      0,      0,     13,      0, }, /* 477 */
+  {    13,      6,     12,      0,      0,     13,      0, }, /* 478 */
+  {    34,      5,     12,      0,  35332,     34,      0, }, /* 479 */
+  {    34,      5,     12,      0,   3814,     34,      0, }, /* 480 */
+  {    34,      5,     12,      0,  35384,     34,      0, }, /* 481 */
+  {    28,     12,      3,      0,      0,    -34,      0, }, /* 482 */
+  {    34,      9,     12,     92,      1,     34,      0, }, /* 483 */
+  {    34,      5,     12,     92,     -1,     34,      0, }, /* 484 */
+  {    34,      5,     12,     92,    -58,     34,      0, }, /* 485 */
+  {    34,      9,     12,      0,  -7615,     34,      0, }, /* 486 */
+  {    20,      5,     12,      0,      8,     20,      0, }, /* 487 */
+  {    20,      9,     12,      0,     -8,     20,      0, }, /* 488 */
+  {    20,      5,     12,      0,     74,     20,      0, }, /* 489 */
+  {    20,      5,     12,      0,     86,     20,      0, }, /* 490 */
+  {    20,      5,     12,      0,    100,     20,      0, }, /* 491 */
+  {    20,      5,     12,      0,    128,     20,      0, }, /* 492 */
+  {    20,      5,     12,      0,    112,     20,      0, }, /* 493 */
+  {    20,      5,     12,      0,    126,     20,      0, }, /* 494 */
+  {    20,      8,     12,      0,     -8,     20,      0, }, /* 495 */
+  {    20,      5,     12,      0,      9,     20,      0, }, /* 496 */
+  {    20,      9,     12,      0,    -74,     20,      0, }, /* 497 */
+  {    20,      8,     12,      0,     -9,     20,      0, }, /* 498 */
+  {    20,      5,     12,     21,  -7173,     20,      0, }, /* 499 */
+  {    20,      9,     12,      0,    -86,     20,      0, }, /* 500 */
+  {    20,      9,     12,      0,   -100,     20,      0, }, /* 501 */
+  {    20,      9,     12,      0,   -112,     20,      0, }, /* 502 */
+  {    20,      9,     12,      0,   -128,     20,      0, }, /* 503 */
+  {    20,      9,     12,      0,   -126,     20,      0, }, /* 504 */
+  {    28,      1,      3,      0,      0,     28,      0, }, /* 505 */
+  {    28,      1,     13,      0,      0,     28,      0, }, /* 506 */
+  {    10,     27,      2,      0,      0,     10,      0, }, /* 507 */
+  {    10,     28,      2,      0,      0,     10,      0, }, /* 508 */
+  {    10,     29,     12,      0,      0,    -70,      0, }, /* 509 */
+  {    10,     21,     14,      0,      0,     10,      0, }, /* 510 */
+  {     0,      2,      2,      0,      0,      0,      0, }, /* 511 */
+  {    28,     12,      3,      0,      0,   -100,      0, }, /* 512 */
+  {    10,      9,     12,      0,      0,     10,      0, }, /* 513 */
+  {    10,      5,     12,      0,      0,     10,      0, }, /* 514 */
+  {    20,      9,     12,     96,  -7517,     20,      0, }, /* 515 */
+  {    34,      9,     12,    100,  -8383,     34,      0, }, /* 516 */
+  {    34,      9,     12,    104,  -8262,     34,      0, }, /* 517 */
+  {    34,      9,     12,      0,     28,     34,      0, }, /* 518 */
+  {    10,      7,     12,      0,      0,     10,      0, }, /* 519 */
+  {    10,      5,     14,      0,      0,     10,      0, }, /* 520 */
+  {    34,      5,     12,      0,    -28,     34,      0, }, /* 521 */
+  {    34,     14,     12,      0,     16,     34,      0, }, /* 522 */
+  {    34,     14,     12,      0,    -16,     34,      0, }, /* 523 */
+  {    34,     14,     12,      0,      0,     34,      0, }, /* 524 */
+  {    10,     25,     14,      0,      0,     10,      0, }, /* 525 */
+  {    10,     26,     12,      0,     26,     10,      0, }, /* 526 */
+  {    10,     26,     14,      0,     26,     10,      0, }, /* 527 */
+  {    10,     26,     12,      0,    -26,     10,      0, }, /* 528 */
+  {     5,     26,     12,      0,      0,      5,      0, }, /* 529 */
+  {    18,      9,     12,      0,     48,     18,      0, }, /* 530 */
+  {    18,      5,     12,      0,    -48,     18,      0, }, /* 531 */
+  {    34,      9,     12,      0, -10743,     34,      0, }, /* 532 */
+  {    34,      9,     12,      0,  -3814,     34,      0, }, /* 533 */
+  {    34,      9,     12,      0, -10727,     34,      0, }, /* 534 */
+  {    34,      5,     12,      0, -10795,     34,      0, }, /* 535 */
+  {    34,      5,     12,      0, -10792,     34,      0, }, /* 536 */
+  {    34,      9,     12,      0, -10780,     34,      0, }, /* 537 */
+  {    34,      9,     12,      0, -10749,     34,      0, }, /* 538 */
+  {    34,      9,     12,      0, -10783,     34,      0, }, /* 539 */
+  {    34,      9,     12,      0, -10782,     34,      0, }, /* 540 */
+  {    34,      9,     12,      0, -10815,     34,      0, }, /* 541 */
+  {    11,      5,     12,      0,      0,     11,      0, }, /* 542 */
+  {    11,     26,     12,      0,      0,     11,      0, }, /* 543 */
+  {    11,     12,      3,      0,      0,     11,      0, }, /* 544 */
+  {    11,     21,     12,      0,      0,     11,      0, }, /* 545 */
+  {    11,     15,     12,      0,      0,     11,      0, }, /* 546 */
+  {    17,      5,     12,      0,  -7264,     17,      0, }, /* 547 */
+  {    59,      7,     12,      0,      0,     59,      0, }, /* 548 */
+  {    59,      6,     12,      0,      0,     59,      0, }, /* 549 */
+  {    59,     21,     12,      0,      0,     59,      0, }, /* 550 */
+  {    59,     12,      3,      0,      0,     59,      0, }, /* 551 */
+  {    13,     12,      3,      0,      0,     13,      0, }, /* 552 */
+  {    10,     21,     12,      0,      0,    -25,      0, }, /* 553 */
+  {    23,     26,     12,      0,      0,     23,      0, }, /* 554 */
+  {    10,     21,     12,      0,      0,   -139,      0, }, /* 555 */
+  {    10,     21,     12,      0,      0,   -133,      0, }, /* 556 */
+  {    23,      6,     12,      0,      0,     23,      0, }, /* 557 */
+  {    10,      7,     12,      0,      0,     23,      0, }, /* 558 */
+  {    23,     14,     12,      0,      0,     23,      0, }, /* 559 */
+  {    10,     22,     12,      0,      0,   -139,      0, }, /* 560 */
+  {    10,     18,     12,      0,      0,   -139,      0, }, /* 561 */
+  {    10,     26,     12,      0,      0,   -133,      0, }, /* 562 */
+  {    10,     17,     12,      0,      0,   -133,      0, }, /* 563 */
+  {    10,     22,     12,      0,      0,   -133,      0, }, /* 564 */
+  {    10,     18,     12,      0,      0,   -133,      0, }, /* 565 */
+  {    28,     12,      3,      0,      0,    -16,      0, }, /* 566 */
+  {    24,     10,      3,      0,      0,     24,      0, }, /* 567 */
+  {    10,     17,     14,      0,      0,   -133,      0, }, /* 568 */
+  {    10,      6,     12,      0,      0,    -64,      0, }, /* 569 */
+  {    10,      7,     12,      0,      0,   -104,      0, }, /* 570 */
+  {    10,     21,     14,      0,      0,   -104,      0, }, /* 571 */
+  {    10,     26,     12,      0,      0,     23,      0, }, /* 572 */
+  {    27,      7,     12,      0,      0,     27,      0, }, /* 573 */
+  {    28,     12,      3,      0,      0,    -64,      0, }, /* 574 */
+  {    10,     24,     12,      0,      0,    -64,      0, }, /* 575 */
+  {    27,      6,     12,      0,      0,     27,      0, }, /* 576 */
+  {    10,     17,     12,      0,      0,    -64,      0, }, /* 577 */
+  {    30,      7,     12,      0,      0,     30,      0, }, /* 578 */
+  {    30,      6,     12,      0,      0,     30,      0, }, /* 579 */
+  {     4,      7,     12,      0,      0,      4,      0, }, /* 580 */
+  {    24,      7,     12,      0,      0,     24,      0, }, /* 581 */
+  {    10,     15,     12,      0,      0,     23,      0, }, /* 582 */
+  {    24,     26,     12,      0,      0,     24,      0, }, /* 583 */
+  {    10,     26,     14,      0,      0,     23,      0, }, /* 584 */
+  {    30,     26,     12,      0,      0,     30,      0, }, /* 585 */
+  {    23,      7,     12,      0,      0,     23,      0, }, /* 586 */
+  {    61,      7,     12,      0,      0,     61,      0, }, /* 587 */
+  {    61,      6,     12,      0,      0,     61,      0, }, /* 588 */
+  {    61,     26,     12,      0,      0,     61,      0, }, /* 589 */
+  {    86,      7,     12,      0,      0,     86,      0, }, /* 590 */
+  {    86,      6,     12,      0,      0,     86,      0, }, /* 591 */
+  {    86,     21,     12,      0,      0,     86,      0, }, /* 592 */
+  {    77,      7,     12,      0,      0,     77,      0, }, /* 593 */
+  {    77,      6,     12,      0,      0,     77,      0, }, /* 594 */
+  {    77,     21,     12,      0,      0,     77,      0, }, /* 595 */
+  {    77,     13,     12,      0,      0,     77,      0, }, /* 596 */
+  {    13,      9,     12,    108,      1,     13,      0, }, /* 597 */
+  {    13,      5,     12,    108, -35267,     13,      0, }, /* 598 */
+  {    13,      7,     12,      0,      0,     13,      0, }, /* 599 */
+  {    13,     21,     12,      0,      0,     13,      0, }, /* 600 */
+  {    79,      7,     12,      0,      0,     79,      0, }, /* 601 */
+  {    79,     14,     12,      0,      0,     79,      0, }, /* 602 */
+  {    79,     12,      3,      0,      0,     79,      0, }, /* 603 */
+  {    79,     21,     12,      0,      0,     79,      0, }, /* 604 */
+  {    10,     24,     12,      0,      0,    -61,      0, }, /* 605 */
+  {    34,      9,     12,      0, -35332,     34,      0, }, /* 606 */
+  {    34,      9,     12,      0, -42280,     34,      0, }, /* 607 */
+  {    34,      5,     12,      0,     48,     34,      0, }, /* 608 */
+  {    34,      9,     12,      0, -42308,     34,      0, }, /* 609 */
+  {    34,      9,     12,      0, -42319,     34,      0, }, /* 610 */
+  {    34,      9,     12,      0, -42315,     34,      0, }, /* 611 */
+  {    34,      9,     12,      0, -42305,     34,      0, }, /* 612 */
+  {    34,      9,     12,      0, -42258,     34,      0, }, /* 613 */
+  {    34,      9,     12,      0, -42282,     34,      0, }, /* 614 */
+  {    34,      9,     12,      0, -42261,     34,      0, }, /* 615 */
+  {    34,      9,     12,      0,    928,     34,      0, }, /* 616 */
+  {    34,      9,     12,      0,    -48,     34,      0, }, /* 617 */
+  {    34,      9,     12,      0, -42307,     34,      0, }, /* 618 */
+  {    34,      9,     12,      0, -35384,     34,      0, }, /* 619 */
+  {    49,      7,     12,      0,      0,     49,      0, }, /* 620 */
+  {    49,     12,      3,      0,      0,     49,      0, }, /* 621 */
+  {    49,     10,      5,      0,      0,     49,      0, }, /* 622 */
+  {    49,     26,     12,      0,      0,     49,      0, }, /* 623 */
+  {    10,     15,     12,      0,      0,   -224,      0, }, /* 624 */
+  {    10,     15,     12,      0,      0,   -210,      0, }, /* 625 */
+  {    10,     26,     12,      0,      0,   -171,      0, }, /* 626 */
+  {    10,     23,     12,      0,      0,   -171,      0, }, /* 627 */
+  {    65,      7,     12,      0,      0,     65,      0, }, /* 628 */
+  {    65,     21,     12,      0,      0,     65,      0, }, /* 629 */
+  {    75,     10,      5,      0,      0,     75,      0, }, /* 630 */
+  {    75,      7,     12,      0,      0,     75,      0, }, /* 631 */
+  {    75,     12,      3,      0,      0,     75,      0, }, /* 632 */
+  {    75,     21,     12,      0,      0,     75,      0, }, /* 633 */
+  {    75,     13,     12,      0,      0,     75,      0, }, /* 634 */
+  {    15,     12,      3,      0,      0,    -13,      0, }, /* 635 */
+  {    15,      7,     12,      0,      0,    -46,      0, }, /* 636 */
+  {    69,     13,     12,      0,      0,     69,      0, }, /* 637 */
+  {    69,      7,     12,      0,      0,     69,      0, }, /* 638 */
+  {    69,     12,      3,      0,      0,     69,      0, }, /* 639 */
+  {    10,     21,     12,      0,      0,   -108,      0, }, /* 640 */
+  {    69,     21,     12,      0,      0,     69,      0, }, /* 641 */
+  {    74,      7,     12,      0,      0,     74,      0, }, /* 642 */
+  {    74,     12,      3,      0,      0,     74,      0, }, /* 643 */
+  {    74,     10,      5,      0,      0,     74,      0, }, /* 644 */
+  {    74,     21,     12,      0,      0,     74,      0, }, /* 645 */
+  {    84,     12,      3,      0,      0,     84,      0, }, /* 646 */
+  {    84,     10,      5,      0,      0,     84,      0, }, /* 647 */
+  {    84,      7,     12,      0,      0,     84,      0, }, /* 648 */
+  {    84,     21,     12,      0,      0,     84,      0, }, /* 649 */
+  {    10,      6,     12,      0,      0,    -19,      0, }, /* 650 */
+  {    84,     13,     12,      0,      0,     84,      0, }, /* 651 */
+  {    39,      6,     12,      0,      0,     39,      0, }, /* 652 */
+  {    68,      7,     12,      0,      0,     68,      0, }, /* 653 */
+  {    68,     12,      3,      0,      0,     68,      0, }, /* 654 */
+  {    68,     10,      5,      0,      0,     68,      0, }, /* 655 */
+  {    68,     13,     12,      0,      0,     68,      0, }, /* 656 */
+  {    68,     21,     12,      0,      0,     68,      0, }, /* 657 */
+  {    92,      7,     12,      0,      0,     92,      0, }, /* 658 */
+  {    92,     12,      3,      0,      0,     92,      0, }, /* 659 */
+  {    92,      6,     12,      0,      0,     92,      0, }, /* 660 */
+  {    92,     21,     12,      0,      0,     92,      0, }, /* 661 */
+  {    87,      7,     12,      0,      0,     87,      0, }, /* 662 */
+  {    87,     10,      5,      0,      0,     87,      0, }, /* 663 */
+  {    87,     12,      3,      0,      0,     87,      0, }, /* 664 */
+  {    87,     21,     12,      0,      0,     87,      0, }, /* 665 */
+  {    87,      6,     12,      0,      0,     87,      0, }, /* 666 */
+  {    34,      5,     12,      0,   -928,     34,      0, }, /* 667 */
+  {     9,      5,     12,      0, -38864,      9,      0, }, /* 668 */
+  {    87,     13,     12,      0,      0,     87,      0, }, /* 669 */
+  {    24,      7,      9,      0,      0,     24,      0, }, /* 670 */
+  {    24,      7,     10,      0,      0,     24,      0, }, /* 671 */
+  {     0,      4,     12,      0,      0,      0,      0, }, /* 672 */
+  {     0,      3,     12,      0,      0,      0,      0, }, /* 673 */
+  {    26,     25,     12,      0,      0,     26,      0, }, /* 674 */
+  {     1,     24,     12,      0,      0,      1,      0, }, /* 675 */
+  {     1,      7,     12,      0,      0,    -10,      0, }, /* 676 */
+  {     1,     26,     12,      0,      0,    -10,      0, }, /* 677 */
+  {    10,      6,      3,      0,      0,    -64,      0, }, /* 678 */
+  {    36,      7,     12,      0,      0,     36,      0, }, /* 679 */
+  {    10,     21,     12,      0,      0,    -22,      0, }, /* 680 */
+  {    10,     15,     12,      0,      0,    -92,      0, }, /* 681 */
+  {    10,     26,     12,      0,      0,    -22,      0, }, /* 682 */
+  {    20,     14,     12,      0,      0,     20,      0, }, /* 683 */
+  {    20,     15,     12,      0,      0,     20,      0, }, /* 684 */
+  {    20,     26,     12,      0,      0,     20,      0, }, /* 685 */
+  {    71,      7,     12,      0,      0,     71,      0, }, /* 686 */
+  {    67,      7,     12,      0,      0,     67,      0, }, /* 687 */
+  {    28,     12,      3,      0,      0,     -1,      0, }, /* 688 */
+  {    10,     15,     12,      0,      0,     -1,      0, }, /* 689 */
+  {    42,      7,     12,      0,      0,     42,      0, }, /* 690 */
+  {    42,     15,     12,      0,      0,     42,      0, }, /* 691 */
+  {    19,      7,     12,      0,      0,     19,      0, }, /* 692 */
+  {    19,     14,     12,      0,      0,     19,      0, }, /* 693 */
+  {   118,      7,     12,      0,      0,    118,      0, }, /* 694 */
+  {   118,     12,      3,      0,      0,    118,      0, }, /* 695 */
+  {    60,      7,     12,      0,      0,     60,      0, }, /* 696 */
+  {    60,     21,     12,      0,      0,     60,      0, }, /* 697 */
+  {    43,      7,     12,      0,      0,     43,      0, }, /* 698 */
+  {    43,     21,     12,      0,      0,     43,      0, }, /* 699 */
+  {    43,     14,     12,      0,      0,     43,      0, }, /* 700 */
+  {    14,      9,     12,      0,     40,     14,      0, }, /* 701 */
+  {    14,      5,     12,      0,    -40,     14,      0, }, /* 702 */
+  {    47,      7,     12,      0,      0,     47,      0, }, /* 703 */
+  {    45,      7,     12,      0,      0,     45,      0, }, /* 704 */
+  {    45,     13,     12,      0,      0,     45,      0, }, /* 705 */
+  {   136,      9,     12,      0,     40,    136,      0, }, /* 706 */
+  {   136,      5,     12,      0,    -40,    136,      0, }, /* 707 */
+  {   106,      7,     12,      0,      0,    106,      0, }, /* 708 */
+  {   104,      7,     12,      0,      0,    104,      0, }, /* 709 */
+  {   104,     21,     12,      0,      0,    104,      0, }, /* 710 */
+  {   110,      7,     12,      0,      0,    110,      0, }, /* 711 */
+  {    12,      7,     12,      0,      0,     12,      0, }, /* 712 */
+  {    81,      7,     12,      0,      0,     81,      0, }, /* 713 */
+  {    81,     21,     12,      0,      0,     81,      0, }, /* 714 */
+  {    81,     15,     12,      0,      0,     81,      0, }, /* 715 */
+  {   120,      7,     12,      0,      0,    120,      0, }, /* 716 */
+  {   120,     26,     12,      0,      0,    120,      0, }, /* 717 */
+  {   120,     15,     12,      0,      0,    120,      0, }, /* 718 */
+  {   116,      7,     12,      0,      0,    116,      0, }, /* 719 */
+  {   116,     15,     12,      0,      0,    116,      0, }, /* 720 */
+  {   128,      7,     12,      0,      0,    128,      0, }, /* 721 */
+  {   128,     15,     12,      0,      0,    128,      0, }, /* 722 */
+  {    66,      7,     12,      0,      0,     66,      0, }, /* 723 */
+  {    66,     15,     12,      0,      0,     66,      0, }, /* 724 */
+  {    66,     21,     12,      0,      0,     66,      0, }, /* 725 */
+  {    72,      7,     12,      0,      0,     72,      0, }, /* 726 */
+  {    72,     21,     12,      0,      0,     72,      0, }, /* 727 */
+  {    98,      7,     12,      0,      0,     98,      0, }, /* 728 */
+  {    97,      7,     12,      0,      0,     97,      0, }, /* 729 */
+  {    97,     15,     12,      0,      0,     97,      0, }, /* 730 */
+  {    31,      7,     12,      0,      0,     31,      0, }, /* 731 */
+  {    31,     12,      3,      0,      0,     31,      0, }, /* 732 */
+  {    31,     15,     12,      0,      0,     31,      0, }, /* 733 */
+  {    31,     21,     12,      0,      0,     31,      0, }, /* 734 */
+  {    88,      7,     12,      0,      0,     88,      0, }, /* 735 */
+  {    88,     15,     12,      0,      0,     88,      0, }, /* 736 */
+  {    88,     21,     12,      0,      0,     88,      0, }, /* 737 */
+  {   117,      7,     12,      0,      0,    117,      0, }, /* 738 */
+  {   117,     15,     12,      0,      0,    117,      0, }, /* 739 */
+  {   112,      7,     12,      0,      0,    112,      0, }, /* 740 */
+  {   112,     26,     12,      0,      0,    112,      0, }, /* 741 */
+  {   112,     12,      3,      0,      0,    112,      0, }, /* 742 */
+  {   112,     15,     12,      0,      0,    112,      0, }, /* 743 */
+  {   112,     21,     12,      0,      0,    112,      0, }, /* 744 */
+  {    78,      7,     12,      0,      0,     78,      0, }, /* 745 */
+  {    78,     21,     12,      0,      0,     78,      0, }, /* 746 */
+  {    83,      7,     12,      0,      0,     83,      0, }, /* 747 */
+  {    83,     15,     12,      0,      0,     83,      0, }, /* 748 */
+  {    82,      7,     12,      0,      0,     82,      0, }, /* 749 */
+  {    82,     15,     12,      0,      0,     82,      0, }, /* 750 */
+  {   121,      7,     12,      0,      0,    121,      0, }, /* 751 */
+  {   121,     21,     12,      0,      0,    121,      0, }, /* 752 */
+  {   121,     15,     12,      0,      0,    121,      0, }, /* 753 */
+  {    89,      7,     12,      0,      0,     89,      0, }, /* 754 */
+  {   130,      9,     12,      0,     64,    130,      0, }, /* 755 */
+  {   130,      5,     12,      0,    -64,    130,      0, }, /* 756 */
+  {   130,     15,     12,      0,      0,    130,      0, }, /* 757 */
+  {   144,      7,     12,      0,      0,    144,      0, }, /* 758 */
+  {   144,     12,      3,      0,      0,    144,      0, }, /* 759 */
+  {   144,     13,     12,      0,      0,    144,      0, }, /* 760 */
+  {     1,     15,     12,      0,      0,      1,      0, }, /* 761 */
+  {   156,      7,     12,      0,      0,    156,      0, }, /* 762 */
+  {   156,     12,      3,      0,      0,    156,      0, }, /* 763 */
+  {   156,     17,     12,      0,      0,    156,      0, }, /* 764 */
+  {   147,      7,     12,      0,      0,    147,      0, }, /* 765 */
+  {   147,     15,     12,      0,      0,    147,      0, }, /* 766 */
+  {   148,      7,     12,      0,      0,    148,      0, }, /* 767 */
+  {   148,     12,      3,      0,      0,    148,      0, }, /* 768 */
+  {   148,     15,     12,      0,      0,    148,      0, }, /* 769 */
+  {   148,     21,     12,      0,      0,    148,      0, }, /* 770 */
+  {   153,      7,     12,      0,      0,    153,      0, }, /* 771 */
+  {   153,     15,     12,      0,      0,    153,      0, }, /* 772 */
+  {   149,      7,     12,      0,      0,    149,      0, }, /* 773 */
+  {    94,     10,      5,      0,      0,     94,      0, }, /* 774 */
+  {    94,     12,      3,      0,      0,     94,      0, }, /* 775 */
+  {    94,      7,     12,      0,      0,     94,      0, }, /* 776 */
+  {    94,     21,     12,      0,      0,     94,      0, }, /* 777 */
+  {    94,     15,     12,      0,      0,     94,      0, }, /* 778 */
+  {    94,     13,     12,      0,      0,     94,      0, }, /* 779 */
+  {    85,     12,      3,      0,      0,     85,      0, }, /* 780 */
+  {    85,     10,      5,      0,      0,     85,      0, }, /* 781 */
+  {    85,      7,     12,      0,      0,     85,      0, }, /* 782 */
+  {    85,     21,     12,      0,      0,     85,      0, }, /* 783 */
+  {    85,      1,      4,      0,      0,     85,      0, }, /* 784 */
+  {   101,      7,     12,      0,      0,    101,      0, }, /* 785 */
+  {   101,     13,     12,      0,      0,    101,      0, }, /* 786 */
+  {    96,     12,      3,      0,      0,     96,      0, }, /* 787 */
+  {    96,      7,     12,      0,      0,     96,      0, }, /* 788 */
+  {    96,     10,      5,      0,      0,     96,      0, }, /* 789 */
+  {    96,     13,     12,      0,      0,     96,      0, }, /* 790 */
+  {    96,     21,     12,      0,      0,     96,      0, }, /* 791 */
+  {   111,      7,     12,      0,      0,    111,      0, }, /* 792 */
+  {   111,     12,      3,      0,      0,    111,      0, }, /* 793 */
+  {   111,     21,     12,      0,      0,    111,      0, }, /* 794 */
+  {   100,     12,      3,      0,      0,    100,      0, }, /* 795 */
+  {   100,     10,      5,      0,      0,    100,      0, }, /* 796 */
+  {   100,      7,     12,      0,      0,    100,      0, }, /* 797 */
+  {   100,      7,      4,      0,      0,    100,      0, }, /* 798 */
+  {   100,     21,     12,      0,      0,    100,      0, }, /* 799 */
+  {   100,     13,     12,      0,      0,    100,      0, }, /* 800 */
+  {    48,     15,     12,      0,      0,     48,      0, }, /* 801 */
+  {   108,      7,     12,      0,      0,    108,      0, }, /* 802 */
+  {   108,     10,      5,      0,      0,    108,      0, }, /* 803 */
+  {   108,     12,      3,      0,      0,    108,      0, }, /* 804 */
+  {   108,     21,     12,      0,      0,    108,      0, }, /* 805 */
+  {   129,      7,     12,      0,      0,    129,      0, }, /* 806 */
+  {   129,     21,     12,      0,      0,    129,      0, }, /* 807 */
+  {   109,      7,     12,      0,      0,    109,      0, }, /* 808 */
+  {   109,     12,      3,      0,      0,    109,      0, }, /* 809 */
+  {   109,     10,      5,      0,      0,    109,      0, }, /* 810 */
+  {   109,     13,     12,      0,      0,    109,      0, }, /* 811 */
+  {   107,     12,      3,      0,      0,    107,      0, }, /* 812 */
+  {   107,     12,      3,      0,      0,    -52,      0, }, /* 813 */
+  {   107,     10,      5,      0,      0,    107,      0, }, /* 814 */
+  {   107,     10,      5,      0,      0,    -52,      0, }, /* 815 */
+  {   107,      7,     12,      0,      0,    107,      0, }, /* 816 */
+  {    28,     12,      3,      0,      0,    -52,      0, }, /* 817 */
+  {   107,     10,      3,      0,      0,    107,      0, }, /* 818 */
+  {   135,      7,     12,      0,      0,    135,      0, }, /* 819 */
+  {   135,     10,      5,      0,      0,    135,      0, }, /* 820 */
+  {   135,     12,      3,      0,      0,    135,      0, }, /* 821 */
+  {   135,     21,     12,      0,      0,    135,      0, }, /* 822 */
+  {   135,     13,     12,      0,      0,    135,      0, }, /* 823 */
+  {   124,      7,     12,      0,      0,    124,      0, }, /* 824 */
+  {   124,     10,      3,      0,      0,    124,      0, }, /* 825 */
+  {   124,     10,      5,      0,      0,    124,      0, }, /* 826 */
+  {   124,     12,      3,      0,      0,    124,      0, }, /* 827 */
+  {   124,     21,     12,      0,      0,    124,      0, }, /* 828 */
+  {   124,     13,     12,      0,      0,    124,      0, }, /* 829 */
+  {   123,      7,     12,      0,      0,    123,      0, }, /* 830 */
+  {   123,     10,      3,      0,      0,    123,      0, }, /* 831 */
+  {   123,     10,      5,      0,      0,    123,      0, }, /* 832 */
+  {   123,     12,      3,      0,      0,    123,      0, }, /* 833 */
+  {   123,     21,     12,      0,      0,    123,      0, }, /* 834 */
+  {   114,      7,     12,      0,      0,    114,      0, }, /* 835 */
+  {   114,     10,      5,      0,      0,    114,      0, }, /* 836 */
+  {   114,     12,      3,      0,      0,    114,      0, }, /* 837 */
+  {   114,     21,     12,      0,      0,    114,      0, }, /* 838 */
+  {   114,     13,     12,      0,      0,    114,      0, }, /* 839 */
+  {   102,      7,     12,      0,      0,    102,      0, }, /* 840 */
+  {   102,     12,      3,      0,      0,    102,      0, }, /* 841 */
+  {   102,     10,      5,      0,      0,    102,      0, }, /* 842 */
+  {   102,     13,     12,      0,      0,    102,      0, }, /* 843 */
+  {   126,      7,     12,      0,      0,    126,      0, }, /* 844 */
+  {   126,     12,      3,      0,      0,    126,      0, }, /* 845 */
+  {   126,     10,      5,      0,      0,    126,      0, }, /* 846 */
+  {   126,     13,     12,      0,      0,    126,      0, }, /* 847 */
+  {   126,     15,     12,      0,      0,    126,      0, }, /* 848 */
+  {   126,     21,     12,      0,      0,    126,      0, }, /* 849 */
+  {   126,     26,     12,      0,      0,    126,      0, }, /* 850 */
+  {   142,      7,     12,      0,      0,    142,      0, }, /* 851 */
+  {   142,     10,      5,      0,      0,    142,      0, }, /* 852 */
+  {   142,     12,      3,      0,      0,    142,      0, }, /* 853 */
+  {   142,     21,     12,      0,      0,    142,      0, }, /* 854 */
+  {   125,      9,     12,      0,     32,    125,      0, }, /* 855 */
+  {   125,      5,     12,      0,    -32,    125,      0, }, /* 856 */
+  {   125,     13,     12,      0,      0,    125,      0, }, /* 857 */
+  {   125,     15,     12,      0,      0,    125,      0, }, /* 858 */
+  {   125,      7,     12,      0,      0,    125,      0, }, /* 859 */
+  {   154,      7,     12,      0,      0,    154,      0, }, /* 860 */
+  {   154,     10,      3,      0,      0,    154,      0, }, /* 861 */
+  {   154,     10,      5,      0,      0,    154,      0, }, /* 862 */
+  {   154,     12,      3,      0,      0,    154,      0, }, /* 863 */
+  {   154,      7,      4,      0,      0,    154,      0, }, /* 864 */
+  {   154,     21,     12,      0,      0,    154,      0, }, /* 865 */
+  {   154,     13,     12,      0,      0,    154,      0, }, /* 866 */
+  {   150,      7,     12,      0,      0,    150,      0, }, /* 867 */
+  {   150,     10,      5,      0,      0,    150,      0, }, /* 868 */
+  {   150,     12,      3,      0,      0,    150,      0, }, /* 869 */
+  {   150,     21,     12,      0,      0,    150,      0, }, /* 870 */
+  {   141,      7,     12,      0,      0,    141,      0, }, /* 871 */
+  {   141,     12,      3,      0,      0,    141,      0, }, /* 872 */
+  {   141,     10,      5,      0,      0,    141,      0, }, /* 873 */
+  {   141,      7,      4,      0,      0,    141,      0, }, /* 874 */
+  {   141,     21,     12,      0,      0,    141,      0, }, /* 875 */
+  {   140,      7,     12,      0,      0,    140,      0, }, /* 876 */
+  {   140,     12,      3,      0,      0,    140,      0, }, /* 877 */
+  {   140,     10,      5,      0,      0,    140,      0, }, /* 878 */
+  {   140,      7,      4,      0,      0,    140,      0, }, /* 879 */
+  {   140,     21,     12,      0,      0,    140,      0, }, /* 880 */
+  {   122,      7,     12,      0,      0,    122,      0, }, /* 881 */
+  {   133,      7,     12,      0,      0,    133,      0, }, /* 882 */
+  {   133,     10,      5,      0,      0,    133,      0, }, /* 883 */
+  {   133,     12,      3,      0,      0,    133,      0, }, /* 884 */
+  {   133,     21,     12,      0,      0,    133,      0, }, /* 885 */
+  {   133,     13,     12,      0,      0,    133,      0, }, /* 886 */
+  {   133,     15,     12,      0,      0,    133,      0, }, /* 887 */
+  {   134,     21,     12,      0,      0,    134,      0, }, /* 888 */
+  {   134,      7,     12,      0,      0,    134,      0, }, /* 889 */
+  {   134,     12,      3,      0,      0,    134,      0, }, /* 890 */
+  {   134,     10,      5,      0,      0,    134,      0, }, /* 891 */
+  {   138,      7,     12,      0,      0,    138,      0, }, /* 892 */
+  {   138,     12,      3,      0,      0,    138,      0, }, /* 893 */
+  {   138,      7,      4,      0,      0,    138,      0, }, /* 894 */
+  {   138,     13,     12,      0,      0,    138,      0, }, /* 895 */
+  {   143,      7,     12,      0,      0,    143,      0, }, /* 896 */
+  {   143,     10,      5,      0,      0,    143,      0, }, /* 897 */
+  {   143,     12,      3,      0,      0,    143,      0, }, /* 898 */
+  {   143,     13,     12,      0,      0,    143,      0, }, /* 899 */
+  {   145,      7,     12,      0,      0,    145,      0, }, /* 900 */
+  {   145,     12,      3,      0,      0,    145,      0, }, /* 901 */
+  {   145,     10,      5,      0,      0,    145,      0, }, /* 902 */
+  {   145,     21,     12,      0,      0,    145,      0, }, /* 903 */
+  {    54,     15,     12,      0,      0,     54,      0, }, /* 904 */
+  {    54,     21,     12,      0,      0,     54,      0, }, /* 905 */
+  {    63,      7,     12,      0,      0,     63,      0, }, /* 906 */
+  {    63,     14,     12,      0,      0,     63,      0, }, /* 907 */
+  {    63,     21,     12,      0,      0,     63,      0, }, /* 908 */
+  {    80,      7,     12,      0,      0,     80,      0, }, /* 909 */
+  {    80,      1,      2,      0,      0,     80,      0, }, /* 910 */
+  {   127,      7,     12,      0,      0,    127,      0, }, /* 911 */
+  {   115,      7,     12,      0,      0,    115,      0, }, /* 912 */
+  {   115,     13,     12,      0,      0,    115,      0, }, /* 913 */
+  {   115,     21,     12,      0,      0,    115,      0, }, /* 914 */
+  {   103,      7,     12,      0,      0,    103,      0, }, /* 915 */
+  {   103,     12,      3,      0,      0,    103,      0, }, /* 916 */
+  {   103,     21,     12,      0,      0,    103,      0, }, /* 917 */
+  {   119,      7,     12,      0,      0,    119,      0, }, /* 918 */
+  {   119,     12,      3,      0,      0,    119,      0, }, /* 919 */
+  {   119,     21,     12,      0,      0,    119,      0, }, /* 920 */
+  {   119,     26,     12,      0,      0,    119,      0, }, /* 921 */
+  {   119,      6,     12,      0,      0,    119,      0, }, /* 922 */
+  {   119,     13,     12,      0,      0,    119,      0, }, /* 923 */
+  {   119,     15,     12,      0,      0,    119,      0, }, /* 924 */
+  {   146,      9,     12,      0,     32,    146,      0, }, /* 925 */
+  {   146,      5,     12,      0,    -32,    146,      0, }, /* 926 */
+  {   146,     15,     12,      0,      0,    146,      0, }, /* 927 */
+  {   146,     21,     12,      0,      0,    146,      0, }, /* 928 */
+  {    99,      7,     12,      0,      0,     99,      0, }, /* 929 */
+  {    99,     12,      3,      0,      0,     99,      0, }, /* 930 */
+  {    99,     10,      5,      0,      0,     99,      0, }, /* 931 */
+  {    99,      6,     12,      0,      0,     99,      0, }, /* 932 */
+  {   137,      6,     12,      0,      0,    137,      0, }, /* 933 */
+  {   139,      6,     12,      0,      0,    139,      0, }, /* 934 */
+  {   155,     12,      3,      0,      0,    155,      0, }, /* 935 */
+  {    23,     10,      5,      0,      0,     23,      0, }, /* 936 */
+  {   137,      7,     12,      0,      0,    137,      0, }, /* 937 */
+  {   155,      7,     12,      0,      0,    155,      0, }, /* 938 */
+  {   139,      7,     12,      0,      0,    139,      0, }, /* 939 */
+  {   105,      7,     12,      0,      0,    105,      0, }, /* 940 */
+  {   105,     26,     12,      0,      0,    105,      0, }, /* 941 */
+  {   105,     12,      3,      0,      0,    105,      0, }, /* 942 */
+  {   105,     21,     12,      0,      0,    105,      0, }, /* 943 */
+  {    10,      1,      2,      0,      0,    105,      0, }, /* 944 */
+  {    10,     10,      3,      0,      0,     10,      0, }, /* 945 */
+  {    10,     10,      5,      0,      0,     10,      0, }, /* 946 */
+  {    20,     12,      3,      0,      0,     20,      0, }, /* 947 */
+  {   131,     26,     12,      0,      0,    131,      0, }, /* 948 */
+  {   131,     12,      3,      0,      0,    131,      0, }, /* 949 */
+  {   131,     21,     12,      0,      0,    131,      0, }, /* 950 */
+  {    18,     12,      3,      0,      0,     18,      0, }, /* 951 */
+  {   151,      7,     12,      0,      0,    151,      0, }, /* 952 */
+  {   151,     12,      3,      0,      0,    151,      0, }, /* 953 */
+  {   151,      6,     12,      0,      0,    151,      0, }, /* 954 */
+  {   151,     13,     12,      0,      0,    151,      0, }, /* 955 */
+  {   151,     26,     12,      0,      0,    151,      0, }, /* 956 */
+  {   152,      7,     12,      0,      0,    152,      0, }, /* 957 */
+  {   152,     12,      3,      0,      0,    152,      0, }, /* 958 */
+  {   152,     13,     12,      0,      0,    152,      0, }, /* 959 */
+  {   152,     23,     12,      0,      0,    152,      0, }, /* 960 */
+  {   113,      7,     12,      0,      0,    113,      0, }, /* 961 */
+  {   113,     15,     12,      0,      0,    113,      0, }, /* 962 */
+  {   113,     12,      3,      0,      0,    113,      0, }, /* 963 */
+  {   132,      9,     12,      0,     34,    132,      0, }, /* 964 */
+  {   132,      5,     12,      0,    -34,    132,      0, }, /* 965 */
+  {   132,     12,      3,      0,      0,    132,      0, }, /* 966 */
+  {   132,      6,     12,      0,      0,    132,      0, }, /* 967 */
+  {   132,     13,     12,      0,      0,    132,      0, }, /* 968 */
+  {   132,     21,     12,      0,      0,    132,      0, }, /* 969 */
+  {     0,      2,     14,      0,      0,      0,      0, }, /* 970 */
+  {    10,     26,     11,      0,      0,     10,      0, }, /* 971 */
+  {    27,     26,     12,      0,      0,     27,      0, }, /* 972 */
+  {    10,     24,      3,      0,      0,     10,      0, }, /* 973 */
+  {    10,      1,      3,      0,      0,     10,      0, }, /* 974 */
+};
+
+const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
+  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, /* U+0000 */
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* U+0800 */
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 41, 41, 42, 43, 44, 45, /* U+1000 */
+ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, /* U+1800 */
+ 62, 63, 64, 65, 66, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, /* U+2000 */
+ 77, 77, 78, 79, 66, 66, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, /* U+2800 */
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 98, 98, 98, 98, 98, 98, 98, /* U+3000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+3800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+4000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 99, 98, 98, 98, 98, /* U+4800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+5000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+5800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+6000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+6800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+7000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+7800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+8000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+8800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+9000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,100, /* U+9800 */
+101,102,102,102,102,102,102,102,102,103,104,104,105,106,107,108, /* U+A000 */
+109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,117, /* U+A800 */
+118,119,120,121,122,123,117,118,119,120,121,122,123,117,118,119, /* U+B000 */
+120,121,122,123,117,118,119,120,121,122,123,117,118,119,120,121, /* U+B800 */
+122,123,117,118,119,120,121,122,123,117,118,119,120,121,122,123, /* U+C000 */
+117,118,119,120,121,122,123,117,118,119,120,121,122,123,117,118, /* U+C800 */
+119,120,121,122,123,117,118,119,120,121,122,123,117,118,119,124, /* U+D000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+D800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+E000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+E800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F000 */
+126,126, 98, 98,127,128,129,130,131,131,132,133,134,135,136,137, /* U+F800 */
+138,139,140,141,142,143,144,145,146,147,148,142,149,149,150,142, /* U+10000 */
+151,152,153,154,155,156,157,158,159,160,161,142,162,163,164,165, /* U+10800 */
+166,167,168,169,170,171,172,142,173,174,142,175,176,177,178,142, /* U+11000 */
+179,180,181,182,183,184,142,142,185,186,187,188,142,189,142,190, /* U+11800 */
+191,191,191,191,191,191,191,192,193,191,194,142,142,142,142,142, /* U+12000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+12800 */
+195,195,195,195,195,195,195,195,196,142,142,142,142,142,142,142, /* U+13000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+13800 */
+142,142,142,142,142,142,142,142,197,197,197,197,198,142,142,142, /* U+14000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+14800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+15000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+15800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+16000 */
+199,199,199,199,200,201,202,203,142,142,142,142,204,205,206,207, /* U+16800 */
+208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, /* U+17000 */
+208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, /* U+17800 */
+208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,209, /* U+18000 */
+208,208,208,208,208,208,210,210,210,211,212,142,142,142,142,142, /* U+18800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+19000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+19800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+1A000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+1A800 */
+213,214,215,216,216,217,142,142,142,142,142,142,142,142,142,142, /* U+1B000 */
+142,142,142,142,142,142,142,142,218,219,142,142,142,142,142,142, /* U+1B800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+1C000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+1C800 */
+ 71,220,221,222,223,224,225,142,226,227,228,229,230,231,232,233, /* U+1D000 */
+234,234,234,234,235,236,142,142,142,142,142,142,142,142,142,142, /* U+1D800 */
+237,142,238,142,142,239,142,142,142,142,142,142,142,142,142,142, /* U+1E000 */
+240,241,242,142,142,142,142,142,243,244,245,142,246,247,142,142, /* U+1E800 */
+248,249,250,251,252,253,254,255,254,254,256,254,257,258,259,260, /* U+1F000 */
+261,262,263,264,265,266, 71,267,253,253,253,253,253,253,253,268, /* U+1F800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+20000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+20800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+21000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+21800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+22000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+22800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+23000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+23800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+24000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+24800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+25000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+25800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+26000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+26800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+27000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+27800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+28000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+28800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+29000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+29800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,269, 98, 98, /* U+2A000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+2A800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,270, 98, /* U+2B000 */
+271, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+2B800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+2C000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,272, 98, 98, /* U+2C800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+2D000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+2D800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+2E000 */
+ 98, 98, 98, 98, 98, 98, 98,273,142,142,142,142,142,142,142,142, /* U+2E800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+2F000 */
+ 98, 98, 98, 98,274,142,142,142,142,142,142,142,142,142,142,142, /* U+2F800 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+30000 */
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, /* U+30800 */
+ 98, 98, 98, 98, 98, 98,275,142,142,142,142,142,142,142,142,142, /* U+31000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+31800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+32000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+32800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+33000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+33800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+34000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+34800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+35000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+35800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+36000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+36800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+37000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+37800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+38000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+38800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+39000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+39800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3A000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3A800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3B000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3B800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3C000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3C800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3D000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3D800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3E000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3E800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3F000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+3F800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+40000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+40800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+41000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+41800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+42000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+42800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+43000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+43800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+44000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+44800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+45000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+45800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+46000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+46800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+47000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+47800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+48000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+48800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+49000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+49800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4A000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4A800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4B000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4B800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4C000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4C800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4D000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4D800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4E000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4E800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4F000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+4F800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+50000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+50800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+51000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+51800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+52000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+52800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+53000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+53800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+54000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+54800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+55000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+55800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+56000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+56800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+57000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+57800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+58000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+58800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+59000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+59800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5A000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5A800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5B000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5B800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5C000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5C800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5D000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5D800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5E000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5E800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5F000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+5F800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+60000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+60800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+61000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+61800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+62000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+62800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+63000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+63800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+64000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+64800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+65000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+65800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+66000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+66800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+67000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+67800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+68000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+68800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+69000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+69800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6A000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6A800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6B000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6B800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6C000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6C800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6D000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6D800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6E000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6E800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6F000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+6F800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+70000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+70800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+71000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+71800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+72000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+72800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+73000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+73800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+74000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+74800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+75000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+75800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+76000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+76800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+77000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+77800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+78000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+78800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+79000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+79800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7A000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7A800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7B000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7B800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7C000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7C800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7D000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7D800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7E000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7E800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7F000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+7F800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+80000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+80800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+81000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+81800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+82000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+82800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+83000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+83800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+84000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+84800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+85000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+85800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+86000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+86800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+87000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+87800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+88000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+88800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+89000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+89800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8A000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8A800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8B000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8B800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8C000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8C800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8D000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8D800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8E000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8E800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8F000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+8F800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+90000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+90800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+91000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+91800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+92000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+92800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+93000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+93800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+94000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+94800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+95000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+95800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+96000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+96800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+97000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+97800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+98000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+98800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+99000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+99800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9A000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9A800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9B000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9B800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9C000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9C800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9D000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9D800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9E000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9E800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9F000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+9F800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A0000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A0800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A1000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A1800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A2000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A2800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A3000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A3800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A4000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A4800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A5000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A5800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A6000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A6800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A7000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A7800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A8000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A8800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A9000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+A9800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AA000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AA800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AB000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AB800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AC000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AC800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AD000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AD800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AE000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AE800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AF000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+AF800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B0000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B0800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B1000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B1800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B2000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B2800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B3000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B3800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B4000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B4800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B5000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B5800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B6000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B6800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B7000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B7800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B8000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B8800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B9000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+B9800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BA000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BA800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BB000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BB800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BC000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BC800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BD000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BD800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BE000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BE800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BF000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+BF800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C0000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C0800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C1000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C1800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C2000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C2800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C3000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C3800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C4000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C4800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C5000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C5800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C6000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C6800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C7000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C7800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C8000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C8800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C9000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+C9800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CA000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CA800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CB000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CB800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CC000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CC800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CD000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CD800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CE000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CE800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CF000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+CF800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D0000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D0800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D1000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D1800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D2000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D2800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D3000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D3800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D4000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D4800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D5000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D5800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D6000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D6800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D7000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D7800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D8000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D8800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D9000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+D9800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DA000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DA800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DB000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DB800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DC000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DC800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DD000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DD800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DE000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DE800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DF000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+DF800 */
+276,277,278,279,277,277,277,277,277,277,277,277,277,277,277,277, /* U+E0000 */
+277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,277, /* U+E0800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E1000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E1800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E2000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E2800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E3000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E3800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E4000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E4800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E5000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E5800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E6000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E6800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E7000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E7800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E8000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E8800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E9000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+E9800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EA000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EA800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EB000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EB800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EC000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EC800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+ED000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+ED800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EE000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EE800 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EF000 */
+142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, /* U+EF800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F0000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F0800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F1000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F1800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F2000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F2800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F3000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F3800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F4000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F4800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F5000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F5800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F6000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F6800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F7000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F7800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F8000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F8800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F9000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+F9800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FA000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FA800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FB000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FB800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FC000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FC800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FD000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FD800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FE000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FE800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+FF000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,280, /* U+FF800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+100000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+100800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+101000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+101800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+102000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+102800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+103000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+103800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+104000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+104800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+105000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+105800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+106000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+106800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+107000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+107800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+108000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+108800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+109000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+109800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10A000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10A800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10B000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10B800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10C000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10C800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10D000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10D800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10E000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10E800 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, /* U+10F000 */
+126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,280, /* U+10F800 */
+};
+
+const uint16_t PRIV(ucd_stage2)[] = { /* 71936 bytes, block = 128 */
+/* block 0 */
+  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  2,  1,  1,  3,  1,  1,
+  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+  4,  5,  5,  5,  6,  5,  5,  5,  7,  8,  5,  9,  5, 10,  5,  5,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,  5,  5,  9,  9,  9,  5,
+  5, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 12, 12, 12, 12,
+ 12, 12, 12, 14, 12, 12, 12, 12, 12, 12, 12,  7,  5,  8, 15, 16,
+ 15, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 17, 17, 17, 17,
+ 17, 17, 17, 19, 17, 17, 17, 17, 17, 17, 17,  7,  9,  8,  9,  1,
+
+/* block 1 */
+  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+  4,  5,  6,  6,  6,  6, 20,  5, 15, 21, 22, 23,  9, 24, 21, 15,
+ 20,  9, 25, 25, 15, 26,  5,  5, 15, 25, 22, 27, 25, 25, 25,  5,
+ 12, 12, 12, 12, 12, 28, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12,  9, 12, 12, 12, 12, 12, 12, 12, 29,
+ 17, 17, 17, 17, 17, 30, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17,  9, 17, 17, 17, 17, 17, 17, 17, 31,
+
+/* block 2 */
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 34, 35, 32, 33, 32, 33, 32, 33, 35, 32, 33, 32, 33, 32, 33, 32,
+ 33, 32, 33, 32, 33, 32, 33, 32, 33, 35, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 36, 32, 33, 32, 33, 32, 33, 37,
+
+/* block 3 */
+ 38, 39, 32, 33, 32, 33, 40, 32, 33, 41, 41, 32, 33, 35, 42, 43,
+ 44, 32, 33, 41, 45, 46, 47, 48, 32, 33, 49, 35, 47, 50, 51, 52,
+ 32, 33, 32, 33, 32, 33, 53, 32, 33, 53, 35, 35, 32, 33, 53, 32,
+ 33, 54, 54, 32, 33, 32, 33, 55, 32, 33, 35, 22, 32, 33, 35, 56,
+ 22, 22, 22, 22, 57, 58, 59, 60, 61, 62, 63, 64, 65, 32, 33, 32,
+ 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 66, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 35, 67, 68, 69, 32, 33, 70, 71, 32, 33, 32, 33, 32, 33, 32, 33,
+
+/* block 4 */
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 72, 35, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 35, 35, 35, 35, 35, 35, 73, 32, 33, 74, 75, 76,
+ 76, 32, 33, 77, 78, 79, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 80, 81, 82, 83, 84, 35, 85, 85, 35, 86, 35, 87, 88, 35, 35, 35,
+ 85, 89, 35, 90, 35, 91, 92, 35, 93, 94, 92, 95, 96, 35, 35, 94,
+ 35, 97, 98, 35, 35, 99, 35, 35, 35, 35, 35, 35, 35,100, 35, 35,
+
+/* block 5 */
+101, 35,102,101, 35, 35, 35,103,101,104,105,105,106, 35, 35, 35,
+ 35, 35,107, 35, 22, 35, 35, 35, 35, 35, 35, 35, 35,108,109, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+110,110,110,110,110,110,110,110,110,111,111,111,111,111,111,111,
+111,111, 15, 15, 15, 15,111,111,111,111,111,111,111,111,111,111,
+111,111, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+110,110,110,110,110, 15, 15, 15, 15, 15,112,112,111, 15,111, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+
+/* block 6 */
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,114,113,113,115,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,116,116,116,116,116,116,116,116,116,116,116,116,116,
+117,118,117,118,111,119,117,118,120,120,121,122,122,122,  5,123,
+
+/* block 7 */
+120,120,120,120,119, 15,124,  5,125,125,125,120,126,120,127,127,
+128,129,130,129,129,131,129,129,132,133,134,129,135,129,129,129,
+136,137,120,138,129,129,139,129,129,140,129,129,141,142,142,142,
+128,143,144,143,143,145,143,143,146,147,148,143,149,143,143,143,
+150,151,152,153,143,143,154,143,143,155,143,143,156,157,157,158,
+159,160,161,161,161,162,163,164,117,118,117,118,117,118,117,118,
+117,118,165,166,165,166,165,166,165,166,165,166,165,166,165,166,
+167,168,169,170,171,172,173,117,118,174,117,118,128,175,175,175,
+
+/* block 8 */
+176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
+177,177,178,177,179,177,177,177,177,177,177,177,177,177,180,177,
+177,181,182,177,177,177,177,177,177,177,183,177,177,177,177,177,
+184,184,185,184,186,184,184,184,184,184,184,184,184,184,187,184,
+184,188,189,184,184,184,184,184,184,184,190,184,184,184,184,184,
+191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,
+192,193,194,195,192,193,192,193,192,193,192,193,192,193,192,193,
+192,193,192,193,192,193,192,193,192,193,192,193,192,193,192,193,
+
+/* block 9 */
+192,193,196,197,198,199,199,198,200,200,192,193,192,193,192,193,
+192,193,192,193,192,193,192,193,192,193,192,193,192,193,192,193,
+192,193,192,193,192,193,192,193,192,193,192,193,192,193,192,193,
+192,193,192,193,192,193,192,193,192,193,192,193,192,193,192,193,
+201,192,193,192,193,192,193,192,193,192,193,192,193,192,193,202,
+192,193,192,193,192,193,192,193,192,193,192,193,192,193,192,193,
+192,193,192,193,192,193,192,193,192,193,192,193,192,193,192,193,
+192,193,192,193,192,193,192,193,192,193,192,193,192,193,192,193,
+
+/* block 10 */
+192,193,192,193,192,193,192,193,192,193,192,193,192,193,192,193,
+192,193,192,193,192,193,192,193,192,193,192,193,192,193,192,193,
+192,193,192,193,192,193,192,193,192,193,192,193,192,193,192,193,
+120,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,
+203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,
+203,203,203,203,203,203,203,120,120,204,205,205,205,205,205,205,
+206,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,
+207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,
+
+/* block 11 */
+207,207,207,207,207,207,207,206,206,205,208,120,120,209,209,210,
+120,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,
+211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,
+211,211,211,211,211,211,211,211,211,211,211,211,211,211,212,211,
+213,211,211,213,211,211,213,211,120,120,120,120,120,120,120,120,
+214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,
+214,214,214,214,214,214,214,214,214,214,214,120,120,120,120,214,
+214,214,214,213,213,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 12 */
+215,215,215,215,215,216,217,217,217,218,218,219,220,218,221,221,
+222,222,222,222,222,222,222,222,222,222,222,220,223,120,218,220,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+225,224,224,224,224,224,224,224,224,224,224,226,226,226,226,226,
+226,226,226,226,226,226,222,222,222,222,222,222,222,222,222,222,
+227,227,227,227,227,227,227,227,227,227,218,218,218,218,224,224,
+226,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+
+/* block 13 */
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,228,224,222,222,222,222,222,222,222,216,221,222,
+222,222,222,222,222,229,229,222,222,221,222,222,222,222,224,224,
+230,230,230,230,230,230,230,230,230,230,224,224,224,221,221,224,
+
+/* block 14 */
+231,231,231,231,231,231,231,231,231,231,231,231,231,231,120,232,
+233,234,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
+233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
+234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,
+234,234,234,234,234,234,234,234,234,234,234,120,120,233,233,233,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+
+/* block 15 */
+235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,
+235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,
+235,235,235,235,235,235,236,236,236,236,236,236,236,236,236,236,
+236,235,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+237,237,237,237,237,237,237,237,237,237,238,238,238,238,238,238,
+238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,
+238,238,238,238,238,238,238,238,238,238,238,239,239,239,239,239,
+239,239,239,239,240,240,241,242,242,242,240,120,120,239,243,243,
+
+/* block 16 */
+244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,
+244,244,244,244,244,244,245,245,245,245,246,245,245,245,245,245,
+245,245,245,245,246,245,245,245,246,245,245,245,245,245,120,120,
+247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,120,
+248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,
+248,248,248,248,248,248,248,248,248,249,249,249,120,120,250,120,
+233,233,233,233,233,233,233,233,233,233,233,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 17 */
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,120,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,120,120,120,120,120,120,120,120,
+120,120,120,222,222,222,222,222,222,222,222,222,222,222,222,222,
+222,222,216,222,222,222,222,222,222,222,222,222,222,222,222,222,
+222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,
+
+/* block 18 */
+251,251,251,252,253,253,253,253,253,253,253,253,253,253,253,253,
+253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,
+253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,
+253,253,253,253,253,253,253,253,253,253,251,252,251,253,252,252,
+252,251,251,251,251,251,251,251,251,252,252,252,252,251,252,252,
+253,254,255,113,113,251,251,251,253,253,253,253,253,253,253,253,
+253,253,251,251,256,257,258,258,258,258,258,258,258,258,258,258,
+259,260,253,253,253,253,253,253,253,253,253,253,253,253,253,253,
+
+/* block 19 */
+261,262,263,263,120,261,261,261,261,261,261,261,261,120,120,261,
+261,120,120,261,261,261,261,261,261,261,261,261,261,261,261,261,
+261,261,261,261,261,261,261,261,261,120,261,261,261,261,261,261,
+261,120,261,120,120,120,261,261,261,261,120,120,262,261,264,263,
+263,262,262,262,262,120,120,263,263,120,120,263,263,262,261,120,
+120,120,120,120,120,120,120,264,120,120,120,120,261,261,120,261,
+261,261,262,262,120,120,265,265,265,265,265,265,265,265,265,265,
+261,261,266,266,267,267,267,267,267,267,268,266,261,269,262,120,
+
+/* block 20 */
+120,270,270,271,120,272,272,272,272,272,272,120,120,120,120,272,
+272,120,120,272,272,272,272,272,272,272,272,272,272,272,272,272,
+272,272,272,272,272,272,272,272,272,120,272,272,272,272,272,272,
+272,120,272,272,120,272,272,120,272,272,120,120,270,120,271,271,
+271,270,270,120,120,120,120,270,270,120,120,270,270,270,120,120,
+120,270,120,120,120,120,120,120,120,272,272,272,272,120,272,120,
+120,120,120,120,120,120,273,273,273,273,273,273,273,273,273,273,
+270,270,272,272,272,270,274,120,120,120,120,120,120,120,120,120,
+
+/* block 21 */
+120,275,275,276,120,277,277,277,277,277,277,277,277,277,120,277,
+277,277,120,277,277,277,277,277,277,277,277,277,277,277,277,277,
+277,277,277,277,277,277,277,277,277,120,277,277,277,277,277,277,
+277,120,277,277,120,277,277,277,277,277,120,120,275,277,276,276,
+276,275,275,275,275,275,120,275,275,276,120,276,276,275,120,120,
+277,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+277,277,275,275,120,120,278,278,278,278,278,278,278,278,278,278,
+279,280,120,120,120,120,120,120,120,277,275,275,275,275,275,275,
+
+/* block 22 */
+120,281,282,282,120,283,283,283,283,283,283,283,283,120,120,283,
+283,120,120,283,283,283,283,283,283,283,283,283,283,283,283,283,
+283,283,283,283,283,283,283,283,283,120,283,283,283,283,283,283,
+283,120,283,283,120,283,283,283,283,283,120,120,281,283,284,281,
+282,281,281,281,281,120,120,282,282,120,120,282,282,281,120,120,
+120,120,120,120,120,281,281,284,120,120,120,120,283,283,120,283,
+283,283,281,281,120,120,285,285,285,285,285,285,285,285,285,285,
+286,283,287,287,287,287,287,287,120,120,120,120,120,120,120,120,
+
+/* block 23 */
+120,120,288,289,120,289,289,289,289,289,289,120,120,120,289,289,
+289,120,289,289,289,289,120,120,120,289,289,120,289,120,289,289,
+120,120,120,289,289,120,120,120,289,289,289,120,120,120,289,289,
+289,289,289,289,289,289,289,289,289,289,120,120,120,120,290,291,
+288,291,291,120,120,120,291,291,291,120,291,291,291,288,120,120,
+289,120,120,120,120,120,120,290,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,292,292,292,292,292,292,292,292,292,292,
+293,293,293,294,295,295,295,295,295,296,295,120,120,120,120,120,
+
+/* block 24 */
+297,298,298,298,297,299,299,299,299,299,299,299,299,120,299,299,
+299,120,299,299,299,299,299,299,299,299,299,299,299,299,299,299,
+299,299,299,299,299,299,299,299,299,120,299,299,299,299,299,299,
+299,299,299,299,299,299,299,299,299,299,120,120,120,299,297,297,
+297,298,298,298,298,120,297,297,297,120,297,297,297,297,120,120,
+120,120,120,120,120,297,297,120,299,299,299,120,120,120,120,120,
+299,299,297,297,120,120,300,300,300,300,300,300,300,300,300,300,
+120,120,120,120,120,120,120,301,302,302,302,302,302,302,302,303,
+
+/* block 25 */
+304,305,306,306,307,304,304,304,304,304,304,304,304,120,304,304,
+304,120,304,304,304,304,304,304,304,304,304,304,304,304,304,304,
+304,304,304,304,304,304,304,304,304,120,304,304,304,304,304,304,
+304,304,304,304,120,304,304,304,304,304,120,120,305,304,306,305,
+306,306,308,306,306,120,305,306,306,120,306,306,305,305,120,120,
+120,120,120,120,120,308,308,120,120,120,120,120,120,120,304,120,
+304,304,305,305,120,120,309,309,309,309,309,309,309,309,309,309,
+120,304,304,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 26 */
+310,310,311,311,312,312,312,312,312,312,312,312,312,120,312,312,
+312,120,312,312,312,312,312,312,312,312,312,312,312,312,312,312,
+312,312,312,312,312,312,312,312,312,312,312,312,312,312,312,312,
+312,312,312,312,312,312,312,312,312,312,312,310,310,312,313,311,
+311,310,310,310,310,120,311,311,311,120,311,311,311,310,314,315,
+120,120,120,120,312,312,312,313,316,316,316,316,316,316,316,312,
+312,312,310,310,120,120,317,317,317,317,317,317,317,317,317,317,
+316,316,316,316,316,316,316,316,316,315,312,312,312,312,312,312,
+
+/* block 27 */
+120,318,319,319,120,320,320,320,320,320,320,320,320,320,320,320,
+320,320,320,320,320,320,320,120,120,120,320,320,320,320,320,320,
+320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,
+320,320,120,320,320,320,320,320,320,320,320,320,120,320,120,120,
+320,320,320,320,320,320,320,120,120,120,318,120,120,120,120,321,
+319,319,318,318,318,120,318,120,319,319,319,319,319,319,319,321,
+120,120,120,120,120,120,322,322,322,322,322,322,322,322,322,322,
+120,120,319,319,323,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 28 */
+120,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
+324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
+324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
+324,325,324,326,325,325,325,325,325,325,325,120,120,120,120,  6,
+324,324,324,324,324,324,327,325,325,325,325,325,325,325,325,328,
+329,329,329,329,329,329,329,329,329,329,328,328,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 29 */
+120,330,330,120,330,120,330,330,330,330,330,120,330,330,330,330,
+330,330,330,330,330,330,330,330,330,330,330,330,330,330,330,330,
+330,330,330,330,120,330,120,330,330,330,330,330,330,330,330,330,
+330,331,330,332,331,331,331,331,331,331,331,331,331,330,120,120,
+330,330,330,330,330,120,333,120,331,331,331,331,331,331,120,120,
+334,334,334,334,334,334,334,334,334,334,120,120,330,330,330,330,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 30 */
+335,336,336,336,337,337,337,337,337,337,337,337,337,337,337,337,
+337,337,337,336,337,336,336,336,338,338,336,336,336,336,336,336,
+339,339,339,339,339,339,339,339,339,339,340,340,340,340,340,340,
+340,340,340,340,336,338,336,338,336,338,341,342,341,342,343,343,
+335,335,335,335,335,335,335,335,120,335,335,335,335,335,335,335,
+335,335,335,335,335,335,335,335,335,335,335,335,335,335,335,335,
+335,335,335,335,335,335,335,335,335,335,335,335,335,120,120,120,
+120,338,338,338,338,338,338,338,338,338,338,338,338,338,338,343,
+
+/* block 31 */
+338,338,338,338,338,337,338,338,335,335,335,335,335,338,338,338,
+338,338,338,338,338,338,338,338,120,338,338,338,338,338,338,338,
+338,338,338,338,338,338,338,338,338,338,338,338,338,338,338,338,
+338,338,338,338,338,338,338,338,338,338,338,338,338,120,336,336,
+336,336,336,336,336,336,338,336,336,336,336,336,336,120,336,336,
+337,337,337,337,337, 20, 20, 20, 20,337,337,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 32 */
+344,344,344,344,344,344,344,344,344,344,344,344,344,344,344,344,
+344,344,344,344,344,344,344,344,344,344,344,344,344,344,344,344,
+344,344,344,344,344,344,344,344,344,344,344,345,345,346,346,346,
+346,347,346,346,346,346,346,346,345,346,346,347,347,346,346,344,
+348,348,348,348,348,348,348,348,348,348,349,349,349,349,349,349,
+344,344,344,344,344,344,347,347,346,346,344,344,344,344,346,346,
+346,344,345,345,345,344,344,345,345,345,345,345,345,345,344,344,
+344,346,346,346,346,344,344,344,344,344,344,344,344,344,344,344,
+
+/* block 33 */
+344,344,346,345,347,346,346,345,345,345,345,345,345,346,344,345,
+350,350,350,350,350,350,350,350,350,350,345,345,345,346,351,351,
+352,352,352,352,352,352,352,352,352,352,352,352,352,352,352,352,
+352,352,352,352,352,352,352,352,352,352,352,352,352,352,352,352,
+352,352,352,352,352,352,120,352,120,120,120,120,120,352,120,120,
+353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,
+353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,
+353,353,353,353,353,353,353,353,353,353,353,354,355,353,353,353,
+
+/* block 34 */
+356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
+356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
+356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
+356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
+356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
+356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
+357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,
+357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,
+
+/* block 35 */
+357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,
+357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,
+357,357,357,357,357,357,357,357,358,358,358,358,358,358,358,358,
+358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,
+358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,
+358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,
+358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,
+358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,
+
+/* block 36 */
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+359,359,359,359,359,359,359,359,359,120,359,359,359,359,120,120,
+359,359,359,359,359,359,359,120,359,120,359,359,359,359,120,120,
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+
+/* block 37 */
+359,359,359,359,359,359,359,359,359,120,359,359,359,359,120,120,
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+359,120,359,359,359,359,120,120,359,359,359,359,359,359,359,120,
+359,120,359,359,359,359,120,120,359,359,359,359,359,359,359,359,
+359,359,359,359,359,359,359,120,359,359,359,359,359,359,359,359,
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+
+/* block 38 */
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+359,120,359,359,359,359,120,120,359,359,359,359,359,359,359,359,
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+359,359,359,359,359,359,359,359,359,359,359,120,120,360,360,360,
+361,361,361,361,361,361,361,361,361,362,362,362,362,362,362,362,
+362,362,362,362,362,362,362,362,362,362,362,362,362,120,120,120,
+
+/* block 39 */
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+363,363,363,363,363,363,363,363,363,363,120,120,120,120,120,120,
+364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,
+364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,
+364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,
+364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,
+364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,
+365,365,365,365,365,365,120,120,366,366,366,366,366,366,120,120,
+
+/* block 40 */
+367,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+
+/* block 41 */
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+
+/* block 42 */
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,369,370,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+
+/* block 43 */
+371,372,372,372,372,372,372,372,372,372,372,372,372,372,372,372,
+372,372,372,372,372,372,372,372,372,372,372,373,374,120,120,120,
+375,375,375,375,375,375,375,375,375,375,375,375,375,375,375,375,
+375,375,375,375,375,375,375,375,375,375,375,375,375,375,375,375,
+375,375,375,375,375,375,375,375,375,375,375,375,375,375,375,375,
+375,375,375,375,375,375,375,375,375,375,375,375,375,375,375,375,
+375,375,375,375,375,375,375,375,375,375,375,  5,  5,  5,376,376,
+376,375,375,375,375,375,375,375,375,120,120,120,120,120,120,120,
+
+/* block 44 */
+377,377,377,377,377,377,377,377,377,377,377,377,377,120,377,377,
+377,377,378,378,378,120,120,120,120,120,120,120,120,120,120,120,
+379,379,379,379,379,379,379,379,379,379,379,379,379,379,379,379,
+379,379,380,380,380,381,381,120,120,120,120,120,120,120,120,120,
+382,382,382,382,382,382,382,382,382,382,382,382,382,382,382,382,
+382,382,383,383,120,120,120,120,120,120,120,120,120,120,120,120,
+384,384,384,384,384,384,384,384,384,384,384,384,384,120,384,384,
+384,120,385,385,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 45 */
+386,386,386,386,386,386,386,386,386,386,386,386,386,386,386,386,
+386,386,386,386,386,386,386,386,386,386,386,386,386,386,386,386,
+386,386,386,386,386,386,386,386,386,386,386,386,386,386,386,386,
+386,386,386,386,387,387,388,387,387,387,387,387,387,387,388,388,
+388,388,388,388,388,388,387,388,388,387,387,387,387,387,387,387,
+387,387,387,387,389,389,389,390,389,389,389,391,386,387,120,120,
+392,392,392,392,392,392,392,392,392,392,120,120,120,120,120,120,
+393,393,393,393,393,393,393,393,393,393,120,120,120,120,120,120,
+
+/* block 46 */
+394,394,395,395,394,395,396,394,394,394,394,397,397,397,398,120,
+399,399,399,399,399,399,399,399,399,399,120,120,120,120,120,120,
+400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,
+400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,
+400,400,400,401,400,400,400,400,400,400,400,400,400,400,400,400,
+400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,
+400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,
+400,400,400,400,400,400,400,400,400,120,120,120,120,120,120,120,
+
+/* block 47 */
+400,400,400,400,400,397,397,400,400,400,400,400,400,400,400,400,
+400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,400,
+400,400,400,400,400,400,400,400,400,397,400,120,120,120,120,120,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+368,368,368,368,368,368,120,120,120,120,120,120,120,120,120,120,
+
+/* block 48 */
+402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,
+402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,120,
+403,403,403,404,404,404,404,403,403,404,404,404,120,120,120,120,
+404,404,403,404,404,404,404,404,404,403,403,403,120,120,120,120,
+405,120,120,120,406,406,407,407,407,407,407,407,407,407,407,407,
+408,408,408,408,408,408,408,408,408,408,408,408,408,408,408,408,
+408,408,408,408,408,408,408,408,408,408,408,408,408,408,120,120,
+408,408,408,408,408,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 49 */
+409,409,409,409,409,409,409,409,409,409,409,409,409,409,409,409,
+409,409,409,409,409,409,409,409,409,409,409,409,409,409,409,409,
+409,409,409,409,409,409,409,409,409,409,409,409,120,120,120,120,
+409,409,409,409,409,409,409,409,409,409,409,409,409,409,409,409,
+409,409,409,409,409,409,409,409,409,409,120,120,120,120,120,120,
+410,410,410,410,410,410,410,410,410,410,411,120,120,120,412,412,
+413,413,413,413,413,413,413,413,413,413,413,413,413,413,413,413,
+413,413,413,413,413,413,413,413,413,413,413,413,413,413,413,413,
+
+/* block 50 */
+414,414,414,414,414,414,414,414,414,414,414,414,414,414,414,414,
+414,414,414,414,414,414,414,415,415,416,416,415,120,120,417,417,
+418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,
+418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,
+418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,
+418,418,418,418,418,419,420,419,420,420,420,420,420,420,420,120,
+420,421,420,421,421,420,420,420,420,420,420,420,420,419,419,419,
+419,419,419,420,420,420,420,420,420,420,420,420,420,120,120,420,
+
+/* block 51 */
+422,422,422,422,422,422,422,422,422,422,120,120,120,120,120,120,
+422,422,422,422,422,422,422,422,422,422,120,120,120,120,120,120,
+423,423,423,423,423,423,423,424,423,423,423,423,423,423,120,120,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,425,113,
+113,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 52 */
+426,426,426,426,427,428,428,428,428,428,428,428,428,428,428,428,
+428,428,428,428,428,428,428,428,428,428,428,428,428,428,428,428,
+428,428,428,428,428,428,428,428,428,428,428,428,428,428,428,428,
+428,428,428,428,426,429,426,426,426,426,426,427,426,427,427,427,
+427,427,426,427,427,428,428,428,428,428,428,428,120,120,120,120,
+430,430,430,430,430,430,430,430,430,430,431,431,431,431,431,431,
+431,432,432,432,432,432,432,432,432,432,432,426,426,426,426,426,
+426,426,426,426,432,432,432,432,432,432,432,432,432,120,120,120,
+
+/* block 53 */
+433,433,434,435,435,435,435,435,435,435,435,435,435,435,435,435,
+435,435,435,435,435,435,435,435,435,435,435,435,435,435,435,435,
+435,434,433,433,433,433,434,434,433,433,434,433,433,433,435,435,
+436,436,436,436,436,436,436,436,436,436,435,435,435,435,435,435,
+437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
+437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
+437,437,437,437,437,437,438,439,438,438,439,439,439,438,439,438,
+438,438,439,439,120,120,120,120,120,120,120,120,440,440,440,440,
+
+/* block 54 */
+441,441,441,441,441,441,441,441,441,441,441,441,441,441,441,441,
+441,441,441,441,441,441,441,441,441,441,441,441,441,441,441,441,
+441,441,441,441,442,442,442,442,442,442,442,442,443,443,443,443,
+443,443,443,443,442,442,443,443,120,120,120,444,444,444,444,444,
+445,445,445,445,445,445,445,445,445,445,120,120,120,441,441,441,
+446,446,446,446,446,446,446,446,446,446,447,447,447,447,447,447,
+447,447,447,447,447,447,447,447,447,447,447,447,447,447,447,447,
+447,447,447,447,447,447,447,447,448,448,448,448,448,448,449,449,
+
+/* block 55 */
+450,451,452,453,454,455,456,457,458,120,120,120,120,120,120,120,
+459,459,459,459,459,459,459,459,459,459,459,459,459,459,459,459,
+459,459,459,459,459,459,459,459,459,459,459,459,459,459,459,459,
+459,459,459,459,459,459,459,459,459,459,459,120,120,459,459,459,
+460,460,460,460,460,460,460,460,120,120,120,120,120,120,120,120,
+461,462,461,463,462,464,464,465,464,465,466,462,465,465,462,462,
+465,467,462,462,462,462,462,462,462,468,469,470,470,464,470,470,
+470,470,471,472,473,469,469,474,475,475,476,120,120,120,120,120,
+
+/* block 56 */
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35,128,128,128,128,128,477,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,121,121,121,
+121,121,110,110,110,110,121,121,121,121,121, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35,478,479, 35, 35, 35,480, 35, 35,
+
+/* block 57 */
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,481, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,121,
+114,114,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,482,113,120,113,113,113,113,113,
+
+/* block 58 */
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+483,484, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+
+/* block 59 */
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 35, 35, 35, 35, 35,485, 35, 35,486, 35,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+
+/* block 60 */
+487,487,487,487,487,487,487,487,488,488,488,488,488,488,488,488,
+487,487,487,487,487,487,120,120,488,488,488,488,488,488,120,120,
+487,487,487,487,487,487,487,487,488,488,488,488,488,488,488,488,
+487,487,487,487,487,487,487,487,488,488,488,488,488,488,488,488,
+487,487,487,487,487,487,120,120,488,488,488,488,488,488,120,120,
+128,487,128,487,128,487,128,487,120,488,120,488,120,488,120,488,
+487,487,487,487,487,487,487,487,488,488,488,488,488,488,488,488,
+489,489,490,490,490,490,491,491,492,492,493,493,494,494,120,120,
+
+/* block 61 */
+487,487,487,487,487,487,487,487,495,495,495,495,495,495,495,495,
+487,487,487,487,487,487,487,487,495,495,495,495,495,495,495,495,
+487,487,487,487,487,487,487,487,495,495,495,495,495,495,495,495,
+487,487,128,496,128,120,128,128,488,488,497,497,498,119,499,119,
+119,119,128,496,128,120,128,128,500,500,500,500,498,119,119,119,
+487,487,128,128,120,120,128,128,488,488,501,501,120,119,119,119,
+487,487,128,128,128,169,128,128,488,488,502,502,174,119,119,119,
+120,120,128,496,128,120,128,128,503,503,504,504,498,119,119,120,
+
+/* block 62 */
+  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4, 24,505,506, 24, 24,
+ 10, 10, 10, 10, 10, 10,  5,  5, 23, 27,  7, 23, 23, 27,  7, 23,
+  5,  5,  5,  5,  5,  5,  5,  5,507,508, 24, 24, 24, 24, 24,509,
+  5,  5,  5,  5,  5,  5,  5,  5,  5, 23, 27,  5,510,  5,  5, 16,
+ 16,  5,  5,  5,  9,  7,  8,  5,  5,510,  5,  5,  5,  5,  5,  5,
+  5,  5,  9,  5, 16,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  4,
+ 24, 24, 24, 24, 24,511, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 25,110,120,120, 25, 25, 25, 25, 25, 25,  9,  9,  9,  7,  8,110,
+
+/* block 63 */
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,  9,  9,  9,  7,  8,120,
+110,110,110,110,110,110,110,110,110,110,110,110,110,120,120,120,
+  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+113,113,113,113,113,113,113,113,113,113,113,113,113,425,425,425,
+425,113,425,425,425,113,113,113,113,113,113,113,113,113,113,113,
+512,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 64 */
+ 20, 20,513, 20, 20, 20, 20,513, 20, 20,514,513,513,513,514,514,
+513,513,513,514, 20,513, 20, 20,  9,513,513,513,513,513, 20, 20,
+ 20, 20, 21, 20,513, 20,515, 20,513, 20,516,517,513,513, 20,514,
+513,513,518,513,514,519,519,519,519,520, 20, 20,514,514,513,513,
+  9,  9,  9,  9,  9,513,514,514,514,514, 20,  9, 20, 20,521, 20,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+
+/* block 65 */
+524,524,524, 32, 33,524,524,524,524, 25, 20, 20,120,120,120,120,
+  9,  9,  9,  9,525, 21, 21, 21, 21, 21,  9,  9, 20, 20, 20, 20,
+  9, 20, 20,  9, 20, 20,  9, 20, 20, 21, 21, 20, 20, 20,  9, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,  9,  9,
+ 20, 20,  9, 20,  9, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+
+/* block 66 */
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+
+/* block 67 */
+ 20, 20, 20, 20, 20, 20, 20, 20,  7,  8,  7,  8, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 20, 20, 20, 20,
+  9,  9, 20, 20, 20, 20, 20, 20, 21,  7,  8, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,  9, 20, 20, 20,
+
+/* block 68 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 21, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,  9,  9,  9,  9,
+  9,  9, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 20, 20, 20, 20, 21, 21, 21, 20, 20, 20, 20, 20,
+
+/* block 69 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+
+/* block 70 */
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20,526,526,526,526,526,526,526,526,526,526,
+526,526,527,526,526,526,526,526,526,526,526,526,526,526,526,526,
+528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,
+528,528,528,528,528,528,528,528,528,528, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+
+/* block 71 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+
+/* block 72 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 21,  9, 20, 20, 20, 20, 20, 20, 20, 20,
+ 21,  9, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20,  9,  9,  9,525,525,525,525,  9,
+
+/* block 73 */
+ 21, 21, 21, 21, 21, 21, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,525,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+
+/* block 74 */
+ 21, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+
+/* block 75 */
+ 21, 21, 21, 21, 21, 21, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 20, 21, 20, 21, 20, 20, 20, 20, 20, 20, 21, 20, 20,
+ 20, 21, 20, 20, 20, 20, 20, 20, 21, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 21, 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 21, 20, 20, 21, 20, 20, 20, 20, 21, 20, 21, 20,
+ 20, 20, 20, 21, 21, 21, 20, 21, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 21, 21, 21, 21, 21,  7,  8,  7,  8,  7,  8,  7,  8,
+  7,  8,  7,  8,  7,  8, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+
+/* block 76 */
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 20, 21, 21, 21, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
+  9,  9,  9,  9,  9,  7,  8,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  7,  8,  7,  8,  7,  8,  7,  8,  7,  8,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+
+/* block 77 */
+529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,
+529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,
+529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,
+529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,
+529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,
+529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,
+529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,
+529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,529,
+
+/* block 78 */
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,525,525,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+
+/* block 79 */
+  9,  9,  9,  7,  8,  7,  8,  7,  8,  7,  8,  7,  8,  7,  8,  7,
+  8,  7,  8,  7,  8,  7,  8,  7,  8,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  7,  8,  7,  8,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  7,  8,  9,  9,
+
+/* block 80 */
+ 20, 20, 20, 20, 20, 21, 21, 21, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+  9,  9,  9,  9,  9, 20, 20,  9,  9,  9,  9,  9,  9, 20, 20, 20,
+ 21, 20, 20, 20, 20, 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20,120,120, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+
+/* block 81 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20,120, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+
+/* block 82 */
+530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,
+530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,
+530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,120,
+531,531,531,531,531,531,531,531,531,531,531,531,531,531,531,531,
+531,531,531,531,531,531,531,531,531,531,531,531,531,531,531,531,
+531,531,531,531,531,531,531,531,531,531,531,531,531,531,531,120,
+ 32, 33,532,533,534,535,536, 32, 33, 32, 33, 32, 33,537,538,539,
+540, 35, 32, 33, 35, 32, 33, 35, 35, 35, 35, 35,110,110,541,541,
+
+/* block 83 */
+165,166,165,166,165,166,165,166,165,166,165,166,165,166,165,166,
+165,166,165,166,165,166,165,166,165,166,165,166,165,166,165,166,
+165,166,165,166,165,166,165,166,165,166,165,166,165,166,165,166,
+165,166,165,166,165,166,165,166,165,166,165,166,165,166,165,166,
+165,166,165,166,165,166,165,166,165,166,165,166,165,166,165,166,
+165,166,165,166,165,166,165,166,165,166,165,166,165,166,165,166,
+165,166,165,166,542,543,543,543,543,543,543,165,166,165,166,544,
+544,544,165,166,120,120,120,120,120,545,545,545,545,546,545,545,
+
+/* block 84 */
+547,547,547,547,547,547,547,547,547,547,547,547,547,547,547,547,
+547,547,547,547,547,547,547,547,547,547,547,547,547,547,547,547,
+547,547,547,547,547,547,120,547,120,120,120,120,120,547,120,120,
+548,548,548,548,548,548,548,548,548,548,548,548,548,548,548,548,
+548,548,548,548,548,548,548,548,548,548,548,548,548,548,548,548,
+548,548,548,548,548,548,548,548,548,548,548,548,548,548,548,548,
+548,548,548,548,548,548,548,548,120,120,120,120,120,120,120,549,
+550,120,120,120,120,120,120,120,120,120,120,120,120,120,120,551,
+
+/* block 85 */
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+359,359,359,359,359,359,359,120,120,120,120,120,120,120,120,120,
+359,359,359,359,359,359,359,120,359,359,359,359,359,359,359,120,
+359,359,359,359,359,359,359,120,359,359,359,359,359,359,359,120,
+359,359,359,359,359,359,359,120,359,359,359,359,359,359,359,120,
+359,359,359,359,359,359,359,120,359,359,359,359,359,359,359,120,
+552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
+552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
+
+/* block 86 */
+  5,  5, 23, 27, 23, 27,  5,  5,  5, 23, 27,  5, 23, 27,  5,  5,
+  5,  5,  5,  5,  5,  5,  5, 10,  5,  5, 10,  5, 23, 27,  5,  5,
+ 23, 27,  7,  8,  7,  8,  7,  8,  7,  8,  5,  5,  5,  5,  5,111,
+  5,  5,  5,  5,  5,  5,  5,  5,  5,  5, 10, 10,  5,  5,  5,  5,
+ 10,  5,  7,553,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,
+ 20, 20,  5,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 87 */
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,554,554,554,554,554,554,120,554,554,554,554,554,
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 88 */
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+
+/* block 89 */
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
+554,554,554,554,554,554,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,120,120,120,120,
+
+/* block 90 */
+  4,555,555,556, 20,557,558,559,560,561,560,561,560,561,560,561,
+560,561, 20,562,560,561,560,561,560,561,560,561,563,564,565,565,
+ 20,559,559,559,559,559,559,559,559,559,566,566,566,566,567,567,
+568,569,569,569,569,569, 20,562,559,559,559,557,570,571,572,572,
+120,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+
+/* block 91 */
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,120,120,574,574,575,575,576,576,573,
+577,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,555,569,579,579,578,
+
+/* block 92 */
+120,120,120,120,120,580,580,580,580,580,580,580,580,580,580,580,
+580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,
+580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,
+120,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
+581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
+581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
+581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
+581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
+
+/* block 93 */
+581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,120,
+572,572,582,582,582,582,572,572,572,572,572,572,572,572,572,572,
+580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,
+580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,
+572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,
+572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,
+572,572,572,572,120,120,120,120,120,120,120,120,120,120,120,120,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+
+/* block 94 */
+583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,
+583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,120,
+582,582,582,582,582,582,582,582,582,582,572,572,572,572,572,572,
+572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,
+572,572,572,572,572,572,572,572, 25, 25, 25, 25, 25, 25, 25, 25,
+ 20, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,
+583,583,583,583,583,583,583,583,583,583,583,583,583,583,583, 20,
+
+/* block 95 */
+582,582,582,582,582,582,582,582,582,582,572,572,572,572,572,572,
+572,572,572,572,572,572,572,584,572,584,572,572,572,572,572,572,
+572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,
+572, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+572,572,572,572,572,572,572,572,572,572,572,572, 20, 20, 20, 20,
+585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
+585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
+585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,572,
+
+/* block 96 */
+585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
+585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
+585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
+585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
+585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,585,
+585,585,585,585,585,585,585,585,572,572,572,572,572,572,572,572,
+572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,
+572, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,572,572,572,572,572,
+
+/* block 97 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,572,
+572,572,572,572,572,572,572,572,572,572,572,572,572,572,572, 20,
+
+/* block 98 */
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+
+/* block 99 */
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+
+/* block 100 */
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,120,120,120,
+
+/* block 101 */
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+587,587,587,587,587,588,587,587,587,587,587,587,587,587,587,587,
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+
+/* block 102 */
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+
+/* block 103 */
+587,587,587,587,587,587,587,587,587,587,587,587,587,120,120,120,
+589,589,589,589,589,589,589,589,589,589,589,589,589,589,589,589,
+589,589,589,589,589,589,589,589,589,589,589,589,589,589,589,589,
+589,589,589,589,589,589,589,589,589,589,589,589,589,589,589,589,
+589,589,589,589,589,589,589,120,120,120,120,120,120,120,120,120,
+590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,
+590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,590,
+590,590,590,590,590,590,590,590,591,591,591,591,591,591,592,592,
+
+/* block 104 */
+593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
+593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
+593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
+593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
+593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
+593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
+593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
+593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
+
+/* block 105 */
+593,593,593,593,593,593,593,593,593,593,593,593,594,595,595,595,
+593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,593,
+596,596,596,596,596,596,596,596,596,596,593,593,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+192,193,192,193,192,193,192,193,192,193,597,598,192,193,192,193,
+192,193,192,193,192,193,192,193,192,193,192,193,192,193,192,193,
+192,193,192,193,192,193,192,193,192,193,192,193,192,193,599,198,
+200,200,200,600,552,552,552,552,552,552,552,552,552,552,600,478,
+
+/* block 106 */
+192,193,192,193,192,193,192,193,192,193,192,193,192,193,192,193,
+192,193,192,193,192,193,192,193,192,193,192,193,478,478,552,552,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,602,602,602,602,602,602,602,602,602,602,
+603,603,604,604,604,604,604,604,120,120,120,120,120,120,120,120,
+
+/* block 107 */
+605,605,605,605,605,605,605,605, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15,111,111,111,111,111,111,111,111,111,
+ 15, 15, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 35, 35, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+110, 35, 35, 35, 35, 35, 35, 35, 35, 32, 33, 32, 33,606, 32, 33,
+
+/* block 108 */
+ 32, 33, 32, 33, 32, 33, 32, 33,111, 15, 15, 32, 33,607, 35, 22,
+ 32, 33, 32, 33,608, 35, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+ 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,609,610,611,612,609, 35,
+613,614,615,616, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33, 32, 33,
+120,120, 32, 33,617,618,619, 32, 33, 32, 33,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120, 32, 33, 22,110,110, 35, 22, 22, 22, 22, 22,
+
+/* block 109 */
+620,620,621,620,620,620,621,620,620,620,620,621,620,620,620,620,
+620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,
+620,620,620,622,622,621,621,622,623,623,623,623,621,120,120,120,
+624,624,624,625,625,625,626,626,627,626,120,120,120,120,120,120,
+628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
+628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
+628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
+628,628,628,628,629,629,629,629,120,120,120,120,120,120,120,120,
+
+/* block 110 */
+630,630,631,631,631,631,631,631,631,631,631,631,631,631,631,631,
+631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,
+631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,
+631,631,631,631,630,630,630,630,630,630,630,630,630,630,630,630,
+630,630,630,630,632,632,120,120,120,120,120,120,120,120,633,633,
+634,634,634,634,634,634,634,634,634,634,120,120,120,120,120,120,
+251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,
+251,635,253,636,253,253,253,253,259,259,259,253,259,253,253,251,
+
+/* block 111 */
+637,637,637,637,637,637,637,637,637,637,638,638,638,638,638,638,
+638,638,638,638,638,638,638,638,638,638,638,638,638,638,638,638,
+638,638,638,638,638,638,639,639,639,639,639,639,639,639,640,641,
+642,642,642,642,642,642,642,642,642,642,642,642,642,642,642,642,
+642,642,642,642,642,642,642,643,643,643,643,643,643,643,643,643,
+643,643,644,644,120,120,120,120,120,120,120,120,120,120,120,645,
+356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
+356,356,356,356,356,356,356,356,356,356,356,356,356,120,120,120,
+
+/* block 112 */
+646,646,646,647,648,648,648,648,648,648,648,648,648,648,648,648,
+648,648,648,648,648,648,648,648,648,648,648,648,648,648,648,648,
+648,648,648,648,648,648,648,648,648,648,648,648,648,648,648,648,
+648,648,648,646,647,647,646,646,646,646,647,647,646,646,647,647,
+647,649,649,649,649,649,649,649,649,649,649,649,649,649,120,650,
+651,651,651,651,651,651,651,651,651,651,120,120,120,120,649,649,
+344,344,344,344,344,346,652,344,344,344,344,344,344,344,344,344,
+350,350,350,350,350,350,350,350,350,350,344,344,344,344,344,120,
+
+/* block 113 */
+653,653,653,653,653,653,653,653,653,653,653,653,653,653,653,653,
+653,653,653,653,653,653,653,653,653,653,653,653,653,653,653,653,
+653,653,653,653,653,653,653,653,653,654,654,654,654,654,654,655,
+655,654,654,655,655,654,654,120,120,120,120,120,120,120,120,120,
+653,653,653,654,653,653,653,653,653,653,653,653,654,655,120,120,
+656,656,656,656,656,656,656,656,656,656,120,120,657,657,657,657,
+344,344,344,344,344,344,344,344,344,344,344,344,344,344,344,344,
+652,344,344,344,344,344,344,351,351,351,344,345,346,345,344,344,
+
+/* block 114 */
+658,658,658,658,658,658,658,658,658,658,658,658,658,658,658,658,
+658,658,658,658,658,658,658,658,658,658,658,658,658,658,658,658,
+658,658,658,658,658,658,658,658,658,658,658,658,658,658,658,658,
+659,658,659,659,659,658,658,659,659,658,658,658,658,658,659,659,
+658,659,658,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,658,658,660,661,661,
+662,662,662,662,662,662,662,662,662,662,662,663,664,664,663,663,
+665,665,662,666,666,663,664,120,120,120,120,120,120,120,120,120,
+
+/* block 115 */
+120,359,359,359,359,359,359,120,120,359,359,359,359,359,359,120,
+120,359,359,359,359,359,359,120,120,120,120,120,120,120,120,120,
+359,359,359,359,359,359,359,120,359,359,359,359,359,359,359,120,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35,667, 35, 35, 35, 35, 35, 35, 35, 15,110,110,110,110,
+ 35, 35, 35, 35, 35,128, 35, 35, 35,110, 15, 15,120,120,120,120,
+668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,
+
+/* block 116 */
+668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,
+668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,
+668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,
+668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,
+662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,
+662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,
+662,662,662,663,663,664,663,663,664,663,663,665,663,664,120,120,
+669,669,669,669,669,669,669,669,669,669,120,120,120,120,120,120,
+
+/* block 117 */
+670,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,670,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,670,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+670,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+
+/* block 118 */
+671,671,671,671,671,671,671,671,671,671,671,671,670,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,670,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+670,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,670,671,671,671,
+
+/* block 119 */
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,670,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+670,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,670,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+
+/* block 120 */
+671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,670,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+670,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,670,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
+
+/* block 121 */
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,670,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+670,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,670,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+
+/* block 122 */
+671,671,671,671,670,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+670,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,670,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,670,671,671,671,671,671,671,671,671,671,671,671,
+
+/* block 123 */
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+670,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,670,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,670,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+
+/* block 124 */
+671,671,671,671,671,671,671,671,670,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,120,120,120,120,120,120,120,120,120,120,120,120,
+357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,357,
+357,357,357,357,357,357,357,120,120,120,120,358,358,358,358,358,
+358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,
+358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,
+358,358,358,358,358,358,358,358,358,358,358,358,120,120,120,120,
+
+/* block 125 */
+672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
+672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
+672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
+672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
+672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
+672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
+672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
+672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
+
+/* block 126 */
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+
+/* block 127 */
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,120,120,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+
+/* block 128 */
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 129 */
+ 35, 35, 35, 35, 35, 35, 35,120,120,120,120,120,120,120,120,120,
+120,120,120,206,206,206,206,206,120,120,120,120,120,214,211,214,
+214,214,214,214,214,214,214,214,214,674,214,214,214,214,214,214,
+214,214,214,214,214,214,214,120,214,214,214,214,214,120,214,120,
+214,214,120,214,214,120,214,214,214,214,214,214,214,214,214,214,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+
+/* block 130 */
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,675,675,675,675,675,675,675,675,675,675,675,675,675,675,
+675,675,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+
+/* block 131 */
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+
+/* block 132 */
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,  8,  7,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+
+/* block 133 */
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+120,120,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+224,224,676,224,224,224,224,224,224,224,224,224,219,677,120,120,
+
+/* block 134 */
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+  5,  5,  5,  5,  5,  5,  5,  7,  8,  5,120,120,120,120,120,120,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,552,552,
+  5, 10, 10, 16, 16,  7,  8,  7,  8,  7,  8,  7,  8,  7,  8,  7,
+  8,  7,  8,  7,  8,556,556,  7,  8,  5,  5,  5,  5, 16, 16, 16,
+  5,  5,  5,120,  5,  5,  5,  5, 10,  7,  8,  7,  8,  7,  8,  5,
+  5,  5,  9, 10,  9,  9,  9,120,  5,  6,  5,  5,120,120,120,120,
+224,224,224,224,224,120,224,224,224,224,224,224,224,224,224,224,
+
+/* block 135 */
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,120,120, 24,
+
+/* block 136 */
+120,  5,  5,  5,  6,  5,  5,  5,  7,  8,  5,  9,  5, 10,  5,  5,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,  5,  5,  9,  9,  9,  5,
+  5, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,  7,  5,  8, 15, 16,
+ 15, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,  7,  9,  8,  9,  7,
+  8,555,560,561,555,555,578,578,578,578,578,578,578,578,578,578,
+569,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+
+/* block 137 */
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
+578,578,578,578,578,578,578,578,578,578,578,578,578,578,678,678,
+581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
+581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,120,
+120,120,581,581,581,581,581,581,120,120,581,581,581,581,581,581,
+120,120,581,581,581,581,581,581,120,120,581,581,581,120,120,120,
+  6,  6,  9, 15, 20,  6,  6,120, 20,  9,  9,  9,  9, 20, 20,120,
+511,511,511,511,511,511,511,511,511, 24, 24, 24, 20, 20,120,120,
+
+/* block 138 */
+679,679,679,679,679,679,679,679,679,679,679,679,120,679,679,679,
+679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,
+679,679,679,679,679,679,679,120,679,679,679,679,679,679,679,679,
+679,679,679,679,679,679,679,679,679,679,679,120,679,679,120,679,
+679,679,679,679,679,679,679,679,679,679,679,679,679,679,120,120,
+679,679,679,679,679,679,679,679,679,679,679,679,679,679,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 139 */
+679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,
+679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,
+679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,
+679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,
+679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,
+679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,
+679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,
+679,679,679,679,679,679,679,679,679,679,679,120,120,120,120,120,
+
+/* block 140 */
+680,680,680,120,120,120,120,681,681,681,681,681,681,681,681,681,
+681,681,681,681,681,681,681,681,681,681,681,681,681,681,681,681,
+681,681,681,681,681,681,681,681,681,681,681,681,681,681,681,681,
+681,681,681,681,120,120,120,682,682,682,682,682,682,682,682,682,
+683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,
+683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,
+683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,
+683,683,683,683,683,684,684,684,684,685,685,685,685,685,685,685,
+
+/* block 141 */
+685,685,685,685,685,685,685,685,685,685,684,684,685,685,685,120,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,120,120,120,
+685,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,113,120,120,
+
+/* block 142 */
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 143 */
+686,686,686,686,686,686,686,686,686,686,686,686,686,686,686,686,
+686,686,686,686,686,686,686,686,686,686,686,686,686,120,120,120,
+687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,
+687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,
+687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,
+687,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+688,689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,
+689,689,689,689,689,689,689,689,689,689,689,689,120,120,120,120,
+
+/* block 144 */
+690,690,690,690,690,690,690,690,690,690,690,690,690,690,690,690,
+690,690,690,690,690,690,690,690,690,690,690,690,690,690,690,690,
+691,691,691,691,120,120,120,120,120,120,120,120,120,690,690,690,
+692,692,692,692,692,692,692,692,692,692,692,692,692,692,692,692,
+692,693,692,692,692,692,692,692,692,692,693,120,120,120,120,120,
+694,694,694,694,694,694,694,694,694,694,694,694,694,694,694,694,
+694,694,694,694,694,694,694,694,694,694,694,694,694,694,694,694,
+694,694,694,694,694,694,695,695,695,695,695,120,120,120,120,120,
+
+/* block 145 */
+696,696,696,696,696,696,696,696,696,696,696,696,696,696,696,696,
+696,696,696,696,696,696,696,696,696,696,696,696,696,696,120,697,
+698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,
+698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,
+698,698,698,698,120,120,120,120,698,698,698,698,698,698,698,698,
+699,700,700,700,700,700,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 146 */
+701,701,701,701,701,701,701,701,701,701,701,701,701,701,701,701,
+701,701,701,701,701,701,701,701,701,701,701,701,701,701,701,701,
+701,701,701,701,701,701,701,701,702,702,702,702,702,702,702,702,
+702,702,702,702,702,702,702,702,702,702,702,702,702,702,702,702,
+702,702,702,702,702,702,702,702,702,702,702,702,702,702,702,702,
+703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,
+703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,
+703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,
+
+/* block 147 */
+704,704,704,704,704,704,704,704,704,704,704,704,704,704,704,704,
+704,704,704,704,704,704,704,704,704,704,704,704,704,704,120,120,
+705,705,705,705,705,705,705,705,705,705,120,120,120,120,120,120,
+706,706,706,706,706,706,706,706,706,706,706,706,706,706,706,706,
+706,706,706,706,706,706,706,706,706,706,706,706,706,706,706,706,
+706,706,706,706,120,120,120,120,707,707,707,707,707,707,707,707,
+707,707,707,707,707,707,707,707,707,707,707,707,707,707,707,707,
+707,707,707,707,707,707,707,707,707,707,707,707,120,120,120,120,
+
+/* block 148 */
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
+708,708,708,708,708,708,708,708,120,120,120,120,120,120,120,120,
+709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
+709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
+709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
+709,709,709,709,120,120,120,120,120,120,120,120,120,120,120,710,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 149 */
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+
+/* block 150 */
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,120,120,120,120,120,120,120,120,120,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,120,120,120,120,120,120,120,120,120,120,
+711,711,711,711,711,711,711,711,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 151 */
+712,712,712,712,712,712,120,120,712,120,712,712,712,712,712,712,
+712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,
+712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,
+712,712,712,712,712,712,120,712,712,120,120,120,712,120,120,712,
+713,713,713,713,713,713,713,713,713,713,713,713,713,713,713,713,
+713,713,713,713,713,713,120,714,715,715,715,715,715,715,715,715,
+716,716,716,716,716,716,716,716,716,716,716,716,716,716,716,716,
+716,716,716,716,716,716,716,717,717,718,718,718,718,718,718,718,
+
+/* block 152 */
+719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,
+719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,120,
+120,120,120,120,120,120,120,720,720,720,720,720,720,720,720,720,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+721,721,721,721,721,721,721,721,721,721,721,721,721,721,721,721,
+721,721,721,120,721,721,120,120,120,120,120,722,722,722,722,722,
+
+/* block 153 */
+723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
+723,723,723,723,723,723,724,724,724,724,724,724,120,120,120,725,
+726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,
+726,726,726,726,726,726,726,726,726,726,120,120,120,120,120,727,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 154 */
+728,728,728,728,728,728,728,728,728,728,728,728,728,728,728,728,
+728,728,728,728,728,728,728,728,728,728,728,728,728,728,728,728,
+729,729,729,729,729,729,729,729,729,729,729,729,729,729,729,729,
+729,729,729,729,729,729,729,729,120,120,120,120,730,730,729,729,
+730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,
+120,120,730,730,730,730,730,730,730,730,730,730,730,730,730,730,
+730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,
+730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,
+
+/* block 155 */
+731,732,732,732,120,732,732,120,120,120,120,120,732,732,732,732,
+731,731,731,731,120,731,731,731,120,731,731,731,731,731,731,731,
+731,731,731,731,731,731,731,731,731,731,731,731,731,731,731,731,
+731,731,731,731,731,731,120,120,732,732,732,120,120,120,120,732,
+733,733,733,733,733,733,733,733,733,120,120,120,120,120,120,120,
+734,734,734,734,734,734,734,734,734,120,120,120,120,120,120,120,
+735,735,735,735,735,735,735,735,735,735,735,735,735,735,735,735,
+735,735,735,735,735,735,735,735,735,735,735,735,735,736,736,737,
+
+/* block 156 */
+738,738,738,738,738,738,738,738,738,738,738,738,738,738,738,738,
+738,738,738,738,738,738,738,738,738,738,738,738,738,739,739,739,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+740,740,740,740,740,740,740,740,741,740,740,740,740,740,740,740,
+740,740,740,740,740,740,740,740,740,740,740,740,740,740,740,740,
+740,740,740,740,740,742,742,120,120,120,120,743,743,743,743,743,
+744,744,744,744,744,744,744,120,120,120,120,120,120,120,120,120,
+
+/* block 157 */
+745,745,745,745,745,745,745,745,745,745,745,745,745,745,745,745,
+745,745,745,745,745,745,745,745,745,745,745,745,745,745,745,745,
+745,745,745,745,745,745,745,745,745,745,745,745,745,745,745,745,
+745,745,745,745,745,745,120,120,120,746,746,746,746,746,746,746,
+747,747,747,747,747,747,747,747,747,747,747,747,747,747,747,747,
+747,747,747,747,747,747,120,120,748,748,748,748,748,748,748,748,
+749,749,749,749,749,749,749,749,749,749,749,749,749,749,749,749,
+749,749,749,120,120,120,120,120,750,750,750,750,750,750,750,750,
+
+/* block 158 */
+751,751,751,751,751,751,751,751,751,751,751,751,751,751,751,751,
+751,751,120,120,120,120,120,120,120,752,752,752,752,120,120,120,
+120,120,120,120,120,120,120,120,120,753,753,753,753,753,753,753,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 159 */
+754,754,754,754,754,754,754,754,754,754,754,754,754,754,754,754,
+754,754,754,754,754,754,754,754,754,754,754,754,754,754,754,754,
+754,754,754,754,754,754,754,754,754,754,754,754,754,754,754,754,
+754,754,754,754,754,754,754,754,754,754,754,754,754,754,754,754,
+754,754,754,754,754,754,754,754,754,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 160 */
+755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,
+755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,
+755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,755,
+755,755,755,120,120,120,120,120,120,120,120,120,120,120,120,120,
+756,756,756,756,756,756,756,756,756,756,756,756,756,756,756,756,
+756,756,756,756,756,756,756,756,756,756,756,756,756,756,756,756,
+756,756,756,756,756,756,756,756,756,756,756,756,756,756,756,756,
+756,756,756,120,120,120,120,120,120,120,757,757,757,757,757,757,
+
+/* block 161 */
+758,758,758,758,758,758,758,758,758,758,758,758,758,758,758,758,
+758,758,758,758,758,758,758,758,758,758,758,758,758,758,758,758,
+758,758,758,758,759,759,759,759,120,120,120,120,120,120,120,120,
+760,760,760,760,760,760,760,760,760,760,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 162 */
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+761,761,761,761,761,761,761,761,761,761,761,761,761,761,761,761,
+761,761,761,761,761,761,761,761,761,761,761,761,761,761,761,120,
+
+/* block 163 */
+762,762,762,762,762,762,762,762,762,762,762,762,762,762,762,762,
+762,762,762,762,762,762,762,762,762,762,762,762,762,762,762,762,
+762,762,762,762,762,762,762,762,762,762,120,763,763,764,120,120,
+762,762,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 164 */
+765,765,765,765,765,765,765,765,765,765,765,765,765,765,765,765,
+765,765,765,765,765,765,765,765,765,765,765,765,765,766,766,766,
+766,766,766,766,766,766,766,765,120,120,120,120,120,120,120,120,
+767,767,767,767,767,767,767,767,767,767,767,767,767,767,767,767,
+767,767,767,767,767,767,768,768,768,768,768,768,768,768,768,768,
+768,769,769,769,769,770,770,770,770,770,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 165 */
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+771,771,771,771,771,771,771,771,771,771,771,771,771,771,771,771,
+771,771,771,771,771,772,772,772,772,772,772,772,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+773,773,773,773,773,773,773,773,773,773,773,773,773,773,773,773,
+773,773,773,773,773,773,773,120,120,120,120,120,120,120,120,120,
+
+/* block 166 */
+774,775,774,776,776,776,776,776,776,776,776,776,776,776,776,776,
+776,776,776,776,776,776,776,776,776,776,776,776,776,776,776,776,
+776,776,776,776,776,776,776,776,776,776,776,776,776,776,776,776,
+776,776,776,776,776,776,776,776,775,775,775,775,775,775,775,775,
+775,775,775,775,775,775,775,777,777,777,777,777,777,777,120,120,
+120,120,778,778,778,778,778,778,778,778,778,778,778,778,778,778,
+778,778,778,778,778,778,779,779,779,779,779,779,779,779,779,779,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,775,
+
+/* block 167 */
+780,780,781,782,782,782,782,782,782,782,782,782,782,782,782,782,
+782,782,782,782,782,782,782,782,782,782,782,782,782,782,782,782,
+782,782,782,782,782,782,782,782,782,782,782,782,782,782,782,782,
+781,781,781,780,780,780,780,781,781,780,780,783,783,784,783,783,
+783,783,120,120,120,120,120,120,120,120,120,120,120,784,120,120,
+785,785,785,785,785,785,785,785,785,785,785,785,785,785,785,785,
+785,785,785,785,785,785,785,785,785,120,120,120,120,120,120,120,
+786,786,786,786,786,786,786,786,786,786,120,120,120,120,120,120,
+
+/* block 168 */
+787,787,787,788,788,788,788,788,788,788,788,788,788,788,788,788,
+788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,
+788,788,788,788,788,788,788,787,787,787,787,787,789,787,787,787,
+787,787,787,787,787,120,790,790,790,790,790,790,790,790,790,790,
+791,791,791,791,788,789,789,788,120,120,120,120,120,120,120,120,
+792,792,792,792,792,792,792,792,792,792,792,792,792,792,792,792,
+792,792,792,792,792,792,792,792,792,792,792,792,792,792,792,792,
+792,792,792,793,794,794,792,120,120,120,120,120,120,120,120,120,
+
+/* block 169 */
+795,795,796,797,797,797,797,797,797,797,797,797,797,797,797,797,
+797,797,797,797,797,797,797,797,797,797,797,797,797,797,797,797,
+797,797,797,797,797,797,797,797,797,797,797,797,797,797,797,797,
+797,797,797,796,796,796,795,795,795,795,795,795,795,795,795,796,
+796,797,798,798,797,799,799,799,799,795,795,795,795,799,796,795,
+800,800,800,800,800,800,800,800,800,800,797,799,797,799,799,799,
+120,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,
+801,801,801,801,801,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 170 */
+802,802,802,802,802,802,802,802,802,802,802,802,802,802,802,802,
+802,802,120,802,802,802,802,802,802,802,802,802,802,802,802,802,
+802,802,802,802,802,802,802,802,802,802,802,802,803,803,803,804,
+804,804,803,803,804,803,804,804,805,805,805,805,805,805,804,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 171 */
+806,806,806,806,806,806,806,120,806,120,806,806,806,806,120,806,
+806,806,806,806,806,806,806,806,806,806,806,806,806,806,120,806,
+806,806,806,806,806,806,806,806,806,807,120,120,120,120,120,120,
+808,808,808,808,808,808,808,808,808,808,808,808,808,808,808,808,
+808,808,808,808,808,808,808,808,808,808,808,808,808,808,808,808,
+808,808,808,808,808,808,808,808,808,808,808,808,808,808,808,809,
+810,810,810,809,809,809,809,809,809,809,809,120,120,120,120,120,
+811,811,811,811,811,811,811,811,811,811,120,120,120,120,120,120,
+
+/* block 172 */
+812,813,814,815,120,816,816,816,816,816,816,816,816,120,120,816,
+816,120,120,816,816,816,816,816,816,816,816,816,816,816,816,816,
+816,816,816,816,816,816,816,816,816,120,816,816,816,816,816,816,
+816,120,816,816,120,816,816,816,816,816,120,817,813,816,818,814,
+812,814,814,814,814,120,120,814,814,120,120,814,814,814,120,120,
+816,120,120,120,120,120,120,818,120,120,120,120,120,816,816,816,
+816,816,814,814,120,120,812,812,812,812,812,812,812,120,120,120,
+812,812,812,812,812,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 173 */
+819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
+819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
+819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
+819,819,819,819,819,820,820,820,821,821,821,821,821,821,821,821,
+820,820,821,821,821,820,821,819,819,819,819,822,822,822,822,822,
+823,823,823,823,823,823,823,823,823,823,822,822,120,822,821,819,
+819,819,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 174 */
+824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,
+824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,
+824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,
+825,826,826,827,827,827,827,827,827,826,827,826,826,825,826,827,
+827,826,827,827,824,824,828,824,120,120,120,120,120,120,120,120,
+829,829,829,829,829,829,829,829,829,829,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 175 */
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,831,
+832,832,833,833,833,833,120,120,832,832,832,832,833,833,832,833,
+833,834,834,834,834,834,834,834,834,834,834,834,834,834,834,834,
+834,834,834,834,834,834,834,834,830,830,830,830,833,833,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 176 */
+835,835,835,835,835,835,835,835,835,835,835,835,835,835,835,835,
+835,835,835,835,835,835,835,835,835,835,835,835,835,835,835,835,
+835,835,835,835,835,835,835,835,835,835,835,835,835,835,835,835,
+836,836,836,837,837,837,837,837,837,837,837,836,836,837,836,837,
+837,838,838,838,835,120,120,120,120,120,120,120,120,120,120,120,
+839,839,839,839,839,839,839,839,839,839,120,120,120,120,120,120,
+394,394,394,394,394,394,394,394,394,394,394,394,394,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 177 */
+840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,
+840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,
+840,840,840,840,840,840,840,840,840,840,840,841,842,841,842,842,
+841,841,841,841,841,841,842,841,840,120,120,120,120,120,120,120,
+843,843,843,843,843,843,843,843,843,843,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 178 */
+844,844,844,844,844,844,844,844,844,844,844,844,844,844,844,844,
+844,844,844,844,844,844,844,844,844,844,844,120,120,845,845,845,
+846,846,845,845,845,845,846,845,845,845,845,845,120,120,120,120,
+847,847,847,847,847,847,847,847,847,847,848,848,849,849,849,850,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 179 */
+851,851,851,851,851,851,851,851,851,851,851,851,851,851,851,851,
+851,851,851,851,851,851,851,851,851,851,851,851,851,851,851,851,
+851,851,851,851,851,851,851,851,851,851,851,851,852,852,852,853,
+853,853,853,853,853,853,853,853,852,853,853,854,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 180 */
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+855,855,855,855,855,855,855,855,855,855,855,855,855,855,855,855,
+855,855,855,855,855,855,855,855,855,855,855,855,855,855,855,855,
+856,856,856,856,856,856,856,856,856,856,856,856,856,856,856,856,
+856,856,856,856,856,856,856,856,856,856,856,856,856,856,856,856,
+857,857,857,857,857,857,857,857,857,857,858,858,858,858,858,858,
+858,858,858,120,120,120,120,120,120,120,120,120,120,120,120,859,
+
+/* block 181 */
+860,860,860,860,860,860,860,120,120,860,120,120,860,860,860,860,
+860,860,860,860,120,860,860,120,860,860,860,860,860,860,860,860,
+860,860,860,860,860,860,860,860,860,860,860,860,860,860,860,860,
+861,862,862,862,862,862,120,862,862,120,120,863,863,862,863,864,
+862,864,862,863,865,865,865,120,120,120,120,120,120,120,120,120,
+866,866,866,866,866,866,866,866,866,866,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 182 */
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+867,867,867,867,867,867,867,867,120,120,867,867,867,867,867,867,
+867,867,867,867,867,867,867,867,867,867,867,867,867,867,867,867,
+867,867,867,867,867,867,867,867,867,867,867,867,867,867,867,867,
+867,868,868,868,869,869,869,869,120,120,869,869,868,868,868,868,
+869,867,870,867,868,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 183 */
+871,872,872,872,872,872,872,872,872,872,872,871,871,871,871,871,
+871,871,871,871,871,871,871,871,871,871,871,871,871,871,871,871,
+871,871,871,871,871,871,871,871,871,871,871,871,871,871,871,871,
+871,871,871,872,872,872,872,872,872,873,874,872,872,872,872,875,
+875,875,875,875,875,875,875,872,120,120,120,120,120,120,120,120,
+876,877,877,877,877,877,877,878,878,877,877,877,876,876,876,876,
+876,876,876,876,876,876,876,876,876,876,876,876,876,876,876,876,
+876,876,876,876,876,876,876,876,876,876,876,876,876,876,876,876,
+
+/* block 184 */
+876,876,876,876,879,879,879,879,879,879,877,877,877,877,877,877,
+877,877,877,877,877,877,877,878,877,877,880,880,880,876,880,880,
+880,880,880,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+881,881,881,881,881,881,881,881,881,881,881,881,881,881,881,881,
+881,881,881,881,881,881,881,881,881,881,881,881,881,881,881,881,
+881,881,881,881,881,881,881,881,881,881,881,881,881,881,881,881,
+881,881,881,881,881,881,881,881,881,120,120,120,120,120,120,120,
+
+/* block 185 */
+882,882,882,882,882,882,882,882,882,120,882,882,882,882,882,882,
+882,882,882,882,882,882,882,882,882,882,882,882,882,882,882,882,
+882,882,882,882,882,882,882,882,882,882,882,882,882,882,882,883,
+884,884,884,884,884,884,884,120,884,884,884,884,884,884,883,884,
+882,885,885,885,885,885,120,120,120,120,120,120,120,120,120,120,
+886,886,886,886,886,886,886,886,886,886,887,887,887,887,887,887,
+887,887,887,887,887,887,887,887,887,887,887,887,887,120,120,120,
+888,888,889,889,889,889,889,889,889,889,889,889,889,889,889,889,
+
+/* block 186 */
+889,889,889,889,889,889,889,889,889,889,889,889,889,889,889,889,
+120,120,890,890,890,890,890,890,890,890,890,890,890,890,890,890,
+890,890,890,890,890,890,890,890,120,891,890,890,890,890,890,890,
+890,891,890,890,891,890,890,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 187 */
+892,892,892,892,892,892,892,120,892,892,120,892,892,892,892,892,
+892,892,892,892,892,892,892,892,892,892,892,892,892,892,892,892,
+892,892,892,892,892,892,892,892,892,892,892,892,892,892,892,892,
+892,893,893,893,893,893,893,120,120,120,893,120,893,893,120,893,
+893,893,893,893,893,893,894,893,120,120,120,120,120,120,120,120,
+895,895,895,895,895,895,895,895,895,895,120,120,120,120,120,120,
+896,896,896,896,896,896,120,896,896,120,896,896,896,896,896,896,
+896,896,896,896,896,896,896,896,896,896,896,896,896,896,896,896,
+
+/* block 188 */
+896,896,896,896,896,896,896,896,896,896,897,897,897,897,897,120,
+898,898,120,897,897,898,897,898,896,120,120,120,120,120,120,120,
+899,899,899,899,899,899,899,899,899,899,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 189 */
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+900,900,900,900,900,900,900,900,900,900,900,900,900,900,900,900,
+900,900,900,901,901,902,902,903,903,120,120,120,120,120,120,120,
+
+/* block 190 */
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+590,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,904,
+293,293,904,293,904,295,295,295,295,295,295,295,295,296,296,296,
+296,295,295,295,295,295,295,295,295,295,295,295,295,295,295,295,
+295,295,120,120,120,120,120,120,120,120,120,120,120,120,120,905,
+
+/* block 191 */
+906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
+906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
+906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
+906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
+906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
+906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
+906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
+906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
+
+/* block 192 */
+906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
+906,906,906,906,906,906,906,906,906,906,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 193 */
+907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,
+907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,
+907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,
+907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,
+907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,
+907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,
+907,907,907,907,907,907,907,907,907,907,907,907,907,907,907,120,
+908,908,908,908,908,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 194 */
+906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
+906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
+906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
+906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,906,
+906,906,906,906,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 195 */
+909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
+909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
+909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
+909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
+909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
+909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
+909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
+909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
+
+/* block 196 */
+909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
+909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,
+909,909,909,909,909,909,909,909,909,909,909,909,909,909,909,120,
+910,910,910,910,910,910,910,910,910,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 197 */
+911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
+911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
+911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
+911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
+911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
+911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
+911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
+911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
+
+/* block 198 */
+911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
+911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
+911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
+911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,911,
+911,911,911,911,911,911,911,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 199 */
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+
+/* block 200 */
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,120,120,120,120,120,120,120,
+912,912,912,912,912,912,912,912,912,912,912,912,912,912,912,912,
+912,912,912,912,912,912,912,912,912,912,912,912,912,912,912,120,
+913,913,913,913,913,913,913,913,913,913,120,120,120,120,914,914,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 201 */
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+915,915,915,915,915,915,915,915,915,915,915,915,915,915,915,915,
+915,915,915,915,915,915,915,915,915,915,915,915,915,915,120,120,
+916,916,916,916,916,917,120,120,120,120,120,120,120,120,120,120,
+
+/* block 202 */
+918,918,918,918,918,918,918,918,918,918,918,918,918,918,918,918,
+918,918,918,918,918,918,918,918,918,918,918,918,918,918,918,918,
+918,918,918,918,918,918,918,918,918,918,918,918,918,918,918,918,
+919,919,919,919,919,919,919,920,920,920,920,920,921,921,921,921,
+922,922,922,922,920,921,120,120,120,120,120,120,120,120,120,120,
+923,923,923,923,923,923,923,923,923,923,120,924,924,924,924,924,
+924,924,120,918,918,918,918,918,918,918,918,918,918,918,918,918,
+918,918,918,918,918,918,918,918,120,120,120,120,120,918,918,918,
+
+/* block 203 */
+918,918,918,918,918,918,918,918,918,918,918,918,918,918,918,918,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 204 */
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+925,925,925,925,925,925,925,925,925,925,925,925,925,925,925,925,
+925,925,925,925,925,925,925,925,925,925,925,925,925,925,925,925,
+926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,
+926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,926,
+
+/* block 205 */
+927,927,927,927,927,927,927,927,927,927,927,927,927,927,927,927,
+927,927,927,927,927,927,927,928,928,928,928,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 206 */
+929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,
+929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,
+929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,
+929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,929,
+929,929,929,929,929,929,929,929,929,929,929,120,120,120,120,930,
+929,931,931,931,931,931,931,931,931,931,931,931,931,931,931,931,
+931,931,931,931,931,931,931,931,931,931,931,931,931,931,931,931,
+931,931,931,931,931,931,931,931,931,931,931,931,931,931,931,931,
+
+/* block 207 */
+931,931,931,931,931,931,931,931,120,120,120,120,120,120,120,930,
+930,930,930,932,932,932,932,932,932,932,932,932,932,932,932,932,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+933,934,  5,111,935,120,120,120,120,120,120,120,120,120,120,120,
+936,936,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 208 */
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+
+/* block 209 */
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,937,
+937,937,937,937,937,937,937,937,120,120,120,120,120,120,120,120,
+
+/* block 210 */
+938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,
+938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,
+938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,
+938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,
+938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,
+938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,
+938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,
+938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,
+
+/* block 211 */
+938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,
+938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,
+938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,
+938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,
+938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,
+938,938,938,938,938,938,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 212 */
+937,937,937,937,937,937,937,937,937,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 213 */
+578,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+
+/* block 214 */
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+
+/* block 215 */
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+573,573,573,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,578,578,578,578,120,120,120,120,120,120,120,120,
+939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+
+/* block 216 */
+939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+
+/* block 217 */
+939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,939,
+939,939,939,939,939,939,939,939,939,939,939,939,120,120,120,120,
+
+/* block 218 */
+940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,
+940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,
+940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,
+940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,
+940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,
+940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,940,
+940,940,940,940,940,940,940,940,940,940,940,120,120,120,120,120,
+940,940,940,940,940,940,940,940,940,940,940,940,940,120,120,120,
+
+/* block 219 */
+940,940,940,940,940,940,940,940,940,120,120,120,120,120,120,120,
+940,940,940,940,940,940,940,940,940,940,120,120,941,942,942,943,
+944,944,944,944,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 220 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20,120,120,120,120,120,120,120,120,120,120,
+
+/* block 221 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20,120,120, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20,945,946,113,113,113, 20, 20, 20,946,945,945,
+945,945,945, 24, 24, 24, 24, 24, 24, 24, 24,113,113,113,113,113,
+
+/* block 222 */
+113,113,113, 20, 20,113,113,113,113,113,113,113, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,113,113,113,113, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 223 */
+685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,
+685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,
+685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,
+685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,
+685,685,947,947,947,685,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 224 */
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 225 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20,120,120,120,120,120,120,120,120,120,
+582,582,582,582,582,582,582,582,582,582,582,582,582,582,582,582,
+582,582, 25, 25, 25, 25, 25, 25, 25,120,120,120,120,120,120,120,
+
+/* block 226 */
+513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
+513,513,513,513,513,513,513,513,513,513,514,514,514,514,514,514,
+514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+514,514,514,514,513,513,513,513,513,513,513,513,513,513,513,513,
+513,513,513,513,513,513,513,513,513,513,513,513,513,513,514,514,
+514,514,514,514,514,120,514,514,514,514,514,514,514,514,514,514,
+514,514,514,514,514,514,514,514,513,513,513,513,513,513,513,513,
+513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
+
+/* block 227 */
+513,513,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+514,514,514,514,514,514,514,514,514,514,514,514,513,120,513,513,
+120,120,513,120,120,513,513,120,120,513,513,513,513,120,513,513,
+513,513,513,513,513,513,514,514,514,514,120,514,120,514,514,514,
+514,514,514,514,120,514,514,514,514,514,514,514,514,514,514,514,
+513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
+513,513,513,513,513,513,513,513,513,513,514,514,514,514,514,514,
+514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+
+/* block 228 */
+514,514,514,514,513,513,120,513,513,513,513,120,120,513,513,513,
+513,513,513,513,513,120,513,513,513,513,513,513,513,120,514,514,
+514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+514,514,514,514,514,514,514,514,513,513,120,513,513,513,513,120,
+513,513,513,513,513,120,513,120,120,120,513,513,513,513,513,513,
+513,120,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+514,514,514,514,514,514,514,514,514,514,514,514,513,513,513,513,
+513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
+
+/* block 229 */
+513,513,513,513,513,513,514,514,514,514,514,514,514,514,514,514,
+514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
+513,513,513,513,513,513,513,513,513,513,514,514,514,514,514,514,
+514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+514,514,514,514,513,513,513,513,513,513,513,513,513,513,513,513,
+513,513,513,513,513,513,513,513,513,513,513,513,513,513,514,514,
+514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+
+/* block 230 */
+514,514,514,514,514,514,514,514,513,513,513,513,513,513,513,513,
+513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
+513,513,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+514,514,514,514,514,514,514,514,514,514,514,514,513,513,513,513,
+513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
+513,513,513,513,513,513,514,514,514,514,514,514,514,514,514,514,
+514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
+
+/* block 231 */
+513,513,513,513,513,513,513,513,513,513,514,514,514,514,514,514,
+514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+514,514,514,514,514,514,120,120,513,513,513,513,513,513,513,513,
+513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
+513,  9,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+514,514,514,514,514,514,514,514,514,514,514,  9,514,514,514,514,
+514,514,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
+513,513,513,513,513,513,513,513,513,513,513,  9,514,514,514,514,
+
+/* block 232 */
+514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+514,514,514,514,514,  9,514,514,514,514,514,514,513,513,513,513,
+513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
+513,513,513,513,513,  9,514,514,514,514,514,514,514,514,514,514,
+514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,  9,
+514,514,514,514,514,514,513,513,513,513,513,513,513,513,513,513,
+513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,  9,
+514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+
+/* block 233 */
+514,514,514,514,514,514,514,514,514,  9,514,514,514,514,514,514,
+513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
+513,513,513,513,513,513,513,513,513,  9,514,514,514,514,514,514,
+514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+514,514,514,  9,514,514,514,514,514,514,513,514,120,120, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+
+/* block 234 */
+948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
+948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
+948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
+948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
+948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
+948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
+948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
+948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,948,
+
+/* block 235 */
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,948,948,948,948,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,948,948,948,
+948,948,948,948,948,949,948,948,948,948,948,948,948,948,948,948,
+
+/* block 236 */
+948,948,948,948,949,948,948,950,950,950,950,950,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,949,949,949,949,949,
+120,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 237 */
+951,951,951,951,951,951,951,120,951,951,951,951,951,951,951,951,
+951,951,951,951,951,951,951,951,951,120,120,951,951,951,951,951,
+951,951,120,951,951,120,951,951,951,951,951,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 238 */
+952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
+952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
+952,952,952,952,952,952,952,952,952,952,952,952,952,120,120,120,
+953,953,953,953,953,953,953,954,954,954,954,954,954,954,120,120,
+955,955,955,955,955,955,955,955,955,955,120,120,120,120,952,956,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 239 */
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+957,957,957,957,957,957,957,957,957,957,957,957,957,957,957,957,
+957,957,957,957,957,957,957,957,957,957,957,957,957,957,957,957,
+957,957,957,957,957,957,957,957,957,957,957,957,958,958,958,958,
+959,959,959,959,959,959,959,959,959,959,120,120,120,120,120,960,
+
+/* block 240 */
+961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
+961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
+961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
+961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
+961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
+961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
+961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
+961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
+
+/* block 241 */
+961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
+961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
+961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
+961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
+961,961,961,961,961,120,120,962,962,962,962,962,962,962,962,962,
+963,963,963,963,963,963,963,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 242 */
+964,964,964,964,964,964,964,964,964,964,964,964,964,964,964,964,
+964,964,964,964,964,964,964,964,964,964,964,964,964,964,964,964,
+964,964,965,965,965,965,965,965,965,965,965,965,965,965,965,965,
+965,965,965,965,965,965,965,965,965,965,965,965,965,965,965,965,
+965,965,965,965,966,966,966,966,966,966,966,967,120,120,120,120,
+968,968,968,968,968,968,968,968,968,968,120,120,120,120,969,969,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 243 */
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+
+/* block 244 */
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 20, 25, 25, 25,
+  6, 25, 25, 25, 25,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 245 */
+120, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 20, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 246 */
+224,224,224,224,120,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+120,224,224,120,224,120,120,224,120,224,224,224,224,224,224,224,
+224,224,224,120,224,224,224,224,120,224,120,224,120,120,120,120,
+120,120,224,120,120,120,120,224,120,224,120,224,120,224,224,224,
+120,224,224,120,224,120,120,224,120,224,120,224,120,224,120,224,
+120,224,224,120,224,120,120,224,224,224,224,120,224,224,224,224,
+224,224,224,120,224,224,224,224,120,224,224,224,224,120,224,120,
+
+/* block 247 */
+224,224,224,224,224,224,224,224,224,224,120,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,120,120,120,120,
+120,224,224,224,120,224,224,224,224,224,120,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+217,217,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 248 */
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,970,970,970,970,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+
+/* block 249 */
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21,970,970,970,970,970,970,970,970,970,970,970,970,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,970,
+970, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+970, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+970, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21,970,970,970,970,970,970,970,970,970,970,
+
+/* block 250 */
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 21, 21, 21,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21,
+ 21, 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21,
+
+/* block 251 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 20,
+ 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,971,971,971,971,971,971,971,971,971,971,
+971,971,971,971,971,971,971,971,971,971,971,971,971,971,971,971,
+
+/* block 252 */
+972, 21, 21,970,970,970,970,970,970,970,970,970,970,970,970,970,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
+ 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 20,970,970,970,970,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20,970,970,970,970,970,970,970,
+584,584,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+ 21, 21, 21, 21, 21, 21,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+
+/* block 253 */
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+
+/* block 254 */
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+
+/* block 255 */
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,973,973,973,973,973,
+
+/* block 256 */
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 20, 20,
+ 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+
+/* block 257 */
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+
+/* block 258 */
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21,970,970,970,970,970,970,970,970,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,970,970,970,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,970,970,970,
+
+/* block 259 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20,970,970,970,970,970,970,970,970,970,970,970,970,
+
+/* block 260 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 21, 21, 21, 21,970,970,970,970,970,970,970,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+
+/* block 261 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,970,970,970,970,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20,970,970,970,970,970,970,970,970,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,970,970,970,970,970,970,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+
+/* block 262 */
+ 20, 20, 20, 20, 20, 20, 20, 20,970,970,970,970,970,970,970,970,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,970,970,
+ 21, 21,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+
+/* block 263 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 20, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21,970, 21, 21, 21, 21, 21, 21,
+
+/* block 264 */
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,970, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+
+/* block 265 */
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21,970,970,970,970,970,970,970,970,970,970,970,970,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,970,970,
+ 21, 21, 21, 21, 21,970,970,970, 21, 21, 21,970,970,970,970,970,
+
+/* block 266 */
+ 21, 21, 21, 21, 21, 21, 21,970,970,970,970,970,970,970,970,970,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21,970,970,970,970,970,970,970,
+ 21, 21, 21, 21, 21, 21, 21,970,970,970,970,970,970,970,970,970,
+ 21, 21, 21,970,970,970,970,970,970,970,970,970,970,970,970,970,
+ 21, 21, 21, 21, 21, 21, 21,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+
+/* block 267 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20,120, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,120,120,120,120,120,120,
+
+/* block 268 */
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,970,
+970,970,970,970,970,970,970,970,970,970,970,970,970,970,120,120,
+
+/* block 269 */
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 270 */
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,120,120,120,120,120,120,120,120,120,120,120,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+
+/* block 271 */
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,120,120,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+
+/* block 272 */
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+
+/* block 273 */
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 274 */
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 275 */
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,
+
+/* block 276 */
+511, 24,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
+511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
+974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,
+974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,
+974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,
+974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,
+974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,
+974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,974,
+
+/* block 277 */
+511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
+511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
+511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
+511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
+511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
+511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
+511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
+511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
+
+/* block 278 */
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+
+/* block 279 */
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,
+511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,
+
+/* block 280 */
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,120,120,
+
+};
+
+#if UCD_BLOCK_SIZE != 128
+#error Please correct UCD_BLOCK_SIZE in pcre2_internal.h
+#endif
+#endif  /* SUPPORT_UNICODE */
+
+#endif  /* PCRE2_PCRE2TEST */
diff --git a/src/c/pcre2/src/pcre2_ucp.h b/src/c/pcre2/src/pcre2_ucp.h
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_ucp.h
@@ -0,0 +1,299 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifndef PCRE2_UCP_H_IDEMPOTENT_GUARD
+#define PCRE2_UCP_H_IDEMPOTENT_GUARD
+
+/* This file contains definitions of the property values that are returned by
+the UCD access macros. New values that are added for new releases of Unicode
+should always be at the end of each enum, for backwards compatibility.
+
+IMPORTANT: Note also that the specific numeric values of the enums have to be
+the same as the values that are generated by the maint/MultiStage2.py script,
+where the equivalent property descriptive names are listed in vectors.
+
+ALSO: The specific values of the first two enums are assumed for the table
+called catposstab in pcre2_compile.c. */
+
+/* These are the general character categories. */
+
+enum {
+  ucp_C,     /* Other */
+  ucp_L,     /* Letter */
+  ucp_M,     /* Mark */
+  ucp_N,     /* Number */
+  ucp_P,     /* Punctuation */
+  ucp_S,     /* Symbol */
+  ucp_Z      /* Separator */
+};
+
+/* These are the particular character categories. */
+
+enum {
+  ucp_Cc,    /* Control */
+  ucp_Cf,    /* Format */
+  ucp_Cn,    /* Unassigned */
+  ucp_Co,    /* Private use */
+  ucp_Cs,    /* Surrogate */
+  ucp_Ll,    /* Lower case letter */
+  ucp_Lm,    /* Modifier letter */
+  ucp_Lo,    /* Other letter */
+  ucp_Lt,    /* Title case letter */
+  ucp_Lu,    /* Upper case letter */
+  ucp_Mc,    /* Spacing mark */
+  ucp_Me,    /* Enclosing mark */
+  ucp_Mn,    /* Non-spacing mark */
+  ucp_Nd,    /* Decimal number */
+  ucp_Nl,    /* Letter number */
+  ucp_No,    /* Other number */
+  ucp_Pc,    /* Connector punctuation */
+  ucp_Pd,    /* Dash punctuation */
+  ucp_Pe,    /* Close punctuation */
+  ucp_Pf,    /* Final punctuation */
+  ucp_Pi,    /* Initial punctuation */
+  ucp_Po,    /* Other punctuation */
+  ucp_Ps,    /* Open punctuation */
+  ucp_Sc,    /* Currency symbol */
+  ucp_Sk,    /* Modifier symbol */
+  ucp_Sm,    /* Mathematical symbol */
+  ucp_So,    /* Other symbol */
+  ucp_Zl,    /* Line separator */
+  ucp_Zp,    /* Paragraph separator */
+  ucp_Zs     /* Space separator */
+};
+
+/* These are grapheme break properties. The Extended Pictographic property
+comes from the emoji-data.txt file. */
+
+enum {
+  ucp_gbCR,                    /*  0 */
+  ucp_gbLF,                    /*  1 */
+  ucp_gbControl,               /*  2 */
+  ucp_gbExtend,                /*  3 */
+  ucp_gbPrepend,               /*  4 */
+  ucp_gbSpacingMark,           /*  5 */
+  ucp_gbL,                     /*  6 Hangul syllable type L */
+  ucp_gbV,                     /*  7 Hangul syllable type V */
+  ucp_gbT,                     /*  8 Hangul syllable type T */
+  ucp_gbLV,                    /*  9 Hangul syllable type LV */
+  ucp_gbLVT,                   /* 10 Hangul syllable type LVT */
+  ucp_gbRegionalIndicator,     /* 11 */
+  ucp_gbOther,                 /* 12 */
+  ucp_gbZWJ,                   /* 13 */
+  ucp_gbExtended_Pictographic  /* 14 */
+};
+
+/* These are the script identifications. */
+
+enum {
+  ucp_Unknown,
+  ucp_Arabic,
+  ucp_Armenian,
+  ucp_Bengali,
+  ucp_Bopomofo,
+  ucp_Braille,
+  ucp_Buginese,
+  ucp_Buhid,
+  ucp_Canadian_Aboriginal,
+  ucp_Cherokee,
+  ucp_Common,
+  ucp_Coptic,
+  ucp_Cypriot,
+  ucp_Cyrillic,
+  ucp_Deseret,
+  ucp_Devanagari,
+  ucp_Ethiopic,
+  ucp_Georgian,
+  ucp_Glagolitic,
+  ucp_Gothic,
+  ucp_Greek,
+  ucp_Gujarati,
+  ucp_Gurmukhi,
+  ucp_Han,
+  ucp_Hangul,
+  ucp_Hanunoo,
+  ucp_Hebrew,
+  ucp_Hiragana,
+  ucp_Inherited,
+  ucp_Kannada,
+  ucp_Katakana,
+  ucp_Kharoshthi,
+  ucp_Khmer,
+  ucp_Lao,
+  ucp_Latin,
+  ucp_Limbu,
+  ucp_Linear_B,
+  ucp_Malayalam,
+  ucp_Mongolian,
+  ucp_Myanmar,
+  ucp_New_Tai_Lue,
+  ucp_Ogham,
+  ucp_Old_Italic,
+  ucp_Old_Persian,
+  ucp_Oriya,
+  ucp_Osmanya,
+  ucp_Runic,
+  ucp_Shavian,
+  ucp_Sinhala,
+  ucp_Syloti_Nagri,
+  ucp_Syriac,
+  ucp_Tagalog,
+  ucp_Tagbanwa,
+  ucp_Tai_Le,
+  ucp_Tamil,
+  ucp_Telugu,
+  ucp_Thaana,
+  ucp_Thai,
+  ucp_Tibetan,
+  ucp_Tifinagh,
+  ucp_Ugaritic,
+  ucp_Yi,
+  /* New for Unicode 5.0 */
+  ucp_Balinese,
+  ucp_Cuneiform,
+  ucp_Nko,
+  ucp_Phags_Pa,
+  ucp_Phoenician,
+  /* New for Unicode 5.1 */
+  ucp_Carian,
+  ucp_Cham,
+  ucp_Kayah_Li,
+  ucp_Lepcha,
+  ucp_Lycian,
+  ucp_Lydian,
+  ucp_Ol_Chiki,
+  ucp_Rejang,
+  ucp_Saurashtra,
+  ucp_Sundanese,
+  ucp_Vai,
+  /* New for Unicode 5.2 */
+  ucp_Avestan,
+  ucp_Bamum,
+  ucp_Egyptian_Hieroglyphs,
+  ucp_Imperial_Aramaic,
+  ucp_Inscriptional_Pahlavi,
+  ucp_Inscriptional_Parthian,
+  ucp_Javanese,
+  ucp_Kaithi,
+  ucp_Lisu,
+  ucp_Meetei_Mayek,
+  ucp_Old_South_Arabian,
+  ucp_Old_Turkic,
+  ucp_Samaritan,
+  ucp_Tai_Tham,
+  ucp_Tai_Viet,
+  /* New for Unicode 6.0.0 */
+  ucp_Batak,
+  ucp_Brahmi,
+  ucp_Mandaic,
+  /* New for Unicode 6.1.0 */
+  ucp_Chakma,
+  ucp_Meroitic_Cursive,
+  ucp_Meroitic_Hieroglyphs,
+  ucp_Miao,
+  ucp_Sharada,
+  ucp_Sora_Sompeng,
+  ucp_Takri,
+  /* New for Unicode 7.0.0 */
+  ucp_Bassa_Vah,
+  ucp_Caucasian_Albanian,
+  ucp_Duployan,
+  ucp_Elbasan,
+  ucp_Grantha,
+  ucp_Khojki,
+  ucp_Khudawadi,
+  ucp_Linear_A,
+  ucp_Mahajani,
+  ucp_Manichaean,
+  ucp_Mende_Kikakui,
+  ucp_Modi,
+  ucp_Mro,
+  ucp_Nabataean,
+  ucp_Old_North_Arabian,
+  ucp_Old_Permic,
+  ucp_Pahawh_Hmong,
+  ucp_Palmyrene,
+  ucp_Psalter_Pahlavi,
+  ucp_Pau_Cin_Hau,
+  ucp_Siddham,
+  ucp_Tirhuta,
+  ucp_Warang_Citi,
+  /* New for Unicode 8.0.0 */
+  ucp_Ahom,
+  ucp_Anatolian_Hieroglyphs,
+  ucp_Hatran,
+  ucp_Multani,
+  ucp_Old_Hungarian,
+  ucp_SignWriting,
+  /* New for Unicode 10.0.0 (no update since 8.0.0) */
+  ucp_Adlam,
+  ucp_Bhaiksuki,
+  ucp_Marchen,
+  ucp_Newa,
+  ucp_Osage,
+  ucp_Tangut,
+  ucp_Masaram_Gondi,
+  ucp_Nushu,
+  ucp_Soyombo,
+  ucp_Zanabazar_Square,
+  /* New for Unicode 11.0.0 */
+  ucp_Dogra,
+  ucp_Gunjala_Gondi,
+  ucp_Hanifi_Rohingya,
+  ucp_Makasar,
+  ucp_Medefaidrin,
+  ucp_Old_Sogdian,
+  ucp_Sogdian,
+  /* New for Unicode 12.0.0 */
+  ucp_Elymaic,
+  ucp_Nandinagari,
+  ucp_Nyiakeng_Puachue_Hmong,
+  ucp_Wancho,
+  /* New for Unicode 13.0.0 */
+  ucp_Chorasmian,
+  ucp_Dives_Akuru,
+  ucp_Khitan_Small_Script,
+  ucp_Yezidi
+};
+
+#endif  /* PCRE2_UCP_H_IDEMPOTENT_GUARD */
+
+/* End of pcre2_ucp.h */
diff --git a/src/c/pcre2/src/pcre2_valid_utf.c b/src/c/pcre2/src/pcre2_valid_utf.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_valid_utf.c
@@ -0,0 +1,398 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2020 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains an internal function for validating UTF character
+strings. This file is also #included by the pcre2test program, which uses
+macros to change names from _pcre2_xxx to xxxx, thereby avoiding name clashes
+with the library. In this case, PCRE2_PCRE2TEST is defined. */
+
+#ifndef PCRE2_PCRE2TEST           /* We're compiling the library */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "pcre2_internal.h"
+#endif /* PCRE2_PCRE2TEST */
+
+
+#ifndef SUPPORT_UNICODE
+/*************************************************
+*  Dummy function when Unicode is not supported  *
+*************************************************/
+
+/* This function should never be called when Unicode is not supported. */
+
+int
+PRIV(valid_utf)(PCRE2_SPTR string, PCRE2_SIZE length, PCRE2_SIZE *erroroffset)
+{
+(void)string;
+(void)length;
+(void)erroroffset;
+return 0;
+}
+#else  /* UTF is supported */
+
+
+
+/*************************************************
+*           Validate a UTF string                *
+*************************************************/
+
+/* This function is called (optionally) at the start of compile or match, to
+check that a supposed UTF string is actually valid. The early check means
+that subsequent code can assume it is dealing with a valid string. The check
+can be turned off for maximum performance, but the consequences of supplying an
+invalid string are then undefined.
+
+Arguments:
+  string       points to the string
+  length       length of string
+  errp         pointer to an error position offset variable
+
+Returns:       == 0    if the string is a valid UTF string
+               != 0    otherwise, setting the offset of the bad character
+*/
+
+int
+PRIV(valid_utf)(PCRE2_SPTR string, PCRE2_SIZE length, PCRE2_SIZE *erroroffset)
+{
+PCRE2_SPTR p;
+uint32_t c;
+
+/* ----------------- Check a UTF-8 string ----------------- */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+
+/* Originally, this function checked according to RFC 2279, allowing for values
+in the range 0 to 0x7fffffff, up to 6 bytes long, but ensuring that they were
+in the canonical format. Once somebody had pointed out RFC 3629 to me (it
+obsoletes 2279), additional restrictions were applied. The values are now
+limited to be between 0 and 0x0010ffff, no more than 4 bytes long, and the
+subrange 0xd000 to 0xdfff is excluded. However, the format of 5-byte and 6-byte
+characters is still checked. Error returns are as follows:
+
+PCRE2_ERROR_UTF8_ERR1   Missing 1 byte at the end of the string
+PCRE2_ERROR_UTF8_ERR2   Missing 2 bytes at the end of the string
+PCRE2_ERROR_UTF8_ERR3   Missing 3 bytes at the end of the string
+PCRE2_ERROR_UTF8_ERR4   Missing 4 bytes at the end of the string
+PCRE2_ERROR_UTF8_ERR5   Missing 5 bytes at the end of the string
+PCRE2_ERROR_UTF8_ERR6   2nd-byte's two top bits are not 0x80
+PCRE2_ERROR_UTF8_ERR7   3rd-byte's two top bits are not 0x80
+PCRE2_ERROR_UTF8_ERR8   4th-byte's two top bits are not 0x80
+PCRE2_ERROR_UTF8_ERR9   5th-byte's two top bits are not 0x80
+PCRE2_ERROR_UTF8_ERR10  6th-byte's two top bits are not 0x80
+PCRE2_ERROR_UTF8_ERR11  5-byte character is not permitted by RFC 3629
+PCRE2_ERROR_UTF8_ERR12  6-byte character is not permitted by RFC 3629
+PCRE2_ERROR_UTF8_ERR13  4-byte character with value > 0x10ffff is not permitted
+PCRE2_ERROR_UTF8_ERR14  3-byte character with value 0xd800-0xdfff is not permitted
+PCRE2_ERROR_UTF8_ERR15  Overlong 2-byte sequence
+PCRE2_ERROR_UTF8_ERR16  Overlong 3-byte sequence
+PCRE2_ERROR_UTF8_ERR17  Overlong 4-byte sequence
+PCRE2_ERROR_UTF8_ERR18  Overlong 5-byte sequence (won't ever occur)
+PCRE2_ERROR_UTF8_ERR19  Overlong 6-byte sequence (won't ever occur)
+PCRE2_ERROR_UTF8_ERR20  Isolated 0x80 byte (not within UTF-8 character)
+PCRE2_ERROR_UTF8_ERR21  Byte with the illegal value 0xfe or 0xff
+*/
+
+for (p = string; length > 0; p++)
+  {
+  uint32_t ab, d;
+
+  c = *p;
+  length--;
+
+  if (c < 128) continue;                /* ASCII character */
+
+  if (c < 0xc0)                         /* Isolated 10xx xxxx byte */
+    {
+    *erroroffset = (PCRE2_SIZE)(p - string);
+    return PCRE2_ERROR_UTF8_ERR20;
+    }
+
+  if (c >= 0xfe)                        /* Invalid 0xfe or 0xff bytes */
+    {
+    *erroroffset = (PCRE2_SIZE)(p - string);
+    return PCRE2_ERROR_UTF8_ERR21;
+    }
+
+  ab = PRIV(utf8_table4)[c & 0x3f];     /* Number of additional bytes (1-5) */
+  if (length < ab)                      /* Missing bytes */
+    {
+    *erroroffset = (PCRE2_SIZE)(p - string);
+    switch(ab - length)
+      {
+      case 1: return PCRE2_ERROR_UTF8_ERR1;
+      case 2: return PCRE2_ERROR_UTF8_ERR2;
+      case 3: return PCRE2_ERROR_UTF8_ERR3;
+      case 4: return PCRE2_ERROR_UTF8_ERR4;
+      case 5: return PCRE2_ERROR_UTF8_ERR5;
+      }
+    }
+  length -= ab;                         /* Length remaining */
+
+  /* Check top bits in the second byte */
+
+  if (((d = *(++p)) & 0xc0) != 0x80)
+    {
+    *erroroffset = (int)(p - string) - 1;
+    return PCRE2_ERROR_UTF8_ERR6;
+    }
+
+  /* For each length, check that the remaining bytes start with the 0x80 bit
+  set and not the 0x40 bit. Then check for an overlong sequence, and for the
+  excluded range 0xd800 to 0xdfff. */
+
+  switch (ab)
+    {
+    /* 2-byte character. No further bytes to check for 0x80. Check first byte
+    for for xx00 000x (overlong sequence). */
+
+    case 1: if ((c & 0x3e) == 0)
+      {
+      *erroroffset = (int)(p - string) - 1;
+      return PCRE2_ERROR_UTF8_ERR15;
+      }
+    break;
+
+    /* 3-byte character. Check third byte for 0x80. Then check first 2 bytes
+      for 1110 0000, xx0x xxxx (overlong sequence) or
+          1110 1101, 1010 xxxx (0xd800 - 0xdfff) */
+
+    case 2:
+    if ((*(++p) & 0xc0) != 0x80)     /* Third byte */
+      {
+      *erroroffset = (int)(p - string) - 2;
+      return PCRE2_ERROR_UTF8_ERR7;
+      }
+    if (c == 0xe0 && (d & 0x20) == 0)
+      {
+      *erroroffset = (int)(p - string) - 2;
+      return PCRE2_ERROR_UTF8_ERR16;
+      }
+    if (c == 0xed && d >= 0xa0)
+      {
+      *erroroffset = (int)(p - string) - 2;
+      return PCRE2_ERROR_UTF8_ERR14;
+      }
+    break;
+
+    /* 4-byte character. Check 3rd and 4th bytes for 0x80. Then check first 2
+       bytes for for 1111 0000, xx00 xxxx (overlong sequence), then check for a
+       character greater than 0x0010ffff (f4 8f bf bf) */
+
+    case 3:
+    if ((*(++p) & 0xc0) != 0x80)     /* Third byte */
+      {
+      *erroroffset = (int)(p - string) - 2;
+      return PCRE2_ERROR_UTF8_ERR7;
+      }
+    if ((*(++p) & 0xc0) != 0x80)     /* Fourth byte */
+      {
+      *erroroffset = (int)(p - string) - 3;
+      return PCRE2_ERROR_UTF8_ERR8;
+      }
+    if (c == 0xf0 && (d & 0x30) == 0)
+      {
+      *erroroffset = (int)(p - string) - 3;
+      return PCRE2_ERROR_UTF8_ERR17;
+      }
+    if (c > 0xf4 || (c == 0xf4 && d > 0x8f))
+      {
+      *erroroffset = (int)(p - string) - 3;
+      return PCRE2_ERROR_UTF8_ERR13;
+      }
+    break;
+
+    /* 5-byte and 6-byte characters are not allowed by RFC 3629, and will be
+    rejected by the length test below. However, we do the appropriate tests
+    here so that overlong sequences get diagnosed, and also in case there is
+    ever an option for handling these larger code points. */
+
+    /* 5-byte character. Check 3rd, 4th, and 5th bytes for 0x80. Then check for
+    1111 1000, xx00 0xxx */
+
+    case 4:
+    if ((*(++p) & 0xc0) != 0x80)     /* Third byte */
+      {
+      *erroroffset = (int)(p - string) - 2;
+      return PCRE2_ERROR_UTF8_ERR7;
+      }
+    if ((*(++p) & 0xc0) != 0x80)     /* Fourth byte */
+      {
+      *erroroffset = (int)(p - string) - 3;
+      return PCRE2_ERROR_UTF8_ERR8;
+      }
+    if ((*(++p) & 0xc0) != 0x80)     /* Fifth byte */
+      {
+      *erroroffset = (int)(p - string) - 4;
+      return PCRE2_ERROR_UTF8_ERR9;
+      }
+    if (c == 0xf8 && (d & 0x38) == 0)
+      {
+      *erroroffset = (int)(p - string) - 4;
+      return PCRE2_ERROR_UTF8_ERR18;
+      }
+    break;
+
+    /* 6-byte character. Check 3rd-6th bytes for 0x80. Then check for
+    1111 1100, xx00 00xx. */
+
+    case 5:
+    if ((*(++p) & 0xc0) != 0x80)     /* Third byte */
+      {
+      *erroroffset = (int)(p - string) - 2;
+      return PCRE2_ERROR_UTF8_ERR7;
+      }
+    if ((*(++p) & 0xc0) != 0x80)     /* Fourth byte */
+      {
+      *erroroffset = (int)(p - string) - 3;
+      return PCRE2_ERROR_UTF8_ERR8;
+      }
+    if ((*(++p) & 0xc0) != 0x80)     /* Fifth byte */
+      {
+      *erroroffset = (int)(p - string) - 4;
+      return PCRE2_ERROR_UTF8_ERR9;
+      }
+    if ((*(++p) & 0xc0) != 0x80)     /* Sixth byte */
+      {
+      *erroroffset = (int)(p - string) - 5;
+      return PCRE2_ERROR_UTF8_ERR10;
+      }
+    if (c == 0xfc && (d & 0x3c) == 0)
+      {
+      *erroroffset = (int)(p - string) - 5;
+      return PCRE2_ERROR_UTF8_ERR19;
+      }
+    break;
+    }
+
+  /* Character is valid under RFC 2279, but 4-byte and 5-byte characters are
+  excluded by RFC 3629. The pointer p is currently at the last byte of the
+  character. */
+
+  if (ab > 3)
+    {
+    *erroroffset = (int)(p - string) - ab;
+    return (ab == 4)? PCRE2_ERROR_UTF8_ERR11 : PCRE2_ERROR_UTF8_ERR12;
+    }
+  }
+return 0;
+
+
+/* ----------------- Check a UTF-16 string ----------------- */
+
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+
+/* There's not so much work, nor so many errors, for UTF-16.
+PCRE2_ERROR_UTF16_ERR1  Missing low surrogate at the end of the string
+PCRE2_ERROR_UTF16_ERR2  Invalid low surrogate
+PCRE2_ERROR_UTF16_ERR3  Isolated low surrogate
+*/
+
+for (p = string; length > 0; p++)
+  {
+  c = *p;
+  length--;
+
+  if ((c & 0xf800) != 0xd800)
+    {
+    /* Normal UTF-16 code point. Neither high nor low surrogate. */
+    }
+  else if ((c & 0x0400) == 0)
+    {
+    /* High surrogate. Must be a followed by a low surrogate. */
+    if (length == 0)
+      {
+      *erroroffset = p - string;
+      return PCRE2_ERROR_UTF16_ERR1;
+      }
+    p++;
+    length--;
+    if ((*p & 0xfc00) != 0xdc00)
+      {
+      *erroroffset = p - string - 1;
+      return PCRE2_ERROR_UTF16_ERR2;
+      }
+    }
+  else
+    {
+    /* Isolated low surrogate. Always an error. */
+    *erroroffset = p - string;
+    return PCRE2_ERROR_UTF16_ERR3;
+    }
+  }
+return 0;
+
+
+
+/* ----------------- Check a UTF-32 string ----------------- */
+
+#else
+
+/* There is very little to do for a UTF-32 string.
+PCRE2_ERROR_UTF32_ERR1  Surrogate character
+PCRE2_ERROR_UTF32_ERR2  Character > 0x10ffff
+*/
+
+for (p = string; length > 0; length--, p++)
+  {
+  c = *p;
+  if ((c & 0xfffff800u) != 0xd800u)
+    {
+    /* Normal UTF-32 code point. Neither high nor low surrogate. */
+    if (c > 0x10ffffu)
+      {
+      *erroroffset = p - string;
+      return PCRE2_ERROR_UTF32_ERR2;
+      }
+    }
+  else
+    {
+    /* A surrogate */
+    *erroroffset = p - string;
+    return PCRE2_ERROR_UTF32_ERR1;
+    }
+  }
+return 0;
+#endif  /* CODE_UNIT_WIDTH */
+}
+#endif  /* SUPPORT_UNICODE */
+
+/* End of pcre2_valid_utf.c */
diff --git a/src/c/pcre2/src/pcre2_xclass.c b/src/c/pcre2/src/pcre2_xclass.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2_xclass.c
@@ -0,0 +1,271 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2019 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains an internal function that is used to match an extended
+class. It is used by pcre2_auto_possessify() and by both pcre2_match() and
+pcre2_def_match(). */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "pcre2_internal.h"
+
+/*************************************************
+*       Match character against an XCLASS        *
+*************************************************/
+
+/* This function is called to match a character against an extended class that
+might contain codepoints above 255 and/or Unicode properties.
+
+Arguments:
+  c           the character
+  data        points to the flag code unit of the XCLASS data
+  utf         TRUE if in UTF mode
+
+Returns:      TRUE if character matches, else FALSE
+*/
+
+BOOL
+PRIV(xclass)(uint32_t c, PCRE2_SPTR data, BOOL utf)
+{
+PCRE2_UCHAR t;
+BOOL negated = (*data & XCL_NOT) != 0;
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+/* In 8 bit mode, this must always be TRUE. Help the compiler to know that. */
+utf = TRUE;
+#endif
+
+/* Code points < 256 are matched against a bitmap, if one is present. If not,
+we still carry on, because there may be ranges that start below 256 in the
+additional data. */
+
+if (c < 256)
+  {
+  if ((*data & XCL_HASPROP) == 0)
+    {
+    if ((*data & XCL_MAP) == 0) return negated;
+    return (((uint8_t *)(data + 1))[c/8] & (1u << (c&7))) != 0;
+    }
+  if ((*data & XCL_MAP) != 0 &&
+    (((uint8_t *)(data + 1))[c/8] & (1u << (c&7))) != 0)
+    return !negated; /* char found */
+  }
+
+/* First skip the bit map if present. Then match against the list of Unicode
+properties or large chars or ranges that end with a large char. We won't ever
+encounter XCL_PROP or XCL_NOTPROP when UTF support is not compiled. */
+
+if ((*data++ & XCL_MAP) != 0) data += 32 / sizeof(PCRE2_UCHAR);
+
+while ((t = *data++) != XCL_END)
+  {
+  uint32_t x, y;
+  if (t == XCL_SINGLE)
+    {
+#ifdef SUPPORT_UNICODE
+    if (utf)
+      {
+      GETCHARINC(x, data); /* macro generates multiple statements */
+      }
+    else
+#endif
+    x = *data++;
+    if (c == x) return !negated;
+    }
+  else if (t == XCL_RANGE)
+    {
+#ifdef SUPPORT_UNICODE
+    if (utf)
+      {
+      GETCHARINC(x, data); /* macro generates multiple statements */
+      GETCHARINC(y, data); /* macro generates multiple statements */
+      }
+    else
+#endif
+      {
+      x = *data++;
+      y = *data++;
+      }
+    if (c >= x && c <= y) return !negated;
+    }
+
+#ifdef SUPPORT_UNICODE
+  else  /* XCL_PROP & XCL_NOTPROP */
+    {
+    const ucd_record *prop = GET_UCD(c);
+    BOOL isprop = t == XCL_PROP;
+
+    switch(*data)
+      {
+      case PT_ANY:
+      if (isprop) return !negated;
+      break;
+
+      case PT_LAMP:
+      if ((prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
+           prop->chartype == ucp_Lt) == isprop) return !negated;
+      break;
+
+      case PT_GC:
+      if ((data[1] == PRIV(ucp_gentype)[prop->chartype]) == isprop)
+        return !negated;
+      break;
+
+      case PT_PC:
+      if ((data[1] == prop->chartype) == isprop) return !negated;
+      break;
+
+      case PT_SC:
+      if ((data[1] == prop->script) == isprop) return !negated;
+      break;
+
+      case PT_ALNUM:
+      if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+           PRIV(ucp_gentype)[prop->chartype] == ucp_N) == isprop)
+        return !negated;
+      break;
+
+      /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+      which means that Perl space and POSIX space are now identical. PCRE
+      was changed at release 8.34. */
+
+      case PT_SPACE:    /* Perl space */
+      case PT_PXSPACE:  /* POSIX space */
+      switch(c)
+        {
+        HSPACE_CASES:
+        VSPACE_CASES:
+        if (isprop) return !negated;
+        break;
+
+        default:
+        if ((PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == isprop)
+          return !negated;
+        break;
+        }
+      break;
+
+      case PT_WORD:
+      if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+           PRIV(ucp_gentype)[prop->chartype] == ucp_N || c == CHAR_UNDERSCORE)
+             == isprop)
+        return !negated;
+      break;
+
+      case PT_UCNC:
+      if (c < 0xa0)
+        {
+        if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT ||
+             c == CHAR_GRAVE_ACCENT) == isprop)
+          return !negated;
+        }
+      else
+        {
+        if ((c < 0xd800 || c > 0xdfff) == isprop)
+          return !negated;
+        }
+      break;
+
+      /* The following three properties can occur only in an XCLASS, as there
+      is no \p or \P coding for them. */
+
+      /* Graphic character. Implement this as not Z (space or separator) and
+      not C (other), except for Cf (format) with a few exceptions. This seems
+      to be what Perl does. The exceptional characters are:
+
+      U+061C           Arabic Letter Mark
+      U+180E           Mongolian Vowel Separator
+      U+2066 - U+2069  Various "isolate"s
+      */
+
+      case PT_PXGRAPH:
+      if ((PRIV(ucp_gentype)[prop->chartype] != ucp_Z &&
+            (PRIV(ucp_gentype)[prop->chartype] != ucp_C ||
+              (prop->chartype == ucp_Cf &&
+                c != 0x061c && c != 0x180e && (c < 0x2066 || c > 0x2069))
+         )) == isprop)
+        return !negated;
+      break;
+
+      /* Printable character: same as graphic, with the addition of Zs, i.e.
+      not Zl and not Zp, and U+180E. */
+
+      case PT_PXPRINT:
+      if ((prop->chartype != ucp_Zl &&
+           prop->chartype != ucp_Zp &&
+            (PRIV(ucp_gentype)[prop->chartype] != ucp_C ||
+              (prop->chartype == ucp_Cf &&
+                c != 0x061c && (c < 0x2066 || c > 0x2069))
+         )) == isprop)
+        return !negated;
+      break;
+
+      /* Punctuation: all Unicode punctuation, plus ASCII characters that
+      Unicode treats as symbols rather than punctuation, for Perl
+      compatibility (these are $+<=>^`|~). */
+
+      case PT_PXPUNCT:
+      if ((PRIV(ucp_gentype)[prop->chartype] == ucp_P ||
+            (c < 128 && PRIV(ucp_gentype)[prop->chartype] == ucp_S)) == isprop)
+        return !negated;
+      break;
+
+      /* This should never occur, but compilers may mutter if there is no
+      default. */
+
+      default:
+      return FALSE;
+      }
+
+    data += 2;
+    }
+#else
+  (void)utf;  /* Avoid compiler warning */
+#endif  /* SUPPORT_UNICODE */
+  }
+
+return negated;   /* char did not match */
+}
+
+/* End of pcre2_xclass.c */
diff --git a/src/c/pcre2/src/pcre2demo.c b/src/c/pcre2/src/pcre2demo.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2demo.c
@@ -0,0 +1,494 @@
+/*************************************************
+*           PCRE2 DEMONSTRATION PROGRAM          *
+*************************************************/
+
+/* This is a demonstration program to illustrate a straightforward way of
+using the PCRE2 regular expression library from a C program. See the
+pcre2sample documentation for a short discussion ("man pcre2sample" if you have
+the PCRE2 man pages installed). PCRE2 is a revised API for the library, and is
+incompatible with the original PCRE API.
+
+There are actually three libraries, each supporting a different code unit
+width. This demonstration program uses the 8-bit library. The default is to
+process each code unit as a separate character, but if the pattern begins with
+"(*UTF)", both it and the subject are treated as UTF-8 strings, where
+characters may occupy multiple code units.
+
+In Unix-like environments, if PCRE2 is installed in your standard system
+libraries, you should be able to compile this program using this command:
+
+cc -Wall pcre2demo.c -lpcre2-8 -o pcre2demo
+
+If PCRE2 is not installed in a standard place, it is likely to be installed
+with support for the pkg-config mechanism. If you have pkg-config, you can
+compile this program using this command:
+
+cc -Wall pcre2demo.c `pkg-config --cflags --libs libpcre2-8` -o pcre2demo
+
+If you do not have pkg-config, you may have to use something like this:
+
+cc -Wall pcre2demo.c -I/usr/local/include -L/usr/local/lib \
+  -R/usr/local/lib -lpcre2-8 -o pcre2demo
+
+Replace "/usr/local/include" and "/usr/local/lib" with wherever the include and
+library files for PCRE2 are installed on your system. Only some operating
+systems (Solaris is one) use the -R option.
+
+Building under Windows:
+
+If you want to statically link this program against a non-dll .a file, you must
+define PCRE2_STATIC before including pcre2.h, so in this environment, uncomment
+the following line. */
+
+/* #define PCRE2_STATIC */
+
+/* The PCRE2_CODE_UNIT_WIDTH macro must be defined before including pcre2.h.
+For a program that uses only one code unit width, setting it to 8, 16, or 32
+makes it possible to use generic function names such as pcre2_compile(). Note
+that just changing 8 to 16 (for example) is not sufficient to convert this
+program to process 16-bit characters. Even in a fully 16-bit environment, where
+string-handling functions such as strcmp() and printf() work with 16-bit
+characters, the code for handling the table of named substrings will still need
+to be modified. */
+
+#define PCRE2_CODE_UNIT_WIDTH 8
+
+#include <stdio.h>
+#include <string.h>
+#include <pcre2.h>
+
+
+/**************************************************************************
+* Here is the program. The API includes the concept of "contexts" for     *
+* setting up unusual interface requirements for compiling and matching,   *
+* such as custom memory managers and non-standard newline definitions.    *
+* This program does not do any of this, so it makes no use of contexts,   *
+* always passing NULL where a context could be given.                     *
+**************************************************************************/
+
+int main(int argc, char **argv)
+{
+pcre2_code *re;
+PCRE2_SPTR pattern;     /* PCRE2_SPTR is a pointer to unsigned code units of */
+PCRE2_SPTR subject;     /* the appropriate width (in this case, 8 bits). */
+PCRE2_SPTR name_table;
+
+int crlf_is_newline;
+int errornumber;
+int find_all;
+int i;
+int rc;
+int utf8;
+
+uint32_t option_bits;
+uint32_t namecount;
+uint32_t name_entry_size;
+uint32_t newline;
+
+PCRE2_SIZE erroroffset;
+PCRE2_SIZE *ovector;
+PCRE2_SIZE subject_length;
+
+pcre2_match_data *match_data;
+
+
+/**************************************************************************
+* First, sort out the command line. There is only one possible option at  *
+* the moment, "-g" to request repeated matching to find all occurrences,  *
+* like Perl's /g option. We set the variable find_all to a non-zero value *
+* if the -g option is present.                                            *
+**************************************************************************/
+
+find_all = 0;
+for (i = 1; i < argc; i++)
+  {
+  if (strcmp(argv[i], "-g") == 0) find_all = 1;
+  else if (argv[i][0] == '-')
+    {
+    printf("Unrecognised option %s\n", argv[i]);
+    return 1;
+    }
+  else break;
+  }
+
+/* After the options, we require exactly two arguments, which are the pattern,
+and the subject string. */
+
+if (argc - i != 2)
+  {
+  printf("Exactly two arguments required: a regex and a subject string\n");
+  return 1;
+  }
+
+/* Pattern and subject are char arguments, so they can be straightforwardly
+cast to PCRE2_SPTR because we are working in 8-bit code units. The subject
+length is cast to PCRE2_SIZE for completeness, though PCRE2_SIZE is in fact
+defined to be size_t. */
+
+pattern = (PCRE2_SPTR)argv[i];
+subject = (PCRE2_SPTR)argv[i+1];
+subject_length = (PCRE2_SIZE)strlen((char *)subject);
+
+
+/*************************************************************************
+* Now we are going to compile the regular expression pattern, and handle *
+* any errors that are detected.                                          *
+*************************************************************************/
+
+re = pcre2_compile(
+  pattern,               /* the pattern */
+  PCRE2_ZERO_TERMINATED, /* indicates pattern is zero-terminated */
+  0,                     /* default options */
+  &errornumber,          /* for error number */
+  &erroroffset,          /* for error offset */
+  NULL);                 /* use default compile context */
+
+/* Compilation failed: print the error message and exit. */
+
+if (re == NULL)
+  {
+  PCRE2_UCHAR buffer[256];
+  pcre2_get_error_message(errornumber, buffer, sizeof(buffer));
+  printf("PCRE2 compilation failed at offset %d: %s\n", (int)erroroffset,
+    buffer);
+  return 1;
+  }
+
+
+/*************************************************************************
+* If the compilation succeeded, we call PCRE2 again, in order to do a    *
+* pattern match against the subject string. This does just ONE match. If *
+* further matching is needed, it will be done below. Before running the  *
+* match we must set up a match_data block for holding the result. Using  *
+* pcre2_match_data_create_from_pattern() ensures that the block is       *
+* exactly the right size for the number of capturing parentheses in the  *
+* pattern. If you need to know the actual size of a match_data block as  *
+* a number of bytes, you can find it like this:                          *
+*                                                                        *
+* PCRE2_SIZE match_data_size = pcre2_get_match_data_size(match_data);    *
+*************************************************************************/
+
+match_data = pcre2_match_data_create_from_pattern(re, NULL);
+
+/* Now run the match. */
+
+rc = pcre2_match(
+  re,                   /* the compiled pattern */
+  subject,              /* the subject string */
+  subject_length,       /* the length of the subject */
+  0,                    /* start at offset 0 in the subject */
+  0,                    /* default options */
+  match_data,           /* block for storing the result */
+  NULL);                /* use default match context */
+
+/* Matching failed: handle error cases */
+
+if (rc < 0)
+  {
+  switch(rc)
+    {
+    case PCRE2_ERROR_NOMATCH: printf("No match\n"); break;
+    /*
+    Handle other special cases if you like
+    */
+    default: printf("Matching error %d\n", rc); break;
+    }
+  pcre2_match_data_free(match_data);   /* Release memory used for the match */
+  pcre2_code_free(re);                 /*   data and the compiled pattern. */
+  return 1;
+  }
+
+/* Match succeded. Get a pointer to the output vector, where string offsets are
+stored. */
+
+ovector = pcre2_get_ovector_pointer(match_data);
+printf("Match succeeded at offset %d\n", (int)ovector[0]);
+
+
+/*************************************************************************
+* We have found the first match within the subject string. If the output *
+* vector wasn't big enough, say so. Then output any substrings that were *
+* captured.                                                              *
+*************************************************************************/
+
+/* The output vector wasn't big enough. This should not happen, because we used
+pcre2_match_data_create_from_pattern() above. */
+
+if (rc == 0)
+  printf("ovector was not big enough for all the captured substrings\n");
+
+/* We must guard against patterns such as /(?=.\K)/ that use \K in an assertion
+to set the start of a match later than its end. In this demonstration program,
+we just detect this case and give up. */
+
+if (ovector[0] > ovector[1])
+  {
+  printf("\\K was used in an assertion to set the match start after its end.\n"
+    "From end to start the match was: %.*s\n", (int)(ovector[0] - ovector[1]),
+      (char *)(subject + ovector[1]));
+  printf("Run abandoned\n");
+  pcre2_match_data_free(match_data);
+  pcre2_code_free(re);
+  return 1;
+  }
+
+/* Show substrings stored in the output vector by number. Obviously, in a real
+application you might want to do things other than print them. */
+
+for (i = 0; i < rc; i++)
+  {
+  PCRE2_SPTR substring_start = subject + ovector[2*i];
+  PCRE2_SIZE substring_length = ovector[2*i+1] - ovector[2*i];
+  printf("%2d: %.*s\n", i, (int)substring_length, (char *)substring_start);
+  }
+
+
+/**************************************************************************
+* That concludes the basic part of this demonstration program. We have    *
+* compiled a pattern, and performed a single match. The code that follows *
+* shows first how to access named substrings, and then how to code for    *
+* repeated matches on the same subject.                                   *
+**************************************************************************/
+
+/* See if there are any named substrings, and if so, show them by name. First
+we have to extract the count of named parentheses from the pattern. */
+
+(void)pcre2_pattern_info(
+  re,                   /* the compiled pattern */
+  PCRE2_INFO_NAMECOUNT, /* get the number of named substrings */
+  &namecount);          /* where to put the answer */
+
+if (namecount == 0) printf("No named substrings\n"); else
+  {
+  PCRE2_SPTR tabptr;
+  printf("Named substrings\n");
+
+  /* Before we can access the substrings, we must extract the table for
+  translating names to numbers, and the size of each entry in the table. */
+
+  (void)pcre2_pattern_info(
+    re,                       /* the compiled pattern */
+    PCRE2_INFO_NAMETABLE,     /* address of the table */
+    &name_table);             /* where to put the answer */
+
+  (void)pcre2_pattern_info(
+    re,                       /* the compiled pattern */
+    PCRE2_INFO_NAMEENTRYSIZE, /* size of each entry in the table */
+    &name_entry_size);        /* where to put the answer */
+
+  /* Now we can scan the table and, for each entry, print the number, the name,
+  and the substring itself. In the 8-bit library the number is held in two
+  bytes, most significant first. */
+
+  tabptr = name_table;
+  for (i = 0; i < namecount; i++)
+    {
+    int n = (tabptr[0] << 8) | tabptr[1];
+    printf("(%d) %*s: %.*s\n", n, name_entry_size - 3, tabptr + 2,
+      (int)(ovector[2*n+1] - ovector[2*n]), subject + ovector[2*n]);
+    tabptr += name_entry_size;
+    }
+  }
+
+
+/*************************************************************************
+* If the "-g" option was given on the command line, we want to continue  *
+* to search for additional matches in the subject string, in a similar   *
+* way to the /g option in Perl. This turns out to be trickier than you   *
+* might think because of the possibility of matching an empty string.    *
+* What happens is as follows:                                            *
+*                                                                        *
+* If the previous match was NOT for an empty string, we can just start   *
+* the next match at the end of the previous one.                         *
+*                                                                        *
+* If the previous match WAS for an empty string, we can't do that, as it *
+* would lead to an infinite loop. Instead, a call of pcre2_match() is    *
+* made with the PCRE2_NOTEMPTY_ATSTART and PCRE2_ANCHORED flags set. The *
+* first of these tells PCRE2 that an empty string at the start of the    *
+* subject is not a valid match; other possibilities must be tried. The   *
+* second flag restricts PCRE2 to one match attempt at the initial string *
+* position. If this match succeeds, an alternative to the empty string   *
+* match has been found, and we can print it and proceed round the loop,  *
+* advancing by the length of whatever was found. If this match does not  *
+* succeed, we still stay in the loop, advancing by just one character.   *
+* In UTF-8 mode, which can be set by (*UTF) in the pattern, this may be  *
+* more than one byte.                                                    *
+*                                                                        *
+* However, there is a complication concerned with newlines. When the     *
+* newline convention is such that CRLF is a valid newline, we must       *
+* advance by two characters rather than one. The newline convention can  *
+* be set in the regex by (*CR), etc.; if not, we must find the default.  *
+*************************************************************************/
+
+if (!find_all)     /* Check for -g */
+  {
+  pcre2_match_data_free(match_data);  /* Release the memory that was used */
+  pcre2_code_free(re);                /* for the match data and the pattern. */
+  return 0;                           /* Exit the program. */
+  }
+
+/* Before running the loop, check for UTF-8 and whether CRLF is a valid newline
+sequence. First, find the options with which the regex was compiled and extract
+the UTF state. */
+
+(void)pcre2_pattern_info(re, PCRE2_INFO_ALLOPTIONS, &option_bits);
+utf8 = (option_bits & PCRE2_UTF) != 0;
+
+/* Now find the newline convention and see whether CRLF is a valid newline
+sequence. */
+
+(void)pcre2_pattern_info(re, PCRE2_INFO_NEWLINE, &newline);
+crlf_is_newline = newline == PCRE2_NEWLINE_ANY ||
+                  newline == PCRE2_NEWLINE_CRLF ||
+                  newline == PCRE2_NEWLINE_ANYCRLF;
+
+/* Loop for second and subsequent matches */
+
+for (;;)
+  {
+  uint32_t options = 0;                   /* Normally no options */
+  PCRE2_SIZE start_offset = ovector[1];   /* Start at end of previous match */
+
+  /* If the previous match was for an empty string, we are finished if we are
+  at the end of the subject. Otherwise, arrange to run another match at the
+  same point to see if a non-empty match can be found. */
+
+  if (ovector[0] == ovector[1])
+    {
+    if (ovector[0] == subject_length) break;
+    options = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED;
+    }
+
+  /* If the previous match was not an empty string, there is one tricky case to
+  consider. If a pattern contains \K within a lookbehind assertion at the
+  start, the end of the matched string can be at the offset where the match
+  started. Without special action, this leads to a loop that keeps on matching
+  the same substring. We must detect this case and arrange to move the start on
+  by one character. The pcre2_get_startchar() function returns the starting
+  offset that was passed to pcre2_match(). */
+
+  else
+    {
+    PCRE2_SIZE startchar = pcre2_get_startchar(match_data);
+    if (start_offset <= startchar)
+      {
+      if (startchar >= subject_length) break;   /* Reached end of subject.   */
+      start_offset = startchar + 1;             /* Advance by one character. */
+      if (utf8)                                 /* If UTF-8, it may be more  */
+        {                                       /*   than one code unit.     */
+        for (; start_offset < subject_length; start_offset++)
+          if ((subject[start_offset] & 0xc0) != 0x80) break;
+        }
+      }
+    }
+
+  /* Run the next matching operation */
+
+  rc = pcre2_match(
+    re,                   /* the compiled pattern */
+    subject,              /* the subject string */
+    subject_length,       /* the length of the subject */
+    start_offset,         /* starting offset in the subject */
+    options,              /* options */
+    match_data,           /* block for storing the result */
+    NULL);                /* use default match context */
+
+  /* This time, a result of NOMATCH isn't an error. If the value in "options"
+  is zero, it just means we have found all possible matches, so the loop ends.
+  Otherwise, it means we have failed to find a non-empty-string match at a
+  point where there was a previous empty-string match. In this case, we do what
+  Perl does: advance the matching position by one character, and continue. We
+  do this by setting the "end of previous match" offset, because that is picked
+  up at the top of the loop as the point at which to start again.
+
+  There are two complications: (a) When CRLF is a valid newline sequence, and
+  the current position is just before it, advance by an extra byte. (b)
+  Otherwise we must ensure that we skip an entire UTF character if we are in
+  UTF mode. */
+
+  if (rc == PCRE2_ERROR_NOMATCH)
+    {
+    if (options == 0) break;                    /* All matches found */
+    ovector[1] = start_offset + 1;              /* Advance one code unit */
+    if (crlf_is_newline &&                      /* If CRLF is a newline & */
+        start_offset < subject_length - 1 &&    /* we are at CRLF, */
+        subject[start_offset] == '\r' &&
+        subject[start_offset + 1] == '\n')
+      ovector[1] += 1;                          /* Advance by one more. */
+    else if (utf8)                              /* Otherwise, ensure we */
+      {                                         /* advance a whole UTF-8 */
+      while (ovector[1] < subject_length)       /* character. */
+        {
+        if ((subject[ovector[1]] & 0xc0) != 0x80) break;
+        ovector[1] += 1;
+        }
+      }
+    continue;    /* Go round the loop again */
+    }
+
+  /* Other matching errors are not recoverable. */
+
+  if (rc < 0)
+    {
+    printf("Matching error %d\n", rc);
+    pcre2_match_data_free(match_data);
+    pcre2_code_free(re);
+    return 1;
+    }
+
+  /* Match succeded */
+
+  printf("\nMatch succeeded again at offset %d\n", (int)ovector[0]);
+
+  /* The match succeeded, but the output vector wasn't big enough. This
+  should not happen. */
+
+  if (rc == 0)
+    printf("ovector was not big enough for all the captured substrings\n");
+
+  /* We must guard against patterns such as /(?=.\K)/ that use \K in an
+  assertion to set the start of a match later than its end. In this
+  demonstration program, we just detect this case and give up. */
+
+  if (ovector[0] > ovector[1])
+    {
+    printf("\\K was used in an assertion to set the match start after its end.\n"
+      "From end to start the match was: %.*s\n", (int)(ovector[0] - ovector[1]),
+        (char *)(subject + ovector[1]));
+    printf("Run abandoned\n");
+    pcre2_match_data_free(match_data);
+    pcre2_code_free(re);
+    return 1;
+    }
+
+  /* As before, show substrings stored in the output vector by number, and then
+  also any named substrings. */
+
+  for (i = 0; i < rc; i++)
+    {
+    PCRE2_SPTR substring_start = subject + ovector[2*i];
+    size_t substring_length = ovector[2*i+1] - ovector[2*i];
+    printf("%2d: %.*s\n", i, (int)substring_length, (char *)substring_start);
+    }
+
+  if (namecount == 0) printf("No named substrings\n"); else
+    {
+    PCRE2_SPTR tabptr = name_table;
+    printf("Named substrings\n");
+    for (i = 0; i < namecount; i++)
+      {
+      int n = (tabptr[0] << 8) | tabptr[1];
+      printf("(%d) %*s: %.*s\n", n, name_entry_size - 3, tabptr + 2,
+        (int)(ovector[2*n+1] - ovector[2*n]), subject + ovector[2*n]);
+      tabptr += name_entry_size;
+      }
+    }
+  }      /* End of loop to find second and subsequent matches */
+
+printf("\n");
+pcre2_match_data_free(match_data);
+pcre2_code_free(re);
+return 0;
+}
+
+/* End of pcre2demo.c */
diff --git a/src/c/pcre2/src/pcre2grep.c b/src/c/pcre2/src/pcre2grep.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2grep.c
@@ -0,0 +1,4553 @@
+/*************************************************
+*               pcre2grep program                *
+*************************************************/
+
+/* This is a grep program that uses the 8-bit PCRE regular expression library
+via the PCRE2 updated API to do its pattern matching. On Unix-like, Windows,
+and native z/OS systems it can recurse into directories, and in z/OS it can
+handle PDS files.
+
+Note that for native z/OS, in addition to defining the NATIVE_ZOS macro, an
+additional header is required. That header is not included in the main PCRE2
+distribution because other apparatus is needed to compile pcre2grep for z/OS.
+The header can be found in the special z/OS distribution, which is available
+from www.zaconsultants.net or from www.cbttape.org.
+
+           Copyright (c) 1997-2020 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ctype.h>
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if (defined _WIN32 || (defined HAVE_WINDOWS_H && HAVE_WINDOWS_H)) \
+  && !defined WIN32 && !defined(__CYGWIN__)
+#define WIN32
+#endif
+
+/* Some cmake's define it still */
+#if defined(__CYGWIN__) && defined(WIN32)
+#undef WIN32
+#endif
+
+#ifdef __VMS
+#include clidef
+#include descrip
+#include lib$routines
+#endif
+
+#ifdef WIN32
+#include <io.h>                /* For _setmode() */
+#include <fcntl.h>             /* For _O_BINARY */
+#endif
+
+#if defined(SUPPORT_PCRE2GREP_CALLOUT) && defined(SUPPORT_PCRE2GREP_CALLOUT_FORK)
+#ifdef WIN32
+#include <process.h>
+#else
+#include <sys/wait.h>
+#endif
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef SUPPORT_LIBZ
+#include <zlib.h>
+#endif
+
+#ifdef SUPPORT_LIBBZ2
+#include <bzlib.h>
+#endif
+
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include "pcre2.h"
+
+/* Older versions of MSVC lack snprintf(). This define allows for
+warning/error-free compilation and testing with MSVC compilers back to at least
+MSVC 10/2010. Except for VC6 (which is missing some fundamentals and fails). */
+
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+#define snprintf _snprintf
+#endif
+
+/* VC and older compilers don't support %td or %zu, and even some that claim to
+be C99 don't support it (hence DISABLE_PERCENT_ZT). */
+
+#if defined(_MSC_VER) || !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L || defined(DISABLE_PERCENT_ZT)
+#define PTR_FORM "lu"
+#define SIZ_FORM "lu"
+#define SIZ_CAST (unsigned long int)
+#else
+#define PTR_FORM "td"
+#define SIZ_FORM "zu"
+#define SIZ_CAST
+#endif
+
+#define FALSE 0
+#define TRUE 1
+
+typedef int BOOL;
+
+#define DEFAULT_CAPTURE_MAX 50
+
+#if BUFSIZ > 8192
+#define MAXPATLEN BUFSIZ
+#else
+#define MAXPATLEN 8192
+#endif
+
+#define FNBUFSIZ 2048
+#define ERRBUFSIZ 256
+
+/* Values for the "filenames" variable, which specifies options for file name
+output. The order is important; it is assumed that a file name is wanted for
+all values greater than FN_DEFAULT. */
+
+enum { FN_NONE, FN_DEFAULT, FN_MATCH_ONLY, FN_NOMATCH_ONLY, FN_FORCE };
+
+/* File reading styles */
+
+enum { FR_PLAIN, FR_LIBZ, FR_LIBBZ2 };
+
+/* Actions for the -d and -D options */
+
+enum { dee_READ, dee_SKIP, dee_RECURSE };
+enum { DEE_READ, DEE_SKIP };
+
+/* Actions for special processing options (flag bits) */
+
+#define PO_WORD_MATCH     0x0001
+#define PO_LINE_MATCH     0x0002
+#define PO_FIXED_STRINGS  0x0004
+
+/* Binary file options */
+
+enum { BIN_BINARY, BIN_NOMATCH, BIN_TEXT };
+
+/* Return values from decode_dollar_escape() */
+
+enum { DDE_ERROR, DDE_CAPTURE, DDE_CHAR };
+
+/* In newer versions of gcc, with FORTIFY_SOURCE set (the default in some
+environments), a warning is issued if the value of fwrite() is ignored.
+Unfortunately, casting to (void) does not suppress the warning. To get round
+this, we use a macro that compiles a fudge. Oddly, this does not also seem to
+apply to fprintf(). */
+
+#define FWRITE_IGNORE(a,b,c,d) if (fwrite(a,b,c,d)) {}
+
+/* Under Windows, we have to set stdout to be binary, so that it does not
+convert \r\n at the ends of output lines to \r\r\n. However, that means that
+any messages written to stdout must have \r\n as their line terminator. This is
+handled by using STDOUT_NL as the newline string. We also use a normal double
+quote for the example, as single quotes aren't usually available. */
+
+#ifdef WIN32
+#define STDOUT_NL     "\r\n"
+#define STDOUT_NL_LEN  2
+#define QUOT          "\""
+#else
+#define STDOUT_NL      "\n"
+#define STDOUT_NL_LEN  1
+#define QUOT           "'"
+#endif
+
+/* This code is returned from decode_dollar_escape() when $n is encountered,
+and used to mean "output STDOUT_NL". It is, of course, not a valid Unicode code
+point. */
+
+#define STDOUT_NL_CODE 0x7fffffffu
+
+
+
+/*************************************************
+*               Global variables                 *
+*************************************************/
+
+/* Jeffrey Friedl has some debugging requirements that are not part of the
+regular code. */
+
+#ifdef JFRIEDL_DEBUG
+static int S_arg = -1;
+static unsigned int jfriedl_XR = 0; /* repeat regex attempt this many times */
+static unsigned int jfriedl_XT = 0; /* replicate text this many times */
+static const char *jfriedl_prefix = "";
+static const char *jfriedl_postfix = "";
+#endif
+
+static const char *colour_string = "1;31";
+static const char *colour_option = NULL;
+static const char *dee_option = NULL;
+static const char *DEE_option = NULL;
+static const char *locale = NULL;
+static const char *newline_arg = NULL;
+static const char *om_separator = NULL;
+static const char *stdin_name = "(standard input)";
+static const char *output_text = NULL;
+
+static char *main_buffer = NULL;
+
+static int after_context = 0;
+static int before_context = 0;
+static int binary_files = BIN_BINARY;
+static int both_context = 0;
+static int bufthird = PCRE2GREP_BUFSIZE;
+static int max_bufthird = PCRE2GREP_MAX_BUFSIZE;
+static int bufsize = 3*PCRE2GREP_BUFSIZE;
+static int endlinetype;
+
+static int count_limit = -1;  /* Not long, so that it works with OP_NUMBER */
+static unsigned long int counts_printed = 0;
+static unsigned long int total_count = 0;
+
+#ifdef WIN32
+static int dee_action = dee_SKIP;
+#else
+static int dee_action = dee_READ;
+#endif
+
+static int DEE_action = DEE_READ;
+static int error_count = 0;
+static int filenames = FN_DEFAULT;
+
+#ifdef SUPPORT_PCRE2GREP_JIT
+static BOOL use_jit = TRUE;
+#else
+static BOOL use_jit = FALSE;
+#endif
+
+static const uint8_t *character_tables = NULL;
+
+static uint32_t pcre2_options = 0;
+static uint32_t extra_options = 0;
+static PCRE2_SIZE heap_limit = PCRE2_UNSET;
+static uint32_t match_limit = 0;
+static uint32_t depth_limit = 0;
+
+static pcre2_compile_context *compile_context;
+static pcre2_match_context *match_context;
+static pcre2_match_data *match_data;
+static PCRE2_SIZE *offsets;
+static uint32_t offset_size;
+static uint32_t capture_max = DEFAULT_CAPTURE_MAX;
+
+static BOOL count_only = FALSE;
+static BOOL do_colour = FALSE;
+#ifdef WIN32
+static BOOL do_ansi = FALSE;
+#endif
+static BOOL file_offsets = FALSE;
+static BOOL hyphenpending = FALSE;
+static BOOL invert = FALSE;
+static BOOL line_buffered = FALSE;
+static BOOL line_offsets = FALSE;
+static BOOL multiline = FALSE;
+static BOOL number = FALSE;
+static BOOL omit_zero_count = FALSE;
+static BOOL resource_error = FALSE;
+static BOOL quiet = FALSE;
+static BOOL show_total_count = FALSE;
+static BOOL silent = FALSE;
+static BOOL utf = FALSE;
+
+static uint8_t utf8_buffer[8];
+
+
+/* Structure for list of --only-matching capturing numbers. */
+
+typedef struct omstr {
+  struct omstr *next;
+  int groupnum;
+} omstr;
+
+static omstr *only_matching = NULL;
+static omstr *only_matching_last = NULL;
+static int only_matching_count;
+
+/* Structure for holding the two variables that describe a number chain. */
+
+typedef struct omdatastr {
+  omstr **anchor;
+  omstr **lastptr;
+} omdatastr;
+
+static omdatastr only_matching_data = { &only_matching, &only_matching_last };
+
+/* Structure for list of file names (for -f and --{in,ex}clude-from) */
+
+typedef struct fnstr {
+  struct fnstr *next;
+  char *name;
+} fnstr;
+
+static fnstr *exclude_from = NULL;
+static fnstr *exclude_from_last = NULL;
+static fnstr *include_from = NULL;
+static fnstr *include_from_last = NULL;
+
+static fnstr *file_lists = NULL;
+static fnstr *file_lists_last = NULL;
+static fnstr *pattern_files = NULL;
+static fnstr *pattern_files_last = NULL;
+
+/* Structure for holding the two variables that describe a file name chain. */
+
+typedef struct fndatastr {
+  fnstr **anchor;
+  fnstr **lastptr;
+} fndatastr;
+
+static fndatastr exclude_from_data = { &exclude_from, &exclude_from_last };
+static fndatastr include_from_data = { &include_from, &include_from_last };
+static fndatastr file_lists_data = { &file_lists, &file_lists_last };
+static fndatastr pattern_files_data = { &pattern_files, &pattern_files_last };
+
+/* Structure for pattern and its compiled form; used for matching patterns and
+also for include/exclude patterns. */
+
+typedef struct patstr {
+  struct patstr *next;
+  char *string;
+  PCRE2_SIZE length;
+  pcre2_code *compiled;
+} patstr;
+
+static patstr *patterns = NULL;
+static patstr *patterns_last = NULL;
+static patstr *include_patterns = NULL;
+static patstr *include_patterns_last = NULL;
+static patstr *exclude_patterns = NULL;
+static patstr *exclude_patterns_last = NULL;
+static patstr *include_dir_patterns = NULL;
+static patstr *include_dir_patterns_last = NULL;
+static patstr *exclude_dir_patterns = NULL;
+static patstr *exclude_dir_patterns_last = NULL;
+
+/* Structure holding the two variables that describe a pattern chain. A pointer
+to such structures is used for each appropriate option. */
+
+typedef struct patdatastr {
+  patstr **anchor;
+  patstr **lastptr;
+} patdatastr;
+
+static patdatastr match_patdata = { &patterns, &patterns_last };
+static patdatastr include_patdata = { &include_patterns, &include_patterns_last };
+static patdatastr exclude_patdata = { &exclude_patterns, &exclude_patterns_last };
+static patdatastr include_dir_patdata = { &include_dir_patterns, &include_dir_patterns_last };
+static patdatastr exclude_dir_patdata = { &exclude_dir_patterns, &exclude_dir_patterns_last };
+
+static patstr **incexlist[4] = { &include_patterns, &exclude_patterns,
+                                 &include_dir_patterns, &exclude_dir_patterns };
+
+static const char *incexname[4] = { "--include", "--exclude",
+                                    "--include-dir", "--exclude-dir" };
+
+/* Structure for options and list of them */
+
+enum { OP_NODATA, OP_STRING, OP_OP_STRING, OP_NUMBER, OP_U32NUMBER, OP_SIZE,
+       OP_OP_NUMBER, OP_OP_NUMBERS, OP_PATLIST, OP_FILELIST, OP_BINFILES };
+
+typedef struct option_item {
+  int type;
+  int one_char;
+  void *dataptr;
+  const char *long_name;
+  const char *help_text;
+} option_item;
+
+/* Options without a single-letter equivalent get a negative value. This can be
+used to identify them. */
+
+#define N_COLOUR       (-1)
+#define N_EXCLUDE      (-2)
+#define N_EXCLUDE_DIR  (-3)
+#define N_HELP         (-4)
+#define N_INCLUDE      (-5)
+#define N_INCLUDE_DIR  (-6)
+#define N_LABEL        (-7)
+#define N_LOCALE       (-8)
+#define N_NULL         (-9)
+#define N_LOFFSETS     (-10)
+#define N_FOFFSETS     (-11)
+#define N_LBUFFER      (-12)
+#define N_H_LIMIT      (-13)
+#define N_M_LIMIT      (-14)
+#define N_M_LIMIT_DEP  (-15)
+#define N_BUFSIZE      (-16)
+#define N_NOJIT        (-17)
+#define N_FILE_LIST    (-18)
+#define N_BINARY_FILES (-19)
+#define N_EXCLUDE_FROM (-20)
+#define N_INCLUDE_FROM (-21)
+#define N_OM_SEPARATOR (-22)
+#define N_MAX_BUFSIZE  (-23)
+#define N_OM_CAPTURE   (-24)
+
+static option_item optionlist[] = {
+  { OP_NODATA,     N_NULL,   NULL,              "",              "terminate options" },
+  { OP_NODATA,     N_HELP,   NULL,              "help",          "display this help and exit" },
+  { OP_NUMBER,     'A',      &after_context,    "after-context=number", "set number of following context lines" },
+  { OP_NODATA,     'a',      NULL,              "text",          "treat binary files as text" },
+  { OP_NUMBER,     'B',      &before_context,   "before-context=number", "set number of prior context lines" },
+  { OP_BINFILES,   N_BINARY_FILES, NULL,        "binary-files=word", "set treatment of binary files" },
+  { OP_NUMBER,     N_BUFSIZE,&bufthird,         "buffer-size=number", "set processing buffer starting size" },
+  { OP_NUMBER,     N_MAX_BUFSIZE,&max_bufthird, "max-buffer-size=number",  "set processing buffer maximum size" },
+  { OP_OP_STRING,  N_COLOUR, &colour_option,    "color=option",  "matched text color option" },
+  { OP_OP_STRING,  N_COLOUR, &colour_option,    "colour=option", "matched text colour option" },
+  { OP_NUMBER,     'C',      &both_context,     "context=number", "set number of context lines, before & after" },
+  { OP_NODATA,     'c',      NULL,              "count",         "print only a count of matching lines per FILE" },
+  { OP_STRING,     'D',      &DEE_option,       "devices=action","how to handle devices, FIFOs, and sockets" },
+  { OP_STRING,     'd',      &dee_option,       "directories=action", "how to handle directories" },
+  { OP_PATLIST,    'e',      &match_patdata,    "regex(p)=pattern", "specify pattern (may be used more than once)" },
+  { OP_NODATA,     'F',      NULL,              "fixed-strings", "patterns are sets of newline-separated strings" },
+  { OP_FILELIST,   'f',      &pattern_files_data, "file=path",   "read patterns from file" },
+  { OP_FILELIST,   N_FILE_LIST, &file_lists_data, "file-list=path","read files to search from file" },
+  { OP_NODATA,     N_FOFFSETS, NULL,            "file-offsets",  "output file offsets, not text" },
+  { OP_NODATA,     'H',      NULL,              "with-filename", "force the prefixing filename on output" },
+  { OP_NODATA,     'h',      NULL,              "no-filename",   "suppress the prefixing filename on output" },
+  { OP_NODATA,     'I',      NULL,              "",              "treat binary files as not matching (ignore)" },
+  { OP_NODATA,     'i',      NULL,              "ignore-case",   "ignore case distinctions" },
+  { OP_NODATA,     'l',      NULL,              "files-with-matches", "print only FILE names containing matches" },
+  { OP_NODATA,     'L',      NULL,              "files-without-match","print only FILE names not containing matches" },
+  { OP_STRING,     N_LABEL,  &stdin_name,       "label=name",    "set name for standard input" },
+  { OP_NODATA,     N_LBUFFER, NULL,             "line-buffered", "use line buffering" },
+  { OP_NODATA,     N_LOFFSETS, NULL,            "line-offsets",  "output line numbers and offsets, not text" },
+  { OP_STRING,     N_LOCALE, &locale,           "locale=locale", "use the named locale" },
+  { OP_SIZE,       N_H_LIMIT, &heap_limit,      "heap-limit=number",  "set PCRE2 heap limit option (kibibytes)" },
+  { OP_U32NUMBER,  N_M_LIMIT, &match_limit,     "match-limit=number", "set PCRE2 match limit option" },
+  { OP_U32NUMBER,  N_M_LIMIT_DEP, &depth_limit, "depth-limit=number", "set PCRE2 depth limit option" },
+  { OP_U32NUMBER,  N_M_LIMIT_DEP, &depth_limit, "recursion-limit=number", "obsolete synonym for depth-limit" },
+  { OP_NODATA,     'M',      NULL,              "multiline",     "run in multiline mode" },
+  { OP_NUMBER,     'm',      &count_limit,      "max-count=number", "stop after <number> matched lines" },
+  { OP_STRING,     'N',      &newline_arg,      "newline=type",  "set newline type (CR, LF, CRLF, ANYCRLF, ANY, or NUL)" },
+  { OP_NODATA,     'n',      NULL,              "line-number",   "print line number with output lines" },
+#ifdef SUPPORT_PCRE2GREP_JIT
+  { OP_NODATA,     N_NOJIT,  NULL,              "no-jit",        "do not use just-in-time compiler optimization" },
+#else
+  { OP_NODATA,     N_NOJIT,  NULL,              "no-jit",        "ignored: this pcre2grep does not support JIT" },
+#endif
+  { OP_STRING,     'O',      &output_text,       "output=text",   "show only this text (possibly expanded)" },
+  { OP_OP_NUMBERS, 'o',      &only_matching_data, "only-matching=n", "show only the part of the line that matched" },
+  { OP_STRING,     N_OM_SEPARATOR, &om_separator, "om-separator=text", "set separator for multiple -o output" },
+  { OP_U32NUMBER,  N_OM_CAPTURE, &capture_max,  "om-capture=n",  "set capture count for --only-matching" },
+  { OP_NODATA,     'q',      NULL,              "quiet",         "suppress output, just set return code" },
+  { OP_NODATA,     'r',      NULL,              "recursive",     "recursively scan sub-directories" },
+  { OP_PATLIST,    N_EXCLUDE,&exclude_patdata,  "exclude=pattern","exclude matching files when recursing" },
+  { OP_PATLIST,    N_INCLUDE,&include_patdata,  "include=pattern","include matching files when recursing" },
+  { OP_PATLIST,    N_EXCLUDE_DIR,&exclude_dir_patdata, "exclude-dir=pattern","exclude matching directories when recursing" },
+  { OP_PATLIST,    N_INCLUDE_DIR,&include_dir_patdata, "include-dir=pattern","include matching directories when recursing" },
+  { OP_FILELIST,   N_EXCLUDE_FROM,&exclude_from_data, "exclude-from=path", "read exclude list from file" },
+  { OP_FILELIST,   N_INCLUDE_FROM,&include_from_data, "include-from=path", "read include list from file" },
+#ifdef JFRIEDL_DEBUG
+  { OP_OP_NUMBER, 'S',      &S_arg,            "jeffS",         "replace matched (sub)string with X" },
+#endif
+  { OP_NODATA,    's',      NULL,              "no-messages",   "suppress error messages" },
+  { OP_NODATA,    't',      NULL,              "total-count",   "print total count of matching lines" },
+  { OP_NODATA,    'u',      NULL,              "utf",           "use UTF mode" },
+  { OP_NODATA,    'U',      NULL,              "utf-allow-invalid", "use UTF mode, allow for invalid code units" },
+  { OP_NODATA,    'V',      NULL,              "version",       "print version information and exit" },
+  { OP_NODATA,    'v',      NULL,              "invert-match",  "select non-matching lines" },
+  { OP_NODATA,    'w',      NULL,              "word-regex(p)", "force patterns to match only as words"  },
+  { OP_NODATA,    'x',      NULL,              "line-regex(p)", "force patterns to match only whole lines" },
+  { OP_NODATA,    0,        NULL,               NULL,            NULL }
+};
+
+/* Table of names for newline types. Must be kept in step with the definitions
+of PCRE2_NEWLINE_xx in pcre2.h. */
+
+static const char *newlines[] = {
+  "DEFAULT", "CR", "LF", "CRLF", "ANY", "ANYCRLF", "NUL" };
+
+/* UTF-8 tables  */
+
+const int utf8_table1[] =
+  { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff};
+const int utf8_table1_size = sizeof(utf8_table1) / sizeof(int);
+
+const int utf8_table2[] = { 0,    0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
+const int utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
+
+const char utf8_table4[] = {
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 };
+
+
+#if !defined(VPCOMPAT) && !defined(HAVE_MEMMOVE)
+/*************************************************
+*    Emulated memmove() for systems without it   *
+*************************************************/
+
+/* This function can make use of bcopy() if it is available. Otherwise do it by
+steam, as there are some non-Unix environments that lack both memmove() and
+bcopy(). */
+
+static void *
+emulated_memmove(void *d, const void *s, size_t n)
+{
+#ifdef HAVE_BCOPY
+bcopy(s, d, n);
+return d;
+#else
+size_t i;
+unsigned char *dest = (unsigned char *)d;
+const unsigned char *src = (const unsigned char *)s;
+if (dest > src)
+  {
+  dest += n;
+  src += n;
+  for (i = 0; i < n; ++i) *(--dest) = *(--src);
+  return (void *)dest;
+  }
+else
+  {
+  for (i = 0; i < n; ++i) *dest++ = *src++;
+  return (void *)(dest - n);
+  }
+#endif   /* not HAVE_BCOPY */
+}
+#undef memmove
+#define memmove(d,s,n) emulated_memmove(d,s,n)
+#endif   /* not VPCOMPAT && not HAVE_MEMMOVE */
+
+
+
+/*************************************************
+*           Convert code point to UTF-8          *
+*************************************************/
+
+/* A static buffer is used. Returns the number of bytes. */
+
+static int
+ord2utf8(uint32_t value)
+{
+int i, j;
+uint8_t *utf8bytes = utf8_buffer;
+for (i = 0; i < utf8_table1_size; i++)
+  if (value <= (uint32_t)utf8_table1[i]) break;
+utf8bytes += i;
+for (j = i; j > 0; j--)
+  {
+  *utf8bytes-- = 0x80 | (value & 0x3f);
+  value >>= 6;
+  }
+*utf8bytes = utf8_table2[i] | value;
+return i + 1;
+}
+
+
+
+/*************************************************
+*         Case-independent string compare        *
+*************************************************/
+
+static int
+strcmpic(const char *str1, const char *str2)
+{
+unsigned int c1, c2;
+while (*str1 != '\0' || *str2 != '\0')
+  {
+  c1 = tolower(*str1++);
+  c2 = tolower(*str2++);
+  if (c1 != c2) return ((c1 > c2) << 1) - 1;
+  }
+return 0;
+}
+
+
+/*************************************************
+*         Parse GREP_COLORS                      *
+*************************************************/
+
+/* Extract ms or mt from GREP_COLORS.
+
+Argument:  the string, possibly NULL
+Returns:   the value of ms or mt, or NULL if neither present
+*/
+
+static char *
+parse_grep_colors(const char *gc)
+{
+static char seq[16];
+char *col;
+uint32_t len;
+if (gc == NULL) return NULL;
+col = strstr(gc, "ms=");
+if (col == NULL) col = strstr(gc, "mt=");
+if (col == NULL) return NULL;
+len = 0;
+col += 3;
+while (*col != ':' && *col != 0 && len < sizeof(seq)-1)
+  seq[len++] = *col++;
+seq[len] = 0;
+return seq;
+}
+
+
+/*************************************************
+*         Exit from the program                  *
+*************************************************/
+
+/* If there has been a resource error, give a suitable message.
+
+Argument:  the return code
+Returns:   does not return
+*/
+
+static void
+pcre2grep_exit(int rc)
+{
+/* VMS does exit codes differently: both exit(1) and exit(0) return with a
+status of 1, which is not helpful. To help with this problem, define a symbol
+(akin to an environment variable) called "PCRE2GREP_RC" and put the exit code
+therein. */
+
+#ifdef __VMS
+  char val_buf[4];
+  $DESCRIPTOR(sym_nam, "PCRE2GREP_RC");
+  $DESCRIPTOR(sym_val, val_buf);
+  sprintf(val_buf, "%d", rc);
+  sym_val.dsc$w_length = strlen(val_buf);
+  lib$set_symbol(&sym_nam, &sym_val);
+#endif
+
+if (resource_error)
+  {
+  fprintf(stderr, "pcre2grep: Error %d, %d, %d or %d means that a resource "
+    "limit was exceeded.\n", PCRE2_ERROR_JIT_STACKLIMIT, PCRE2_ERROR_MATCHLIMIT,
+    PCRE2_ERROR_DEPTHLIMIT, PCRE2_ERROR_HEAPLIMIT);
+  fprintf(stderr, "pcre2grep: Check your regex for nested unlimited loops.\n");
+  }
+exit(rc);
+}
+
+
+/*************************************************
+*          Add item to chain of patterns         *
+*************************************************/
+
+/* Used to add an item onto a chain, or just return an unconnected item if the
+"after" argument is NULL.
+
+Arguments:
+  s          pattern string to add
+  patlen     length of pattern
+  after      if not NULL points to item to insert after
+
+Returns:     new pattern block or NULL on error
+*/
+
+static patstr *
+add_pattern(char *s, PCRE2_SIZE patlen, patstr *after)
+{
+patstr *p = (patstr *)malloc(sizeof(patstr));
+if (p == NULL)
+  {
+  fprintf(stderr, "pcre2grep: malloc failed\n");
+  pcre2grep_exit(2);
+  }
+if (patlen > MAXPATLEN)
+  {
+  fprintf(stderr, "pcre2grep: pattern is too long (limit is %d bytes)\n",
+    MAXPATLEN);
+  free(p);
+  return NULL;
+  }
+p->next = NULL;
+p->string = s;
+p->length = patlen;
+p->compiled = NULL;
+
+if (after != NULL)
+  {
+  p->next = after->next;
+  after->next = p;
+  }
+return p;
+}
+
+
+/*************************************************
+*           Free chain of patterns               *
+*************************************************/
+
+/* Used for several chains of patterns.
+
+Argument: pointer to start of chain
+Returns:  nothing
+*/
+
+static void
+free_pattern_chain(patstr *pc)
+{
+while (pc != NULL)
+  {
+  patstr *p = pc;
+  pc = p->next;
+  if (p->compiled != NULL) pcre2_code_free(p->compiled);
+  free(p);
+  }
+}
+
+
+/*************************************************
+*           Free chain of file names             *
+*************************************************/
+
+/*
+Argument: pointer to start of chain
+Returns:  nothing
+*/
+
+static void
+free_file_chain(fnstr *fn)
+{
+while (fn != NULL)
+  {
+  fnstr *f = fn;
+  fn = f->next;
+  free(f);
+  }
+}
+
+
+/*************************************************
+*            OS-specific functions               *
+*************************************************/
+
+/* These definitions are needed in all Windows environments, even those where
+Unix-style directory scanning can be used (see below). */
+
+#ifdef WIN32
+
+#ifndef STRICT
+# define STRICT
+#endif
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <windows.h>
+
+#define iswild(name) (strpbrk(name, "*?") != NULL)
+
+/* Convert ANSI BGR format to RGB used by Windows */
+#define BGR_RGB(x) ((x & 1 ? 4 : 0) | (x & 2) | (x & 4 ? 1 : 0))
+
+static HANDLE hstdout;
+static CONSOLE_SCREEN_BUFFER_INFO csbi;
+static WORD match_colour;
+
+static WORD
+decode_ANSI_colour(const char *cs)
+{
+WORD result = csbi.wAttributes;
+while (*cs)
+  {
+  if (isdigit(*cs))
+    {
+    int code = atoi(cs);
+    if (code == 1) result |= 0x08;
+    else if (code == 4) result |= 0x8000;
+    else if (code == 5) result |= 0x80;
+    else if (code >= 30 && code <= 37) result = (result & 0xF8) | BGR_RGB(code - 30);
+    else if (code == 39) result = (result & 0xF0) | (csbi.wAttributes & 0x0F);
+    else if (code >= 40 && code <= 47) result = (result & 0x8F) | (BGR_RGB(code - 40) << 4);
+    else if (code == 49) result = (result & 0x0F) | (csbi.wAttributes & 0xF0);
+    /* aixterm high intensity colour codes */
+    else if (code >= 90 && code <= 97) result = (result & 0xF0) | BGR_RGB(code - 90) | 0x08;
+    else if (code >= 100 && code <= 107) result = (result & 0x0F) | (BGR_RGB(code - 100) << 4) | 0x80;
+
+    while (isdigit(*cs)) cs++;
+    }
+  if (*cs) cs++;
+  }
+return result;
+}
+
+
+static void
+init_colour_output()
+{
+if (do_colour)
+  {
+  hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
+  /* This fails when redirected to con; try again if so. */
+  if (!GetConsoleScreenBufferInfo(hstdout, &csbi) && !do_ansi)
+    {
+    HANDLE hcon = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE,
+      FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+    GetConsoleScreenBufferInfo(hcon, &csbi);
+    CloseHandle(hcon);
+    }
+  match_colour = decode_ANSI_colour(colour_string);
+  /* No valid colour found - turn off colouring */
+  if (!match_colour) do_colour = FALSE;
+  }
+}
+
+#endif  /* WIN32 */
+
+
+/* The following sets of functions are defined so that they can be made system
+specific. At present there are versions for Unix-style environments, Windows,
+native z/OS, and "no support". */
+
+
+/************* Directory scanning Unix-style and z/OS ***********/
+
+#if (defined HAVE_SYS_STAT_H && defined HAVE_DIRENT_H && defined HAVE_SYS_TYPES_H) || defined NATIVE_ZOS
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#if defined NATIVE_ZOS
+/************* Directory and PDS/E scanning for z/OS ***********/
+/************* z/OS looks mostly like Unix with USS ************/
+/* However, z/OS needs the #include statements in this header */
+#include "pcrzosfs.h"
+/* That header is not included in the main PCRE distribution because
+   other apparatus is needed to compile pcre2grep for z/OS. The header
+   can be found in the special z/OS distribution, which is available
+   from www.zaconsultants.net or from www.cbttape.org. */
+#endif
+
+typedef DIR directory_type;
+#define FILESEP '/'
+
+static int
+isdirectory(char *filename)
+{
+struct stat statbuf;
+if (stat(filename, &statbuf) < 0)
+  return 0;        /* In the expectation that opening as a file will fail */
+return S_ISDIR(statbuf.st_mode);
+}
+
+static directory_type *
+opendirectory(char *filename)
+{
+return opendir(filename);
+}
+
+static char *
+readdirectory(directory_type *dir)
+{
+for (;;)
+  {
+  struct dirent *dent = readdir(dir);
+  if (dent == NULL) return NULL;
+  if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0)
+    return dent->d_name;
+  }
+/* Control never reaches here */
+}
+
+static void
+closedirectory(directory_type *dir)
+{
+closedir(dir);
+}
+
+
+/************* Test for regular file, Unix-style **********/
+
+static int
+isregfile(char *filename)
+{
+struct stat statbuf;
+if (stat(filename, &statbuf) < 0)
+  return 1;        /* In the expectation that opening as a file will fail */
+return S_ISREG(statbuf.st_mode);
+}
+
+
+#if defined NATIVE_ZOS
+/************* Test for a terminal in z/OS **********/
+/* isatty() does not work in a TSO environment, so always give FALSE.*/
+
+static BOOL
+is_stdout_tty(void)
+{
+return FALSE;
+}
+
+static BOOL
+is_file_tty(FILE *f)
+{
+return FALSE;
+}
+
+
+/************* Test for a terminal, Unix-style **********/
+
+#else
+static BOOL
+is_stdout_tty(void)
+{
+return isatty(fileno(stdout));
+}
+
+static BOOL
+is_file_tty(FILE *f)
+{
+return isatty(fileno(f));
+}
+#endif
+
+
+/************* Print optionally coloured match Unix-style and z/OS **********/
+
+static void
+print_match(const void *buf, int length)
+{
+if (length == 0) return;
+if (do_colour) fprintf(stdout, "%c[%sm", 0x1b, colour_string);
+FWRITE_IGNORE(buf, 1, length, stdout);
+if (do_colour) fprintf(stdout, "%c[0m", 0x1b);
+}
+
+/* End of Unix-style or native z/OS environment functions. */
+
+
+/************* Directory scanning in Windows ***********/
+
+/* I (Philip Hazel) have no means of testing this code. It was contributed by
+Lionel Fourquaux. David Burgess added a patch to define INVALID_FILE_ATTRIBUTES
+when it did not exist. David Byron added a patch that moved the #include of
+<windows.h> to before the INVALID_FILE_ATTRIBUTES definition rather than after.
+*/
+
+#elif defined WIN32
+
+#ifndef INVALID_FILE_ATTRIBUTES
+#define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF
+#endif
+
+typedef struct directory_type
+{
+HANDLE handle;
+BOOL first;
+WIN32_FIND_DATA data;
+} directory_type;
+
+#define FILESEP '/'
+
+int
+isdirectory(char *filename)
+{
+DWORD attr = GetFileAttributes(filename);
+if (attr == INVALID_FILE_ATTRIBUTES)
+  return 0;
+return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0;
+}
+
+directory_type *
+opendirectory(char *filename)
+{
+size_t len;
+char *pattern;
+directory_type *dir;
+DWORD err;
+len = strlen(filename);
+pattern = (char *)malloc(len + 3);
+dir = (directory_type *)malloc(sizeof(*dir));
+if ((pattern == NULL) || (dir == NULL))
+  {
+  fprintf(stderr, "pcre2grep: malloc failed\n");
+  pcre2grep_exit(2);
+  }
+memcpy(pattern, filename, len);
+if (iswild(filename))
+  pattern[len] = 0;
+else
+  memcpy(&(pattern[len]), "\\*", 3);
+dir->handle = FindFirstFile(pattern, &(dir->data));
+if (dir->handle != INVALID_HANDLE_VALUE)
+  {
+  free(pattern);
+  dir->first = TRUE;
+  return dir;
+  }
+err = GetLastError();
+free(pattern);
+free(dir);
+errno = (err == ERROR_ACCESS_DENIED) ? EACCES : ENOENT;
+return NULL;
+}
+
+char *
+readdirectory(directory_type *dir)
+{
+for (;;)
+  {
+  if (!dir->first)
+    {
+    if (!FindNextFile(dir->handle, &(dir->data)))
+      return NULL;
+    }
+  else
+    {
+    dir->first = FALSE;
+    }
+  if (strcmp(dir->data.cFileName, ".") != 0 && strcmp(dir->data.cFileName, "..") != 0)
+    return dir->data.cFileName;
+  }
+#ifndef _MSC_VER
+return NULL;   /* Keep compiler happy; never executed */
+#endif
+}
+
+void
+closedirectory(directory_type *dir)
+{
+FindClose(dir->handle);
+free(dir);
+}
+
+
+/************* Test for regular file in Windows **********/
+
+/* I don't know how to do this, or if it can be done; assume all paths are
+regular if they are not directories. */
+
+int isregfile(char *filename)
+{
+return !isdirectory(filename);
+}
+
+
+/************* Test for a terminal in Windows **********/
+
+static BOOL
+is_stdout_tty(void)
+{
+return _isatty(_fileno(stdout));
+}
+
+static BOOL
+is_file_tty(FILE *f)
+{
+return _isatty(_fileno(f));
+}
+
+
+/************* Print optionally coloured match in Windows **********/
+
+static void
+print_match(const void *buf, int length)
+{
+if (length == 0) return;
+if (do_colour)
+  {
+  if (do_ansi) fprintf(stdout, "%c[%sm", 0x1b, colour_string);
+    else SetConsoleTextAttribute(hstdout, match_colour);
+  }
+FWRITE_IGNORE(buf, 1, length, stdout);
+if (do_colour)
+  {
+  if (do_ansi) fprintf(stdout, "%c[0m", 0x1b);
+    else SetConsoleTextAttribute(hstdout, csbi.wAttributes);
+  }
+}
+
+/* End of Windows functions */
+
+
+/************* Directory scanning when we can't do it ***********/
+
+/* The type is void, and apart from isdirectory(), the functions do nothing. */
+
+#else
+
+#define FILESEP 0
+typedef void directory_type;
+
+int isdirectory(char *filename) { return 0; }
+directory_type * opendirectory(char *filename) { return (directory_type*)0;}
+char *readdirectory(directory_type *dir) { return (char*)0;}
+void closedirectory(directory_type *dir) {}
+
+
+/************* Test for regular file when we can't do it **********/
+
+/* Assume all files are regular. */
+
+int isregfile(char *filename) { return 1; }
+
+
+/************* Test for a terminal when we can't do it **********/
+
+static BOOL
+is_stdout_tty(void)
+{
+return FALSE;
+}
+
+static BOOL
+is_file_tty(FILE *f)
+{
+return FALSE;
+}
+
+
+/************* Print optionally coloured match when we can't do it **********/
+
+static void
+print_match(const void *buf, int length)
+{
+if (length == 0) return;
+FWRITE_IGNORE(buf, 1, length, stdout);
+}
+
+#endif  /* End of system-specific functions */
+
+
+
+#ifndef HAVE_STRERROR
+/*************************************************
+*     Provide strerror() for non-ANSI libraries  *
+*************************************************/
+
+/* Some old-fashioned systems still around (e.g. SunOS4) don't have strerror()
+in their libraries, but can provide the same facility by this simple
+alternative function. */
+
+extern int   sys_nerr;
+extern char *sys_errlist[];
+
+char *
+strerror(int n)
+{
+if (n < 0 || n >= sys_nerr) return "unknown error number";
+return sys_errlist[n];
+}
+#endif /* HAVE_STRERROR */
+
+
+
+/*************************************************
+*                Usage function                  *
+*************************************************/
+
+static int
+usage(int rc)
+{
+option_item *op;
+fprintf(stderr, "Usage: pcre2grep [-");
+for (op = optionlist; op->one_char != 0; op++)
+  {
+  if (op->one_char > 0) fprintf(stderr, "%c", op->one_char);
+  }
+fprintf(stderr, "] [long options] [pattern] [files]\n");
+fprintf(stderr, "Type \"pcre2grep --help\" for more information and the long "
+  "options.\n");
+return rc;
+}
+
+
+
+/*************************************************
+*                Help function                   *
+*************************************************/
+
+static void
+help(void)
+{
+option_item *op;
+
+printf("Usage: pcre2grep [OPTION]... [PATTERN] [FILE1 FILE2 ...]" STDOUT_NL);
+printf("Search for PATTERN in each FILE or standard input." STDOUT_NL);
+printf("PATTERN must be present if neither -e nor -f is used." STDOUT_NL);
+
+#ifdef SUPPORT_PCRE2GREP_CALLOUT
+#ifdef SUPPORT_PCRE2GREP_CALLOUT_FORK
+printf("All callout scripts in patterns are supported." STDOUT_NL);
+#else
+printf("Non-fork callout scripts in patterns are supported." STDOUT_NL);
+#endif
+#else
+printf("Callout scripts are not supported in this pcre2grep." STDOUT_NL);
+#endif
+
+printf("\"-\" can be used as a file name to mean STDIN." STDOUT_NL);
+
+#ifdef SUPPORT_LIBZ
+printf("Files whose names end in .gz are read using zlib." STDOUT_NL);
+#endif
+
+#ifdef SUPPORT_LIBBZ2
+printf("Files whose names end in .bz2 are read using bzlib2." STDOUT_NL);
+#endif
+
+#if defined SUPPORT_LIBZ || defined SUPPORT_LIBBZ2
+printf("Other files and the standard input are read as plain files." STDOUT_NL STDOUT_NL);
+#else
+printf("All files are read as plain files, without any interpretation." STDOUT_NL STDOUT_NL);
+#endif
+
+printf("Example: pcre2grep -i " QUOT "hello.*world" QUOT " menu.h main.c" STDOUT_NL STDOUT_NL);
+printf("Options:" STDOUT_NL);
+
+for (op = optionlist; op->one_char != 0; op++)
+  {
+  int n;
+  char s[4];
+
+  if (op->one_char > 0 && (op->long_name)[0] == 0)
+    n = 31 - printf("  -%c", op->one_char);
+  else
+    {
+    if (op->one_char > 0) sprintf(s, "-%c,", op->one_char);
+      else strcpy(s, "   ");
+    n = 31 - printf("  %s --%s", s, op->long_name);
+    }
+
+  if (n < 1) n = 1;
+  printf("%.*s%s" STDOUT_NL, n, "                           ", op->help_text);
+  }
+
+printf(STDOUT_NL "Numbers may be followed by K or M, e.g. --max-buffer-size=100K." STDOUT_NL);
+printf("The default value for --buffer-size is %d." STDOUT_NL, PCRE2GREP_BUFSIZE);
+printf("The default value for --max-buffer-size is %d." STDOUT_NL, PCRE2GREP_MAX_BUFSIZE);
+printf("When reading patterns or file names from a file, trailing white" STDOUT_NL);
+printf("space is removed and blank lines are ignored." STDOUT_NL);
+printf("The maximum size of any pattern is %d bytes." STDOUT_NL, MAXPATLEN);
+
+printf(STDOUT_NL "With no FILEs, read standard input. If fewer than two FILEs given, assume -h." STDOUT_NL);
+printf("Exit status is 0 if any matches, 1 if no matches, and 2 if trouble." STDOUT_NL);
+}
+
+
+
+/*************************************************
+*            Test exclude/includes               *
+*************************************************/
+
+/* If any exclude pattern matches, the path is excluded. Otherwise, unless
+there are no includes, the path must match an include pattern.
+
+Arguments:
+  path      the path to be matched
+  ip        the chain of include patterns
+  ep        the chain of exclude patterns
+
+Returns:    TRUE if the path is not excluded
+*/
+
+static BOOL
+test_incexc(char *path, patstr *ip, patstr *ep)
+{
+int plen = strlen((const char *)path);
+
+for (; ep != NULL; ep = ep->next)
+  {
+  if (pcre2_match(ep->compiled, (PCRE2_SPTR)path, plen, 0, 0, match_data, NULL) >= 0)
+    return FALSE;
+  }
+
+if (ip == NULL) return TRUE;
+
+for (; ip != NULL; ip = ip->next)
+  {
+  if (pcre2_match(ip->compiled, (PCRE2_SPTR)path, plen, 0, 0, match_data, NULL) >= 0)
+    return TRUE;
+  }
+
+return FALSE;
+}
+
+
+
+/*************************************************
+*         Decode integer argument value          *
+*************************************************/
+
+/* Integer arguments can be followed by K or M. Avoid the use of strtoul()
+because SunOS4 doesn't have it. This is used only for unpicking arguments, so
+just keep it simple.
+
+Arguments:
+  option_data   the option data string
+  op            the option item (for error messages)
+  longop        TRUE if option given in long form
+
+Returns:        a long integer
+*/
+
+static long int
+decode_number(char *option_data, option_item *op, BOOL longop)
+{
+unsigned long int n = 0;
+char *endptr = option_data;
+while (*endptr != 0 && isspace((unsigned char)(*endptr))) endptr++;
+while (isdigit((unsigned char)(*endptr)))
+  n = n * 10 + (int)(*endptr++ - '0');
+if (toupper(*endptr) == 'K')
+  {
+  n *= 1024;
+  endptr++;
+  }
+else if (toupper(*endptr) == 'M')
+  {
+  n *= 1024*1024;
+  endptr++;
+  }
+
+if (*endptr != 0)   /* Error */
+  {
+  if (longop)
+    {
+    char *equals = strchr(op->long_name, '=');
+    int nlen = (equals == NULL)? (int)strlen(op->long_name) :
+      (int)(equals - op->long_name);
+    fprintf(stderr, "pcre2grep: Malformed number \"%s\" after --%.*s\n",
+      option_data, nlen, op->long_name);
+    }
+  else
+    fprintf(stderr, "pcre2grep: Malformed number \"%s\" after -%c\n",
+      option_data, op->one_char);
+  pcre2grep_exit(usage(2));
+  }
+
+return n;
+}
+
+
+
+/*************************************************
+*       Add item to a chain of numbers           *
+*************************************************/
+
+/* Used to add an item onto a chain, or just return an unconnected item if the
+"after" argument is NULL.
+
+Arguments:
+  n          the number to add
+  after      if not NULL points to item to insert after
+
+Returns:     new number block
+*/
+
+static omstr *
+add_number(int n, omstr *after)
+{
+omstr *om = (omstr *)malloc(sizeof(omstr));
+
+if (om == NULL)
+  {
+  fprintf(stderr, "pcre2grep: malloc failed\n");
+  pcre2grep_exit(2);
+  }
+om->next = NULL;
+om->groupnum = n;
+
+if (after != NULL)
+  {
+  om->next = after->next;
+  after->next = om;
+  }
+return om;
+}
+
+
+
+/*************************************************
+*            Read one line of input              *
+*************************************************/
+
+/* Normally, input that is to be scanned is read using fread() (or gzread, or
+BZ2_read) into a large buffer, so many lines may be read at once. However,
+doing this for tty input means that no output appears until a lot of input has
+been typed. Instead, tty input is handled line by line. We cannot use fgets()
+for this, because it does not stop at a binary zero, and therefore there is no
+way of telling how many characters it has read, because there may be binary
+zeros embedded in the data. This function is also used for reading patterns
+from files (the -f option).
+
+Arguments:
+  buffer     the buffer to read into
+  length     the maximum number of characters to read
+  f          the file
+
+Returns:     the number of characters read, zero at end of file
+*/
+
+static PCRE2_SIZE
+read_one_line(char *buffer, int length, FILE *f)
+{
+int c;
+int yield = 0;
+while ((c = fgetc(f)) != EOF)
+  {
+  buffer[yield++] = c;
+  if (c == '\n' || yield >= length) break;
+  }
+return yield;
+}
+
+
+
+/*************************************************
+*             Find end of line                   *
+*************************************************/
+
+/* The length of the endline sequence that is found is set via lenptr. This may
+be zero at the very end of the file if there is no line-ending sequence there.
+
+Arguments:
+  p         current position in line
+  endptr    end of available data
+  lenptr    where to put the length of the eol sequence
+
+Returns:    pointer after the last byte of the line,
+            including the newline byte(s)
+*/
+
+static char *
+end_of_line(char *p, char *endptr, int *lenptr)
+{
+switch(endlinetype)
+  {
+  default:      /* Just in case */
+  case PCRE2_NEWLINE_LF:
+  while (p < endptr && *p != '\n') p++;
+  if (p < endptr)
+    {
+    *lenptr = 1;
+    return p + 1;
+    }
+  *lenptr = 0;
+  return endptr;
+
+  case PCRE2_NEWLINE_CR:
+  while (p < endptr && *p != '\r') p++;
+  if (p < endptr)
+    {
+    *lenptr = 1;
+    return p + 1;
+    }
+  *lenptr = 0;
+  return endptr;
+
+  case PCRE2_NEWLINE_NUL:
+  while (p < endptr && *p != '\0') p++;
+  if (p < endptr)
+    {
+    *lenptr = 1;
+    return p + 1;
+    }
+  *lenptr = 0;
+  return endptr;
+
+  case PCRE2_NEWLINE_CRLF:
+  for (;;)
+    {
+    while (p < endptr && *p != '\r') p++;
+    if (++p >= endptr)
+      {
+      *lenptr = 0;
+      return endptr;
+      }
+    if (*p == '\n')
+      {
+      *lenptr = 2;
+      return p + 1;
+      }
+    }
+  break;
+
+  case PCRE2_NEWLINE_ANYCRLF:
+  while (p < endptr)
+    {
+    int extra = 0;
+    int c = *((unsigned char *)p);
+
+    if (utf && c >= 0xc0)
+      {
+      int gcii, gcss;
+      extra = utf8_table4[c & 0x3f];  /* Number of additional bytes */
+      gcss = 6*extra;
+      c = (c & utf8_table3[extra]) << gcss;
+      for (gcii = 1; gcii <= extra; gcii++)
+        {
+        gcss -= 6;
+        c |= (p[gcii] & 0x3f) << gcss;
+        }
+      }
+
+    p += 1 + extra;
+
+    switch (c)
+      {
+      case '\n':
+      *lenptr = 1;
+      return p;
+
+      case '\r':
+      if (p < endptr && *p == '\n')
+        {
+        *lenptr = 2;
+        p++;
+        }
+      else *lenptr = 1;
+      return p;
+
+      default:
+      break;
+      }
+    }   /* End of loop for ANYCRLF case */
+
+  *lenptr = 0;  /* Must have hit the end */
+  return endptr;
+
+  case PCRE2_NEWLINE_ANY:
+  while (p < endptr)
+    {
+    int extra = 0;
+    int c = *((unsigned char *)p);
+
+    if (utf && c >= 0xc0)
+      {
+      int gcii, gcss;
+      extra = utf8_table4[c & 0x3f];  /* Number of additional bytes */
+      gcss = 6*extra;
+      c = (c & utf8_table3[extra]) << gcss;
+      for (gcii = 1; gcii <= extra; gcii++)
+        {
+        gcss -= 6;
+        c |= (p[gcii] & 0x3f) << gcss;
+        }
+      }
+
+    p += 1 + extra;
+
+    switch (c)
+      {
+      case '\n':    /* LF */
+      case '\v':    /* VT */
+      case '\f':    /* FF */
+      *lenptr = 1;
+      return p;
+
+      case '\r':    /* CR */
+      if (p < endptr && *p == '\n')
+        {
+        *lenptr = 2;
+        p++;
+        }
+      else *lenptr = 1;
+      return p;
+
+#ifndef EBCDIC
+      case 0x85:    /* Unicode NEL */
+      *lenptr = utf? 2 : 1;
+      return p;
+
+      case 0x2028:  /* Unicode LS */
+      case 0x2029:  /* Unicode PS */
+      *lenptr = 3;
+      return p;
+#endif  /* Not EBCDIC */
+
+      default:
+      break;
+      }
+    }   /* End of loop for ANY case */
+
+  *lenptr = 0;  /* Must have hit the end */
+  return endptr;
+  }     /* End of overall switch */
+}
+
+
+
+/*************************************************
+*         Find start of previous line            *
+*************************************************/
+
+/* This is called when looking back for before lines to print.
+
+Arguments:
+  p         start of the subsequent line
+  startptr  start of available data
+
+Returns:    pointer to the start of the previous line
+*/
+
+static char *
+previous_line(char *p, char *startptr)
+{
+switch(endlinetype)
+  {
+  default:      /* Just in case */
+  case PCRE2_NEWLINE_LF:
+  p--;
+  while (p > startptr && p[-1] != '\n') p--;
+  return p;
+
+  case PCRE2_NEWLINE_CR:
+  p--;
+  while (p > startptr && p[-1] != '\n') p--;
+  return p;
+
+  case PCRE2_NEWLINE_NUL:
+  p--;
+  while (p > startptr && p[-1] != '\0') p--;
+  return p;
+
+  case PCRE2_NEWLINE_CRLF:
+  for (;;)
+    {
+    p -= 2;
+    while (p > startptr && p[-1] != '\n') p--;
+    if (p <= startptr + 1 || p[-2] == '\r') return p;
+    }
+  /* Control can never get here */
+
+  case PCRE2_NEWLINE_ANY:
+  case PCRE2_NEWLINE_ANYCRLF:
+  if (*(--p) == '\n' && p > startptr && p[-1] == '\r') p--;
+  if (utf) while ((*p & 0xc0) == 0x80) p--;
+
+  while (p > startptr)
+    {
+    unsigned int c;
+    char *pp = p - 1;
+
+    if (utf)
+      {
+      int extra = 0;
+      while ((*pp & 0xc0) == 0x80) pp--;
+      c = *((unsigned char *)pp);
+      if (c >= 0xc0)
+        {
+        int gcii, gcss;
+        extra = utf8_table4[c & 0x3f];  /* Number of additional bytes */
+        gcss = 6*extra;
+        c = (c & utf8_table3[extra]) << gcss;
+        for (gcii = 1; gcii <= extra; gcii++)
+          {
+          gcss -= 6;
+          c |= (pp[gcii] & 0x3f) << gcss;
+          }
+        }
+      }
+    else c = *((unsigned char *)pp);
+
+    if (endlinetype == PCRE2_NEWLINE_ANYCRLF) switch (c)
+      {
+      case '\n':    /* LF */
+      case '\r':    /* CR */
+      return p;
+
+      default:
+      break;
+      }
+
+    else switch (c)
+      {
+      case '\n':    /* LF */
+      case '\v':    /* VT */
+      case '\f':    /* FF */
+      case '\r':    /* CR */
+#ifndef EBCDIC
+      case 0x85:    /* Unicode NEL */
+      case 0x2028:  /* Unicode LS */
+      case 0x2029:  /* Unicode PS */
+#endif  /* Not EBCDIC */
+      return p;
+
+      default:
+      break;
+      }
+
+    p = pp;  /* Back one character */
+    }        /* End of loop for ANY case */
+
+  return startptr;  /* Hit start of data */
+  }     /* End of overall switch */
+}
+
+
+
+/*************************************************
+*              Output newline at end             *
+*************************************************/
+
+/* This function is called if the final line of a file has been written to
+stdout, but it does not have a terminating newline.
+
+Arguments:  none
+Returns:    nothing
+*/
+
+static void
+write_final_newline(void)
+{
+switch(endlinetype)
+  {
+  default:      /* Just in case */
+  case PCRE2_NEWLINE_LF:
+  case PCRE2_NEWLINE_ANY:
+  case PCRE2_NEWLINE_ANYCRLF:
+  fprintf(stdout, "\n");
+  break;
+
+  case PCRE2_NEWLINE_CR:
+  fprintf(stdout, "\r");
+  break;
+
+  case PCRE2_NEWLINE_CRLF:
+  fprintf(stdout, "\r\n");
+  break;
+
+  case PCRE2_NEWLINE_NUL:
+  fprintf(stdout, "%c", 0);
+  break;
+  }
+}
+
+
+/*************************************************
+*       Print the previous "after" lines         *
+*************************************************/
+
+/* This is called if we are about to lose said lines because of buffer filling,
+and at the end of the file. The data in the line is written using fwrite() so
+that a binary zero does not terminate it.
+
+Arguments:
+  lastmatchnumber   the number of the last matching line, plus one
+  lastmatchrestart  where we restarted after the last match
+  endptr            end of available data
+  printname         filename for printing
+
+Returns:            nothing
+*/
+
+static void
+do_after_lines(unsigned long int lastmatchnumber, char *lastmatchrestart,
+  char *endptr, const char *printname)
+{
+if (after_context > 0 && lastmatchnumber > 0)
+  {
+  int count = 0;
+  int ellength = 0;
+  while (lastmatchrestart < endptr && count < after_context)
+    {
+    char *pp = end_of_line(lastmatchrestart, endptr, &ellength);
+    if (ellength == 0 && pp == main_buffer + bufsize) break;
+    if (printname != NULL) fprintf(stdout, "%s-", printname);
+    if (number) fprintf(stdout, "%lu-", lastmatchnumber++);
+    FWRITE_IGNORE(lastmatchrestart, 1, pp - lastmatchrestart, stdout);
+    lastmatchrestart = pp;
+    count++;
+    }
+
+  /* If we have printed any lines, arrange for a hyphen separator if anything
+  else follows. Also, if the last line is the final line in the file and it had
+  no newline, add one. */
+
+  if (count > 0)
+    {
+    hyphenpending = TRUE;
+    if (ellength == 0 && lastmatchrestart >= endptr)
+      write_final_newline();
+    }
+  }
+}
+
+
+
+/*************************************************
+*   Apply patterns to subject till one matches   *
+*************************************************/
+
+/* This function is called to run through all patterns, looking for a match. It
+is used multiple times for the same subject when colouring is enabled, in order
+to find all possible matches.
+
+Arguments:
+  matchptr     the start of the subject
+  length       the length of the subject to match
+  options      options for pcre_exec
+  startoffset  where to start matching
+  mrc          address of where to put the result of pcre2_match()
+
+Returns:      TRUE if there was a match
+              FALSE if there was no match
+              invert if there was a non-fatal error
+*/
+
+static BOOL
+match_patterns(char *matchptr, PCRE2_SIZE length, unsigned int options,
+  PCRE2_SIZE startoffset, int *mrc)
+{
+int i;
+PCRE2_SIZE slen = length;
+patstr *p = patterns;
+const char *msg = "this text:\n\n";
+
+if (slen > 200)
+  {
+  slen = 200;
+  msg = "text that starts:\n\n";
+  }
+
+for (i = 1; p != NULL; p = p->next, i++)
+  {
+  *mrc = pcre2_match(p->compiled, (PCRE2_SPTR)matchptr, (int)length,
+    startoffset, options, match_data, match_context);
+  if (*mrc >= 0) return TRUE;
+  if (*mrc == PCRE2_ERROR_NOMATCH) continue;
+  fprintf(stderr, "pcre2grep: pcre2_match() gave error %d while matching ", *mrc);
+  if (patterns->next != NULL) fprintf(stderr, "pattern number %d to ", i);
+  fprintf(stderr, "%s", msg);
+  FWRITE_IGNORE(matchptr, 1, slen, stderr);   /* In case binary zero included */
+  fprintf(stderr, "\n\n");
+  if (*mrc <= PCRE2_ERROR_UTF8_ERR1 &&
+      *mrc >= PCRE2_ERROR_UTF8_ERR21)
+    {
+    unsigned char mbuffer[256];
+    PCRE2_SIZE startchar = pcre2_get_startchar(match_data);
+    (void)pcre2_get_error_message(*mrc, mbuffer, sizeof(mbuffer));
+    fprintf(stderr, "%s at offset %" SIZ_FORM "\n\n", mbuffer,
+      SIZ_CAST startchar);
+    }
+  if (*mrc == PCRE2_ERROR_MATCHLIMIT || *mrc == PCRE2_ERROR_DEPTHLIMIT ||
+      *mrc == PCRE2_ERROR_HEAPLIMIT || *mrc == PCRE2_ERROR_JIT_STACKLIMIT)
+    resource_error = TRUE;
+  if (error_count++ > 20)
+    {
+    fprintf(stderr, "pcre2grep: Too many errors - abandoned.\n");
+    pcre2grep_exit(2);
+    }
+  return invert;    /* No more matching; don't show the line again */
+  }
+
+return FALSE;  /* No match, no errors */
+}
+
+
+
+/*************************************************
+*          Decode dollar escape sequence         *
+*************************************************/
+
+/* Called from various places to decode $ escapes in output strings. The escape
+sequences are as follows:
+
+$<digits> or ${<digits>} returns a capture number. However, if callout is TRUE,
+zero is never returned; '0' is substituted.
+
+$a returns bell.
+$b returns backspace.
+$e returns escape.
+$f returns form feed.
+$n returns newline.
+$r returns carriage return.
+$t returns tab.
+$v returns vertical tab.
+$o<digits> returns the character represented by the given octal
+  number; up to three digits are processed.
+$o{<digits>} does the same, up to 7 digits, but gives an error for mode-invalid
+  code points.
+$x<digits> returns the character represented by the given hexadecimal
+  number; up to two digits are processed.
+$x{<digits} does the same, up to 6 digits, but gives an error for mode-invalid
+  code points.
+Any other character is substituted by itself. E.g: $$ is replaced by a single
+dollar.
+
+Arguments:
+  begin      the start of the whole string
+  string     points to the $
+  callout    TRUE if in a callout (inhibits error messages)
+  value      where to return a value
+  last       where to return pointer to the last used character
+
+Returns:     DDE_ERROR    after a syntax error
+             DDE_CAPTURE  if *value is a capture number
+             DDE_CHAR     if *value is a character code
+*/
+
+static int
+decode_dollar_escape(PCRE2_SPTR begin, PCRE2_SPTR string, BOOL callout,
+  uint32_t *value, PCRE2_SPTR *last)
+{
+uint32_t c = 0;
+int base = 10;
+int dcount;
+int rc = DDE_CHAR;
+BOOL brace = FALSE;
+
+switch (*(++string))
+  {
+  case 0:   /* Syntax error: a character must be present after $. */
+  if (!callout)
+    fprintf(stderr, "pcre2grep: Error in output text at offset %d: %s\n",
+      (int)(string - begin), "no character after $");
+  *last = string;
+  return DDE_ERROR;
+
+  case '{':
+  brace = TRUE;
+  string++;
+  if (!isdigit(*string))  /* Syntax error: a decimal number required. */
+    {
+    if (!callout)
+      fprintf(stderr, "pcre2grep: Error in output text at offset %d: %s\n",
+        (int)(string - begin), "decimal number expected");
+    rc = DDE_ERROR;
+    break;
+    }
+
+  /* Fall through */
+
+  /* The maximum capture number is 65535, so any number greater than that will
+  always be an unknown capture number. We just stop incrementing, in order to
+  avoid overflow. */
+
+  case '0': case '1': case '2': case '3': case '4':
+  case '5': case '6': case '7': case '8': case '9':
+  do
+    {
+    if (c <= 65535) c = c * 10 + (*string - '0');
+    string++;
+    }
+  while (*string >= '0' && *string <= '9');
+  string--;  /* Point to last digit */
+
+  /* In a callout, capture number 0 is not available. No error can be given,
+  so just return the character '0'. */
+
+  if (callout && c == 0)
+    {
+    *value = '0';
+    }
+  else
+    {
+    *value = c;
+    rc = DDE_CAPTURE;
+    }
+  break;
+
+  /* Limit octal numbers to 3 digits without braces, or up to 7 with braces,
+  for valid Unicode code points. */
+
+  case 'o':
+  base = 8;
+  string++;
+  if (*string == '{')
+    {
+    brace = TRUE;
+    string++;
+    dcount = 7;
+    }
+  else dcount = 3;
+  for (; dcount > 0; dcount--)
+    {
+    if (*string < '0' || *string > '7') break;
+    c = c * 8 + (*string++ - '0');
+    }
+  *value = c;
+  string--;  /* Point to last digit */
+  break;
+
+  /* Limit hex numbers to 2 digits without braces, or up to 6 with braces,
+  for valid Unicode code points. */
+
+  case 'x':
+  base = 16;
+  string++;
+  if (*string == '{')
+    {
+    brace = TRUE;
+    string++;
+    dcount = 6;
+    }
+  else dcount = 2;
+  for (; dcount > 0; dcount--)
+    {
+    if (!isxdigit(*string)) break;
+    if (*string >= '0' && *string <= '9')
+      c = c *16 + *string++ - '0';
+    else
+      c = c * 16 + (*string++ | 0x20) - 'a' + 10;
+    }
+  *value = c;
+  string--;  /* Point to last digit */
+  break;
+
+  case 'a': *value = '\a'; break;
+  case 'b': *value = '\b'; break;
+#ifndef EBCDIC
+  case 'e': *value = '\033'; break;
+#else
+  case 'e': *value = '\047'; break;
+#endif
+  case 'f': *value = '\f'; break;
+  case 'n': *value = STDOUT_NL_CODE; break;
+  case 'r': *value = '\r'; break;
+  case 't': *value = '\t'; break;
+  case 'v': *value = '\v'; break;
+
+  default: *value = *string; break;
+  }
+
+if (brace)
+  {
+  c = string[1];
+  if (c != '}')
+    {
+    rc = DDE_ERROR;
+    if (!callout)
+      {
+      if ((base == 8 && c >= '0' && c <= '7') ||
+          (base == 16 && isxdigit(c)))
+        {
+        fprintf(stderr, "pcre2grep: Error in output text at offset %d: "
+          "too many %s digits\n", (int)(string - begin),
+          (base == 8)? "octal" : "hex");
+        }
+      else
+        {
+        fprintf(stderr, "pcre2grep: Error in output text at offset %d: %s\n",
+          (int)(string - begin), "missing closing brace");
+        }
+      }
+    }
+  else string++;
+  }
+
+/* Check maximum code point values, but take note of STDOUT_NL_CODE. */
+
+if (rc == DDE_CHAR && *value != STDOUT_NL_CODE)
+  {
+  uint32_t max = utf? 0x0010ffffu : 0xffu;
+  if (*value > max)
+    {
+    if (!callout) 
+      fprintf(stderr, "pcre2grep: Error in output text at offset %d: "
+        "code point greater than 0x%x is invalid\n", (int)(string - begin), max);
+    rc = DDE_ERROR;
+    }
+  }
+
+*last = string;
+return rc;
+}
+
+
+
+/*************************************************
+*          Check output text for errors          *
+*************************************************/
+
+/* Called early, to get errors before doing anything for -O text; also called
+from callouts to check before outputting.
+
+Arguments:
+  string    an --output text string
+  callout   TRUE if in a callout (stops printing errors)
+
+Returns:    TRUE if OK, FALSE on error
+*/
+
+static BOOL
+syntax_check_output_text(PCRE2_SPTR string, BOOL callout)
+{
+uint32_t value;
+PCRE2_SPTR begin = string;
+
+for (; *string != 0; string++)
+  {
+  if (*string == '$' &&
+    decode_dollar_escape(begin, string, callout, &value, &string) == DDE_ERROR)
+      return FALSE;
+  }
+
+return TRUE;
+}
+
+
+/*************************************************
+*              Display output text               *
+*************************************************/
+
+/* Display the output text, which is assumed to have already been syntax
+checked. Output may contain escape sequences started by the dollar sign.
+
+Arguments:
+  string:       the output text
+  callout:      TRUE for the builtin callout, FALSE for --output
+  subject       the start of the subject
+  ovector:      capture offsets
+  capture_top:  number of captures
+
+Returns:        TRUE if something was output, other than newline
+                FALSE if nothing was output, or newline was last output
+*/
+
+static BOOL
+display_output_text(PCRE2_SPTR string, BOOL callout, PCRE2_SPTR subject,
+  PCRE2_SIZE *ovector, PCRE2_SIZE capture_top)
+{
+uint32_t value;
+BOOL printed = FALSE;
+PCRE2_SPTR begin = string;
+
+for (; *string != 0; string++)
+  {
+  if (*string == '$')
+    {
+    switch(decode_dollar_escape(begin, string, callout, &value, &string))
+      {
+      case DDE_CHAR:
+      if (value == STDOUT_NL_CODE)
+        {
+        fprintf(stdout, STDOUT_NL);
+        printed = FALSE;
+        continue;
+        }
+      break;  /* Will print value */
+
+      case DDE_CAPTURE:
+      if (value < capture_top)
+        {
+        PCRE2_SIZE capturesize;
+        value *= 2;
+        capturesize = ovector[value + 1] - ovector[value];
+        if (capturesize > 0)
+          {
+          print_match(subject + ovector[value], capturesize);
+          printed = TRUE;
+          }
+        }
+      continue;
+
+      default:  /* Should not occur */
+      break;
+      }
+    }
+
+  else value = *string;  /* Not a $ escape */
+
+  if (utf && value <= 127) fprintf(stdout, "%c", *string); else
+    {
+    int i;
+    int n = ord2utf8(value);
+    for (i = 0; i < n; i++) fputc(utf8_buffer[i], stdout);
+    }
+
+  printed = TRUE;
+  }
+
+return printed;
+}
+
+
+#ifdef SUPPORT_PCRE2GREP_CALLOUT
+
+/*************************************************
+*        Parse and execute callout scripts       *
+*************************************************/
+
+/* If SUPPORT_PCRE2GREP_CALLOUT_FORK is defined, this function parses a callout
+string block and executes the program specified by the string. The string is a
+list of substrings separated by pipe characters. The first substring represents
+the executable name, and the following substrings specify the arguments:
+
+  program_name|param1|param2|...
+
+Any substring (including the program name) can contain escape sequences
+started by the dollar character. The escape sequences are substituted as
+follows:
+
+  $<digits> or ${<digits>} is replaced by the captured substring of the given
+  decimal number, which must be greater than zero. If the number is greater
+  than the number of capturing substrings, or if the capture is unset, the
+  replacement is empty.
+
+  Any other character is substituted by itself. E.g: $$ is replaced by a single
+  dollar or $| replaced by a pipe character.
+
+Alternatively, if string starts with pipe, the remainder is taken as an output
+string, same as --output. This is the only form that is supported if
+SUPPORT_PCRE2GREP_FORK is not defined. In this case, --om-separator is used to
+separate each callout, defaulting to newline.
+
+Example:
+
+  echo -e "abcde\n12345" | pcre2grep \
+    '(.)(..(.))(?C"/bin/echo|Arg1: [$1] [$2] [$3]|Arg2: $|${1}$| ($4)")()' -
+
+  Output:
+
+    Arg1: [a] [bcd] [d] Arg2: |a| ()
+    abcde
+    Arg1: [1] [234] [4] Arg2: |1| ()
+    12345
+
+Arguments:
+  blockptr     the callout block
+
+Returns:       currently it always returns with 0
+*/
+
+static int
+pcre2grep_callout(pcre2_callout_block *calloutptr, void *unused)
+{
+PCRE2_SIZE length = calloutptr->callout_string_length;
+PCRE2_SPTR string = calloutptr->callout_string;
+PCRE2_SPTR subject = calloutptr->subject;
+PCRE2_SIZE *ovector = calloutptr->offset_vector;
+PCRE2_SIZE capture_top = calloutptr->capture_top;
+
+#ifdef SUPPORT_PCRE2GREP_CALLOUT_FORK
+PCRE2_SIZE argsvectorlen = 2;
+PCRE2_SIZE argslen = 1;
+char *args;
+char *argsptr;
+char **argsvector;
+char **argsvectorptr;
+#ifndef WIN32
+pid_t pid;
+#endif
+int result = 0;
+#endif  /* SUPPORT_PCRE2GREP_CALLOUT_FORK */
+
+(void)unused;   /* Avoid compiler warning */
+
+/* Only callouts with strings are supported. */
+
+if (string == NULL || length == 0) return 0;
+
+/* If there's no command, output the remainder directly. */
+
+if (*string == '|')
+  {
+  string++;
+  if (!syntax_check_output_text(string, TRUE)) return 0;
+  (void)display_output_text(string, TRUE, subject, ovector, capture_top);
+  return 0;
+  }
+
+#ifndef SUPPORT_PCRE2GREP_CALLOUT_FORK
+return 0;
+#else
+
+/* Checking syntax and compute the number of string fragments. Callout strings
+are silently ignored in the event of a syntax error. */
+
+while (length > 0)
+  {
+  if (*string == '|')
+    {
+    argsvectorlen++;
+    if (argsvectorlen > 10000) return 0;  /* Too many args */
+    }
+
+  else if (*string == '$')
+    {
+    uint32_t value;
+    PCRE2_SPTR begin = string;
+
+    switch (decode_dollar_escape(begin, string, TRUE, &value, &string))
+      {
+      case DDE_CAPTURE:
+      if (value < capture_top)
+        {
+        value *= 2;
+        argslen += ovector[value + 1] - ovector[value];
+        }
+      argslen--;   /* Negate the effect of argslen++ below. */
+      break;
+
+      case DDE_CHAR:
+      if (value == STDOUT_NL_CODE) argslen += STDOUT_NL_LEN - 1;
+        else if (utf && value > 127) argslen += ord2utf8(value) - 1;
+      break;
+
+      default:         /* Should not occur */
+      case DDE_ERROR:
+      return 0;
+      }
+
+    length -= (string - begin);
+    }
+
+  string++;
+  length--;
+  argslen++;
+  }
+
+/* Get memory for the argument vector and its strings. */
+
+args = (char*)malloc(argslen);
+if (args == NULL) return 0;
+
+argsvector = (char**)malloc(argsvectorlen * sizeof(char*));
+if (argsvector == NULL)
+  {
+  free(args);
+  return 0;
+  }
+
+/* Now reprocess the string and set up the arguments. */
+
+argsptr = args;
+argsvectorptr = argsvector;
+*argsvectorptr++ = argsptr;
+
+length = calloutptr->callout_string_length;
+string = calloutptr->callout_string;
+
+while (length > 0)
+  {
+  if (*string == '|')
+    {
+    *argsptr++ = '\0';
+    *argsvectorptr++ = argsptr;
+    }
+
+  else if (*string == '$')
+    {
+    uint32_t value;
+    PCRE2_SPTR begin = string;
+
+    switch (decode_dollar_escape(begin, string, TRUE, &value, &string))
+      {
+      case DDE_CAPTURE:
+      if (value < capture_top)
+        {
+        PCRE2_SIZE capturesize;
+        value *= 2;
+        capturesize = ovector[value + 1] - ovector[value];
+        memcpy(argsptr, subject + ovector[value], capturesize);
+        argsptr += capturesize;
+        }
+      break;
+
+      case DDE_CHAR:
+      if (value == STDOUT_NL_CODE)
+        {
+        memcpy(argsptr, STDOUT_NL, STDOUT_NL_LEN);
+        argsptr += STDOUT_NL_LEN;  
+        }   
+      else if (utf && value > 127)
+        {
+        int n = ord2utf8(value);
+        memcpy(argsptr, utf8_buffer, n);
+        argsptr += n;
+        }
+      else
+        {
+        *argsptr++ = value;
+        }
+      break;
+
+      default:         /* Even though this should not occur, the string having */
+      case DDE_ERROR:  /* been checked above, we need to include the free() */
+      free(args);      /* calls so that source checkers do not complain. */
+      free(argsvector);
+      return 0;
+      }
+
+    length -= (string - begin);
+    }
+
+  else *argsptr++ = *string;
+
+  /* Advance along the string */
+
+  string++;
+  length--;
+  }
+
+*argsptr++ = '\0';
+*argsvectorptr = NULL;
+
+/* Running an external command is system-dependent. Handle Windows and VMS as
+necessary, otherwise assume fork(). */
+
+#ifdef WIN32
+result = _spawnvp(_P_WAIT, argsvector[0], (const char * const *)argsvector);
+
+#elif defined __VMS
+  {
+  char cmdbuf[500];
+  short i = 0;
+  int flags = CLI$M_NOCLISYM|CLI$M_NOLOGNAM|CLI$M_NOKEYPAD, status, retstat;
+  $DESCRIPTOR(cmd, cmdbuf);
+
+  cmdbuf[0] = 0;
+  while (argsvector[i])
+  {
+    strcat(cmdbuf, argsvector[i]);
+    strcat(cmdbuf, " ");
+    i++;
+  }
+  cmd.dsc$w_length = strlen(cmdbuf) - 1;
+  status = lib$spawn(&cmd, 0,0, &flags, 0,0, &retstat);
+  if (!(status & 1)) result = 0;
+  else result = retstat & 1 ? 0 : 1;
+  }
+
+#else  /* Neither Windows nor VMS */
+pid = fork();
+if (pid == 0)
+  {
+  (void)execv(argsvector[0], argsvector);
+  /* Control gets here if there is an error, e.g. a non-existent program */
+  exit(1);
+  }
+else if (pid > 0)
+  (void)waitpid(pid, &result, 0);
+#endif  /* End Windows/VMS/other handling */
+
+free(args);
+free(argsvector);
+
+/* Currently negative return values are not supported, only zero (match
+continues) or non-zero (match fails). */
+
+return result != 0;
+#endif  /* SUPPORT_PCRE2GREP_CALLOUT_FORK */
+}
+#endif  /* SUPPORT_PCRE2GREP_CALLOUT */
+
+
+
+/*************************************************
+*     Read a portion of the file into buffer     *
+*************************************************/
+
+static int
+fill_buffer(void *handle, int frtype, char *buffer, int length,
+  BOOL input_line_buffered)
+{
+(void)frtype;  /* Avoid warning when not used */
+
+#ifdef SUPPORT_LIBZ
+if (frtype == FR_LIBZ)
+  return gzread((gzFile)handle, buffer, length);
+else
+#endif
+
+#ifdef SUPPORT_LIBBZ2
+if (frtype == FR_LIBBZ2)
+  return BZ2_bzread((BZFILE *)handle, buffer, length);
+else
+#endif
+
+return (input_line_buffered ?
+  read_one_line(buffer, length, (FILE *)handle) :
+  fread(buffer, 1, length, (FILE *)handle));
+}
+
+
+
+/*************************************************
+*            Grep an individual file             *
+*************************************************/
+
+/* This is called from grep_or_recurse() below. It uses a buffer that is three
+times the value of bufthird. The matching point is never allowed to stray into
+the top third of the buffer, thus keeping more of the file available for
+context printing or for multiline scanning. For large files, the pointer will
+be in the middle third most of the time, so the bottom third is available for
+"before" context printing.
+
+Arguments:
+  handle       the fopened FILE stream for a normal file
+               the gzFile pointer when reading is via libz
+               the BZFILE pointer when reading is via libbz2
+  frtype       FR_PLAIN, FR_LIBZ, or FR_LIBBZ2
+  filename     the file name or NULL (for errors)
+  printname    the file name if it is to be printed for each match
+               or NULL if the file name is not to be printed
+               it cannot be NULL if filenames[_nomatch]_only is set
+
+Returns:       0 if there was at least one match
+               1 otherwise (no matches)
+               2 if an overlong line is encountered
+               3 if there is a read error on a .bz2 file
+*/
+
+static int
+pcre2grep(void *handle, int frtype, const char *filename, const char *printname)
+{
+int rc = 1;
+int filepos = 0;
+unsigned long int linenumber = 1;
+unsigned long int lastmatchnumber = 0;
+unsigned long int count = 0;
+long int count_matched_lines = 0;
+char *lastmatchrestart = main_buffer;
+char *ptr = main_buffer;
+char *endptr;
+PCRE2_SIZE bufflength;
+BOOL binary = FALSE;
+BOOL endhyphenpending = FALSE;
+BOOL lines_printed = FALSE;
+BOOL input_line_buffered = line_buffered;
+FILE *in = NULL;                    /* Ensure initialized */
+
+/* Do the first read into the start of the buffer and set up the pointer to end
+of what we have. In the case of libz, a non-zipped .gz file will be read as a
+plain file. However, if a .bz2 file isn't actually bzipped, the first read will
+fail. */
+
+if (frtype != FR_LIBZ && frtype != FR_LIBBZ2)
+  {
+  in = (FILE *)handle;
+  if (is_file_tty(in)) input_line_buffered = TRUE;
+  }
+else input_line_buffered = FALSE;
+
+bufflength = fill_buffer(handle, frtype, main_buffer, bufsize,
+  input_line_buffered);
+
+#ifdef SUPPORT_LIBBZ2
+if (frtype == FR_LIBBZ2 && (int)bufflength < 0) return 2;   /* Gotcha: bufflength is PCRE2_SIZE */
+#endif
+
+endptr = main_buffer + bufflength;
+
+/* Unless binary-files=text, see if we have a binary file. This uses the same
+rule as GNU grep, namely, a search for a binary zero byte near the start of the
+file. However, when the newline convention is binary zero, we can't do this. */
+
+if (binary_files != BIN_TEXT)
+  {
+  if (endlinetype != PCRE2_NEWLINE_NUL)
+    binary = memchr(main_buffer, 0, (bufflength > 1024)? 1024 : bufflength)
+      != NULL;
+  if (binary && binary_files == BIN_NOMATCH) return 1;
+  }
+
+/* Loop while the current pointer is not at the end of the file. For large
+files, endptr will be at the end of the buffer when we are in the middle of the
+file, but ptr will never get there, because as soon as it gets over 2/3 of the
+way, the buffer is shifted left and re-filled. */
+
+while (ptr < endptr)
+  {
+  int endlinelength;
+  int mrc = 0;
+  unsigned int options = 0;
+  BOOL match;
+  BOOL line_matched = FALSE;
+  char *t = ptr;
+  PCRE2_SIZE length, linelength;
+  PCRE2_SIZE startoffset = 0;
+
+  /* If the -m option set a limit for the number of matched or non-matched
+  lines, check it here. A limit of zero means that no matching is ever done.
+  For stdin from a file, set the file position. */
+
+  if (count_limit >= 0 && count_matched_lines >= count_limit)
+    {
+    if (frtype == FR_PLAIN && filename == stdin_name && !is_file_tty(handle))
+      (void)fseek(handle, (long int)filepos, SEEK_SET);
+    rc = (count_limit == 0)? 1 : 0;
+    break;
+    }
+
+  /* At this point, ptr is at the start of a line. We need to find the length
+  of the subject string to pass to pcre2_match(). In multiline mode, it is the
+  length remainder of the data in the buffer. Otherwise, it is the length of
+  the next line, excluding the terminating newline. After matching, we always
+  advance by the length of the next line. In multiline mode the PCRE2_FIRSTLINE
+  option is used for compiling, so that any match is constrained to be in the
+  first line. */
+
+  t = end_of_line(t, endptr, &endlinelength);
+  linelength = t - ptr - endlinelength;
+  length = multiline? (PCRE2_SIZE)(endptr - ptr) : linelength;
+
+  /* Check to see if the line we are looking at extends right to the very end
+  of the buffer without a line terminator. This means the line is too long to
+  handle at the current buffer size. Until the buffer reaches its maximum size,
+  try doubling it and reading more data. */
+
+  if (endlinelength == 0 && t == main_buffer + bufsize)
+    {
+    if (bufthird < max_bufthird)
+      {
+      char *new_buffer;
+      int new_bufthird = 2*bufthird;
+
+      if (new_bufthird > max_bufthird) new_bufthird = max_bufthird;
+      new_buffer = (char *)malloc(3*new_bufthird);
+
+      if (new_buffer == NULL)
+        {
+        fprintf(stderr,
+          "pcre2grep: line %lu%s%s is too long for the internal buffer\n"
+          "pcre2grep: not enough memory to increase the buffer size to %d\n",
+          linenumber,
+          (filename == NULL)? "" : " of file ",
+          (filename == NULL)? "" : filename,
+          new_bufthird);
+        return 2;
+        }
+
+      /* Copy the data and adjust pointers to the new buffer location. */
+
+      memcpy(new_buffer, main_buffer, bufsize);
+      bufthird = new_bufthird;
+      bufsize = 3*bufthird;
+      ptr = new_buffer + (ptr - main_buffer);
+      lastmatchrestart = new_buffer + (lastmatchrestart - main_buffer);
+      free(main_buffer);
+      main_buffer = new_buffer;
+
+      /* Read more data into the buffer and then try to find the line ending
+      again. */
+
+      bufflength += fill_buffer(handle, frtype, main_buffer + bufflength,
+        bufsize - bufflength, input_line_buffered);
+      endptr = main_buffer + bufflength;
+      continue;
+      }
+    else
+      {
+      fprintf(stderr,
+        "pcre2grep: line %lu%s%s is too long for the internal buffer\n"
+        "pcre2grep: the maximum buffer size is %d\n"
+        "pcre2grep: use the --max-buffer-size option to change it\n",
+        linenumber,
+        (filename == NULL)? "" : " of file ",
+        (filename == NULL)? "" : filename,
+        bufthird);
+      return 2;
+      }
+    }
+
+  /* Extra processing for Jeffrey Friedl's debugging. */
+
+#ifdef JFRIEDL_DEBUG
+  if (jfriedl_XT || jfriedl_XR)
+  {
+#     include <sys/time.h>
+#     include <time.h>
+      struct timeval start_time, end_time;
+      struct timezone dummy;
+      int i;
+
+      if (jfriedl_XT)
+      {
+          unsigned long newlen = length * jfriedl_XT + strlen(jfriedl_prefix) + strlen(jfriedl_postfix);
+          const char *orig = ptr;
+          ptr = malloc(newlen + 1);
+          if (!ptr) {
+                  printf("out of memory");
+                  pcre2grep_exit(2);
+          }
+          endptr = ptr;
+          strcpy(endptr, jfriedl_prefix); endptr += strlen(jfriedl_prefix);
+          for (i = 0; i < jfriedl_XT; i++) {
+                  strncpy(endptr, orig,  length);
+                  endptr += length;
+          }
+          strcpy(endptr, jfriedl_postfix); endptr += strlen(jfriedl_postfix);
+          length = newlen;
+      }
+
+      if (gettimeofday(&start_time, &dummy) != 0)
+              perror("bad gettimeofday");
+
+
+      for (i = 0; i < jfriedl_XR; i++)
+          match = (pcre_exec(patterns->compiled, patterns->hint, ptr, length, 0,
+              PCRE2_NOTEMPTY, offsets, offset_size) >= 0);
+
+      if (gettimeofday(&end_time, &dummy) != 0)
+              perror("bad gettimeofday");
+
+      double delta = ((end_time.tv_sec + (end_time.tv_usec / 1000000.0))
+                      -
+                      (start_time.tv_sec + (start_time.tv_usec / 1000000.0)));
+
+      printf("%s TIMER[%.4f]\n", match ? "MATCH" : "FAIL", delta);
+      return 0;
+  }
+#endif
+
+  /* We come back here after a match when only_matching_count is non-zero, in
+  order to find any further matches in the same line. This applies to
+  --only-matching, --file-offsets, and --line-offsets. */
+
+  ONLY_MATCHING_RESTART:
+
+  /* Run through all the patterns until one matches or there is an error other
+  than NOMATCH. This code is in a subroutine so that it can be re-used for
+  finding subsequent matches when colouring matched lines. After finding one
+  match, set PCRE2_NOTEMPTY to disable any further matches of null strings in
+  this line. */
+
+  match = match_patterns(ptr, length, options, startoffset, &mrc);
+  options = PCRE2_NOTEMPTY;
+
+  /* If it's a match or a not-match (as required), do what's wanted. NOTE: Use
+  only FWRITE_IGNORE() - which is just a packaged fwrite() that ignores its
+  return code - to output data lines, so that binary zeroes are treated as just
+  another data character. */
+
+  if (match != invert)
+    {
+    BOOL hyphenprinted = FALSE;
+
+    /* We've failed if we want a file that doesn't have any matches. */
+
+    if (filenames == FN_NOMATCH_ONLY) return 1;
+
+    /* Remember that this line matched (for counting matched lines) */
+
+    line_matched = TRUE;
+
+    /* If all we want is a yes/no answer, we can return immediately. */
+
+    if (quiet) return 0;
+
+    /* Just count if just counting is wanted. */
+
+    else if (count_only || show_total_count) count++;
+
+    /* When handling a binary file and binary-files==binary, the "binary"
+    variable will be set true (it's false in all other cases). In this
+    situation we just want to output the file name. No need to scan further. */
+
+    else if (binary)
+      {
+      fprintf(stdout, "Binary file %s matches" STDOUT_NL, filename);
+      return 0;
+      }
+
+    /* Likewise, if all we want is a file name, there is no need to scan any
+    more lines in the file. */
+
+    else if (filenames == FN_MATCH_ONLY)
+      {
+      fprintf(stdout, "%s" STDOUT_NL, printname);
+      return 0;
+      }
+
+    /* The --only-matching option prints just the substring that matched,
+    and/or one or more captured portions of it, as long as these strings are
+    not empty. The --file-offsets and --line-offsets options output offsets for
+    the matching substring (all three set only_matching_count non-zero). None
+    of these mutually exclusive options prints any context. Afterwards, adjust
+    the start and then jump back to look for further matches in the same line.
+    If we are in invert mode, however, nothing is printed and we do not restart
+    - this could still be useful because the return code is set. */
+
+    else if (only_matching_count != 0)
+      {
+      if (!invert)
+        {
+        PCRE2_SIZE oldstartoffset;
+
+        if (printname != NULL) fprintf(stdout, "%s:", printname);
+        if (number) fprintf(stdout, "%lu:", linenumber);
+
+        /* Handle --line-offsets */
+
+        if (line_offsets)
+          fprintf(stdout, "%d,%d" STDOUT_NL, (int)(ptr + offsets[0] - ptr),
+            (int)(offsets[1] - offsets[0]));
+
+        /* Handle --file-offsets */
+
+        else if (file_offsets)
+          fprintf(stdout, "%d,%d" STDOUT_NL,
+            (int)(filepos + ptr + offsets[0] - ptr),
+            (int)(offsets[1] - offsets[0]));
+
+        /* Handle --output (which has already been syntax checked) */
+
+        else if (output_text != NULL)
+          {
+          if (display_output_text((PCRE2_SPTR)output_text, FALSE,
+              (PCRE2_SPTR)ptr, offsets, mrc) || printname != NULL ||
+              number)
+            fprintf(stdout, STDOUT_NL);
+          }
+
+        /* Handle --only-matching, which may occur many times */
+
+        else
+          {
+          BOOL printed = FALSE;
+          omstr *om;
+
+          for (om = only_matching; om != NULL; om = om->next)
+            {
+            int n = om->groupnum;
+            if (n == 0 || n < mrc)
+              {
+              int plen = offsets[2*n + 1] - offsets[2*n];
+              if (plen > 0)
+                {
+                if (printed && om_separator != NULL)
+                  fprintf(stdout, "%s", om_separator);
+                print_match(ptr + offsets[n*2], plen);
+                printed = TRUE;
+                }
+              }
+            }
+
+          if (printed || printname != NULL || number)
+            fprintf(stdout, STDOUT_NL);
+          }
+
+        /* Prepare to repeat to find the next match in the line. */
+
+        match = FALSE;
+        if (line_buffered) fflush(stdout);
+        rc = 0;                      /* Had some success */
+
+        /* If the pattern contained a lookbehind that included \K, it is
+        possible that the end of the match might be at or before the actual
+        starting offset we have just used. In this case, start one character
+        further on. */
+
+        startoffset = offsets[1];    /* Restart after the match */
+        oldstartoffset = pcre2_get_startchar(match_data);
+        if (startoffset <= oldstartoffset)
+          {
+          if (startoffset >= length) goto END_ONE_MATCH;  /* Were at end */
+          startoffset = oldstartoffset + 1;
+          if (utf) while ((ptr[startoffset] & 0xc0) == 0x80) startoffset++;
+          }
+
+        /* If the current match ended past the end of the line (only possible
+        in multiline mode), we must move on to the line in which it did end
+        before searching for more matches. */
+
+        while (startoffset > linelength)
+          {
+          ptr += linelength + endlinelength;
+          filepos += (int)(linelength + endlinelength);
+          linenumber++;
+          startoffset -= (int)(linelength + endlinelength);
+          t = end_of_line(ptr, endptr, &endlinelength);
+          linelength = t - ptr - endlinelength;
+          length = (PCRE2_SIZE)(endptr - ptr);
+          }
+
+        goto ONLY_MATCHING_RESTART;
+        }
+      }
+
+    /* This is the default case when none of the above options is set. We print
+    the matching lines(s), possibly preceded and/or followed by other lines of
+    context. */
+
+    else
+      {
+      lines_printed = TRUE;
+
+      /* See if there is a requirement to print some "after" lines from a
+      previous match. We never print any overlaps. */
+
+      if (after_context > 0 && lastmatchnumber > 0)
+        {
+        int ellength;
+        int linecount = 0;
+        char *p = lastmatchrestart;
+
+        while (p < ptr && linecount < after_context)
+          {
+          p = end_of_line(p, ptr, &ellength);
+          linecount++;
+          }
+
+        /* It is important to advance lastmatchrestart during this printing so
+        that it interacts correctly with any "before" printing below. Print
+        each line's data using fwrite() in case there are binary zeroes. */
+
+        while (lastmatchrestart < p)
+          {
+          char *pp = lastmatchrestart;
+          if (printname != NULL) fprintf(stdout, "%s-", printname);
+          if (number) fprintf(stdout, "%lu-", lastmatchnumber++);
+          pp = end_of_line(pp, endptr, &ellength);
+          FWRITE_IGNORE(lastmatchrestart, 1, pp - lastmatchrestart, stdout);
+          lastmatchrestart = pp;
+          }
+        if (lastmatchrestart != ptr) hyphenpending = TRUE;
+        }
+
+      /* If there were non-contiguous lines printed above, insert hyphens. */
+
+      if (hyphenpending)
+        {
+        fprintf(stdout, "--" STDOUT_NL);
+        hyphenpending = FALSE;
+        hyphenprinted = TRUE;
+        }
+
+      /* See if there is a requirement to print some "before" lines for this
+      match. Again, don't print overlaps. */
+
+      if (before_context > 0)
+        {
+        int linecount = 0;
+        char *p = ptr;
+
+        while (p > main_buffer &&
+               (lastmatchnumber == 0 || p > lastmatchrestart) &&
+               linecount < before_context)
+          {
+          linecount++;
+          p = previous_line(p, main_buffer);
+          }
+
+        if (lastmatchnumber > 0 && p > lastmatchrestart && !hyphenprinted)
+          fprintf(stdout, "--" STDOUT_NL);
+
+        while (p < ptr)
+          {
+          int ellength;
+          char *pp = p;
+          if (printname != NULL) fprintf(stdout, "%s-", printname);
+          if (number) fprintf(stdout, "%lu-", linenumber - linecount--);
+          pp = end_of_line(pp, endptr, &ellength);
+          FWRITE_IGNORE(p, 1, pp - p, stdout);
+          p = pp;
+          }
+        }
+
+      /* Now print the matching line(s); ensure we set hyphenpending at the end
+      of the file if any context lines are being output. */
+
+      if (after_context > 0 || before_context > 0)
+        endhyphenpending = TRUE;
+
+      if (printname != NULL) fprintf(stdout, "%s:", printname);
+      if (number) fprintf(stdout, "%lu:", linenumber);
+
+      /* This extra option, for Jeffrey Friedl's debugging requirements,
+      replaces the matched string, or a specific captured string if it exists,
+      with X. When this happens, colouring is ignored. */
+
+#ifdef JFRIEDL_DEBUG
+      if (S_arg >= 0 && S_arg < mrc)
+        {
+        int first = S_arg * 2;
+        int last  = first + 1;
+        FWRITE_IGNORE(ptr, 1, offsets[first], stdout);
+        fprintf(stdout, "X");
+        FWRITE_IGNORE(ptr + offsets[last], 1, linelength - offsets[last], stdout);
+        }
+      else
+#endif
+
+      /* In multiline mode, or if colouring, we have to split the line(s) up
+      and search for further matches, but not of course if the line is a
+      non-match. In multiline mode this is necessary in case there is another
+      match that spans the end of the current line. When colouring we want to
+      colour all matches. */
+
+      if ((multiline || do_colour) && !invert)
+        {
+        int plength;
+        PCRE2_SIZE endprevious;
+
+        /* The use of \K may make the end offset earlier than the start. In
+        this situation, swap them round. */
+
+        if (offsets[0] > offsets[1])
+          {
+          PCRE2_SIZE temp = offsets[0];
+          offsets[0] = offsets[1];
+          offsets[1] = temp;
+          }
+
+        FWRITE_IGNORE(ptr, 1, offsets[0], stdout);
+        print_match(ptr + offsets[0], offsets[1] - offsets[0]);
+
+        for (;;)
+          {
+          PCRE2_SIZE oldstartoffset = pcre2_get_startchar(match_data);
+
+          endprevious = offsets[1];
+          startoffset = endprevious;  /* Advance after previous match. */
+
+          /* If the pattern contained a lookbehind that included \K, it is
+          possible that the end of the match might be at or before the actual
+          starting offset we have just used. In this case, start one character
+          further on. */
+
+          if (startoffset <= oldstartoffset)
+            {
+            startoffset = oldstartoffset + 1;
+            if (utf) while ((ptr[startoffset] & 0xc0) == 0x80) startoffset++;
+            }
+
+          /* If the current match ended past the end of the line (only possible
+          in multiline mode), we must move on to the line in which it did end
+          before searching for more matches. Because the PCRE2_FIRSTLINE option
+          is set, the start of the match will always be before the first
+          newline sequence. */
+
+          while (startoffset > linelength + endlinelength)
+            {
+            ptr += linelength + endlinelength;
+            filepos += (int)(linelength + endlinelength);
+            linenumber++;
+            startoffset -= (int)(linelength + endlinelength);
+            endprevious -= (int)(linelength + endlinelength);
+            t = end_of_line(ptr, endptr, &endlinelength);
+            linelength = t - ptr - endlinelength;
+            length = (PCRE2_SIZE)(endptr - ptr);
+            }
+
+          /* If startoffset is at the exact end of the line it means this
+          complete line was the final part of the match, so there is nothing
+          more to do. */
+
+          if (startoffset == linelength + endlinelength) break;
+
+          /* Otherwise, run a match from within the final line, and if found,
+          loop for any that may follow. */
+
+          if (!match_patterns(ptr, length, options, startoffset, &mrc)) break;
+
+          /* The use of \K may make the end offset earlier than the start. In
+          this situation, swap them round. */
+
+          if (offsets[0] > offsets[1])
+            {
+            PCRE2_SIZE temp = offsets[0];
+            offsets[0] = offsets[1];
+            offsets[1] = temp;
+            }
+
+          FWRITE_IGNORE(ptr + endprevious, 1, offsets[0] - endprevious, stdout);
+          print_match(ptr + offsets[0], offsets[1] - offsets[0]);
+          }
+
+        /* In multiline mode, we may have already printed the complete line
+        and its line-ending characters (if they matched the pattern), so there
+        may be no more to print. */
+
+        plength = (int)((linelength + endlinelength) - endprevious);
+        if (plength > 0) FWRITE_IGNORE(ptr + endprevious, 1, plength, stdout);
+        }
+
+      /* Not colouring or multiline; no need to search for further matches. */
+
+      else FWRITE_IGNORE(ptr, 1, linelength + endlinelength, stdout);
+      }
+
+    /* End of doing what has to be done for a match. If --line-buffered was
+    given, flush the output. */
+
+    if (line_buffered) fflush(stdout);
+    rc = 0;    /* Had some success */
+
+    /* Remember where the last match happened for after_context. We remember
+    where we are about to restart, and that line's number. */
+
+    lastmatchrestart = ptr + linelength + endlinelength;
+    lastmatchnumber = linenumber + 1;
+
+    /* If a line was printed and we are now at the end of the file and the last
+    line had no newline, output one. */
+
+    if (lines_printed && lastmatchrestart >= endptr && endlinelength == 0)
+      write_final_newline();
+    }
+
+  /* For a match in multiline inverted mode (which of course did not cause
+  anything to be printed), we have to move on to the end of the match before
+  proceeding. */
+
+  if (multiline && invert && match)
+    {
+    int ellength;
+    char *endmatch = ptr + offsets[1];
+    t = ptr;
+    while (t < endmatch)
+      {
+      t = end_of_line(t, endptr, &ellength);
+      if (t <= endmatch) linenumber++; else break;
+      }
+    endmatch = end_of_line(endmatch, endptr, &ellength);
+    linelength = endmatch - ptr - ellength;
+    }
+
+  /* Advance to after the newline and increment the line number. The file
+  offset to the current line is maintained in filepos. */
+
+  END_ONE_MATCH:
+  ptr += linelength + endlinelength;
+  filepos += (int)(linelength + endlinelength);
+  linenumber++;
+
+  /* If there was at least one match (or a non-match, as required) in the line,
+  increment the count for the -m option. */
+
+  if (line_matched) count_matched_lines++;
+
+  /* If input is line buffered, and the buffer is not yet full, read another
+  line and add it into the buffer. */
+
+  if (input_line_buffered && bufflength < (PCRE2_SIZE)bufsize)
+    {
+    int add = read_one_line(ptr, bufsize - (int)(ptr - main_buffer), in);
+    bufflength += add;
+    endptr += add;
+    }
+
+  /* If we haven't yet reached the end of the file (the buffer is full), and
+  the current point is in the top 1/3 of the buffer, slide the buffer down by
+  1/3 and refill it. Before we do this, if some unprinted "after" lines are
+  about to be lost, print them. */
+
+  if (bufflength >= (PCRE2_SIZE)bufsize && ptr > main_buffer + 2*bufthird)
+    {
+    if (after_context > 0 &&
+        lastmatchnumber > 0 &&
+        lastmatchrestart < main_buffer + bufthird)
+      {
+      do_after_lines(lastmatchnumber, lastmatchrestart, endptr, printname);
+      lastmatchnumber = 0;  /* Indicates no after lines pending */
+      }
+
+    /* Now do the shuffle */
+
+    (void)memmove(main_buffer, main_buffer + bufthird, 2*bufthird);
+    ptr -= bufthird;
+
+    bufflength = 2*bufthird + fill_buffer(handle, frtype,
+      main_buffer + 2*bufthird, bufthird, input_line_buffered);
+    endptr = main_buffer + bufflength;
+
+    /* Adjust any last match point */
+
+    if (lastmatchnumber > 0) lastmatchrestart -= bufthird;
+    }
+  }     /* Loop through the whole file */
+
+/* End of file; print final "after" lines if wanted; do_after_lines sets
+hyphenpending if it prints something. */
+
+if (only_matching_count == 0 && !(count_only|show_total_count))
+  {
+  do_after_lines(lastmatchnumber, lastmatchrestart, endptr, printname);
+  hyphenpending |= endhyphenpending;
+  }
+
+/* Print the file name if we are looking for those without matches and there
+were none. If we found a match, we won't have got this far. */
+
+if (filenames == FN_NOMATCH_ONLY)
+  {
+  fprintf(stdout, "%s" STDOUT_NL, printname);
+  return 0;
+  }
+
+/* Print the match count if wanted */
+
+if (count_only && !quiet)
+  {
+  if (count > 0 || !omit_zero_count)
+    {
+    if (printname != NULL && filenames != FN_NONE)
+      fprintf(stdout, "%s:", printname);
+    fprintf(stdout, "%lu" STDOUT_NL, count);
+    counts_printed++;
+    }
+  }
+
+total_count += count;   /* Can be set without count_only */
+return rc;
+}
+
+
+
+/*************************************************
+*     Grep a file or recurse into a directory    *
+*************************************************/
+
+/* Given a path name, if it's a directory, scan all the files if we are
+recursing; if it's a file, grep it.
+
+Arguments:
+  pathname          the path to investigate
+  dir_recurse       TRUE if recursing is wanted (-r or -drecurse)
+  only_one_at_top   TRUE if the path is the only one at toplevel
+
+Returns:  -1 the file/directory was skipped
+           0 if there was at least one match
+           1 if there were no matches
+           2 there was some kind of error
+
+However, file opening failures are suppressed if "silent" is set.
+*/
+
+static int
+grep_or_recurse(char *pathname, BOOL dir_recurse, BOOL only_one_at_top)
+{
+int rc = 1;
+int frtype;
+void *handle;
+char *lastcomp;
+FILE *in = NULL;           /* Ensure initialized */
+
+#ifdef SUPPORT_LIBZ
+gzFile ingz = NULL;
+#endif
+
+#ifdef SUPPORT_LIBBZ2
+BZFILE *inbz2 = NULL;
+#endif
+
+#if defined SUPPORT_LIBZ || defined SUPPORT_LIBBZ2
+int pathlen;
+#endif
+
+#if defined NATIVE_ZOS
+int zos_type;
+FILE *zos_test_file;
+#endif
+
+/* If the file name is "-" we scan stdin */
+
+if (strcmp(pathname, "-") == 0)
+  {
+  return pcre2grep(stdin, FR_PLAIN, stdin_name,
+    (filenames > FN_DEFAULT || (filenames == FN_DEFAULT && !only_one_at_top))?
+      stdin_name : NULL);
+  }
+
+/* Inclusion and exclusion: --include-dir and --exclude-dir apply only to
+directories, whereas --include and --exclude apply to everything else. The test
+is against the final component of the path. */
+
+lastcomp = strrchr(pathname, FILESEP);
+lastcomp = (lastcomp == NULL)? pathname : lastcomp + 1;
+
+/* If the file is a directory, skip if not recursing or if explicitly excluded.
+Otherwise, scan the directory and recurse for each path within it. The scanning
+code is localized so it can be made system-specific. */
+
+
+/* For z/OS, determine the file type. */
+
+#if defined NATIVE_ZOS
+zos_test_file =  fopen(pathname,"rb");
+
+if (zos_test_file == NULL)
+   {
+   if (!silent) fprintf(stderr, "pcre2grep: failed to test next file %s\n",
+     pathname, strerror(errno));
+   return -1;
+   }
+zos_type = identifyzosfiletype (zos_test_file);
+fclose (zos_test_file);
+
+/* Handle a PDS in separate code */
+
+if (zos_type == __ZOS_PDS || zos_type == __ZOS_PDSE)
+   {
+   return travelonpdsdir (pathname, only_one_at_top);
+   }
+
+/* Deal with regular files in the normal way below. These types are:
+   zos_type == __ZOS_PDS_MEMBER
+   zos_type == __ZOS_PS
+   zos_type == __ZOS_VSAM_KSDS
+   zos_type == __ZOS_VSAM_ESDS
+   zos_type == __ZOS_VSAM_RRDS
+*/
+
+/* Handle a z/OS directory using common code. */
+
+else if (zos_type == __ZOS_HFS)
+ {
+#endif  /* NATIVE_ZOS */
+
+
+/* Handle directories: common code for all OS */
+
+if (isdirectory(pathname))
+  {
+  if (dee_action == dee_SKIP ||
+      !test_incexc(lastcomp, include_dir_patterns, exclude_dir_patterns))
+    return -1;
+
+  if (dee_action == dee_RECURSE)
+    {
+    char buffer[FNBUFSIZ];
+    char *nextfile;
+    directory_type *dir = opendirectory(pathname);
+
+    if (dir == NULL)
+      {
+      if (!silent)
+        fprintf(stderr, "pcre2grep: Failed to open directory %s: %s\n", pathname,
+          strerror(errno));
+      return 2;
+      }
+
+    while ((nextfile = readdirectory(dir)) != NULL)
+      {
+      int frc;
+      int fnlength = strlen(pathname) + strlen(nextfile) + 2;
+      if (fnlength > FNBUFSIZ)
+        {
+        fprintf(stderr, "pcre2grep: recursive filename is too long\n");
+        rc = 2;
+        break;
+        }
+      sprintf(buffer, "%s%c%s", pathname, FILESEP, nextfile);
+      frc = grep_or_recurse(buffer, dir_recurse, FALSE);
+      if (frc > 1) rc = frc;
+       else if (frc == 0 && rc == 1) rc = 0;
+      }
+
+    closedirectory(dir);
+    return rc;
+    }
+  }
+
+#ifdef WIN32
+if (iswild(pathname))
+  {
+  char buffer[1024];
+  char *nextfile;
+  char *name;
+  directory_type *dir = opendirectory(pathname);
+
+  if (dir == NULL)
+    return 0;
+
+  for (nextfile = name = pathname; *nextfile != 0; nextfile++)
+    if (*nextfile == '/' || *nextfile == '\\')
+      name = nextfile + 1;
+  *name = 0;
+
+  while ((nextfile = readdirectory(dir)) != NULL)
+    {
+    int frc;
+    sprintf(buffer, "%.512s%.128s", pathname, nextfile);
+    frc = grep_or_recurse(buffer, dir_recurse, FALSE);
+    if (frc > 1) rc = frc;
+     else if (frc == 0 && rc == 1) rc = 0;
+    }
+
+  closedirectory(dir);
+  return rc;
+  }
+#endif
+
+#if defined NATIVE_ZOS
+ }
+#endif
+
+/* If the file is not a directory, check for a regular file, and if it is not,
+skip it if that's been requested. Otherwise, check for an explicit inclusion or
+exclusion. */
+
+else if (
+#if defined NATIVE_ZOS
+        (zos_type == __ZOS_NOFILE && DEE_action == DEE_SKIP) ||
+#else  /* all other OS */
+        (!isregfile(pathname) && DEE_action == DEE_SKIP) ||
+#endif
+        !test_incexc(lastcomp, include_patterns, exclude_patterns))
+  return -1;  /* File skipped */
+
+/* Control reaches here if we have a regular file, or if we have a directory
+and recursion or skipping was not requested, or if we have anything else and
+skipping was not requested. The scan proceeds. If this is the first and only
+argument at top level, we don't show the file name, unless we are only showing
+the file name, or the filename was forced (-H). */
+
+#if defined SUPPORT_LIBZ || defined SUPPORT_LIBBZ2
+pathlen = (int)(strlen(pathname));
+#endif
+
+/* Open using zlib if it is supported and the file name ends with .gz. */
+
+#ifdef SUPPORT_LIBZ
+if (pathlen > 3 && strcmp(pathname + pathlen - 3, ".gz") == 0)
+  {
+  ingz = gzopen(pathname, "rb");
+  if (ingz == NULL)
+    {
+    if (!silent)
+      fprintf(stderr, "pcre2grep: Failed to open %s: %s\n", pathname,
+        strerror(errno));
+    return 2;
+    }
+  handle = (void *)ingz;
+  frtype = FR_LIBZ;
+  }
+else
+#endif
+
+/* Otherwise open with bz2lib if it is supported and the name ends with .bz2. */
+
+#ifdef SUPPORT_LIBBZ2
+if (pathlen > 4 && strcmp(pathname + pathlen - 4, ".bz2") == 0)
+  {
+  inbz2 = BZ2_bzopen(pathname, "rb");
+  handle = (void *)inbz2;
+  frtype = FR_LIBBZ2;
+  }
+else
+#endif
+
+/* Otherwise use plain fopen(). The label is so that we can come back here if
+an attempt to read a .bz2 file indicates that it really is a plain file. */
+
+#ifdef SUPPORT_LIBBZ2
+PLAIN_FILE:
+#endif
+  {
+  in = fopen(pathname, "rb");
+  handle = (void *)in;
+  frtype = FR_PLAIN;
+  }
+
+/* All the opening methods return errno when they fail. */
+
+if (handle == NULL)
+  {
+  if (!silent)
+    fprintf(stderr, "pcre2grep: Failed to open %s: %s\n", pathname,
+      strerror(errno));
+  return 2;
+  }
+
+/* Now grep the file */
+
+rc = pcre2grep(handle, frtype, pathname, (filenames > FN_DEFAULT ||
+  (filenames == FN_DEFAULT && !only_one_at_top))? pathname : NULL);
+
+/* Close in an appropriate manner. */
+
+#ifdef SUPPORT_LIBZ
+if (frtype == FR_LIBZ)
+  gzclose(ingz);
+else
+#endif
+
+/* If it is a .bz2 file and the result is 3, it means that the first attempt to
+read failed. If the error indicates that the file isn't in fact bzipped, try
+again as a normal file. */
+
+#ifdef SUPPORT_LIBBZ2
+if (frtype == FR_LIBBZ2)
+  {
+  if (rc == 3)
+    {
+    int errnum;
+    const char *err = BZ2_bzerror(inbz2, &errnum);
+    if (errnum == BZ_DATA_ERROR_MAGIC)
+      {
+      BZ2_bzclose(inbz2);
+      goto PLAIN_FILE;
+      }
+    else if (!silent)
+      fprintf(stderr, "pcre2grep: Failed to read %s using bzlib: %s\n",
+        pathname, err);
+    rc = 2;    /* The normal "something went wrong" code */
+    }
+  BZ2_bzclose(inbz2);
+  }
+else
+#endif
+
+/* Normal file close */
+
+fclose(in);
+
+/* Pass back the yield from pcre2grep(). */
+
+return rc;
+}
+
+
+
+/*************************************************
+*    Handle a single-letter, no data option      *
+*************************************************/
+
+static int
+handle_option(int letter, int options)
+{
+switch(letter)
+  {
+  case N_FOFFSETS: file_offsets = TRUE; break;
+  case N_HELP: help(); pcre2grep_exit(0); break; /* Stops compiler warning */
+  case N_LBUFFER: line_buffered = TRUE; break;
+  case N_LOFFSETS: line_offsets = number = TRUE; break;
+  case N_NOJIT: use_jit = FALSE; break;
+  case 'a': binary_files = BIN_TEXT; break;
+  case 'c': count_only = TRUE; break;
+  case 'F': options |= PCRE2_LITERAL; break;
+  case 'H': filenames = FN_FORCE; break;
+  case 'I': binary_files = BIN_NOMATCH; break;
+  case 'h': filenames = FN_NONE; break;
+  case 'i': options |= PCRE2_CASELESS; break;
+  case 'l': omit_zero_count = TRUE; filenames = FN_MATCH_ONLY; break;
+  case 'L': filenames = FN_NOMATCH_ONLY; break;
+  case 'M': multiline = TRUE; options |= PCRE2_MULTILINE|PCRE2_FIRSTLINE; break;
+  case 'n': number = TRUE; break;
+
+  case 'o':
+  only_matching_last = add_number(0, only_matching_last);
+  if (only_matching == NULL) only_matching = only_matching_last;
+  break;
+
+  case 'q': quiet = TRUE; break;
+  case 'r': dee_action = dee_RECURSE; break;
+  case 's': silent = TRUE; break;
+  case 't': show_total_count = TRUE; break;
+  case 'u': options |= PCRE2_UTF; utf = TRUE; break;
+  case 'U': options |= PCRE2_UTF|PCRE2_MATCH_INVALID_UTF; utf = TRUE; break;
+  case 'v': invert = TRUE; break;
+  case 'w': extra_options |= PCRE2_EXTRA_MATCH_WORD; break;
+  case 'x': extra_options |= PCRE2_EXTRA_MATCH_LINE; break;
+
+  case 'V':
+    {
+    unsigned char buffer[128];
+    (void)pcre2_config(PCRE2_CONFIG_VERSION, buffer);
+    fprintf(stdout, "pcre2grep version %s" STDOUT_NL, buffer);
+    }
+  pcre2grep_exit(0);
+  break;
+
+  default:
+  fprintf(stderr, "pcre2grep: Unknown option -%c\n", letter);
+  pcre2grep_exit(usage(2));
+  }
+
+return options;
+}
+
+
+
+/*************************************************
+*          Construct printed ordinal             *
+*************************************************/
+
+/* This turns a number into "1st", "3rd", etc. */
+
+static char *
+ordin(int n)
+{
+static char buffer[14];
+char *p = buffer;
+sprintf(p, "%d", n);
+while (*p != 0) p++;
+n %= 100;
+if (n >= 11 && n <= 13) n = 0;
+switch (n%10)
+  {
+  case 1: strcpy(p, "st"); break;
+  case 2: strcpy(p, "nd"); break;
+  case 3: strcpy(p, "rd"); break;
+  default: strcpy(p, "th"); break;
+  }
+return buffer;
+}
+
+
+
+/*************************************************
+*          Compile a single pattern              *
+*************************************************/
+
+/* Do nothing if the pattern has already been compiled. This is the case for
+include/exclude patterns read from a file.
+
+When the -F option has been used, each "pattern" may be a list of strings,
+separated by line breaks. They will be matched literally. We split such a
+string and compile the first substring, inserting an additional block into the
+pattern chain.
+
+Arguments:
+  p              points to the pattern block
+  options        the PCRE options
+  fromfile       TRUE if the pattern was read from a file
+  fromtext       file name or identifying text (e.g. "include")
+  count          0 if this is the only command line pattern, or
+                 number of the command line pattern, or
+                 linenumber for a pattern from a file
+
+Returns:         TRUE on success, FALSE after an error
+*/
+
+static BOOL
+compile_pattern(patstr *p, int options, int fromfile, const char *fromtext,
+  int count)
+{
+char *ps;
+int errcode;
+PCRE2_SIZE patlen, erroffset;
+PCRE2_UCHAR errmessbuffer[ERRBUFSIZ];
+
+if (p->compiled != NULL) return TRUE;
+ps = p->string;
+patlen = p->length;
+
+if ((options & PCRE2_LITERAL) != 0)
+  {
+  int ellength;
+  char *eop = ps + patlen;
+  char *pe = end_of_line(ps, eop, &ellength);
+
+  if (ellength != 0)
+    {
+    patlen = pe - ps - ellength;
+    if (add_pattern(pe, p->length-patlen-ellength, p) == NULL) return FALSE;
+    }
+  }
+
+p->compiled = pcre2_compile((PCRE2_SPTR)ps, patlen, options, &errcode,
+  &erroffset, compile_context);
+
+/* Handle successful compile. Try JIT-compiling if supported and enabled. We
+ignore any JIT compiler errors, relying falling back to interpreting if
+anything goes wrong with JIT. */
+
+if (p->compiled != NULL)
+  {
+#ifdef SUPPORT_PCRE2GREP_JIT
+  if (use_jit) (void)pcre2_jit_compile(p->compiled, PCRE2_JIT_COMPLETE);
+#endif
+  return TRUE;
+  }
+
+/* Handle compile errors */
+
+if (erroffset > patlen) erroffset = patlen;
+pcre2_get_error_message(errcode, errmessbuffer, sizeof(errmessbuffer));
+
+if (fromfile)
+  {
+  fprintf(stderr, "pcre2grep: Error in regex in line %d of %s "
+    "at offset %d: %s\n", count, fromtext, (int)erroffset, errmessbuffer);
+  }
+else
+  {
+  if (count == 0)
+    fprintf(stderr, "pcre2grep: Error in %s regex at offset %d: %s\n",
+      fromtext, (int)erroffset, errmessbuffer);
+  else
+    fprintf(stderr, "pcre2grep: Error in %s %s regex at offset %d: %s\n",
+      ordin(count), fromtext, (int)erroffset, errmessbuffer);
+  }
+
+return FALSE;
+}
+
+
+
+/*************************************************
+*     Read and compile a file of patterns        *
+*************************************************/
+
+/* This is used for --filelist, --include-from, and --exclude-from.
+
+Arguments:
+  name         the name of the file; "-" is stdin
+  patptr       pointer to the pattern chain anchor
+  patlastptr   pointer to the last pattern pointer
+
+Returns:       TRUE if all went well
+*/
+
+static BOOL
+read_pattern_file(char *name, patstr **patptr, patstr **patlastptr)
+{
+int linenumber = 0;
+PCRE2_SIZE patlen;
+FILE *f;
+const char *filename;
+char buffer[MAXPATLEN+20];
+
+if (strcmp(name, "-") == 0)
+  {
+  f = stdin;
+  filename = stdin_name;
+  }
+else
+  {
+  f = fopen(name, "r");
+  if (f == NULL)
+    {
+    fprintf(stderr, "pcre2grep: Failed to open %s: %s\n", name, strerror(errno));
+    return FALSE;
+    }
+  filename = name;
+  }
+
+while ((patlen = read_one_line(buffer, sizeof(buffer), f)) > 0)
+  {
+  while (patlen > 0 && isspace((unsigned char)(buffer[patlen-1]))) patlen--;
+  linenumber++;
+  if (patlen == 0) continue;   /* Skip blank lines */
+
+  /* Note: this call to add_pattern() puts a pointer to the local variable
+  "buffer" into the pattern chain. However, that pointer is used only when
+  compiling the pattern, which happens immediately below, so we flatten it
+  afterwards, as a precaution against any later code trying to use it. */
+
+  *patlastptr = add_pattern(buffer, patlen, *patlastptr);
+  if (*patlastptr == NULL)
+    {
+    if (f != stdin) fclose(f);
+    return FALSE;
+    }
+  if (*patptr == NULL) *patptr = *patlastptr;
+
+  /* This loop is needed because compiling a "pattern" when -F is set may add
+  on additional literal patterns if the original contains a newline. In the
+  common case, it never will, because read_one_line() stops at a newline.
+  However, the -N option can be used to give pcre2grep a different newline
+  setting. */
+
+  for(;;)
+    {
+    if (!compile_pattern(*patlastptr, pcre2_options, TRUE, filename,
+        linenumber))
+      {
+      if (f != stdin) fclose(f);
+      return FALSE;
+      }
+    (*patlastptr)->string = NULL;            /* Insurance */
+    if ((*patlastptr)->next == NULL) break;
+    *patlastptr = (*patlastptr)->next;
+    }
+  }
+
+if (f != stdin) fclose(f);
+return TRUE;
+}
+
+
+
+/*************************************************
+*                Main program                    *
+*************************************************/
+
+/* Returns 0 if something matched, 1 if nothing matched, 2 after an error. */
+
+int
+main(int argc, char **argv)
+{
+int i, j;
+int rc = 1;
+BOOL only_one_at_top;
+patstr *cp;
+fnstr *fn;
+omstr *om;
+const char *locale_from = "--locale";
+
+#ifdef SUPPORT_PCRE2GREP_JIT
+pcre2_jit_stack *jit_stack = NULL;
+#endif
+
+/* In Windows, stdout is set up as a text stream, which means that \n is
+converted to \r\n. This causes output lines that are copied from the input to
+change from ....\r\n to ....\r\r\n, which is not right. We therefore ensure
+that stdout is a binary stream. Note that this means all other output to stdout
+must use STDOUT_NL to terminate lines. */
+
+#ifdef WIN32
+_setmode(_fileno(stdout), _O_BINARY);
+#endif
+
+/* Process the options */
+
+for (i = 1; i < argc; i++)
+  {
+  option_item *op = NULL;
+  char *option_data = (char *)"";    /* default to keep compiler happy */
+  BOOL longop;
+  BOOL longopwasequals = FALSE;
+
+  if (argv[i][0] != '-') break;
+
+  /* If we hit an argument that is just "-", it may be a reference to STDIN,
+  but only if we have previously had -e or -f to define the patterns. */
+
+  if (argv[i][1] == 0)
+    {
+    if (pattern_files != NULL || patterns != NULL) break;
+      else pcre2grep_exit(usage(2));
+    }
+
+  /* Handle a long name option, or -- to terminate the options */
+
+  if (argv[i][1] == '-')
+    {
+    char *arg = argv[i] + 2;
+    char *argequals = strchr(arg, '=');
+
+    if (*arg == 0)    /* -- terminates options */
+      {
+      i++;
+      break;                /* out of the options-handling loop */
+      }
+
+    longop = TRUE;
+
+    /* Some long options have data that follows after =, for example file=name.
+    Some options have variations in the long name spelling: specifically, we
+    allow "regexp" because GNU grep allows it, though I personally go along
+    with Jeffrey Friedl and Larry Wall in preferring "regex" without the "p".
+    These options are entered in the table as "regex(p)". Options can be in
+    both these categories. */
+
+    for (op = optionlist; op->one_char != 0; op++)
+      {
+      char *opbra = strchr(op->long_name, '(');
+      char *equals = strchr(op->long_name, '=');
+
+      /* Handle options with only one spelling of the name */
+
+      if (opbra == NULL)     /* Does not contain '(' */
+        {
+        if (equals == NULL)  /* Not thing=data case */
+          {
+          if (strcmp(arg, op->long_name) == 0) break;
+          }
+        else                 /* Special case xxx=data */
+          {
+          int oplen = (int)(equals - op->long_name);
+          int arglen = (argequals == NULL)?
+            (int)strlen(arg) : (int)(argequals - arg);
+          if (oplen == arglen && strncmp(arg, op->long_name, oplen) == 0)
+            {
+            option_data = arg + arglen;
+            if (*option_data == '=')
+              {
+              option_data++;
+              longopwasequals = TRUE;
+              }
+            break;
+            }
+          }
+        }
+
+      /* Handle options with an alternate spelling of the name */
+
+      else
+        {
+        char buff1[24];
+        char buff2[24];
+        int ret;
+
+        int baselen = (int)(opbra - op->long_name);
+        int fulllen = (int)(strchr(op->long_name, ')') - op->long_name + 1);
+        int arglen = (argequals == NULL || equals == NULL)?
+          (int)strlen(arg) : (int)(argequals - arg);
+
+        if ((ret = snprintf(buff1, sizeof(buff1), "%.*s", baselen, op->long_name),
+             ret < 0 || ret > (int)sizeof(buff1)) ||
+            (ret = snprintf(buff2, sizeof(buff2), "%s%.*s", buff1,
+                     fulllen - baselen - 2, opbra + 1),
+             ret < 0 || ret > (int)sizeof(buff2)))
+          {
+          fprintf(stderr, "pcre2grep: Buffer overflow when parsing %s option\n",
+            op->long_name);
+          pcre2grep_exit(2);
+          }
+
+        if (strncmp(arg, buff1, arglen) == 0 ||
+           strncmp(arg, buff2, arglen) == 0)
+          {
+          if (equals != NULL && argequals != NULL)
+            {
+            option_data = argequals;
+            if (*option_data == '=')
+              {
+              option_data++;
+              longopwasequals = TRUE;
+              }
+            }
+          break;
+          }
+        }
+      }
+
+    if (op->one_char == 0)
+      {
+      fprintf(stderr, "pcre2grep: Unknown option %s\n", argv[i]);
+      pcre2grep_exit(usage(2));
+      }
+    }
+
+  /* Jeffrey Friedl's debugging harness uses these additional options which
+  are not in the right form for putting in the option table because they use
+  only one hyphen, yet are more than one character long. By putting them
+  separately here, they will not get displayed as part of the help() output,
+  but I don't think Jeffrey will care about that. */
+
+#ifdef JFRIEDL_DEBUG
+  else if (strcmp(argv[i], "-pre") == 0) {
+          jfriedl_prefix = argv[++i];
+          continue;
+  } else if (strcmp(argv[i], "-post") == 0) {
+          jfriedl_postfix = argv[++i];
+          continue;
+  } else if (strcmp(argv[i], "-XT") == 0) {
+          sscanf(argv[++i], "%d", &jfriedl_XT);
+          continue;
+  } else if (strcmp(argv[i], "-XR") == 0) {
+          sscanf(argv[++i], "%d", &jfriedl_XR);
+          continue;
+  }
+#endif
+
+
+  /* One-char options; many that have no data may be in a single argument; we
+  continue till we hit the last one or one that needs data. */
+
+  else
+    {
+    char *s = argv[i] + 1;
+    longop = FALSE;
+
+    while (*s != 0)
+      {
+      for (op = optionlist; op->one_char != 0; op++)
+        {
+        if (*s == op->one_char) break;
+        }
+      if (op->one_char == 0)
+        {
+        fprintf(stderr, "pcre2grep: Unknown option letter '%c' in \"%s\"\n",
+          *s, argv[i]);
+        pcre2grep_exit(usage(2));
+        }
+
+      option_data = s+1;
+
+      /* Break out if this is the last character in the string; it's handled
+      below like a single multi-char option. */
+
+      if (*option_data == 0) break;
+
+      /* Check for a single-character option that has data: OP_OP_NUMBER(S)
+      are used for ones that either have a numerical number or defaults, i.e.
+      the data is optional. If a digit follows, there is data; if not, carry on
+      with other single-character options in the same string. */
+
+      if (op->type == OP_OP_NUMBER || op->type == OP_OP_NUMBERS)
+        {
+        if (isdigit((unsigned char)s[1])) break;
+        }
+      else   /* Check for an option with data */
+        {
+        if (op->type != OP_NODATA) break;
+        }
+
+      /* Handle a single-character option with no data, then loop for the
+      next character in the string. */
+
+      pcre2_options = handle_option(*s++, pcre2_options);
+      }
+    }
+
+  /* At this point we should have op pointing to a matched option. If the type
+  is NO_DATA, it means that there is no data, and the option might set
+  something in the PCRE options. */
+
+  if (op->type == OP_NODATA)
+    {
+    pcre2_options = handle_option(op->one_char, pcre2_options);
+    continue;
+    }
+
+  /* If the option type is OP_OP_STRING or OP_OP_NUMBER(S), it's an option that
+  either has a value or defaults to something. It cannot have data in a
+  separate item. At the moment, the only such options are "colo(u)r",
+  "only-matching", and Jeffrey Friedl's special -S debugging option. */
+
+  if (*option_data == 0 &&
+      (op->type == OP_OP_STRING || op->type == OP_OP_NUMBER ||
+       op->type == OP_OP_NUMBERS))
+    {
+    switch (op->one_char)
+      {
+      case N_COLOUR:
+      colour_option = "auto";
+      break;
+
+      case 'o':
+      only_matching_last = add_number(0, only_matching_last);
+      if (only_matching == NULL) only_matching = only_matching_last;
+      break;
+
+#ifdef JFRIEDL_DEBUG
+      case 'S':
+      S_arg = 0;
+      break;
+#endif
+      }
+    continue;
+    }
+
+  /* Otherwise, find the data string for the option. */
+
+  if (*option_data == 0)
+    {
+    if (i >= argc - 1 || longopwasequals)
+      {
+      fprintf(stderr, "pcre2grep: Data missing after %s\n", argv[i]);
+      pcre2grep_exit(usage(2));
+      }
+    option_data = argv[++i];
+    }
+
+  /* If the option type is OP_OP_NUMBERS, the value is a number that is to be
+  added to a chain of numbers. */
+
+  if (op->type == OP_OP_NUMBERS)
+    {
+    unsigned long int n = decode_number(option_data, op, longop);
+    omdatastr *omd = (omdatastr *)op->dataptr;
+    *(omd->lastptr) = add_number((int)n, *(omd->lastptr));
+    if (*(omd->anchor) == NULL) *(omd->anchor) = *(omd->lastptr);
+    }
+
+  /* If the option type is OP_PATLIST, it's the -e option, or one of the
+  include/exclude options, which can be called multiple times to create lists
+  of patterns. */
+
+  else if (op->type == OP_PATLIST)
+    {
+    patdatastr *pd = (patdatastr *)op->dataptr;
+    *(pd->lastptr) = add_pattern(option_data, (PCRE2_SIZE)strlen(option_data),
+      *(pd->lastptr));
+    if (*(pd->lastptr) == NULL) goto EXIT2;
+    if (*(pd->anchor) == NULL) *(pd->anchor) = *(pd->lastptr);
+    }
+
+  /* If the option type is OP_FILELIST, it's one of the options that names a
+  file. */
+
+  else if (op->type == OP_FILELIST)
+    {
+    fndatastr *fd = (fndatastr *)op->dataptr;
+    fn = (fnstr *)malloc(sizeof(fnstr));
+    if (fn == NULL)
+      {
+      fprintf(stderr, "pcre2grep: malloc failed\n");
+      goto EXIT2;
+      }
+    fn->next = NULL;
+    fn->name = option_data;
+    if (*(fd->anchor) == NULL)
+      *(fd->anchor) = fn;
+    else
+      (*(fd->lastptr))->next = fn;
+    *(fd->lastptr) = fn;
+    }
+
+  /* Handle OP_BINARY_FILES */
+
+  else if (op->type == OP_BINFILES)
+    {
+    if (strcmp(option_data, "binary") == 0)
+      binary_files = BIN_BINARY;
+    else if (strcmp(option_data, "without-match") == 0)
+      binary_files = BIN_NOMATCH;
+    else if (strcmp(option_data, "text") == 0)
+      binary_files = BIN_TEXT;
+    else
+      {
+      fprintf(stderr, "pcre2grep: unknown value \"%s\" for binary-files\n",
+        option_data);
+      pcre2grep_exit(usage(2));
+      }
+    }
+
+  /* Otherwise, deal with a single string or numeric data value. */
+
+  else if (op->type != OP_NUMBER && op->type != OP_U32NUMBER &&
+           op->type != OP_OP_NUMBER && op->type != OP_SIZE)
+    {
+    *((char **)op->dataptr) = option_data;
+    }
+  else
+    {
+    unsigned long int n = decode_number(option_data, op, longop);
+    if (op->type == OP_U32NUMBER) *((uint32_t *)op->dataptr) = n;
+      else if (op->type == OP_SIZE) *((PCRE2_SIZE *)op->dataptr) = n;
+      else *((int *)op->dataptr) = n;
+    }
+  }
+
+/* Options have been decoded. If -C was used, its value is used as a default
+for -A and -B. */
+
+if (both_context > 0)
+  {
+  if (after_context == 0) after_context = both_context;
+  if (before_context == 0) before_context = both_context;
+  }
+
+/* Only one of --only-matching, --output, --file-offsets, or --line-offsets is
+permitted. They display, each in their own way, only the data that has matched.
+*/
+
+only_matching_count = (only_matching != NULL) + (output_text != NULL) +
+  file_offsets + line_offsets;
+
+if (only_matching_count > 1)
+  {
+  fprintf(stderr, "pcre2grep: Cannot mix --only-matching, --output, "
+    "--file-offsets and/or --line-offsets\n");
+  pcre2grep_exit(usage(2));
+  }
+
+
+/* Check that there is a big enough ovector for all -o settings. */
+
+for (om = only_matching; om != NULL; om = om->next)
+  {
+  int n = om->groupnum;
+  if (n > (int)capture_max)
+    {
+    fprintf(stderr, "pcre2grep: Requested group %d cannot be captured.\n", n);
+    fprintf(stderr, "pcre2grep: Use --om-capture to increase the size of the capture vector.\n");
+    goto EXIT2;
+    }
+  }
+
+/* Check the text supplied to --output for errors. */
+
+if (output_text != NULL &&
+    !syntax_check_output_text((PCRE2_SPTR)output_text, FALSE))
+  goto EXIT2;
+
+/* Set up default compile and match contexts and a match data block. */
+
+offset_size = capture_max + 1;
+compile_context = pcre2_compile_context_create(NULL);
+match_context = pcre2_match_context_create(NULL);
+match_data = pcre2_match_data_create(offset_size, NULL);
+offsets = pcre2_get_ovector_pointer(match_data);
+
+/* If string (script) callouts are supported, set up the callout processing
+function. */
+
+#ifdef SUPPORT_PCRE2GREP_CALLOUT
+pcre2_set_callout(match_context, pcre2grep_callout, NULL);
+#endif
+
+/* Put limits into the match data block. */
+
+if (heap_limit != PCRE2_UNSET) pcre2_set_heap_limit(match_context, heap_limit);
+if (match_limit > 0) pcre2_set_match_limit(match_context, match_limit);
+if (depth_limit > 0) pcre2_set_depth_limit(match_context, depth_limit);
+
+/* If a locale has not been provided as an option, see if the LC_CTYPE or
+LC_ALL environment variable is set, and if so, use it. */
+
+if (locale == NULL)
+  {
+  locale = getenv("LC_ALL");
+  locale_from = "LC_ALL";
+  }
+
+if (locale == NULL)
+  {
+  locale = getenv("LC_CTYPE");
+  locale_from = "LC_CTYPE";
+  }
+
+/* If a locale is set, use it to generate the tables the PCRE needs. Passing
+NULL to pcre2_maketables() means that malloc() is used to get the memory. */
+
+if (locale != NULL)
+  {
+  if (setlocale(LC_CTYPE, locale) == NULL)
+    {
+    fprintf(stderr, "pcre2grep: Failed to set locale %s (obtained from %s)\n",
+      locale, locale_from);
+    goto EXIT2;
+    }
+  character_tables = pcre2_maketables(NULL);
+  pcre2_set_character_tables(compile_context, character_tables);
+  }
+
+/* Sort out colouring */
+
+if (colour_option != NULL && strcmp(colour_option, "never") != 0)
+  {
+  if (strcmp(colour_option, "always") == 0)
+#ifdef WIN32
+    do_ansi = !is_stdout_tty(),
+#endif
+    do_colour = TRUE;
+  else if (strcmp(colour_option, "auto") == 0) do_colour = is_stdout_tty();
+  else
+    {
+    fprintf(stderr, "pcre2grep: Unknown colour setting \"%s\"\n",
+      colour_option);
+    goto EXIT2;
+    }
+  if (do_colour)
+    {
+    char *cs = getenv("PCRE2GREP_COLOUR");
+    if (cs == NULL) cs = getenv("PCRE2GREP_COLOR");
+    if (cs == NULL) cs = getenv("PCREGREP_COLOUR");
+    if (cs == NULL) cs = getenv("PCREGREP_COLOR");
+    if (cs == NULL) cs = parse_grep_colors(getenv("GREP_COLORS"));
+    if (cs == NULL) cs = getenv("GREP_COLOR");
+    if (cs != NULL)
+      {
+      if (strspn(cs, ";0123456789") == strlen(cs)) colour_string = cs;
+      }
+#ifdef WIN32
+    init_colour_output();
+#endif
+    }
+  }
+
+/* Sort out a newline setting. */
+
+if (newline_arg != NULL)
+  {
+  for (endlinetype = 1; endlinetype < (int)(sizeof(newlines)/sizeof(char *));
+       endlinetype++)
+    {
+    if (strcmpic(newline_arg, newlines[endlinetype]) == 0) break;
+    }
+  if (endlinetype < (int)(sizeof(newlines)/sizeof(char *)))
+    pcre2_set_newline(compile_context, endlinetype);
+  else
+    {
+    fprintf(stderr, "pcre2grep: Invalid newline specifier \"%s\"\n",
+      newline_arg);
+    goto EXIT2;
+    }
+  }
+
+/* Find default newline convention */
+
+else
+  {
+  (void)pcre2_config(PCRE2_CONFIG_NEWLINE, &endlinetype);
+  }
+
+/* Interpret the text values for -d and -D */
+
+if (dee_option != NULL)
+  {
+  if (strcmp(dee_option, "read") == 0) dee_action = dee_READ;
+  else if (strcmp(dee_option, "recurse") == 0) dee_action = dee_RECURSE;
+  else if (strcmp(dee_option, "skip") == 0) dee_action = dee_SKIP;
+  else
+    {
+    fprintf(stderr, "pcre2grep: Invalid value \"%s\" for -d\n", dee_option);
+    goto EXIT2;
+    }
+  }
+
+if (DEE_option != NULL)
+  {
+  if (strcmp(DEE_option, "read") == 0) DEE_action = DEE_READ;
+  else if (strcmp(DEE_option, "skip") == 0) DEE_action = DEE_SKIP;
+  else
+    {
+    fprintf(stderr, "pcre2grep: Invalid value \"%s\" for -D\n", DEE_option);
+    goto EXIT2;
+    }
+  }
+
+/* Set the extra options */
+
+(void)pcre2_set_compile_extra_options(compile_context, extra_options);
+
+/* Check the values for Jeffrey Friedl's debugging options. */
+
+#ifdef JFRIEDL_DEBUG
+if (S_arg > 9)
+  {
+  fprintf(stderr, "pcre2grep: bad value for -S option\n");
+  return 2;
+  }
+if (jfriedl_XT != 0 || jfriedl_XR != 0)
+  {
+  if (jfriedl_XT == 0) jfriedl_XT = 1;
+  if (jfriedl_XR == 0) jfriedl_XR = 1;
+  }
+#endif
+
+/* If use_jit is set, check whether JIT is available. If not, do not try
+to use JIT. */
+
+if (use_jit)
+  {
+  uint32_t answer;
+  (void)pcre2_config(PCRE2_CONFIG_JIT, &answer);
+  if (!answer) use_jit = FALSE;
+  }
+
+/* Get memory for the main buffer. */
+
+if (bufthird <= 0)
+  {
+  fprintf(stderr, "pcre2grep: --buffer-size must be greater than zero\n");
+  goto EXIT2;
+  }
+
+bufsize = 3*bufthird;
+main_buffer = (char *)malloc(bufsize);
+
+if (main_buffer == NULL)
+  {
+  fprintf(stderr, "pcre2grep: malloc failed\n");
+  goto EXIT2;
+  }
+
+/* If no patterns were provided by -e, and there are no files provided by -f,
+the first argument is the one and only pattern, and it must exist. */
+
+if (patterns == NULL && pattern_files == NULL)
+  {
+  if (i >= argc) return usage(2);
+  patterns = patterns_last = add_pattern(argv[i], (PCRE2_SIZE)strlen(argv[i]),
+    NULL);
+  i++;
+  if (patterns == NULL) goto EXIT2;
+  }
+
+/* Compile the patterns that were provided on the command line, either by
+multiple uses of -e or as a single unkeyed pattern. We cannot do this until
+after all the command-line options are read so that we know which PCRE options
+to use. When -F is used, compile_pattern() may add another block into the
+chain, so we must not access the next pointer till after the compile. */
+
+for (j = 1, cp = patterns; cp != NULL; j++, cp = cp->next)
+  {
+  if (!compile_pattern(cp, pcre2_options, FALSE, "command-line",
+       (j == 1 && patterns->next == NULL)? 0 : j))
+    goto EXIT2;
+  }
+
+/* Read and compile the regular expressions that are provided in files. */
+
+for (fn = pattern_files; fn != NULL; fn = fn->next)
+  {
+  if (!read_pattern_file(fn->name, &patterns, &patterns_last)) goto EXIT2;
+  }
+
+/* Unless JIT has been explicitly disabled, arrange a stack for it to use. */
+
+#ifdef SUPPORT_PCRE2GREP_JIT
+if (use_jit)
+  {
+  jit_stack = pcre2_jit_stack_create(32*1024, 1024*1024, NULL);
+  if (jit_stack != NULL                        )
+    pcre2_jit_stack_assign(match_context, NULL, jit_stack);
+  }
+#endif
+
+/* -F, -w, and -x do not apply to include or exclude patterns, so we must
+adjust the options. */
+
+pcre2_options &= ~PCRE2_LITERAL;
+(void)pcre2_set_compile_extra_options(compile_context, 0);
+
+/* If there are include or exclude patterns read from the command line, compile
+them. */
+
+for (j = 0; j < 4; j++)
+  {
+  int k;
+  for (k = 1, cp = *(incexlist[j]); cp != NULL; k++, cp = cp->next)
+    {
+    if (!compile_pattern(cp, pcre2_options, FALSE, incexname[j],
+         (k == 1 && cp->next == NULL)? 0 : k))
+      goto EXIT2;
+    }
+  }
+
+/* Read and compile include/exclude patterns from files. */
+
+for (fn = include_from; fn != NULL; fn = fn->next)
+  {
+  if (!read_pattern_file(fn->name, &include_patterns, &include_patterns_last))
+    goto EXIT2;
+  }
+
+for (fn = exclude_from; fn != NULL; fn = fn->next)
+  {
+  if (!read_pattern_file(fn->name, &exclude_patterns, &exclude_patterns_last))
+    goto EXIT2;
+  }
+
+/* If there are no files that contain lists of files to search, and there are
+no file arguments, search stdin, and then exit. */
+
+if (file_lists == NULL && i >= argc)
+  {
+  rc = pcre2grep(stdin, FR_PLAIN, stdin_name,
+    (filenames > FN_DEFAULT)? stdin_name : NULL);
+  goto EXIT;
+  }
+
+/* If any files that contains a list of files to search have been specified,
+read them line by line and search the given files. */
+
+for (fn = file_lists; fn != NULL; fn = fn->next)
+  {
+  char buffer[FNBUFSIZ];
+  FILE *fl;
+  if (strcmp(fn->name, "-") == 0) fl = stdin; else
+    {
+    fl = fopen(fn->name, "rb");
+    if (fl == NULL)
+      {
+      fprintf(stderr, "pcre2grep: Failed to open %s: %s\n", fn->name,
+        strerror(errno));
+      goto EXIT2;
+      }
+    }
+  while (fgets(buffer, sizeof(buffer), fl) != NULL)
+    {
+    int frc;
+    char *end = buffer + (int)strlen(buffer);
+    while (end > buffer && isspace(end[-1])) end--;
+    *end = 0;
+    if (*buffer != 0)
+      {
+      frc = grep_or_recurse(buffer, dee_action == dee_RECURSE, FALSE);
+      if (frc > 1) rc = frc;
+        else if (frc == 0 && rc == 1) rc = 0;
+      }
+    }
+  if (fl != stdin) fclose(fl);
+  }
+
+/* After handling file-list, work through remaining arguments. Pass in the fact
+that there is only one argument at top level - this suppresses the file name if
+the argument is not a directory and filenames are not otherwise forced. */
+
+only_one_at_top = i == argc - 1 && file_lists == NULL;
+
+for (; i < argc; i++)
+  {
+  int frc = grep_or_recurse(argv[i], dee_action == dee_RECURSE,
+    only_one_at_top);
+  if (frc > 1) rc = frc;
+    else if (frc == 0 && rc == 1) rc = 0;
+  }
+
+#ifdef SUPPORT_PCRE2GREP_CALLOUT
+/* If separating builtin echo callouts by implicit newline, add one more for
+the final item. */
+
+if (om_separator != NULL && strcmp(om_separator, STDOUT_NL) == 0)
+  fprintf(stdout, STDOUT_NL);
+#endif
+
+/* Show the total number of matches if requested, but not if only one file's
+count was printed. */
+
+if (show_total_count && counts_printed != 1 && filenames != FN_NOMATCH_ONLY)
+  {
+  if (counts_printed != 0 && filenames >= FN_DEFAULT)
+    fprintf(stdout, "TOTAL:");
+  fprintf(stdout, "%lu" STDOUT_NL, total_count);
+  }
+
+EXIT:
+#ifdef SUPPORT_PCRE2GREP_JIT
+pcre2_jit_free_unused_memory(NULL);
+if (jit_stack != NULL) pcre2_jit_stack_free(jit_stack);
+#endif
+
+free(main_buffer);
+if (character_tables != NULL) pcre2_maketables_free(NULL, character_tables);
+
+pcre2_compile_context_free(compile_context);
+pcre2_match_context_free(match_context);
+pcre2_match_data_free(match_data);
+
+free_pattern_chain(patterns);
+free_pattern_chain(include_patterns);
+free_pattern_chain(include_dir_patterns);
+free_pattern_chain(exclude_patterns);
+free_pattern_chain(exclude_dir_patterns);
+
+free_file_chain(exclude_from);
+free_file_chain(include_from);
+free_file_chain(pattern_files);
+free_file_chain(file_lists);
+
+while (only_matching != NULL)
+  {
+  omstr *this = only_matching;
+  only_matching = this->next;
+  free(this);
+  }
+
+pcre2grep_exit(rc);
+
+EXIT2:
+rc = 2;
+goto EXIT;
+}
+
+/* End of pcre2grep */
diff --git a/src/c/pcre2/src/pcre2posix.c b/src/c/pcre2/src/pcre2posix.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2posix.c
@@ -0,0 +1,423 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2019 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module is a wrapper that provides a POSIX API to the underlying PCRE2
+functions. The operative functions are called pcre2_regcomp(), etc., with
+wrappers that use the plain POSIX names. In addition, pcre2posix.h defines the
+POSIX names as macros for the pcre2_xxx functions, so any program that includes
+it and uses the POSIX names will call the base functions directly. This makes
+it easier for an application to be sure it gets the PCRE2 versions in the
+presence of other POSIX regex libraries. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+/* Ensure that the PCRE2POSIX_EXP_xxx macros are set appropriately for
+compiling these functions. This must come before including pcre2posix.h, where
+they are set for an application (using these functions) if they have not
+previously been set. */
+
+#if defined(_WIN32) && !defined(PCRE2_STATIC)
+#  define PCRE2POSIX_EXP_DECL extern __declspec(dllexport)
+#  define PCRE2POSIX_EXP_DEFN __declspec(dllexport)
+#endif
+
+/* Older versions of MSVC lack snprintf(). This define allows for
+warning/error-free compilation and testing with MSVC compilers back to at least
+MSVC 10/2010. Except for VC6 (which is missing some fundamentals and fails). */
+
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+#define snprintf _snprintf
+#endif
+
+
+/* Compile-time error numbers start at this value. It should probably never be
+changed. This #define is a copy of the one in pcre2_internal.h. */
+
+#define COMPILE_ERROR_BASE 100
+
+
+/* Standard C headers */
+
+#include <ctype.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* PCRE2 headers */
+
+#include "pcre2.h"
+#include "pcre2posix.h"
+
+/* When compiling with the MSVC compiler, it is sometimes necessary to include
+a "calling convention" before exported function names. (This is secondhand
+information; I know nothing about MSVC myself). For example, something like
+
+  void __cdecl function(....)
+
+might be needed. In order to make this easy, all the exported functions have
+PCRE2_CALL_CONVENTION just before their names. It is rarely needed; if not
+set, we ensure here that it has no effect. */
+
+#ifndef PCRE2_CALL_CONVENTION
+#define PCRE2_CALL_CONVENTION
+#endif
+
+/* Table to translate PCRE2 compile time error codes into POSIX error codes.
+Only a few PCRE2 errors with a value greater than 23 turn into special POSIX
+codes: most go to REG_BADPAT. The second table lists, in pairs, those that
+don't. */
+
+static const int eint1[] = {
+  0,           /* No error */
+  REG_EESCAPE, /* \ at end of pattern */
+  REG_EESCAPE, /* \c at end of pattern */
+  REG_EESCAPE, /* unrecognized character follows \ */
+  REG_BADBR,   /* numbers out of order in {} quantifier */
+  /* 5 */
+  REG_BADBR,   /* number too big in {} quantifier */
+  REG_EBRACK,  /* missing terminating ] for character class */
+  REG_ECTYPE,  /* invalid escape sequence in character class */
+  REG_ERANGE,  /* range out of order in character class */
+  REG_BADRPT,  /* nothing to repeat */
+  /* 10 */
+  REG_ASSERT,  /* internal error: unexpected repeat */
+  REG_BADPAT,  /* unrecognized character after (? or (?- */
+  REG_BADPAT,  /* POSIX named classes are supported only within a class */
+  REG_BADPAT,  /* POSIX collating elements are not supported */
+  REG_EPAREN,  /* missing ) */
+  /* 15 */
+  REG_ESUBREG, /* reference to non-existent subpattern */
+  REG_INVARG,  /* pattern passed as NULL */
+  REG_INVARG,  /* unknown compile-time option bit(s) */
+  REG_EPAREN,  /* missing ) after (?# comment */
+  REG_ESIZE,   /* parentheses nested too deeply */
+  /* 20 */
+  REG_ESIZE,   /* regular expression too large */
+  REG_ESPACE,  /* failed to get memory */
+  REG_EPAREN,  /* unmatched closing parenthesis */
+  REG_ASSERT   /* internal error: code overflow */
+  };
+
+static const int eint2[] = {
+  30, REG_ECTYPE,  /* unknown POSIX class name */
+  32, REG_INVARG,  /* this version of PCRE2 does not have Unicode support */
+  37, REG_EESCAPE, /* PCRE2 does not support \L, \l, \N{name}, \U, or \u */
+  56, REG_INVARG,  /* internal error: unknown newline setting */
+  92, REG_INVARG,  /* invalid option bits with PCRE2_LITERAL */
+};
+
+/* Table of texts corresponding to POSIX error codes */
+
+static const char *const pstring[] = {
+  "",                                /* Dummy for value 0 */
+  "internal error",                  /* REG_ASSERT */
+  "invalid repeat counts in {}",     /* BADBR      */
+  "pattern error",                   /* BADPAT     */
+  "? * + invalid",                   /* BADRPT     */
+  "unbalanced {}",                   /* EBRACE     */
+  "unbalanced []",                   /* EBRACK     */
+  "collation error - not relevant",  /* ECOLLATE   */
+  "bad class",                       /* ECTYPE     */
+  "bad escape sequence",             /* EESCAPE    */
+  "empty expression",                /* EMPTY      */
+  "unbalanced ()",                   /* EPAREN     */
+  "bad range inside []",             /* ERANGE     */
+  "expression too big",              /* ESIZE      */
+  "failed to get memory",            /* ESPACE     */
+  "bad back reference",              /* ESUBREG    */
+  "bad argument",                    /* INVARG     */
+  "match failed"                     /* NOMATCH    */
+};
+
+
+
+/*************************************************
+*      Wrappers with traditional POSIX names     *
+*************************************************/
+
+/* Keep defining them to preseve the ABI for applications linked to the pcre2
+POSIX library before these names were changed into macros in pcre2posix.h.
+This also ensures that the POSIX names are callable from languages that do not
+include pcre2posix.h. It is vital to #undef the macro definitions from
+pcre2posix.h! */
+
+#undef regerror
+PCRE2POSIX_EXP_DECL size_t regerror(int, const regex_t *, char *, size_t);
+PCRE2POSIX_EXP_DEFN size_t PCRE2_CALL_CONVENTION
+regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
+{
+return pcre2_regerror(errcode, preg, errbuf, errbuf_size);
+}
+
+#undef regfree
+PCRE2POSIX_EXP_DECL void regfree(regex_t *);
+PCRE2POSIX_EXP_DEFN void PCRE2_CALL_CONVENTION
+regfree(regex_t *preg)
+{
+pcre2_regfree(preg);
+}
+
+#undef regcomp
+PCRE2POSIX_EXP_DECL int regcomp(regex_t *, const char *, int);
+PCRE2POSIX_EXP_DEFN int PCRE2_CALL_CONVENTION
+regcomp(regex_t *preg, const char *pattern, int cflags)
+{
+return pcre2_regcomp(preg, pattern, cflags);
+}
+
+#undef regexec
+PCRE2POSIX_EXP_DECL int regexec(const regex_t *, const char *, size_t,
+  regmatch_t *, int);
+PCRE2POSIX_EXP_DEFN int PCRE2_CALL_CONVENTION
+regexec(const regex_t *preg, const char *string, size_t nmatch,
+  regmatch_t pmatch[], int eflags)
+{
+return pcre2_regexec(preg, string, nmatch, pmatch, eflags);
+}
+
+
+
+/*************************************************
+*          Translate error code to string        *
+*************************************************/
+
+PCRE2POSIX_EXP_DEFN size_t PCRE2_CALL_CONVENTION
+pcre2_regerror(int errcode, const regex_t *preg, char *errbuf,
+  size_t errbuf_size)
+{
+int used;
+const char *message;
+
+message = (errcode <= 0 || errcode >= (int)(sizeof(pstring)/sizeof(char *)))?
+  "unknown error code" : pstring[errcode];
+
+if (preg != NULL && (int)preg->re_erroffset != -1)
+  {
+  used = snprintf(errbuf, errbuf_size, "%s at offset %-6d", message,
+    (int)preg->re_erroffset);
+  }
+else
+  {
+  used = snprintf(errbuf, errbuf_size, "%s", message);
+  }
+
+return used + 1;
+}
+
+
+
+/*************************************************
+*           Free store held by a regex           *
+*************************************************/
+
+PCRE2POSIX_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_regfree(regex_t *preg)
+{
+pcre2_match_data_free(preg->re_match_data);
+pcre2_code_free(preg->re_pcre2_code);
+}
+
+
+
+/*************************************************
+*            Compile a regular expression        *
+*************************************************/
+
+/*
+Arguments:
+  preg        points to a structure for recording the compiled expression
+  pattern     the pattern to compile
+  cflags      compilation flags
+
+Returns:      0 on success
+              various non-zero codes on failure
+*/
+
+PCRE2POSIX_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_regcomp(regex_t *preg, const char *pattern, int cflags)
+{
+PCRE2_SIZE erroffset;
+PCRE2_SIZE patlen;
+int errorcode;
+int options = 0;
+int re_nsub = 0;
+
+patlen = ((cflags & REG_PEND) != 0)? (PCRE2_SIZE)(preg->re_endp - pattern) :
+  PCRE2_ZERO_TERMINATED;
+
+if ((cflags & REG_ICASE) != 0)    options |= PCRE2_CASELESS;
+if ((cflags & REG_NEWLINE) != 0)  options |= PCRE2_MULTILINE;
+if ((cflags & REG_DOTALL) != 0)   options |= PCRE2_DOTALL;
+if ((cflags & REG_NOSPEC) != 0)   options |= PCRE2_LITERAL;
+if ((cflags & REG_UTF) != 0)      options |= PCRE2_UTF;
+if ((cflags & REG_UCP) != 0)      options |= PCRE2_UCP;
+if ((cflags & REG_UNGREEDY) != 0) options |= PCRE2_UNGREEDY;
+
+preg->re_cflags = cflags;
+preg->re_pcre2_code = pcre2_compile((PCRE2_SPTR)pattern, patlen, options,
+  &errorcode, &erroffset, NULL);
+preg->re_erroffset = erroffset;
+
+if (preg->re_pcre2_code == NULL)
+  {
+  unsigned int i;
+
+  /* A negative value is a UTF error; otherwise all error codes are greater
+  than COMPILE_ERROR_BASE, but check, just in case. */
+
+  if (errorcode < COMPILE_ERROR_BASE) return REG_BADPAT;
+  errorcode -= COMPILE_ERROR_BASE;
+
+  if (errorcode < (int)(sizeof(eint1)/sizeof(const int)))
+    return eint1[errorcode];
+  for (i = 0; i < sizeof(eint2)/sizeof(const int); i += 2)
+    if (errorcode == eint2[i]) return eint2[i+1];
+  return REG_BADPAT;
+  }
+
+(void)pcre2_pattern_info((const pcre2_code *)preg->re_pcre2_code,
+  PCRE2_INFO_CAPTURECOUNT, &re_nsub);
+preg->re_nsub = (size_t)re_nsub;
+preg->re_match_data = pcre2_match_data_create(re_nsub + 1, NULL);
+preg->re_erroffset = (size_t)(-1);  /* No meaning after successful compile */
+
+if (preg->re_match_data == NULL)
+  {
+  pcre2_code_free(preg->re_pcre2_code);
+  return REG_ESPACE;
+  }
+
+return 0;
+}
+
+
+
+/*************************************************
+*              Match a regular expression        *
+*************************************************/
+
+/* A suitable match_data block, large enough to hold all possible captures, was
+obtained when the pattern was compiled, to save having to allocate and free it
+for each match. If REG_NOSUB was specified at compile time, the nmatch and
+pmatch arguments are ignored, and the only result is yes/no/error. */
+
+PCRE2POSIX_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_regexec(const regex_t *preg, const char *string, size_t nmatch,
+  regmatch_t pmatch[], int eflags)
+{
+int rc, so, eo;
+int options = 0;
+pcre2_match_data *md = (pcre2_match_data *)preg->re_match_data;
+
+if ((eflags & REG_NOTBOL) != 0) options |= PCRE2_NOTBOL;
+if ((eflags & REG_NOTEOL) != 0) options |= PCRE2_NOTEOL;
+if ((eflags & REG_NOTEMPTY) != 0) options |= PCRE2_NOTEMPTY;
+
+/* When REG_NOSUB was specified, or if no vector has been passed in which to
+put captured strings, ensure that nmatch is zero. This will stop any attempt to
+write to pmatch. */
+
+if ((preg->re_cflags & REG_NOSUB) != 0 || pmatch == NULL) nmatch = 0;
+
+/* REG_STARTEND is a BSD extension, to allow for non-NUL-terminated strings.
+The man page from OS X says "REG_STARTEND affects only the location of the
+string, not how it is matched". That is why the "so" value is used to bump the
+start location rather than being passed as a PCRE2 "starting offset". */
+
+if ((eflags & REG_STARTEND) != 0)
+  {
+  if (pmatch == NULL) return REG_INVARG;
+  so = pmatch[0].rm_so;
+  eo = pmatch[0].rm_eo;
+  }
+else
+  {
+  so = 0;
+  eo = (int)strlen(string);
+  }
+
+rc = pcre2_match((const pcre2_code *)preg->re_pcre2_code,
+  (PCRE2_SPTR)string + so, (eo - so), 0, options, md, NULL);
+
+/* Successful match */
+
+if (rc >= 0)
+  {
+  size_t i;
+  PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(md);
+  if ((size_t)rc > nmatch) rc = (int)nmatch;
+  for (i = 0; i < (size_t)rc; i++)
+    {
+    pmatch[i].rm_so = (ovector[i*2] == PCRE2_UNSET)? -1 :
+      (int)(ovector[i*2] + so);
+    pmatch[i].rm_eo = (ovector[i*2+1] == PCRE2_UNSET)? -1 :
+      (int)(ovector[i*2+1] + so);
+    }
+  for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1;
+  return 0;
+  }
+
+/* Unsuccessful match */
+
+if (rc <= PCRE2_ERROR_UTF8_ERR1 && rc >= PCRE2_ERROR_UTF8_ERR21)
+  return REG_INVARG;
+
+switch(rc)
+  {
+  default: return REG_ASSERT;
+  case PCRE2_ERROR_BADMODE: return REG_INVARG;
+  case PCRE2_ERROR_BADMAGIC: return REG_INVARG;
+  case PCRE2_ERROR_BADOPTION: return REG_INVARG;
+  case PCRE2_ERROR_BADUTFOFFSET: return REG_INVARG;
+  case PCRE2_ERROR_MATCHLIMIT: return REG_ESPACE;
+  case PCRE2_ERROR_NOMATCH: return REG_NOMATCH;
+  case PCRE2_ERROR_NOMEMORY: return REG_ESPACE;
+  case PCRE2_ERROR_NULL: return REG_INVARG;
+  }
+}
+
+/* End of pcre2posix.c */
diff --git a/src/c/pcre2/src/pcre2posix.h b/src/c/pcre2/src/pcre2posix.h
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2posix.h
@@ -0,0 +1,170 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* PCRE2 is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language. This is
+the public header file to be #included by applications that call PCRE2 via the
+POSIX wrapper interface.
+
+                       Written by Philip Hazel
+     Original API code Copyright (c) 1997-2012 University of Cambridge
+          New API code Copyright (c) 2016-2019 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* Have to include stdlib.h in order to ensure that size_t is defined. */
+
+#include <stdlib.h>
+
+/* Allow for C++ users */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Options, mostly defined by POSIX, but with some extras. */
+
+#define REG_ICASE     0x0001  /* Maps to PCRE2_CASELESS */
+#define REG_NEWLINE   0x0002  /* Maps to PCRE2_MULTILINE */
+#define REG_NOTBOL    0x0004  /* Maps to PCRE2_NOTBOL */
+#define REG_NOTEOL    0x0008  /* Maps to PCRE2_NOTEOL */
+#define REG_DOTALL    0x0010  /* NOT defined by POSIX; maps to PCRE2_DOTALL */
+#define REG_NOSUB     0x0020  /* Do not report what was matched */
+#define REG_UTF       0x0040  /* NOT defined by POSIX; maps to PCRE2_UTF */
+#define REG_STARTEND  0x0080  /* BSD feature: pass subject string by so,eo */
+#define REG_NOTEMPTY  0x0100  /* NOT defined by POSIX; maps to PCRE2_NOTEMPTY */
+#define REG_UNGREEDY  0x0200  /* NOT defined by POSIX; maps to PCRE2_UNGREEDY */
+#define REG_UCP       0x0400  /* NOT defined by POSIX; maps to PCRE2_UCP */
+#define REG_PEND      0x0800  /* GNU feature: pass end pattern by re_endp */
+#define REG_NOSPEC    0x1000  /* Maps to PCRE2_LITERAL */
+
+/* This is not used by PCRE2, but by defining it we make it easier
+to slot PCRE2 into existing programs that make POSIX calls. */
+
+#define REG_EXTENDED  0
+
+/* Error values. Not all these are relevant or used by the wrapper. */
+
+enum {
+  REG_ASSERT = 1,  /* internal error ? */
+  REG_BADBR,       /* invalid repeat counts in {} */
+  REG_BADPAT,      /* pattern error */
+  REG_BADRPT,      /* ? * + invalid */
+  REG_EBRACE,      /* unbalanced {} */
+  REG_EBRACK,      /* unbalanced [] */
+  REG_ECOLLATE,    /* collation error - not relevant */
+  REG_ECTYPE,      /* bad class */
+  REG_EESCAPE,     /* bad escape sequence */
+  REG_EMPTY,       /* empty expression */
+  REG_EPAREN,      /* unbalanced () */
+  REG_ERANGE,      /* bad range inside [] */
+  REG_ESIZE,       /* expression too big */
+  REG_ESPACE,      /* failed to get memory */
+  REG_ESUBREG,     /* bad back reference */
+  REG_INVARG,      /* bad argument */
+  REG_NOMATCH      /* match failed */
+};
+
+
+/* The structure representing a compiled regular expression. It is also used
+for passing the pattern end pointer when REG_PEND is set. */
+
+typedef struct {
+  void *re_pcre2_code;
+  void *re_match_data;
+  const char *re_endp;
+  size_t re_nsub;
+  size_t re_erroffset;
+  int re_cflags;
+} regex_t;
+
+/* The structure in which a captured offset is returned. */
+
+typedef int regoff_t;
+
+typedef struct {
+  regoff_t rm_so;
+  regoff_t rm_eo;
+} regmatch_t;
+
+/* When an application links to a PCRE2 DLL in Windows, the symbols that are
+imported have to be identified as such. When building PCRE2, the appropriate
+export settings are needed, and are set in pcre2posix.c before including this
+file. */
+
+#if defined(_WIN32) && !defined(PCRE2_STATIC) && !defined(PCRE2POSIX_EXP_DECL)
+#  define PCRE2POSIX_EXP_DECL  extern __declspec(dllimport)
+#  define PCRE2POSIX_EXP_DEFN  __declspec(dllimport)
+#endif
+
+/* By default, we use the standard "extern" declarations. */
+
+#ifndef PCRE2POSIX_EXP_DECL
+#  ifdef __cplusplus
+#    define PCRE2POSIX_EXP_DECL  extern "C"
+#    define PCRE2POSIX_EXP_DEFN  extern "C"
+#  else
+#    define PCRE2POSIX_EXP_DECL  extern
+#    define PCRE2POSIX_EXP_DEFN  extern
+#  endif
+#endif
+
+/* The functions. The actual code is in functions with pcre2_xxx names for
+uniqueness. POSIX names are provided as macros for API compatibility with POSIX
+regex functions. It's done this way to ensure to they are always linked from
+the PCRE2 library and not by accident from elsewhere (regex_t differs in size
+elsewhere). */
+
+PCRE2POSIX_EXP_DECL int pcre2_regcomp(regex_t *, const char *, int);
+PCRE2POSIX_EXP_DECL int pcre2_regexec(const regex_t *, const char *, size_t,
+                     regmatch_t *, int);
+PCRE2POSIX_EXP_DECL size_t pcre2_regerror(int, const regex_t *, char *, size_t);
+PCRE2POSIX_EXP_DECL void pcre2_regfree(regex_t *);
+
+#define regcomp  pcre2_regcomp
+#define regexec  pcre2_regexec
+#define regerror pcre2_regerror
+#define regfree  pcre2_regfree
+
+/* Debian had a patch that used different names. These are now here to save
+them having to maintain their own patch, but are not documented by PCRE2. */
+
+#define PCRE2regcomp  pcre2_regcomp
+#define PCRE2regexec  pcre2_regexec
+#define PCRE2regerror pcre2_regerror
+#define PCRE2regfree  pcre2_regfree
+
+#ifdef __cplusplus
+}   /* extern "C" */
+#endif
+
+/* End of pcre2posix.h */
diff --git a/src/c/pcre2/src/pcre2test.c b/src/c/pcre2/src/pcre2test.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/pcre2test.c
@@ -0,0 +1,9220 @@
+/*************************************************
+*             PCRE2 testing program              *
+*************************************************/
+
+/* PCRE2 is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language. In 2014
+the API was completely revised and '2' was added to the name, because the old
+API, which had lasted for 16 years, could not accommodate new requirements. At
+the same time, this testing program was re-designed because its original
+hacked-up (non-) design had also run out of steam.
+
+                       Written by Philip Hazel
+     Original code Copyright (c) 1997-2012 University of Cambridge
+    Rewritten code Copyright (c) 2016-2020 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This program supports testing of the 8-bit, 16-bit, and 32-bit PCRE2
+libraries in a single program, though its input and output are always 8-bit.
+It is different from modules such as pcre2_compile.c in the library itself,
+which are compiled separately for each code unit width. If two widths are
+enabled, for example, pcre2_compile.c is compiled twice. In contrast,
+pcre2test.c is compiled only once, and linked with all the enabled libraries.
+Therefore, it must not make use of any of the macros from pcre2.h or
+pcre2_internal.h that depend on PCRE2_CODE_UNIT_WIDTH. It does, however, make
+use of SUPPORT_PCRE2_8, SUPPORT_PCRE2_16, and SUPPORT_PCRE2_32, to ensure that
+it references only the enabled library functions. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <locale.h>
+#include <errno.h>
+
+#if defined NATIVE_ZOS
+#include "pcrzoscs.h"
+/* That header is not included in the main PCRE2 distribution because other
+apparatus is needed to compile pcre2test for z/OS. The header can be found in
+the special z/OS distribution, which is available from www.zaconsultants.net or
+from www.cbttape.org. */
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* Debugging code enabler */
+
+/* #define DEBUG_SHOW_MALLOC_ADDRESSES */
+
+/* Both libreadline and libedit are optionally supported. The user-supplied
+original patch uses readline/readline.h for libedit, but in at least one system
+it is installed as editline/readline.h, so the configuration code now looks for
+that first, falling back to readline/readline.h. */
+
+#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT)
+#if defined(SUPPORT_LIBREADLINE)
+#include <readline/readline.h>
+#include <readline/history.h>
+#else
+#if defined(HAVE_EDITLINE_READLINE_H)
+#include <editline/readline.h>
+#else
+#include <readline/readline.h>
+#endif
+#endif
+#endif
+
+/* Put the test for interactive input into a macro so that it can be changed if
+required for different environments. */
+
+#define INTERACTIVE(f) isatty(fileno(f))
+
+
+/* ---------------------- System-specific definitions ---------------------- */
+
+/* A number of things vary for Windows builds. Originally, pcretest opened its
+input and output without "b"; then I was told that "b" was needed in some
+environments, so it was added for release 5.0 to both the input and output. (It
+makes no difference on Unix-like systems.) Later I was told that it is wrong
+for the input on Windows. I've now abstracted the modes into macros that are
+set here, to make it easier to fiddle with them, and removed "b" from the input
+mode under Windows. The BINARY versions are used when saving/restoring compiled
+patterns. */
+
+#if defined(_WIN32) || defined(WIN32)
+#include <io.h>                /* For _setmode() */
+#include <fcntl.h>             /* For _O_BINARY */
+#define INPUT_MODE          "r"
+#define OUTPUT_MODE         "wb"
+#define BINARY_INPUT_MODE   "rb"
+#define BINARY_OUTPUT_MODE  "wb"
+
+#ifndef isatty
+#define isatty _isatty         /* This is what Windows calls them, I'm told, */
+#endif                         /* though in some environments they seem to   */
+                               /* be already defined, hence the #ifndefs.    */
+#ifndef fileno
+#define fileno _fileno
+#endif
+
+/* A user sent this fix for Borland Builder 5 under Windows. */
+
+#ifdef __BORLANDC__
+#define _setmode(handle, mode) setmode(handle, mode)
+#endif
+
+/* Not Windows */
+
+#else
+#include <sys/time.h>          /* These two includes are needed */
+#include <sys/resource.h>      /* for setrlimit(). */
+#if defined NATIVE_ZOS         /* z/OS uses non-binary I/O */
+#define INPUT_MODE   "r"
+#define OUTPUT_MODE  "w"
+#define BINARY_INPUT_MODE   "rb"
+#define BINARY_OUTPUT_MODE  "wb"
+#else
+#define INPUT_MODE          "rb"
+#define OUTPUT_MODE         "wb"
+#define BINARY_INPUT_MODE   "rb"
+#define BINARY_OUTPUT_MODE  "wb"
+#endif
+#endif
+
+/* VMS-specific code was included as suggested by a VMS user [1]. Another VMS
+user [2] provided alternative code which worked better for him. I have
+commented out the original, but kept it around just in case. */
+
+#ifdef __VMS
+#include <ssdef.h>
+/* These two includes came from [2]. */
+#include descrip
+#include lib$routines
+/* void vms_setsymbol( char *, char *, int ); Original code from [1]. */
+#endif
+
+/* VC and older compilers don't support %td or %zu, and even some that claim to
+be C99 don't support it (hence DISABLE_PERCENT_ZT). There are some non-C99
+environments where %lu gives a warning with 32-bit pointers. As there doesn't
+seem to be an easy way round this, just live with it (the cases are rare). */
+
+#if defined(_MSC_VER) || !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L || defined(DISABLE_PERCENT_ZT)
+#define PTR_FORM "lu"
+#define SIZ_FORM "lu"
+#define SIZ_CAST (unsigned long int)
+#else
+#define PTR_FORM "td"
+#define SIZ_FORM "zu"
+#define SIZ_CAST
+#endif
+
+/* ------------------End of system-specific definitions -------------------- */
+
+/* Glueing macros that are used in several places below. */
+
+#define glue(a,b) a##b
+#define G(a,b) glue(a,b)
+
+/* Miscellaneous parameters and manifests */
+
+#ifndef CLOCKS_PER_SEC
+#ifdef CLK_TCK
+#define CLOCKS_PER_SEC CLK_TCK
+#else
+#define CLOCKS_PER_SEC 100
+#endif
+#endif
+
+#define CFORE_UNSET UINT32_MAX    /* Unset value for startend/cfail/cerror fields */
+#define CONVERT_UNSET UINT32_MAX  /* Unset value for convert_type field */
+#define DFA_WS_DIMENSION 1000     /* Size of DFA workspace */
+#define DEFAULT_OVECCOUNT 15      /* Default ovector count */
+#define JUNK_OFFSET 0xdeadbeef    /* For initializing ovector */
+#define LOCALESIZE 32             /* Size of locale name */
+#define LOOPREPEAT 500000         /* Default loop count for timing */
+#define MALLOCLISTSIZE 20         /* For remembering mallocs */
+#define PARENS_NEST_DEFAULT 220   /* Default parentheses nest limit */
+#define PATSTACKSIZE 20           /* Pattern stack for save/restore testing */
+#define REPLACE_MODSIZE 100       /* Field for reading 8-bit replacement */
+#define VERSION_SIZE 64           /* Size of buffer for the version strings */
+
+/* Default JIT compile options */
+
+#define JIT_DEFAULT (PCRE2_JIT_COMPLETE|\
+                     PCRE2_JIT_PARTIAL_SOFT|\
+                     PCRE2_JIT_PARTIAL_HARD)
+
+/* Make sure the buffer into which replacement strings are copied is big enough
+to hold them as 32-bit code units. */
+
+#define REPLACE_BUFFSIZE 1024   /* This is a byte value */
+
+/* Execution modes */
+
+#define PCRE8_MODE   8
+#define PCRE16_MODE 16
+#define PCRE32_MODE 32
+
+/* Processing returns */
+
+enum { PR_OK, PR_SKIP, PR_ABEND };
+
+/* The macro PRINTABLE determines whether to print an output character as-is or
+as a hex value when showing compiled patterns. is We use it in cases when the
+locale has not been explicitly changed, so as to get consistent output from
+systems that differ in their output from isprint() even in the "C" locale. */
+
+#ifdef EBCDIC
+#define PRINTABLE(c) ((c) >= 64 && (c) < 255)
+#else
+#define PRINTABLE(c) ((c) >= 32 && (c) < 127)
+#endif
+
+#define PRINTOK(c) ((use_tables != NULL && c < 256)? isprint(c) : PRINTABLE(c))
+
+/* We have to include some of the library source files because we need
+to use some of the macros, internal structure definitions, and other internal
+values - pcre2test has "inside information" compared to an application program
+that strictly follows the PCRE2 API.
+
+Before including pcre2_internal.h we define PRIV so that it does not get
+defined therein. This ensures that PRIV names in the included files do not
+clash with those in the libraries. Also, although pcre2_internal.h does itself
+include pcre2.h, we explicitly include it beforehand, along with pcre2posix.h,
+so that the PCRE2_EXP_xxx macros get set appropriately for an application, not
+for building the library. */
+
+#define PRIV(name) name
+#define PCRE2_CODE_UNIT_WIDTH 0
+#include "pcre2.h"
+#include "pcre2posix.h"
+#include "pcre2_internal.h"
+
+/* We need access to some of the data tables that PCRE2 uses. Defining
+PCRE2_PCRETEST makes some minor changes in the files. The previous definition
+of PRIV avoids name clashes. */
+
+#define PCRE2_PCRE2TEST
+#include "pcre2_tables.c"
+#include "pcre2_ucd.c"
+
+/* 32-bit integer values in the input are read by strtoul() or strtol(). The
+check needed for overflow depends on whether long ints are in fact longer than
+ints. They are defined not to be shorter. */
+
+#if ULONG_MAX > UINT32_MAX
+#define U32OVERFLOW(x) (x > UINT32_MAX)
+#else
+#define U32OVERFLOW(x) (x == UINT32_MAX)
+#endif
+
+#if LONG_MAX > INT32_MAX
+#define S32OVERFLOW(x) (x > INT32_MAX || x < INT32_MIN)
+#else
+#define S32OVERFLOW(x) (x == INT32_MAX || x == INT32_MIN)
+#endif
+
+/* When PCRE2_CODE_UNIT_WIDTH is zero, pcre2_internal.h does not include
+pcre2_intmodedep.h, which is where mode-dependent macros and structures are
+defined. We can now include it for each supported code unit width. Because
+PCRE2_CODE_UNIT_WIDTH was defined as zero before including pcre2.h, it will
+have left PCRE2_SUFFIX defined as a no-op. We must re-define it appropriately
+while including these files, and then restore it to a no-op. Because LINK_SIZE
+may be changed in 16-bit mode and forced to 1 in 32-bit mode, the order of
+these inclusions should not be changed. */
+
+#undef PCRE2_SUFFIX
+#undef PCRE2_CODE_UNIT_WIDTH
+
+#ifdef   SUPPORT_PCRE2_8
+#define  PCRE2_CODE_UNIT_WIDTH 8
+#define  PCRE2_SUFFIX(a) G(a,8)
+#include "pcre2_intmodedep.h"
+#include "pcre2_printint.c"
+#undef   PCRE2_CODE_UNIT_WIDTH
+#undef   PCRE2_SUFFIX
+#endif   /* SUPPORT_PCRE2_8 */
+
+#ifdef   SUPPORT_PCRE2_16
+#define  PCRE2_CODE_UNIT_WIDTH 16
+#define  PCRE2_SUFFIX(a) G(a,16)
+#include "pcre2_intmodedep.h"
+#include "pcre2_printint.c"
+#undef   PCRE2_CODE_UNIT_WIDTH
+#undef   PCRE2_SUFFIX
+#endif   /* SUPPORT_PCRE2_16 */
+
+#ifdef   SUPPORT_PCRE2_32
+#define  PCRE2_CODE_UNIT_WIDTH 32
+#define  PCRE2_SUFFIX(a) G(a,32)
+#include "pcre2_intmodedep.h"
+#include "pcre2_printint.c"
+#undef   PCRE2_CODE_UNIT_WIDTH
+#undef   PCRE2_SUFFIX
+#endif   /* SUPPORT_PCRE2_32 */
+
+#define PCRE2_SUFFIX(a) a
+
+/* We need to be able to check input text for UTF-8 validity, whatever code
+widths are actually available, because the input to pcre2test is always in
+8-bit code units. So we include the UTF validity checking function for 8-bit
+code units. */
+
+extern int valid_utf(PCRE2_SPTR8, PCRE2_SIZE, PCRE2_SIZE *);
+
+#define  PCRE2_CODE_UNIT_WIDTH 8
+#undef   PCRE2_SPTR
+#define  PCRE2_SPTR PCRE2_SPTR8
+#include "pcre2_valid_utf.c"
+#undef   PCRE2_CODE_UNIT_WIDTH
+#undef   PCRE2_SPTR
+
+/* If we have 8-bit support, default to it; if there is also 16-or 32-bit
+support, it can be selected by a command-line option. If there is no 8-bit
+support, there must be 16-bit or 32-bit support, so default to one of them. The
+config function, JIT stack, contexts, and version string are the same in all
+modes, so use the form of the first that is available. */
+
+#if defined SUPPORT_PCRE2_8
+#define DEFAULT_TEST_MODE PCRE8_MODE
+#define VERSION_TYPE PCRE2_UCHAR8
+#define PCRE2_CONFIG pcre2_config_8
+#define PCRE2_JIT_STACK pcre2_jit_stack_8
+#define PCRE2_REAL_GENERAL_CONTEXT pcre2_real_general_context_8
+#define PCRE2_REAL_COMPILE_CONTEXT pcre2_real_compile_context_8
+#define PCRE2_REAL_CONVERT_CONTEXT pcre2_real_convert_context_8
+#define PCRE2_REAL_MATCH_CONTEXT pcre2_real_match_context_8
+
+#elif defined SUPPORT_PCRE2_16
+#define DEFAULT_TEST_MODE PCRE16_MODE
+#define VERSION_TYPE PCRE2_UCHAR16
+#define PCRE2_CONFIG pcre2_config_16
+#define PCRE2_JIT_STACK pcre2_jit_stack_16
+#define PCRE2_REAL_GENERAL_CONTEXT pcre2_real_general_context_16
+#define PCRE2_REAL_COMPILE_CONTEXT pcre2_real_compile_context_16
+#define PCRE2_REAL_CONVERT_CONTEXT pcre2_real_convert_context_16
+#define PCRE2_REAL_MATCH_CONTEXT pcre2_real_match_context_16
+
+#elif defined SUPPORT_PCRE2_32
+#define DEFAULT_TEST_MODE PCRE32_MODE
+#define VERSION_TYPE PCRE2_UCHAR32
+#define PCRE2_CONFIG pcre2_config_32
+#define PCRE2_JIT_STACK pcre2_jit_stack_32
+#define PCRE2_REAL_GENERAL_CONTEXT pcre2_real_general_context_32
+#define PCRE2_REAL_COMPILE_CONTEXT pcre2_real_compile_context_32
+#define PCRE2_REAL_CONVERT_CONTEXT pcre2_real_convert_context_32
+#define PCRE2_REAL_MATCH_CONTEXT pcre2_real_match_context_32
+#endif
+
+/* ------------- Structure and table for handling #-commands ------------- */
+
+typedef struct cmdstruct {
+  const char *name;
+  int  value;
+} cmdstruct;
+
+enum { CMD_FORBID_UTF, CMD_LOAD, CMD_LOADTABLES, CMD_NEWLINE_DEFAULT,
+  CMD_PATTERN, CMD_PERLTEST, CMD_POP, CMD_POPCOPY, CMD_SAVE, CMD_SUBJECT,
+  CMD_UNKNOWN };
+
+static cmdstruct cmdlist[] = {
+  { "forbid_utf",      CMD_FORBID_UTF },
+  { "load",            CMD_LOAD },
+  { "loadtables",      CMD_LOADTABLES },
+  { "newline_default", CMD_NEWLINE_DEFAULT },
+  { "pattern",         CMD_PATTERN },
+  { "perltest",        CMD_PERLTEST },
+  { "pop",             CMD_POP },
+  { "popcopy",         CMD_POPCOPY },
+  { "save",            CMD_SAVE },
+  { "subject",         CMD_SUBJECT }};
+
+#define cmdlistcount (sizeof(cmdlist)/sizeof(cmdstruct))
+
+/* ------------- Structures and tables for handling modifiers -------------- */
+
+/* Table of names for newline types. Must be kept in step with the definitions
+of PCRE2_NEWLINE_xx in pcre2.h. */
+
+static const char *newlines[] = {
+  "DEFAULT", "CR", "LF", "CRLF", "ANY", "ANYCRLF", "NUL" };
+
+/* Structure and table for handling pattern conversion types. */
+
+typedef struct convertstruct {
+  const char *name;
+  uint32_t option;
+} convertstruct;
+
+static convertstruct convertlist[] = {
+  { "glob",                   PCRE2_CONVERT_GLOB },
+  { "glob_no_starstar",       PCRE2_CONVERT_GLOB_NO_STARSTAR },
+  { "glob_no_wild_separator", PCRE2_CONVERT_GLOB_NO_WILD_SEPARATOR },
+  { "posix_basic",            PCRE2_CONVERT_POSIX_BASIC },
+  { "posix_extended",         PCRE2_CONVERT_POSIX_EXTENDED },
+  { "unset",                  CONVERT_UNSET }};
+
+#define convertlistcount (sizeof(convertlist)/sizeof(convertstruct))
+
+/* Modifier types and applicability */
+
+enum { MOD_CTC,    /* Applies to a compile context */
+       MOD_CTM,    /* Applies to a match context */
+       MOD_PAT,    /* Applies to a pattern */
+       MOD_PATP,   /* Ditto, OK for Perl test */
+       MOD_DAT,    /* Applies to a data line */
+       MOD_PD,     /* Applies to a pattern or a data line */
+       MOD_PDP,    /* As MOD_PD, OK for Perl test */
+       MOD_PND,    /* As MOD_PD, but not for a default pattern */
+       MOD_PNDP,   /* As MOD_PND, OK for Perl test */
+       MOD_CHR,    /* Is a single character */
+       MOD_CON,    /* Is a "convert" type/options list */
+       MOD_CTL,    /* Is a control bit */
+       MOD_BSR,    /* Is a BSR value */
+       MOD_IN2,    /* Is one or two unsigned integers */
+       MOD_INS,    /* Is a signed integer */
+       MOD_INT,    /* Is an unsigned integer */
+       MOD_IND,    /* Is an unsigned integer, but no value => default */
+       MOD_NL,     /* Is a newline value */
+       MOD_NN,     /* Is a number or a name; more than one may occur */
+       MOD_OPT,    /* Is an option bit */
+       MOD_SIZ,    /* Is a PCRE2_SIZE value */
+       MOD_STR };  /* Is a string */
+
+/* Control bits. Some apply to compiling, some to matching, but some can be set
+either on a pattern or a data line, so they must all be distinct. There are now
+so many of them that they are split into two fields. */
+
+#define CTL_AFTERTEXT                    0x00000001u
+#define CTL_ALLAFTERTEXT                 0x00000002u
+#define CTL_ALLCAPTURES                  0x00000004u
+#define CTL_ALLUSEDTEXT                  0x00000008u
+#define CTL_ALTGLOBAL                    0x00000010u
+#define CTL_BINCODE                      0x00000020u
+#define CTL_CALLOUT_CAPTURE              0x00000040u
+#define CTL_CALLOUT_INFO                 0x00000080u
+#define CTL_CALLOUT_NONE                 0x00000100u
+#define CTL_DFA                          0x00000200u
+#define CTL_EXPAND                       0x00000400u
+#define CTL_FINDLIMITS                   0x00000800u
+#define CTL_FRAMESIZE                    0x00001000u
+#define CTL_FULLBINCODE                  0x00002000u
+#define CTL_GETALL                       0x00004000u
+#define CTL_GLOBAL                       0x00008000u
+#define CTL_HEXPAT                       0x00010000u  /* Same word as USE_LENGTH */
+#define CTL_INFO                         0x00020000u
+#define CTL_JITFAST                      0x00040000u
+#define CTL_JITVERIFY                    0x00080000u
+#define CTL_MARK                         0x00100000u
+#define CTL_MEMORY                       0x00200000u
+#define CTL_NULLCONTEXT                  0x00400000u
+#define CTL_POSIX                        0x00800000u
+#define CTL_POSIX_NOSUB                  0x01000000u
+#define CTL_PUSH                         0x02000000u  /* These three must be */
+#define CTL_PUSHCOPY                     0x04000000u  /*   all in the same */
+#define CTL_PUSHTABLESCOPY               0x08000000u  /*     word. */
+#define CTL_STARTCHAR                    0x10000000u
+#define CTL_USE_LENGTH                   0x20000000u  /* Same word as HEXPAT */
+#define CTL_UTF8_INPUT                   0x40000000u
+#define CTL_ZERO_TERMINATE               0x80000000u
+
+/* Combinations */
+
+#define CTL_DEBUG            (CTL_FULLBINCODE|CTL_INFO)  /* For setting */
+#define CTL_ANYINFO          (CTL_DEBUG|CTL_BINCODE|CTL_CALLOUT_INFO)
+#define CTL_ANYGLOB          (CTL_ALTGLOBAL|CTL_GLOBAL)
+
+/* Second control word */
+
+#define CTL2_SUBSTITUTE_CALLOUT          0x00000001u
+#define CTL2_SUBSTITUTE_EXTENDED         0x00000002u
+#define CTL2_SUBSTITUTE_LITERAL          0x00000004u
+#define CTL2_SUBSTITUTE_MATCHED          0x00000008u
+#define CTL2_SUBSTITUTE_OVERFLOW_LENGTH  0x00000010u
+#define CTL2_SUBSTITUTE_REPLACEMENT_ONLY 0x00000020u
+#define CTL2_SUBSTITUTE_UNKNOWN_UNSET    0x00000040u
+#define CTL2_SUBSTITUTE_UNSET_EMPTY      0x00000080u
+#define CTL2_SUBJECT_LITERAL             0x00000100u
+#define CTL2_CALLOUT_NO_WHERE            0x00000200u
+#define CTL2_CALLOUT_EXTRA               0x00000400u
+#define CTL2_ALLVECTOR                   0x00000800u
+
+#define CTL2_NL_SET                      0x40000000u  /* Informational */
+#define CTL2_BSR_SET                     0x80000000u  /* Informational */
+
+/* These are the matching controls that may be set either on a pattern or on a
+data line. They are copied from the pattern controls as initial settings for
+data line controls. Note that CTL_MEMORY is not included here, because it does
+different things in the two cases. */
+
+#define CTL_ALLPD  (CTL_AFTERTEXT|\
+                    CTL_ALLAFTERTEXT|\
+                    CTL_ALLCAPTURES|\
+                    CTL_ALLUSEDTEXT|\
+                    CTL_ALTGLOBAL|\
+                    CTL_GLOBAL|\
+                    CTL_MARK|\
+                    CTL_STARTCHAR|\
+                    CTL_UTF8_INPUT)
+
+#define CTL2_ALLPD (CTL2_SUBSTITUTE_CALLOUT|\
+                    CTL2_SUBSTITUTE_EXTENDED|\
+                    CTL2_SUBSTITUTE_LITERAL|\
+                    CTL2_SUBSTITUTE_MATCHED|\
+                    CTL2_SUBSTITUTE_OVERFLOW_LENGTH|\
+                    CTL2_SUBSTITUTE_REPLACEMENT_ONLY|\
+                    CTL2_SUBSTITUTE_UNKNOWN_UNSET|\
+                    CTL2_SUBSTITUTE_UNSET_EMPTY|\
+                    CTL2_ALLVECTOR)
+
+/* Structures for holding modifier information for patterns and subject strings
+(data). Fields containing modifiers that can be set either for a pattern or a
+subject must be at the start and in the same order in both cases so that the
+same offset in the big table below works for both. */
+
+typedef struct patctl {       /* Structure for pattern modifiers. */
+  uint32_t  options;          /* Must be in same position as datctl */
+  uint32_t  control;          /* Must be in same position as datctl */
+  uint32_t  control2;         /* Must be in same position as datctl */
+  uint32_t  jitstack;         /* Must be in same position as datctl */
+   uint8_t  replacement[REPLACE_MODSIZE];  /* So must this */
+  uint32_t  substitute_skip;  /* Must be in same position as patctl */
+  uint32_t  substitute_stop;  /* Must be in same position as patctl */
+  uint32_t  jit;
+  uint32_t  stackguard_test;
+  uint32_t  tables_id;
+  uint32_t  convert_type;
+  uint32_t  convert_length;
+  uint32_t  convert_glob_escape;
+  uint32_t  convert_glob_separator;
+  uint32_t  regerror_buffsize;
+   uint8_t  locale[LOCALESIZE];
+} patctl;
+
+#define MAXCPYGET 10
+#define LENCPYGET 64
+
+typedef struct datctl {       /* Structure for data line modifiers. */
+  uint32_t  options;          /* Must be in same position as patctl */
+  uint32_t  control;          /* Must be in same position as patctl */
+  uint32_t  control2;         /* Must be in same position as patctl */
+  uint32_t  jitstack;         /* Must be in same position as patctl */
+   uint8_t  replacement[REPLACE_MODSIZE];  /* So must this */
+  uint32_t  substitute_skip;  /* Must be in same position as patctl */
+  uint32_t  substitute_stop;  /* Must be in same position as patctl */
+  uint32_t  startend[2];
+  uint32_t  cerror[2];
+  uint32_t  cfail[2];
+   int32_t  callout_data;
+   int32_t  copy_numbers[MAXCPYGET];
+   int32_t  get_numbers[MAXCPYGET];
+  uint32_t  oveccount;
+  uint32_t  offset;
+  uint8_t   copy_names[LENCPYGET];
+  uint8_t   get_names[LENCPYGET];
+} datctl;
+
+/* Ids for which context to modify. */
+
+enum { CTX_PAT,            /* Active pattern context */
+       CTX_POPPAT,         /* Ditto, for a popped pattern */
+       CTX_DEFPAT,         /* Default pattern context */
+       CTX_DAT,            /* Active data (match) context */
+       CTX_DEFDAT };       /* Default data (match) context */
+
+/* Macros to simplify the big table below. */
+
+#define CO(name) offsetof(PCRE2_REAL_COMPILE_CONTEXT, name)
+#define MO(name) offsetof(PCRE2_REAL_MATCH_CONTEXT, name)
+#define PO(name) offsetof(patctl, name)
+#define PD(name) PO(name)
+#define DO(name) offsetof(datctl, name)
+
+/* Table of all long-form modifiers. Must be in collating sequence of modifier
+name because it is searched by binary chop. */
+
+typedef struct modstruct {
+  const char   *name;
+  uint16_t      which;
+  uint16_t      type;
+  uint32_t      value;
+  PCRE2_SIZE    offset;
+} modstruct;
+
+static modstruct modlist[] = {
+  { "aftertext",                   MOD_PNDP, MOD_CTL, CTL_AFTERTEXT,              PO(control) },
+  { "allaftertext",                MOD_PNDP, MOD_CTL, CTL_ALLAFTERTEXT,           PO(control) },
+  { "allcaptures",                 MOD_PND,  MOD_CTL, CTL_ALLCAPTURES,            PO(control) },
+  { "allow_empty_class",           MOD_PAT,  MOD_OPT, PCRE2_ALLOW_EMPTY_CLASS,    PO(options) },
+  { "allow_surrogate_escapes",     MOD_CTC,  MOD_OPT, PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES, CO(extra_options) },
+  { "allusedtext",                 MOD_PNDP, MOD_CTL, CTL_ALLUSEDTEXT,            PO(control) },
+  { "allvector",                   MOD_PND,  MOD_CTL, CTL2_ALLVECTOR,             PO(control2) },
+  { "alt_bsux",                    MOD_PAT,  MOD_OPT, PCRE2_ALT_BSUX,             PO(options) },
+  { "alt_circumflex",              MOD_PAT,  MOD_OPT, PCRE2_ALT_CIRCUMFLEX,       PO(options) },
+  { "alt_verbnames",               MOD_PAT,  MOD_OPT, PCRE2_ALT_VERBNAMES,        PO(options) },
+  { "altglobal",                   MOD_PND,  MOD_CTL, CTL_ALTGLOBAL,              PO(control) },
+  { "anchored",                    MOD_PD,   MOD_OPT, PCRE2_ANCHORED,             PD(options) },
+  { "auto_callout",                MOD_PAT,  MOD_OPT, PCRE2_AUTO_CALLOUT,         PO(options) },
+  { "bad_escape_is_literal",       MOD_CTC,  MOD_OPT, PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL, CO(extra_options) },
+  { "bincode",                     MOD_PAT,  MOD_CTL, CTL_BINCODE,                PO(control) },
+  { "bsr",                         MOD_CTC,  MOD_BSR, 0,                          CO(bsr_convention) },
+  { "callout_capture",             MOD_DAT,  MOD_CTL, CTL_CALLOUT_CAPTURE,        DO(control) },
+  { "callout_data",                MOD_DAT,  MOD_INS, 0,                          DO(callout_data) },
+  { "callout_error",               MOD_DAT,  MOD_IN2, 0,                          DO(cerror) },
+  { "callout_extra",               MOD_DAT,  MOD_CTL, CTL2_CALLOUT_EXTRA,         DO(control2) },
+  { "callout_fail",                MOD_DAT,  MOD_IN2, 0,                          DO(cfail) },
+  { "callout_info",                MOD_PAT,  MOD_CTL, CTL_CALLOUT_INFO,           PO(control) },
+  { "callout_no_where",            MOD_DAT,  MOD_CTL, CTL2_CALLOUT_NO_WHERE,      DO(control2) },
+  { "callout_none",                MOD_DAT,  MOD_CTL, CTL_CALLOUT_NONE,           DO(control) },
+  { "caseless",                    MOD_PATP, MOD_OPT, PCRE2_CASELESS,             PO(options) },
+  { "convert",                     MOD_PAT,  MOD_CON, 0,                          PO(convert_type) },
+  { "convert_glob_escape",         MOD_PAT,  MOD_CHR, 0,                          PO(convert_glob_escape) },
+  { "convert_glob_separator",      MOD_PAT,  MOD_CHR, 0,                          PO(convert_glob_separator) },
+  { "convert_length",              MOD_PAT,  MOD_INT, 0,                          PO(convert_length) },
+  { "copy",                        MOD_DAT,  MOD_NN,  DO(copy_numbers),           DO(copy_names) },
+  { "copy_matched_subject",        MOD_DAT,  MOD_OPT, PCRE2_COPY_MATCHED_SUBJECT, DO(options) },
+  { "debug",                       MOD_PAT,  MOD_CTL, CTL_DEBUG,                  PO(control) },
+  { "depth_limit",                 MOD_CTM,  MOD_INT, 0,                          MO(depth_limit) },
+  { "dfa",                         MOD_DAT,  MOD_CTL, CTL_DFA,                    DO(control) },
+  { "dfa_restart",                 MOD_DAT,  MOD_OPT, PCRE2_DFA_RESTART,          DO(options) },
+  { "dfa_shortest",                MOD_DAT,  MOD_OPT, PCRE2_DFA_SHORTEST,         DO(options) },
+  { "dollar_endonly",              MOD_PAT,  MOD_OPT, PCRE2_DOLLAR_ENDONLY,       PO(options) },
+  { "dotall",                      MOD_PATP, MOD_OPT, PCRE2_DOTALL,               PO(options) },
+  { "dupnames",                    MOD_PATP, MOD_OPT, PCRE2_DUPNAMES,             PO(options) },
+  { "endanchored",                 MOD_PD,   MOD_OPT, PCRE2_ENDANCHORED,          PD(options) },
+  { "escaped_cr_is_lf",            MOD_CTC,  MOD_OPT, PCRE2_EXTRA_ESCAPED_CR_IS_LF, CO(extra_options) },
+  { "expand",                      MOD_PAT,  MOD_CTL, CTL_EXPAND,                 PO(control) },
+  { "extended",                    MOD_PATP, MOD_OPT, PCRE2_EXTENDED,             PO(options) },
+  { "extended_more",               MOD_PATP, MOD_OPT, PCRE2_EXTENDED_MORE,        PO(options) },
+  { "extra_alt_bsux",              MOD_CTC,  MOD_OPT, PCRE2_EXTRA_ALT_BSUX,       CO(extra_options) },
+  { "find_limits",                 MOD_DAT,  MOD_CTL, CTL_FINDLIMITS,             DO(control) },
+  { "firstline",                   MOD_PAT,  MOD_OPT, PCRE2_FIRSTLINE,            PO(options) },
+  { "framesize",                   MOD_PAT,  MOD_CTL, CTL_FRAMESIZE,              PO(control) },
+  { "fullbincode",                 MOD_PAT,  MOD_CTL, CTL_FULLBINCODE,            PO(control) },
+  { "get",                         MOD_DAT,  MOD_NN,  DO(get_numbers),            DO(get_names) },
+  { "getall",                      MOD_DAT,  MOD_CTL, CTL_GETALL,                 DO(control) },
+  { "global",                      MOD_PNDP, MOD_CTL, CTL_GLOBAL,                 PO(control) },
+  { "heap_limit",                  MOD_CTM,  MOD_INT, 0,                          MO(heap_limit) },
+  { "hex",                         MOD_PAT,  MOD_CTL, CTL_HEXPAT,                 PO(control) },
+  { "info",                        MOD_PAT,  MOD_CTL, CTL_INFO,                   PO(control) },
+  { "jit",                         MOD_PAT,  MOD_IND, 7,                          PO(jit) },
+  { "jitfast",                     MOD_PAT,  MOD_CTL, CTL_JITFAST,                PO(control) },
+  { "jitstack",                    MOD_PNDP, MOD_INT, 0,                          PO(jitstack) },
+  { "jitverify",                   MOD_PAT,  MOD_CTL, CTL_JITVERIFY,              PO(control) },
+  { "literal",                     MOD_PAT,  MOD_OPT, PCRE2_LITERAL,              PO(options) },
+  { "locale",                      MOD_PAT,  MOD_STR, LOCALESIZE,                 PO(locale) },
+  { "mark",                        MOD_PNDP, MOD_CTL, CTL_MARK,                   PO(control) },
+  { "match_invalid_utf",           MOD_PAT,  MOD_OPT, PCRE2_MATCH_INVALID_UTF,    PO(options) },
+  { "match_limit",                 MOD_CTM,  MOD_INT, 0,                          MO(match_limit) },
+  { "match_line",                  MOD_CTC,  MOD_OPT, PCRE2_EXTRA_MATCH_LINE,     CO(extra_options) },
+  { "match_unset_backref",         MOD_PAT,  MOD_OPT, PCRE2_MATCH_UNSET_BACKREF,  PO(options) },
+  { "match_word",                  MOD_CTC,  MOD_OPT, PCRE2_EXTRA_MATCH_WORD,     CO(extra_options) },
+  { "max_pattern_length",          MOD_CTC,  MOD_SIZ, 0,                          CO(max_pattern_length) },
+  { "memory",                      MOD_PD,   MOD_CTL, CTL_MEMORY,                 PD(control) },
+  { "multiline",                   MOD_PATP, MOD_OPT, PCRE2_MULTILINE,            PO(options) },
+  { "never_backslash_c",           MOD_PAT,  MOD_OPT, PCRE2_NEVER_BACKSLASH_C,    PO(options) },
+  { "never_ucp",                   MOD_PAT,  MOD_OPT, PCRE2_NEVER_UCP,            PO(options) },
+  { "never_utf",                   MOD_PAT,  MOD_OPT, PCRE2_NEVER_UTF,            PO(options) },
+  { "newline",                     MOD_CTC,  MOD_NL,  0,                          CO(newline_convention) },
+  { "no_auto_capture",             MOD_PAT,  MOD_OPT, PCRE2_NO_AUTO_CAPTURE,      PO(options) },
+  { "no_auto_possess",             MOD_PATP, MOD_OPT, PCRE2_NO_AUTO_POSSESS,      PO(options) },
+  { "no_dotstar_anchor",           MOD_PAT,  MOD_OPT, PCRE2_NO_DOTSTAR_ANCHOR,    PO(options) },
+  { "no_jit",                      MOD_DAT,  MOD_OPT, PCRE2_NO_JIT,               DO(options) },
+  { "no_start_optimize",           MOD_PATP, MOD_OPT, PCRE2_NO_START_OPTIMIZE,    PO(options) },
+  { "no_utf_check",                MOD_PD,   MOD_OPT, PCRE2_NO_UTF_CHECK,         PD(options) },
+  { "notbol",                      MOD_DAT,  MOD_OPT, PCRE2_NOTBOL,               DO(options) },
+  { "notempty",                    MOD_DAT,  MOD_OPT, PCRE2_NOTEMPTY,             DO(options) },
+  { "notempty_atstart",            MOD_DAT,  MOD_OPT, PCRE2_NOTEMPTY_ATSTART,     DO(options) },
+  { "noteol",                      MOD_DAT,  MOD_OPT, PCRE2_NOTEOL,               DO(options) },
+  { "null_context",                MOD_PD,   MOD_CTL, CTL_NULLCONTEXT,            PO(control) },
+  { "offset",                      MOD_DAT,  MOD_INT, 0,                          DO(offset) },
+  { "offset_limit",                MOD_CTM,  MOD_SIZ, 0,                          MO(offset_limit)},
+  { "ovector",                     MOD_DAT,  MOD_INT, 0,                          DO(oveccount) },
+  { "parens_nest_limit",           MOD_CTC,  MOD_INT, 0,                          CO(parens_nest_limit) },
+  { "partial_hard",                MOD_DAT,  MOD_OPT, PCRE2_PARTIAL_HARD,         DO(options) },
+  { "partial_soft",                MOD_DAT,  MOD_OPT, PCRE2_PARTIAL_SOFT,         DO(options) },
+  { "ph",                          MOD_DAT,  MOD_OPT, PCRE2_PARTIAL_HARD,         DO(options) },
+  { "posix",                       MOD_PAT,  MOD_CTL, CTL_POSIX,                  PO(control) },
+  { "posix_nosub",                 MOD_PAT,  MOD_CTL, CTL_POSIX|CTL_POSIX_NOSUB,  PO(control) },
+  { "posix_startend",              MOD_DAT,  MOD_IN2, 0,                          DO(startend) },
+  { "ps",                          MOD_DAT,  MOD_OPT, PCRE2_PARTIAL_SOFT,         DO(options) },
+  { "push",                        MOD_PAT,  MOD_CTL, CTL_PUSH,                   PO(control) },
+  { "pushcopy",                    MOD_PAT,  MOD_CTL, CTL_PUSHCOPY,               PO(control) },
+  { "pushtablescopy",              MOD_PAT,  MOD_CTL, CTL_PUSHTABLESCOPY,         PO(control) },
+  { "recursion_limit",             MOD_CTM,  MOD_INT, 0,                          MO(depth_limit) },  /* Obsolete synonym */
+  { "regerror_buffsize",           MOD_PAT,  MOD_INT, 0,                          PO(regerror_buffsize) },
+  { "replace",                     MOD_PND,  MOD_STR, REPLACE_MODSIZE,            PO(replacement) },
+  { "stackguard",                  MOD_PAT,  MOD_INT, 0,                          PO(stackguard_test) },
+  { "startchar",                   MOD_PND,  MOD_CTL, CTL_STARTCHAR,              PO(control) },
+  { "startoffset",                 MOD_DAT,  MOD_INT, 0,                          DO(offset) },
+  { "subject_literal",             MOD_PATP, MOD_CTL, CTL2_SUBJECT_LITERAL,       PO(control2) },
+  { "substitute_callout",          MOD_PND,  MOD_CTL, CTL2_SUBSTITUTE_CALLOUT,    PO(control2) },
+  { "substitute_extended",         MOD_PND,  MOD_CTL, CTL2_SUBSTITUTE_EXTENDED,   PO(control2) },
+  { "substitute_literal",          MOD_PND,  MOD_CTL, CTL2_SUBSTITUTE_LITERAL,    PO(control2) },
+  { "substitute_matched",          MOD_PND,  MOD_CTL, CTL2_SUBSTITUTE_MATCHED,    PO(control2) },
+  { "substitute_overflow_length",  MOD_PND,  MOD_CTL, CTL2_SUBSTITUTE_OVERFLOW_LENGTH, PO(control2) },
+  { "substitute_replacement_only", MOD_PND,  MOD_CTL, CTL2_SUBSTITUTE_REPLACEMENT_ONLY, PO(control2) },
+  { "substitute_skip",             MOD_PND,  MOD_INT, 0,                          PO(substitute_skip) },
+  { "substitute_stop",             MOD_PND,  MOD_INT, 0,                          PO(substitute_stop) },
+  { "substitute_unknown_unset",    MOD_PND,  MOD_CTL, CTL2_SUBSTITUTE_UNKNOWN_UNSET, PO(control2) },
+  { "substitute_unset_empty",      MOD_PND,  MOD_CTL, CTL2_SUBSTITUTE_UNSET_EMPTY, PO(control2) },
+  { "tables",                      MOD_PAT,  MOD_INT, 0,                          PO(tables_id) },
+  { "ucp",                         MOD_PATP, MOD_OPT, PCRE2_UCP,                  PO(options) },
+  { "ungreedy",                    MOD_PAT,  MOD_OPT, PCRE2_UNGREEDY,             PO(options) },
+  { "use_length",                  MOD_PAT,  MOD_CTL, CTL_USE_LENGTH,             PO(control) },
+  { "use_offset_limit",            MOD_PAT,  MOD_OPT, PCRE2_USE_OFFSET_LIMIT,     PO(options) },
+  { "utf",                         MOD_PATP, MOD_OPT, PCRE2_UTF,                  PO(options) },
+  { "utf8_input",                  MOD_PAT,  MOD_CTL, CTL_UTF8_INPUT,             PO(control) },
+  { "zero_terminate",              MOD_DAT,  MOD_CTL, CTL_ZERO_TERMINATE,         DO(control) }
+};
+
+#define MODLISTCOUNT sizeof(modlist)/sizeof(modstruct)
+
+/* Controls and options that are supported for use with the POSIX interface. */
+
+#define POSIX_SUPPORTED_COMPILE_OPTIONS ( \
+  PCRE2_CASELESS|PCRE2_DOTALL|PCRE2_LITERAL|PCRE2_MULTILINE|PCRE2_UCP| \
+  PCRE2_UTF|PCRE2_UNGREEDY)
+
+#define POSIX_SUPPORTED_COMPILE_EXTRA_OPTIONS (0)
+
+#define POSIX_SUPPORTED_COMPILE_CONTROLS ( \
+  CTL_AFTERTEXT|CTL_ALLAFTERTEXT|CTL_EXPAND|CTL_HEXPAT|CTL_POSIX| \
+  CTL_POSIX_NOSUB|CTL_USE_LENGTH)
+
+#define POSIX_SUPPORTED_COMPILE_CONTROLS2 (0)
+
+#define POSIX_SUPPORTED_MATCH_OPTIONS ( \
+  PCRE2_NOTBOL|PCRE2_NOTEMPTY|PCRE2_NOTEOL)
+
+#define POSIX_SUPPORTED_MATCH_CONTROLS  (CTL_AFTERTEXT|CTL_ALLAFTERTEXT)
+#define POSIX_SUPPORTED_MATCH_CONTROLS2 (0)
+
+/* Control bits that are not ignored with 'push'. */
+
+#define PUSH_SUPPORTED_COMPILE_CONTROLS ( \
+  CTL_BINCODE|CTL_CALLOUT_INFO|CTL_FULLBINCODE|CTL_HEXPAT|CTL_INFO| \
+  CTL_JITVERIFY|CTL_MEMORY|CTL_FRAMESIZE|CTL_PUSH|CTL_PUSHCOPY| \
+  CTL_PUSHTABLESCOPY|CTL_USE_LENGTH)
+
+#define PUSH_SUPPORTED_COMPILE_CONTROLS2 (CTL2_BSR_SET|CTL2_NL_SET)
+
+/* Controls that apply only at compile time with 'push'. */
+
+#define PUSH_COMPILE_ONLY_CONTROLS   CTL_JITVERIFY
+#define PUSH_COMPILE_ONLY_CONTROLS2  (0)
+
+/* Controls that are forbidden with #pop or #popcopy. */
+
+#define NOTPOP_CONTROLS (CTL_HEXPAT|CTL_POSIX|CTL_POSIX_NOSUB|CTL_PUSH| \
+  CTL_PUSHCOPY|CTL_PUSHTABLESCOPY|CTL_USE_LENGTH)
+
+/* Pattern controls that are mutually exclusive. At present these are all in
+the first control word. Note that CTL_POSIX_NOSUB is always accompanied by
+CTL_POSIX, so it doesn't need its own entries. */
+
+static uint32_t exclusive_pat_controls[] = {
+  CTL_POSIX    | CTL_PUSH,
+  CTL_POSIX    | CTL_PUSHCOPY,
+  CTL_POSIX    | CTL_PUSHTABLESCOPY,
+  CTL_PUSH     | CTL_PUSHCOPY,
+  CTL_PUSH     | CTL_PUSHTABLESCOPY,
+  CTL_PUSHCOPY | CTL_PUSHTABLESCOPY,
+  CTL_EXPAND   | CTL_HEXPAT };
+
+/* Data controls that are mutually exclusive. At present these are all in the
+first control word. */
+
+static uint32_t exclusive_dat_controls[] = {
+  CTL_ALLUSEDTEXT | CTL_STARTCHAR,
+  CTL_FINDLIMITS  | CTL_NULLCONTEXT };
+
+/* Table of single-character abbreviated modifiers. The index field is
+initialized to -1, but the first time the modifier is encountered, it is filled
+in with the index of the full entry in modlist, to save repeated searching when
+processing multiple test items. This short list is searched serially, so its
+order does not matter. */
+
+typedef struct c1modstruct {
+  const char *fullname;
+  uint32_t    onechar;
+  int         index;
+} c1modstruct;
+
+static c1modstruct c1modlist[] = {
+  { "bincode",         'B',           -1 },
+  { "info",            'I',           -1 },
+  { "global",          'g',           -1 },
+  { "caseless",        'i',           -1 },
+  { "multiline",       'm',           -1 },
+  { "no_auto_capture", 'n',           -1 },
+  { "dotall",          's',           -1 },
+  { "extended",        'x',           -1 }
+};
+
+#define C1MODLISTCOUNT sizeof(c1modlist)/sizeof(c1modstruct)
+
+/* Table of arguments for the -C command line option. Use macros to make the
+table itself easier to read. */
+
+#if defined SUPPORT_PCRE2_8
+#define SUPPORT_8 1
+#endif
+#if defined SUPPORT_PCRE2_16
+#define SUPPORT_16 1
+#endif
+#if defined SUPPORT_PCRE2_32
+#define SUPPORT_32 1
+#endif
+
+#ifndef SUPPORT_8
+#define SUPPORT_8 0
+#endif
+#ifndef SUPPORT_16
+#define SUPPORT_16 0
+#endif
+#ifndef SUPPORT_32
+#define SUPPORT_32 0
+#endif
+
+#ifdef EBCDIC
+#define SUPPORT_EBCDIC 1
+#define EBCDIC_NL CHAR_LF
+#else
+#define SUPPORT_EBCDIC 0
+#define EBCDIC_NL 0
+#endif
+
+#ifdef NEVER_BACKSLASH_C
+#define BACKSLASH_C 0
+#else
+#define BACKSLASH_C 1
+#endif
+
+typedef struct coptstruct {
+  const char *name;
+  uint32_t    type;
+  uint32_t    value;
+} coptstruct;
+
+enum { CONF_BSR,
+       CONF_FIX,
+       CONF_FIZ,
+       CONF_INT,
+       CONF_NL
+};
+
+static coptstruct coptlist[] = {
+  { "backslash-C", CONF_FIX, BACKSLASH_C },
+  { "bsr",         CONF_BSR, PCRE2_CONFIG_BSR },
+  { "ebcdic",      CONF_FIX, SUPPORT_EBCDIC },
+  { "ebcdic-nl",   CONF_FIZ, EBCDIC_NL },
+  { "jit",         CONF_INT, PCRE2_CONFIG_JIT },
+  { "linksize",    CONF_INT, PCRE2_CONFIG_LINKSIZE },
+  { "newline",     CONF_NL,  PCRE2_CONFIG_NEWLINE },
+  { "pcre2-16",    CONF_FIX, SUPPORT_16 },
+  { "pcre2-32",    CONF_FIX, SUPPORT_32 },
+  { "pcre2-8",     CONF_FIX, SUPPORT_8 },
+  { "unicode",     CONF_INT, PCRE2_CONFIG_UNICODE }
+};
+
+#define COPTLISTCOUNT sizeof(coptlist)/sizeof(coptstruct)
+
+#undef SUPPORT_8
+#undef SUPPORT_16
+#undef SUPPORT_32
+#undef SUPPORT_EBCDIC
+
+
+/* ----------------------- Static variables ------------------------ */
+
+static FILE *infile;
+static FILE *outfile;
+
+static const void *last_callout_mark;
+static PCRE2_JIT_STACK *jit_stack = NULL;
+static size_t jit_stack_size = 0;
+
+static BOOL first_callout;
+static BOOL jit_was_used;
+static BOOL restrict_for_perl_test = FALSE;
+static BOOL show_memory = FALSE;
+
+static int code_unit_size;                    /* Bytes */
+static int jitrc;                             /* Return from JIT compile */
+static int test_mode = DEFAULT_TEST_MODE;
+static int timeit = 0;
+static int timeitm = 0;
+
+clock_t total_compile_time = 0;
+clock_t total_jit_compile_time = 0;
+clock_t total_match_time = 0;
+
+static uint32_t dfa_matched;
+static uint32_t forbid_utf = 0;
+static uint32_t maxlookbehind;
+static uint32_t max_oveccount;
+static uint32_t callout_count;
+static uint32_t maxcapcount;
+
+static uint16_t local_newline_default = 0;
+
+static VERSION_TYPE jittarget[VERSION_SIZE];
+static VERSION_TYPE version[VERSION_SIZE];
+static VERSION_TYPE uversion[VERSION_SIZE];
+
+static patctl def_patctl;
+static patctl pat_patctl;
+static datctl def_datctl;
+static datctl dat_datctl;
+
+static void *patstack[PATSTACKSIZE];
+static int patstacknext = 0;
+
+static void *malloclist[MALLOCLISTSIZE];
+static PCRE2_SIZE malloclistlength[MALLOCLISTSIZE];
+static uint32_t malloclistptr = 0;
+
+#ifdef SUPPORT_PCRE2_8
+static regex_t preg = { NULL, NULL, 0, 0, 0, 0 };
+#endif
+
+static int *dfa_workspace = NULL;
+static const uint8_t *locale_tables = NULL;
+static const uint8_t *use_tables = NULL;
+static uint8_t locale_name[32];
+static uint8_t *tables3 = NULL;         /* For binary-loaded tables */
+static uint32_t loadtables_length = 0;
+
+/* We need buffers for building 16/32-bit strings; 8-bit strings don't need
+rebuilding, but set up the same naming scheme for use in macros. The "buffer"
+buffer is where all input lines are read. Its size is the same as pbuffer8.
+Pattern lines are always copied to pbuffer8 for use in callouts, even if they
+are actually compiled from pbuffer16 or pbuffer32. */
+
+static size_t    pbuffer8_size  = 50000;        /* Initial size, bytes */
+static uint8_t  *pbuffer8 = NULL;
+static uint8_t  *buffer = NULL;
+
+/* The dbuffer is where all processed data lines are put. In non-8-bit modes it
+is cast as needed. For long data lines it grows as necessary. */
+
+static size_t dbuffer_size = 1u << 14;    /* Initial size, bytes */
+static uint8_t *dbuffer = NULL;
+
+
+/* ---------------- Mode-dependent variables -------------------*/
+
+#ifdef SUPPORT_PCRE2_8
+static pcre2_code_8             *compiled_code8;
+static pcre2_general_context_8  *general_context8, *general_context_copy8;
+static pcre2_compile_context_8  *pat_context8, *default_pat_context8;
+static pcre2_convert_context_8  *con_context8, *default_con_context8;
+static pcre2_match_context_8    *dat_context8, *default_dat_context8;
+static pcre2_match_data_8       *match_data8;
+#endif
+
+#ifdef SUPPORT_PCRE2_16
+static pcre2_code_16            *compiled_code16;
+static pcre2_general_context_16 *general_context16, *general_context_copy16;
+static pcre2_compile_context_16 *pat_context16, *default_pat_context16;
+static pcre2_convert_context_16 *con_context16, *default_con_context16;
+static pcre2_match_context_16   *dat_context16, *default_dat_context16;
+static pcre2_match_data_16      *match_data16;
+static PCRE2_SIZE pbuffer16_size = 0;   /* Set only when needed */
+static uint16_t *pbuffer16 = NULL;
+#endif
+
+#ifdef SUPPORT_PCRE2_32
+static pcre2_code_32            *compiled_code32;
+static pcre2_general_context_32 *general_context32, *general_context_copy32;
+static pcre2_compile_context_32 *pat_context32, *default_pat_context32;
+static pcre2_convert_context_32 *con_context32, *default_con_context32;
+static pcre2_match_context_32   *dat_context32, *default_dat_context32;
+static pcre2_match_data_32      *match_data32;
+static PCRE2_SIZE pbuffer32_size = 0;   /* Set only when needed */
+static uint32_t *pbuffer32 = NULL;
+#endif
+
+
+/* ---------------- Macros that work in all modes ----------------- */
+
+#define CAST8VAR(x) CASTVAR(uint8_t *, x)
+#define SET(x,y) SETOP(x,y,=)
+#define SETPLUS(x,y) SETOP(x,y,+=)
+#define strlen8(x) strlen((char *)x)
+
+
+/* ---------------- Mode-dependent, runtime-testing macros ------------------*/
+
+/* Define macros for variables and functions that must be selected dynamically
+depending on the mode setting (8, 16, 32). These are dependent on which modes
+are supported. */
+
+#if (defined (SUPPORT_PCRE2_8) + defined (SUPPORT_PCRE2_16) + \
+     defined (SUPPORT_PCRE2_32)) >= 2
+
+/* ----- All three modes supported ----- */
+
+#if defined(SUPPORT_PCRE2_8) && defined(SUPPORT_PCRE2_16) && defined(SUPPORT_PCRE2_32)
+
+#define CASTFLD(t,a,b) ((test_mode == PCRE8_MODE)? (t)(G(a,8)->b) : \
+  (test_mode == PCRE16_MODE)? (t)(G(a,16)->b) : (t)(G(a,32)->b))
+
+#define CASTVAR(t,x) ( \
+  (test_mode == PCRE8_MODE)? (t)G(x,8) : \
+  (test_mode == PCRE16_MODE)? (t)G(x,16) : (t)G(x,32))
+
+#define CODE_UNIT(a,b) ( \
+  (test_mode == PCRE8_MODE)? (uint32_t)(((PCRE2_SPTR8)(a))[b]) : \
+  (test_mode == PCRE16_MODE)? (uint32_t)(((PCRE2_SPTR16)(a))[b]) : \
+  (uint32_t)(((PCRE2_SPTR32)(a))[b]))
+
+#define CONCTXCPY(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    memcpy(G(a,8),G(b,8),sizeof(pcre2_convert_context_8)); \
+  else if (test_mode == PCRE16_MODE) \
+    memcpy(G(a,16),G(b,16),sizeof(pcre2_convert_context_16)); \
+  else memcpy(G(a,32),G(b,32),sizeof(pcre2_convert_context_32))
+
+#define CONVERT_COPY(a,b,c) \
+  if (test_mode == PCRE8_MODE) \
+    memcpy(G(a,8),(char *)b,c); \
+  else if (test_mode == PCRE16_MODE) \
+    memcpy(G(a,16),(char *)b,(c)*2); \
+  else if (test_mode == PCRE32_MODE) \
+    memcpy(G(a,32),(char *)b,(c)*4)
+
+#define DATCTXCPY(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    memcpy(G(a,8),G(b,8),sizeof(pcre2_match_context_8)); \
+  else if (test_mode == PCRE16_MODE) \
+    memcpy(G(a,16),G(b,16),sizeof(pcre2_match_context_16)); \
+  else memcpy(G(a,32),G(b,32),sizeof(pcre2_match_context_32))
+
+#define FLD(a,b) ((test_mode == PCRE8_MODE)? G(a,8)->b : \
+  (test_mode == PCRE16_MODE)? G(a,16)->b : G(a,32)->b)
+
+#define PATCTXCPY(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    memcpy(G(a,8),G(b,8),sizeof(pcre2_compile_context_8)); \
+  else if (test_mode == PCRE16_MODE) \
+    memcpy(G(a,16),G(b,16),sizeof(pcre2_compile_context_16)); \
+  else memcpy(G(a,32),G(b,32),sizeof(pcre2_compile_context_32))
+
+#define PCHARS(lv, p, offset, len, utf, f) \
+  if (test_mode == PCRE32_MODE) \
+    lv = pchars32((PCRE2_SPTR32)(p)+offset, len, utf, f); \
+  else if (test_mode == PCRE16_MODE) \
+    lv = pchars16((PCRE2_SPTR16)(p)+offset, len, utf, f); \
+  else \
+    lv = pchars8((PCRE2_SPTR8)(p)+offset, len, utf, f)
+
+#define PCHARSV(p, offset, len, utf, f) \
+  if (test_mode == PCRE32_MODE) \
+    (void)pchars32((PCRE2_SPTR32)(p)+offset, len, utf, f); \
+  else if (test_mode == PCRE16_MODE) \
+    (void)pchars16((PCRE2_SPTR16)(p)+offset, len, utf, f); \
+  else \
+    (void)pchars8((PCRE2_SPTR8)(p)+offset, len, utf, f)
+
+#define PCRE2_CALLOUT_ENUMERATE(a,b,c) \
+  if (test_mode == PCRE8_MODE) \
+     a = pcre2_callout_enumerate_8(compiled_code8, \
+       (int (*)(struct pcre2_callout_enumerate_block_8 *, void *))b,c); \
+  else if (test_mode == PCRE16_MODE) \
+     a = pcre2_callout_enumerate_16(compiled_code16, \
+       (int(*)(struct pcre2_callout_enumerate_block_16 *, void *))b,c); \
+  else \
+     a = pcre2_callout_enumerate_32(compiled_code32, \
+       (int (*)(struct pcre2_callout_enumerate_block_32 *, void *))b,c)
+
+#define PCRE2_CODE_COPY_FROM_VOID(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    G(a,8) = pcre2_code_copy_8(b); \
+  else if (test_mode == PCRE16_MODE) \
+    G(a,16) = pcre2_code_copy_16(b); \
+  else \
+    G(a,32) = pcre2_code_copy_32(b)
+
+#define PCRE2_CODE_COPY_TO_VOID(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    a = (void *)pcre2_code_copy_8(G(b,8)); \
+  else if (test_mode == PCRE16_MODE) \
+    a = (void *)pcre2_code_copy_16(G(b,16)); \
+  else \
+    a = (void *)pcre2_code_copy_32(G(b,32))
+
+#define PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    a = (void *)pcre2_code_copy_with_tables_8(G(b,8)); \
+  else if (test_mode == PCRE16_MODE) \
+    a = (void *)pcre2_code_copy_with_tables_16(G(b,16)); \
+  else \
+    a = (void *)pcre2_code_copy_with_tables_32(G(b,32))
+
+#define PCRE2_COMPILE(a,b,c,d,e,f,g) \
+  if (test_mode == PCRE8_MODE) \
+    G(a,8) = pcre2_compile_8(G(b,8),c,d,e,f,g); \
+  else if (test_mode == PCRE16_MODE) \
+    G(a,16) = pcre2_compile_16(G(b,16),c,d,e,f,g); \
+  else \
+    G(a,32) = pcre2_compile_32(G(b,32),c,d,e,f,g)
+
+#define PCRE2_CONVERTED_PATTERN_FREE(a) \
+  if (test_mode == PCRE8_MODE) pcre2_converted_pattern_free_8((PCRE2_UCHAR8 *)a); \
+  else if (test_mode == PCRE16_MODE) pcre2_converted_pattern_free_16((PCRE2_UCHAR16 *)a); \
+  else pcre2_converted_pattern_free_32((PCRE2_UCHAR32 *)a)
+
+#define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_dfa_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h,i,j); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_dfa_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h,i,j); \
+  else \
+    a = pcre2_dfa_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h,i,j)
+
+#define PCRE2_GET_ERROR_MESSAGE(r,a,b) \
+  if (test_mode == PCRE8_MODE) \
+    r = pcre2_get_error_message_8(a,G(b,8),G(G(b,8),_size)); \
+  else if (test_mode == PCRE16_MODE) \
+    r = pcre2_get_error_message_16(a,G(b,16),G(G(b,16),_size/2)); \
+  else \
+    r = pcre2_get_error_message_32(a,G(b,32),G(G(b,32),_size/4))
+
+#define PCRE2_GET_OVECTOR_COUNT(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_get_ovector_count_8(G(b,8)); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_get_ovector_count_16(G(b,16)); \
+  else \
+    a = pcre2_get_ovector_count_32(G(b,32))
+
+#define PCRE2_GET_STARTCHAR(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_get_startchar_8(G(b,8)); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_get_startchar_16(G(b,16)); \
+  else \
+    a = pcre2_get_startchar_32(G(b,32))
+
+#define PCRE2_JIT_COMPILE(r,a,b) \
+  if (test_mode == PCRE8_MODE) r = pcre2_jit_compile_8(G(a,8),b); \
+  else if (test_mode == PCRE16_MODE) r = pcre2_jit_compile_16(G(a,16),b); \
+  else r = pcre2_jit_compile_32(G(a,32),b)
+
+#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) \
+  if (test_mode == PCRE8_MODE) pcre2_jit_free_unused_memory_8(G(a,8)); \
+  else if (test_mode == PCRE16_MODE) pcre2_jit_free_unused_memory_16(G(a,16)); \
+  else pcre2_jit_free_unused_memory_32(G(a,32))
+
+#define PCRE2_JIT_MATCH(a,b,c,d,e,f,g,h) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_jit_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_jit_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h); \
+  else \
+    a = pcre2_jit_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h)
+
+#define PCRE2_JIT_STACK_CREATE(a,b,c,d) \
+  if (test_mode == PCRE8_MODE) \
+    a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_8(b,c,d); \
+  else if (test_mode == PCRE16_MODE) \
+    a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_16(b,c,d); \
+  else \
+    a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_32(b,c,d);
+
+#define PCRE2_JIT_STACK_ASSIGN(a,b,c) \
+  if (test_mode == PCRE8_MODE) \
+    pcre2_jit_stack_assign_8(G(a,8),(pcre2_jit_callback_8)b,c); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_jit_stack_assign_16(G(a,16),(pcre2_jit_callback_16)b,c); \
+  else \
+    pcre2_jit_stack_assign_32(G(a,32),(pcre2_jit_callback_32)b,c);
+
+#define PCRE2_JIT_STACK_FREE(a) \
+  if (test_mode == PCRE8_MODE) \
+    pcre2_jit_stack_free_8((pcre2_jit_stack_8 *)a); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_jit_stack_free_16((pcre2_jit_stack_16 *)a); \
+  else \
+    pcre2_jit_stack_free_32((pcre2_jit_stack_32 *)a);
+
+#define PCRE2_MAKETABLES(a) \
+  if (test_mode == PCRE8_MODE) a = pcre2_maketables_8(NULL); \
+  else if (test_mode == PCRE16_MODE) a = pcre2_maketables_16(NULL); \
+  else a = pcre2_maketables_32(NULL)
+
+#define PCRE2_MATCH(a,b,c,d,e,f,g,h) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h); \
+  else \
+    a = pcre2_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h)
+
+#define PCRE2_MATCH_DATA_CREATE(a,b,c) \
+  if (test_mode == PCRE8_MODE) \
+    G(a,8) = pcre2_match_data_create_8(b,c); \
+  else if (test_mode == PCRE16_MODE) \
+    G(a,16) = pcre2_match_data_create_16(b,c); \
+  else \
+    G(a,32) = pcre2_match_data_create_32(b,c)
+
+#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \
+  if (test_mode == PCRE8_MODE) \
+    G(a,8) = pcre2_match_data_create_from_pattern_8(G(b,8),c); \
+  else if (test_mode == PCRE16_MODE) \
+    G(a,16) = pcre2_match_data_create_from_pattern_16(G(b,16),c); \
+  else \
+    G(a,32) = pcre2_match_data_create_from_pattern_32(G(b,32),c)
+
+#define PCRE2_MATCH_DATA_FREE(a) \
+  if (test_mode == PCRE8_MODE) \
+    pcre2_match_data_free_8(G(a,8)); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_match_data_free_16(G(a,16)); \
+  else \
+    pcre2_match_data_free_32(G(a,32))
+
+#define PCRE2_PATTERN_CONVERT(a,b,c,d,e,f,g) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_pattern_convert_8(G(b,8),c,d,(PCRE2_UCHAR8 **)e,f,G(g,8)); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_pattern_convert_16(G(b,16),c,d,(PCRE2_UCHAR16 **)e,f,G(g,16)); \
+  else \
+    a = pcre2_pattern_convert_32(G(b,32),c,d,(PCRE2_UCHAR32 **)e,f,G(g,32))
+
+#define PCRE2_PATTERN_INFO(a,b,c,d) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_pattern_info_8(G(b,8),c,d); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_pattern_info_16(G(b,16),c,d); \
+  else \
+    a = pcre2_pattern_info_32(G(b,32),c,d)
+
+#define PCRE2_PRINTINT(a) \
+  if (test_mode == PCRE8_MODE) \
+    pcre2_printint_8(compiled_code8,outfile,a); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_printint_16(compiled_code16,outfile,a); \
+  else \
+    pcre2_printint_32(compiled_code32,outfile,a)
+
+#define PCRE2_SERIALIZE_DECODE(r,a,b,c,d) \
+  if (test_mode == PCRE8_MODE) \
+    r = pcre2_serialize_decode_8((pcre2_code_8 **)a,b,c,G(d,8)); \
+  else if (test_mode == PCRE16_MODE) \
+    r = pcre2_serialize_decode_16((pcre2_code_16 **)a,b,c,G(d,16)); \
+  else \
+    r = pcre2_serialize_decode_32((pcre2_code_32 **)a,b,c,G(d,32))
+
+#define PCRE2_SERIALIZE_ENCODE(r,a,b,c,d,e) \
+  if (test_mode == PCRE8_MODE) \
+    r = pcre2_serialize_encode_8((const pcre2_code_8 **)a,b,c,d,G(e,8)); \
+  else if (test_mode == PCRE16_MODE) \
+    r = pcre2_serialize_encode_16((const pcre2_code_16 **)a,b,c,d,G(e,16)); \
+  else \
+    r = pcre2_serialize_encode_32((const pcre2_code_32 **)a,b,c,d,G(e,32))
+
+#define PCRE2_SERIALIZE_FREE(a) \
+  if (test_mode == PCRE8_MODE) \
+    pcre2_serialize_free_8(a); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_serialize_free_16(a); \
+  else \
+    pcre2_serialize_free_32(a)
+
+#define PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(r,a) \
+  if (test_mode == PCRE8_MODE) \
+    r = pcre2_serialize_get_number_of_codes_8(a); \
+  else if (test_mode == PCRE16_MODE) \
+    r = pcre2_serialize_get_number_of_codes_16(a); \
+  else \
+    r = pcre2_serialize_get_number_of_codes_32(a); \
+
+#define PCRE2_SET_CALLOUT(a,b,c) \
+  if (test_mode == PCRE8_MODE) \
+    pcre2_set_callout_8(G(a,8),(int (*)(pcre2_callout_block_8 *, void *))b,c); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_set_callout_16(G(a,16),(int (*)(pcre2_callout_block_16 *, void *))b,c); \
+  else \
+    pcre2_set_callout_32(G(a,32),(int (*)(pcre2_callout_block_32 *, void *))b,c);
+
+#define PCRE2_SET_CHARACTER_TABLES(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    pcre2_set_character_tables_8(G(a,8),b); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_set_character_tables_16(G(a,16),b); \
+  else \
+    pcre2_set_character_tables_32(G(a,32),b)
+
+#define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b,c) \
+  if (test_mode == PCRE8_MODE) \
+    pcre2_set_compile_recursion_guard_8(G(a,8),b,c); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_set_compile_recursion_guard_16(G(a,16),b,c); \
+  else \
+    pcre2_set_compile_recursion_guard_32(G(a,32),b,c)
+
+#define PCRE2_SET_DEPTH_LIMIT(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    pcre2_set_depth_limit_8(G(a,8),b); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_set_depth_limit_16(G(a,16),b); \
+  else \
+    pcre2_set_depth_limit_32(G(a,32),b)
+
+#define PCRE2_SET_GLOB_SEPARATOR(r,a,b) \
+  if (test_mode == PCRE8_MODE) \
+    r = pcre2_set_glob_separator_8(G(a,8),b); \
+  else if (test_mode == PCRE16_MODE) \
+    r = pcre2_set_glob_separator_16(G(a,16),b); \
+  else \
+    r = pcre2_set_glob_separator_32(G(a,32),b)
+
+#define PCRE2_SET_GLOB_ESCAPE(r,a,b) \
+  if (test_mode == PCRE8_MODE) \
+    r = pcre2_set_glob_escape_8(G(a,8),b); \
+  else if (test_mode == PCRE16_MODE) \
+    r = pcre2_set_glob_escape_16(G(a,16),b); \
+  else \
+    r = pcre2_set_glob_escape_32(G(a,32),b)
+
+#define PCRE2_SET_HEAP_LIMIT(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    pcre2_set_heap_limit_8(G(a,8),b); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_set_heap_limit_16(G(a,16),b); \
+  else \
+    pcre2_set_heap_limit_32(G(a,32),b)
+
+#define PCRE2_SET_MATCH_LIMIT(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    pcre2_set_match_limit_8(G(a,8),b); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_set_match_limit_16(G(a,16),b); \
+  else \
+    pcre2_set_match_limit_32(G(a,32),b)
+
+#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    pcre2_set_max_pattern_length_8(G(a,8),b); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_set_max_pattern_length_16(G(a,16),b); \
+  else \
+    pcre2_set_max_pattern_length_32(G(a,32),b)
+
+#define PCRE2_SET_OFFSET_LIMIT(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    pcre2_set_offset_limit_8(G(a,8),b); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_set_offset_limit_16(G(a,16),b); \
+  else \
+    pcre2_set_offset_limit_32(G(a,32),b)
+
+#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) \
+  if (test_mode == PCRE8_MODE) \
+    pcre2_set_parens_nest_limit_8(G(a,8),b); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_set_parens_nest_limit_16(G(a,16),b); \
+  else \
+    pcre2_set_parens_nest_limit_32(G(a,32),b)
+
+#define PCRE2_SET_SUBSTITUTE_CALLOUT(a,b,c) \
+  if (test_mode == PCRE8_MODE) \
+    pcre2_set_substitute_callout_8(G(a,8), \
+      (int (*)(pcre2_substitute_callout_block_8 *, void *))b,c); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_set_substitute_callout_16(G(a,16), \
+      (int (*)(pcre2_substitute_callout_block_16 *, void *))b,c); \
+  else \
+    pcre2_set_substitute_callout_32(G(a,32), \
+      (int (*)(pcre2_substitute_callout_block_32 *, void *))b,c)
+
+#define PCRE2_SUBSTITUTE(a,b,c,d,e,f,g,h,i,j,k,l) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_substitute_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h, \
+      (PCRE2_SPTR8)i,j,(PCRE2_UCHAR8 *)k,l); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_substitute_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h, \
+      (PCRE2_SPTR16)i,j,(PCRE2_UCHAR16 *)k,l); \
+  else \
+    a = pcre2_substitute_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h, \
+      (PCRE2_SPTR32)i,j,(PCRE2_UCHAR32 *)k,l)
+
+#define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_substring_copy_byname_8(G(b,8),G(c,8),(PCRE2_UCHAR8 *)d,e); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_substring_copy_byname_16(G(b,16),G(c,16),(PCRE2_UCHAR16 *)d,e); \
+  else \
+    a = pcre2_substring_copy_byname_32(G(b,32),G(c,32),(PCRE2_UCHAR32 *)d,e)
+
+#define PCRE2_SUBSTRING_COPY_BYNUMBER(a,b,c,d,e) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_substring_copy_bynumber_8(G(b,8),c,(PCRE2_UCHAR8 *)d,e); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_substring_copy_bynumber_16(G(b,16),c,(PCRE2_UCHAR16 *)d,e); \
+  else \
+    a = pcre2_substring_copy_bynumber_32(G(b,32),c,(PCRE2_UCHAR32 *)d,e)
+
+#define PCRE2_SUBSTRING_FREE(a) \
+  if (test_mode == PCRE8_MODE) pcre2_substring_free_8((PCRE2_UCHAR8 *)a); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_substring_free_16((PCRE2_UCHAR16 *)a); \
+  else pcre2_substring_free_32((PCRE2_UCHAR32 *)a)
+
+#define PCRE2_SUBSTRING_GET_BYNAME(a,b,c,d,e) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_substring_get_byname_8(G(b,8),G(c,8),(PCRE2_UCHAR8 **)d,e); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_substring_get_byname_16(G(b,16),G(c,16),(PCRE2_UCHAR16 **)d,e); \
+  else \
+    a = pcre2_substring_get_byname_32(G(b,32),G(c,32),(PCRE2_UCHAR32 **)d,e)
+
+#define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_substring_get_bynumber_8(G(b,8),c,(PCRE2_UCHAR8 **)d,e); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_substring_get_bynumber_16(G(b,16),c,(PCRE2_UCHAR16 **)d,e); \
+  else \
+    a = pcre2_substring_get_bynumber_32(G(b,32),c,(PCRE2_UCHAR32 **)d,e)
+
+#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_substring_length_byname_8(G(b,8),G(c,8),d); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_substring_length_byname_16(G(b,16),G(c,16),d); \
+  else \
+    a = pcre2_substring_length_byname_32(G(b,32),G(c,32),d)
+
+#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_substring_length_bynumber_8(G(b,8),c,d); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_substring_length_bynumber_16(G(b,16),c,d); \
+  else \
+    a = pcre2_substring_length_bynumber_32(G(b,32),c,d)
+
+#define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_substring_list_get_8(G(b,8),(PCRE2_UCHAR8 ***)c,d); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_substring_list_get_16(G(b,16),(PCRE2_UCHAR16 ***)c,d); \
+  else \
+    a = pcre2_substring_list_get_32(G(b,32),(PCRE2_UCHAR32 ***)c,d)
+
+#define PCRE2_SUBSTRING_LIST_FREE(a) \
+  if (test_mode == PCRE8_MODE) \
+    pcre2_substring_list_free_8((PCRE2_SPTR8 *)a); \
+  else if (test_mode == PCRE16_MODE) \
+    pcre2_substring_list_free_16((PCRE2_SPTR16 *)a); \
+  else \
+    pcre2_substring_list_free_32((PCRE2_SPTR32 *)a)
+
+#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \
+  if (test_mode == PCRE8_MODE) \
+    a = pcre2_substring_number_from_name_8(G(b,8),G(c,8)); \
+  else if (test_mode == PCRE16_MODE) \
+    a = pcre2_substring_number_from_name_16(G(b,16),G(c,16)); \
+  else \
+    a = pcre2_substring_number_from_name_32(G(b,32),G(c,32))
+
+#define PTR(x) ( \
+  (test_mode == PCRE8_MODE)? (void *)G(x,8) : \
+  (test_mode == PCRE16_MODE)? (void *)G(x,16) : \
+  (void *)G(x,32))
+
+#define SETFLD(x,y,z) \
+  if (test_mode == PCRE8_MODE) G(x,8)->y = z; \
+  else if (test_mode == PCRE16_MODE) G(x,16)->y = z; \
+  else G(x,32)->y = z
+
+#define SETFLDVEC(x,y,v,z) \
+  if (test_mode == PCRE8_MODE) G(x,8)->y[v] = z; \
+  else if (test_mode == PCRE16_MODE) G(x,16)->y[v] = z; \
+  else G(x,32)->y[v] = z
+
+#define SETOP(x,y,z) \
+  if (test_mode == PCRE8_MODE) G(x,8) z y; \
+  else if (test_mode == PCRE16_MODE) G(x,16) z y; \
+  else G(x,32) z y
+
+#define SETCASTPTR(x,y) \
+  if (test_mode == PCRE8_MODE) \
+    G(x,8) = (uint8_t *)(y); \
+  else if (test_mode == PCRE16_MODE) \
+    G(x,16) = (uint16_t *)(y); \
+  else \
+    G(x,32) = (uint32_t *)(y)
+
+#define STRLEN(p) ((test_mode == PCRE8_MODE)? ((int)strlen((char *)p)) : \
+  (test_mode == PCRE16_MODE)? ((int)strlen16((PCRE2_SPTR16)p)) : \
+  ((int)strlen32((PCRE2_SPTR32)p)))
+
+#define SUB1(a,b) \
+  if (test_mode == PCRE8_MODE) G(a,8)(G(b,8)); \
+  else if (test_mode == PCRE16_MODE) G(a,16)(G(b,16)); \
+  else G(a,32)(G(b,32))
+
+#define SUB2(a,b,c) \
+  if (test_mode == PCRE8_MODE) G(a,8)(G(b,8),G(c,8)); \
+  else if (test_mode == PCRE16_MODE) G(a,16)(G(b,16),G(c,16)); \
+  else G(a,32)(G(b,32),G(c,32))
+
+#define TEST(x,r,y) ( \
+  (test_mode == PCRE8_MODE && G(x,8) r (y)) || \
+  (test_mode == PCRE16_MODE && G(x,16) r (y)) || \
+  (test_mode == PCRE32_MODE && G(x,32) r (y)))
+
+#define TESTFLD(x,f,r,y) ( \
+  (test_mode == PCRE8_MODE && G(x,8)->f r (y)) || \
+  (test_mode == PCRE16_MODE && G(x,16)->f r (y)) || \
+  (test_mode == PCRE32_MODE && G(x,32)->f r (y)))
+
+
+/* ----- Two out of three modes are supported ----- */
+
+#else
+
+/* We can use some macro trickery to make a single set of definitions work in
+the three different cases. */
+
+/* ----- 32-bit and 16-bit but not 8-bit supported ----- */
+
+#if defined(SUPPORT_PCRE2_32) && defined(SUPPORT_PCRE2_16)
+#define BITONE 32
+#define BITTWO 16
+
+/* ----- 32-bit and 8-bit but not 16-bit supported ----- */
+
+#elif defined(SUPPORT_PCRE2_32) && defined(SUPPORT_PCRE2_8)
+#define BITONE 32
+#define BITTWO 8
+
+/* ----- 16-bit and 8-bit but not 32-bit supported ----- */
+
+#else
+#define BITONE 16
+#define BITTWO 8
+#endif
+
+
+/* ----- Common macros for two-mode cases ----- */
+
+#define BYTEONE (BITONE/8)
+#define BYTETWO (BITTWO/8)
+
+#define CASTFLD(t,a,b) \
+  ((test_mode == G(G(PCRE,BITONE),_MODE))? (t)(G(a,BITONE)->b) : \
+    (t)(G(a,BITTWO)->b))
+
+#define CASTVAR(t,x) ( \
+  (test_mode == G(G(PCRE,BITONE),_MODE))? \
+    (t)G(x,BITONE) : (t)G(x,BITTWO))
+
+#define CODE_UNIT(a,b) ( \
+  (test_mode == G(G(PCRE,BITONE),_MODE))? \
+  (uint32_t)(((G(PCRE2_SPTR,BITONE))(a))[b]) : \
+  (uint32_t)(((G(PCRE2_SPTR,BITTWO))(a))[b]))
+
+#define CONCTXCPY(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    memcpy(G(a,BITONE),G(b,BITONE),sizeof(G(pcre2_convert_context_,BITONE))); \
+  else \
+    memcpy(G(a,BITTWO),G(b,BITTWO),sizeof(G(pcre2_convert_context_,BITTWO)))
+
+#define CONVERT_COPY(a,b,c) \
+  (test_mode == G(G(PCRE,BITONE),_MODE))? \
+  memcpy(G(a,BITONE),(char *)b,(c)*BYTEONE) : \
+  memcpy(G(a,BITTWO),(char *)b,(c)*BYTETWO)
+
+#define DATCTXCPY(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    memcpy(G(a,BITONE),G(b,BITONE),sizeof(G(pcre2_match_context_,BITONE))); \
+  else \
+    memcpy(G(a,BITTWO),G(b,BITTWO),sizeof(G(pcre2_match_context_,BITTWO)))
+
+#define FLD(a,b) \
+  ((test_mode == G(G(PCRE,BITONE),_MODE))? G(a,BITONE)->b : G(a,BITTWO)->b)
+
+#define PATCTXCPY(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    memcpy(G(a,BITONE),G(b,BITONE),sizeof(G(pcre2_compile_context_,BITONE))); \
+  else \
+    memcpy(G(a,BITTWO),G(b,BITTWO),sizeof(G(pcre2_compile_context_,BITTWO)))
+
+#define PCHARS(lv, p, offset, len, utf, f) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    lv = G(pchars,BITONE)((G(PCRE2_SPTR,BITONE))(p)+offset, len, utf, f); \
+  else \
+    lv = G(pchars,BITTWO)((G(PCRE2_SPTR,BITTWO))(p)+offset, len, utf, f)
+
+#define PCHARSV(p, offset, len, utf, f) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    (void)G(pchars,BITONE)((G(PCRE2_SPTR,BITONE))(p)+offset, len, utf, f); \
+  else \
+    (void)G(pchars,BITTWO)((G(PCRE2_SPTR,BITTWO))(p)+offset, len, utf, f)
+
+#define PCRE2_CALLOUT_ENUMERATE(a,b,c) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+     a = G(pcre2_callout_enumerate,BITONE)(G(compiled_code,BITONE), \
+       (int (*)(struct G(pcre2_callout_enumerate_block_,BITONE) *, void *))b,c); \
+  else \
+     a = G(pcre2_callout_enumerate,BITTWO)(G(compiled_code,BITTWO), \
+       (int (*)(struct G(pcre2_callout_enumerate_block_,BITTWO) *, void *))b,c)
+
+#define PCRE2_CODE_COPY_FROM_VOID(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(a,BITONE) = G(pcre2_code_copy_,BITONE)(b); \
+  else \
+    G(a,BITTWO) = G(pcre2_code_copy_,BITTWO)(b)
+
+#define PCRE2_CODE_COPY_TO_VOID(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = (void *)G(pcre2_code_copy_,BITONE)(G(b,BITONE)); \
+  else \
+    a = (void *)G(pcre2_code_copy_,BITTWO)(G(b,BITTWO))
+
+#define PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = (void *)G(pcre2_code_copy_with_tables_,BITONE)(G(b,BITONE)); \
+  else \
+    a = (void *)G(pcre2_code_copy_with_tables_,BITTWO)(G(b,BITTWO))
+
+#define PCRE2_COMPILE(a,b,c,d,e,f,g) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(a,BITONE) = G(pcre2_compile_,BITONE)(G(b,BITONE),c,d,e,f,g); \
+  else \
+    G(a,BITTWO) = G(pcre2_compile_,BITTWO)(G(b,BITTWO),c,d,e,f,g)
+
+#define PCRE2_CONVERTED_PATTERN_FREE(a) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_converted_pattern_free_,BITONE)((G(PCRE2_UCHAR,BITONE) *)a); \
+  else \
+    G(pcre2_converted_pattern_free_,BITTWO)((G(PCRE2_UCHAR,BITTWO) *)a)
+
+#define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_dfa_match_,BITONE)(G(b,BITONE),(G(PCRE2_SPTR,BITONE))c,d,e,f, \
+      G(g,BITONE),h,i,j); \
+  else \
+    a = G(pcre2_dfa_match_,BITTWO)(G(b,BITTWO),(G(PCRE2_SPTR,BITTWO))c,d,e,f, \
+      G(g,BITTWO),h,i,j)
+
+#define PCRE2_GET_ERROR_MESSAGE(r,a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    r = G(pcre2_get_error_message_,BITONE)(a,G(b,BITONE),G(G(b,BITONE),_size/BYTEONE)); \
+  else \
+    r = G(pcre2_get_error_message_,BITTWO)(a,G(b,BITTWO),G(G(b,BITTWO),_size/BYTETWO))
+
+#define PCRE2_GET_OVECTOR_COUNT(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_get_ovector_count_,BITONE)(G(b,BITONE)); \
+  else \
+    a = G(pcre2_get_ovector_count_,BITTWO)(G(b,BITTWO))
+
+#define PCRE2_GET_STARTCHAR(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_get_startchar_,BITONE)(G(b,BITONE)); \
+  else \
+    a = G(pcre2_get_startchar_,BITTWO)(G(b,BITTWO))
+
+#define PCRE2_JIT_COMPILE(r,a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    r = G(pcre2_jit_compile_,BITONE)(G(a,BITONE),b); \
+  else \
+    r = G(pcre2_jit_compile_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_jit_free_unused_memory_,BITONE)(G(a,BITONE)); \
+  else \
+    G(pcre2_jit_free_unused_memory_,BITTWO)(G(a,BITTWO))
+
+#define PCRE2_JIT_MATCH(a,b,c,d,e,f,g,h) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_jit_match_,BITONE)(G(b,BITONE),(G(PCRE2_SPTR,BITONE))c,d,e,f, \
+      G(g,BITONE),h); \
+  else \
+    a = G(pcre2_jit_match_,BITTWO)(G(b,BITTWO),(G(PCRE2_SPTR,BITTWO))c,d,e,f, \
+      G(g,BITTWO),h)
+
+#define PCRE2_JIT_STACK_CREATE(a,b,c,d) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = (PCRE2_JIT_STACK *)G(pcre2_jit_stack_create_,BITONE)(b,c,d); \
+  else \
+    a = (PCRE2_JIT_STACK *)G(pcre2_jit_stack_create_,BITTWO)(b,c,d); \
+
+#define PCRE2_JIT_STACK_ASSIGN(a,b,c) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_jit_stack_assign_,BITONE)(G(a,BITONE),(G(pcre2_jit_callback_,BITONE))b,c); \
+  else \
+    G(pcre2_jit_stack_assign_,BITTWO)(G(a,BITTWO),(G(pcre2_jit_callback_,BITTWO))b,c);
+
+#define PCRE2_JIT_STACK_FREE(a) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_jit_stack_free_,BITONE)((G(pcre2_jit_stack_,BITONE) *)a); \
+  else \
+    G(pcre2_jit_stack_free_,BITTWO)((G(pcre2_jit_stack_,BITTWO) *)a);
+
+#define PCRE2_MAKETABLES(a) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_maketables_,BITONE)(NULL); \
+  else \
+    a = G(pcre2_maketables_,BITTWO)(NULL)
+
+#define PCRE2_MATCH(a,b,c,d,e,f,g,h) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_match_,BITONE)(G(b,BITONE),(G(PCRE2_SPTR,BITONE))c,d,e,f, \
+      G(g,BITONE),h); \
+  else \
+    a = G(pcre2_match_,BITTWO)(G(b,BITTWO),(G(PCRE2_SPTR,BITTWO))c,d,e,f, \
+      G(g,BITTWO),h)
+
+#define PCRE2_MATCH_DATA_CREATE(a,b,c) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(a,BITONE) = G(pcre2_match_data_create_,BITONE)(b,c); \
+  else \
+    G(a,BITTWO) = G(pcre2_match_data_create_,BITTWO)(b,c)
+
+#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(a,BITONE) = G(pcre2_match_data_create_from_pattern_,BITONE)(G(b,BITONE),c); \
+  else \
+    G(a,BITTWO) = G(pcre2_match_data_create_from_pattern_,BITTWO)(G(b,BITTWO),c)
+
+#define PCRE2_MATCH_DATA_FREE(a) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_match_data_free_,BITONE)(G(a,BITONE)); \
+  else \
+    G(pcre2_match_data_free_,BITTWO)(G(a,BITTWO))
+
+#define PCRE2_PATTERN_CONVERT(a,b,c,d,e,f,g) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_pattern_convert_,BITONE)(G(b,BITONE),c,d,(G(PCRE2_UCHAR,BITONE) **)e,f,G(g,BITONE)); \
+  else \
+    a = G(pcre2_pattern_convert_,BITTWO)(G(b,BITTWO),c,d,(G(PCRE2_UCHAR,BITTWO) **)e,f,G(g,BITTWO))
+
+#define PCRE2_PATTERN_INFO(a,b,c,d) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_pattern_info_,BITONE)(G(b,BITONE),c,d); \
+  else \
+    a = G(pcre2_pattern_info_,BITTWO)(G(b,BITTWO),c,d)
+
+#define PCRE2_PRINTINT(a) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_printint_,BITONE)(G(compiled_code,BITONE),outfile,a); \
+  else \
+    G(pcre2_printint_,BITTWO)(G(compiled_code,BITTWO),outfile,a)
+
+#define PCRE2_SERIALIZE_DECODE(r,a,b,c,d) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    r = G(pcre2_serialize_decode_,BITONE)((G(pcre2_code_,BITONE) **)a,b,c,G(d,BITONE)); \
+  else \
+    r = G(pcre2_serialize_decode_,BITTWO)((G(pcre2_code_,BITTWO) **)a,b,c,G(d,BITTWO))
+
+#define PCRE2_SERIALIZE_ENCODE(r,a,b,c,d,e) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    r = G(pcre2_serialize_encode_,BITONE)((G(const pcre2_code_,BITONE) **)a,b,c,d,G(e,BITONE)); \
+  else \
+    r = G(pcre2_serialize_encode_,BITTWO)((G(const pcre2_code_,BITTWO) **)a,b,c,d,G(e,BITTWO))
+
+#define PCRE2_SERIALIZE_FREE(a) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_serialize_free_,BITONE)(a); \
+  else \
+    G(pcre2_serialize_free_,BITTWO)(a)
+
+#define PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(r,a) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    r = G(pcre2_serialize_get_number_of_codes_,BITONE)(a); \
+  else \
+    r = G(pcre2_serialize_get_number_of_codes_,BITTWO)(a)
+
+#define PCRE2_SET_CALLOUT(a,b,c) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_set_callout_,BITONE)(G(a,BITONE), \
+      (int (*)(G(pcre2_callout_block_,BITONE) *, void *))b,c); \
+  else \
+    G(pcre2_set_callout_,BITTWO)(G(a,BITTWO), \
+      (int (*)(G(pcre2_callout_block_,BITTWO) *, void *))b,c);
+
+#define PCRE2_SET_CHARACTER_TABLES(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_set_character_tables_,BITONE)(G(a,BITONE),b); \
+  else \
+    G(pcre2_set_character_tables_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b,c) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_set_compile_recursion_guard_,BITONE)(G(a,BITONE),b,c); \
+  else \
+    G(pcre2_set_compile_recursion_guard_,BITTWO)(G(a,BITTWO),b,c)
+
+#define PCRE2_SET_DEPTH_LIMIT(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_set_depth_limit_,BITONE)(G(a,BITONE),b); \
+  else \
+    G(pcre2_set_depth_limit_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SET_GLOB_ESCAPE(r,a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    r = G(pcre2_set_glob_escape_,BITONE)(G(a,BITONE),b); \
+  else \
+    r = G(pcre2_set_glob_escape_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SET_GLOB_SEPARATOR(r,a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    r = G(pcre2_set_glob_separator_,BITONE)(G(a,BITONE),b); \
+  else \
+    r = G(pcre2_set_glob_separator_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SET_HEAP_LIMIT(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_set_heap_limit_,BITONE)(G(a,BITONE),b); \
+  else \
+    G(pcre2_set_heap_limit_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SET_MATCH_LIMIT(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_set_match_limit_,BITONE)(G(a,BITONE),b); \
+  else \
+    G(pcre2_set_match_limit_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_set_max_pattern_length_,BITONE)(G(a,BITONE),b); \
+  else \
+    G(pcre2_set_max_pattern_length_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SET_OFFSET_LIMIT(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_set_offset_limit_,BITONE)(G(a,BITONE),b); \
+  else \
+    G(pcre2_set_offset_limit_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_set_parens_nest_limit_,BITONE)(G(a,BITONE),b); \
+  else \
+    G(pcre2_set_parens_nest_limit_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SET_SUBSTITUTE_CALLOUT(a,b,c) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_set_substitute_callout_,BITONE)(G(a,BITONE), \
+      (int (*)(G(pcre2_substitute_callout_block_,BITONE) *, void *))b,c); \
+  else \
+    G(pcre2_set_substitute_callout_,BITTWO)(G(a,BITTWO), \
+      (int (*)(G(pcre2_substitute_callout_block_,BITTWO) *, void *))b,c)
+
+#define PCRE2_SUBSTITUTE(a,b,c,d,e,f,g,h,i,j,k,l) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_substitute_,BITONE)(G(b,BITONE),(G(PCRE2_SPTR,BITONE))c,d,e,f, \
+      G(g,BITONE),h,(G(PCRE2_SPTR,BITONE))i,j, \
+      (G(PCRE2_UCHAR,BITONE) *)k,l); \
+  else \
+    a = G(pcre2_substitute_,BITTWO)(G(b,BITTWO),(G(PCRE2_SPTR,BITTWO))c,d,e,f, \
+      G(g,BITTWO),h,(G(PCRE2_SPTR,BITTWO))i,j, \
+      (G(PCRE2_UCHAR,BITTWO) *)k,l)
+
+#define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_substring_copy_byname_,BITONE)(G(b,BITONE),G(c,BITONE),\
+      (G(PCRE2_UCHAR,BITONE) *)d,e); \
+  else \
+    a = G(pcre2_substring_copy_byname_,BITTWO)(G(b,BITTWO),G(c,BITTWO),\
+      (G(PCRE2_UCHAR,BITTWO) *)d,e)
+
+#define PCRE2_SUBSTRING_COPY_BYNUMBER(a,b,c,d,e) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_substring_copy_bynumber_,BITONE)(G(b,BITONE),c,\
+      (G(PCRE2_UCHAR,BITONE) *)d,e); \
+  else \
+    a = G(pcre2_substring_copy_bynumber_,BITTWO)(G(b,BITTWO),c,\
+      (G(PCRE2_UCHAR,BITTWO) *)d,e)
+
+#define PCRE2_SUBSTRING_FREE(a) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_substring_free_,BITONE)((G(PCRE2_UCHAR,BITONE) *)a); \
+  else G(pcre2_substring_free_,BITTWO)((G(PCRE2_UCHAR,BITTWO) *)a)
+
+#define PCRE2_SUBSTRING_GET_BYNAME(a,b,c,d,e) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_substring_get_byname_,BITONE)(G(b,BITONE),G(c,BITONE),\
+      (G(PCRE2_UCHAR,BITONE) **)d,e); \
+  else \
+    a = G(pcre2_substring_get_byname_,BITTWO)(G(b,BITTWO),G(c,BITTWO),\
+      (G(PCRE2_UCHAR,BITTWO) **)d,e)
+
+#define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_substring_get_bynumber_,BITONE)(G(b,BITONE),c,\
+      (G(PCRE2_UCHAR,BITONE) **)d,e); \
+  else \
+    a = G(pcre2_substring_get_bynumber_,BITTWO)(G(b,BITTWO),c,\
+      (G(PCRE2_UCHAR,BITTWO) **)d,e)
+
+#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_substring_length_byname_,BITONE)(G(b,BITONE),G(c,BITONE),d); \
+  else \
+    a = G(pcre2_substring_length_byname_,BITTWO)(G(b,BITTWO),G(c,BITTWO),d)
+
+#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_substring_length_bynumber_,BITONE)(G(b,BITONE),c,d); \
+  else \
+    a = G(pcre2_substring_length_bynumber_,BITTWO)(G(b,BITTWO),c,d)
+
+#define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_substring_list_get_,BITONE)(G(b,BITONE), \
+      (G(PCRE2_UCHAR,BITONE) ***)c,d); \
+  else \
+    a = G(pcre2_substring_list_get_,BITTWO)(G(b,BITTWO), \
+      (G(PCRE2_UCHAR,BITTWO) ***)c,d)
+
+#define PCRE2_SUBSTRING_LIST_FREE(a) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(pcre2_substring_list_free_,BITONE)((G(PCRE2_SPTR,BITONE) *)a); \
+  else \
+    G(pcre2_substring_list_free_,BITTWO)((G(PCRE2_SPTR,BITTWO) *)a)
+
+#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    a = G(pcre2_substring_number_from_name_,BITONE)(G(b,BITONE),G(c,BITONE)); \
+  else \
+    a = G(pcre2_substring_number_from_name_,BITTWO)(G(b,BITTWO),G(c,BITTWO))
+
+#define PTR(x) ( \
+  (test_mode == G(G(PCRE,BITONE),_MODE))? (void *)G(x,BITONE) : \
+  (void *)G(x,BITTWO))
+
+#define SETFLD(x,y,z) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) G(x,BITONE)->y = z; \
+  else G(x,BITTWO)->y = z
+
+#define SETFLDVEC(x,y,v,z) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) G(x,BITONE)->y[v] = z; \
+  else G(x,BITTWO)->y[v] = z
+
+#define SETOP(x,y,z) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) G(x,BITONE) z y; \
+  else G(x,BITTWO) z y
+
+#define SETCASTPTR(x,y) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(x,BITONE) = (G(G(uint,BITONE),_t) *)(y); \
+  else \
+    G(x,BITTWO) = (G(G(uint,BITTWO),_t) *)(y)
+
+#define STRLEN(p) ((test_mode == G(G(PCRE,BITONE),_MODE))? \
+  G(strlen,BITONE)((G(PCRE2_SPTR,BITONE))p) : \
+  G(strlen,BITTWO)((G(PCRE2_SPTR,BITTWO))p))
+
+#define SUB1(a,b) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(a,BITONE)(G(b,BITONE)); \
+  else \
+    G(a,BITTWO)(G(b,BITTWO))
+
+#define SUB2(a,b,c) \
+  if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+    G(a,BITONE))(G(b,BITONE),G(c,BITONE)); \
+  else \
+    G(a,BITTWO))(G(b,BITTWO),G(c,BITTWO))
+
+#define TEST(x,r,y) ( \
+  (test_mode == G(G(PCRE,BITONE),_MODE) && G(x,BITONE) r (y)) || \
+  (test_mode == G(G(PCRE,BITTWO),_MODE) && G(x,BITTWO) r (y)))
+
+#define TESTFLD(x,f,r,y) ( \
+  (test_mode == G(G(PCRE,BITONE),_MODE) && G(x,BITONE)->f r (y)) || \
+  (test_mode == G(G(PCRE,BITTWO),_MODE) && G(x,BITTWO)->f r (y)))
+
+
+#endif  /* Two out of three modes */
+
+/* ----- End of cases where more than one mode is supported ----- */
+
+
+/* ----- Only 8-bit mode is supported ----- */
+
+#elif defined SUPPORT_PCRE2_8
+#define CASTFLD(t,a,b) (t)(G(a,8)->b)
+#define CASTVAR(t,x) (t)G(x,8)
+#define CODE_UNIT(a,b) (uint32_t)(((PCRE2_SPTR8)(a))[b])
+#define CONCTXCPY(a,b) memcpy(G(a,8),G(b,8),sizeof(pcre2_convert_context_8))
+#define CONVERT_COPY(a,b,c) memcpy(G(a,8),(char *)b, c)
+#define DATCTXCPY(a,b) memcpy(G(a,8),G(b,8),sizeof(pcre2_match_context_8))
+#define FLD(a,b) G(a,8)->b
+#define PATCTXCPY(a,b) memcpy(G(a,8),G(b,8),sizeof(pcre2_compile_context_8))
+#define PCHARS(lv, p, offset, len, utf, f) \
+  lv = pchars8((PCRE2_SPTR8)(p)+offset, len, utf, f)
+#define PCHARSV(p, offset, len, utf, f) \
+  (void)pchars8((PCRE2_SPTR8)(p)+offset, len, utf, f)
+#define PCRE2_CALLOUT_ENUMERATE(a,b,c) \
+   a = pcre2_callout_enumerate_8(compiled_code8, \
+     (int (*)(struct pcre2_callout_enumerate_block_8 *, void *))b,c)
+#define PCRE2_CODE_COPY_FROM_VOID(a,b) G(a,8) = pcre2_code_copy_8(b)
+#define PCRE2_CODE_COPY_TO_VOID(a,b) a = (void *)pcre2_code_copy_8(G(b,8))
+#define PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(a,b) a = (void *)pcre2_code_copy_with_tables_8(G(b,8))
+#define PCRE2_COMPILE(a,b,c,d,e,f,g) \
+  G(a,8) = pcre2_compile_8(G(b,8),c,d,e,f,g)
+#define PCRE2_CONVERTED_PATTERN_FREE(a) \
+  pcre2_converted_pattern_free_8((PCRE2_UCHAR8 *)a)
+#define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \
+  a = pcre2_dfa_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h,i,j)
+#define PCRE2_GET_ERROR_MESSAGE(r,a,b) \
+  r = pcre2_get_error_message_8(a,G(b,8),G(G(b,8),_size))
+#define PCRE2_GET_OVECTOR_COUNT(a,b) a = pcre2_get_ovector_count_8(G(b,8))
+#define PCRE2_GET_STARTCHAR(a,b) a = pcre2_get_startchar_8(G(b,8))
+#define PCRE2_JIT_COMPILE(r,a,b) r = pcre2_jit_compile_8(G(a,8),b)
+#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) pcre2_jit_free_unused_memory_8(G(a,8))
+#define PCRE2_JIT_MATCH(a,b,c,d,e,f,g,h) \
+  a = pcre2_jit_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h)
+#define PCRE2_JIT_STACK_CREATE(a,b,c,d) \
+  a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_8(b,c,d);
+#define PCRE2_JIT_STACK_ASSIGN(a,b,c) \
+  pcre2_jit_stack_assign_8(G(a,8),(pcre2_jit_callback_8)b,c);
+#define PCRE2_JIT_STACK_FREE(a) pcre2_jit_stack_free_8((pcre2_jit_stack_8 *)a);
+#define PCRE2_MAKETABLES(a) a = pcre2_maketables_8(NULL)
+#define PCRE2_MATCH(a,b,c,d,e,f,g,h) \
+  a = pcre2_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h)
+#define PCRE2_MATCH_DATA_CREATE(a,b,c) G(a,8) = pcre2_match_data_create_8(b,c)
+#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \
+  G(a,8) = pcre2_match_data_create_from_pattern_8(G(b,8),c)
+#define PCRE2_MATCH_DATA_FREE(a) pcre2_match_data_free_8(G(a,8))
+#define PCRE2_PATTERN_CONVERT(a,b,c,d,e,f,g) a = pcre2_pattern_convert_8(G(b,8),c,d,(PCRE2_UCHAR8 **)e,f,G(g,8))
+#define PCRE2_PATTERN_INFO(a,b,c,d) a = pcre2_pattern_info_8(G(b,8),c,d)
+#define PCRE2_PRINTINT(a) pcre2_printint_8(compiled_code8,outfile,a)
+#define PCRE2_SERIALIZE_DECODE(r,a,b,c,d) \
+  r = pcre2_serialize_decode_8((pcre2_code_8 **)a,b,c,G(d,8))
+#define PCRE2_SERIALIZE_ENCODE(r,a,b,c,d,e) \
+  r = pcre2_serialize_encode_8((const pcre2_code_8 **)a,b,c,d,G(e,8))
+#define PCRE2_SERIALIZE_FREE(a) pcre2_serialize_free_8(a)
+#define PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(r,a) \
+  r = pcre2_serialize_get_number_of_codes_8(a)
+#define PCRE2_SET_CALLOUT(a,b,c) \
+  pcre2_set_callout_8(G(a,8),(int (*)(pcre2_callout_block_8 *, void *))b,c)
+#define PCRE2_SET_CHARACTER_TABLES(a,b) pcre2_set_character_tables_8(G(a,8),b)
+#define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b,c) \
+  pcre2_set_compile_recursion_guard_8(G(a,8),b,c)
+#define PCRE2_SET_DEPTH_LIMIT(a,b) pcre2_set_depth_limit_8(G(a,8),b)
+#define PCRE2_SET_GLOB_ESCAPE(r,a,b) r = pcre2_set_glob_escape_8(G(a,8),b)
+#define PCRE2_SET_GLOB_SEPARATOR(r,a,b) r = pcre2_set_glob_separator_8(G(a,8),b)
+#define PCRE2_SET_HEAP_LIMIT(a,b) pcre2_set_heap_limit_8(G(a,8),b)
+#define PCRE2_SET_MATCH_LIMIT(a,b) pcre2_set_match_limit_8(G(a,8),b)
+#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) pcre2_set_max_pattern_length_8(G(a,8),b)
+#define PCRE2_SET_OFFSET_LIMIT(a,b) pcre2_set_offset_limit_8(G(a,8),b)
+#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) pcre2_set_parens_nest_limit_8(G(a,8),b)
+#define PCRE2_SET_SUBSTITUTE_CALLOUT(a,b,c) \
+  pcre2_set_substitute_callout_8(G(a,8), \
+    (int (*)(pcre2_substitute_callout_block_8 *, void *))b,c)
+#define PCRE2_SUBSTITUTE(a,b,c,d,e,f,g,h,i,j,k,l) \
+  a = pcre2_substitute_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h, \
+    (PCRE2_SPTR8)i,j,(PCRE2_UCHAR8 *)k,l)
+#define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \
+  a = pcre2_substring_copy_byname_8(G(b,8),G(c,8),(PCRE2_UCHAR8 *)d,e)
+#define PCRE2_SUBSTRING_COPY_BYNUMBER(a,b,c,d,e) \
+  a = pcre2_substring_copy_bynumber_8(G(b,8),c,(PCRE2_UCHAR8 *)d,e)
+#define PCRE2_SUBSTRING_FREE(a) pcre2_substring_free_8((PCRE2_UCHAR8 *)a)
+#define PCRE2_SUBSTRING_GET_BYNAME(a,b,c,d,e) \
+  a = pcre2_substring_get_byname_8(G(b,8),G(c,8),(PCRE2_UCHAR8 **)d,e)
+#define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \
+  a = pcre2_substring_get_bynumber_8(G(b,8),c,(PCRE2_UCHAR8 **)d,e)
+#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \
+    a = pcre2_substring_length_byname_8(G(b,8),G(c,8),d)
+#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \
+    a = pcre2_substring_length_bynumber_8(G(b,8),c,d)
+#define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \
+  a = pcre2_substring_list_get_8(G(b,8),(PCRE2_UCHAR8 ***)c,d)
+#define PCRE2_SUBSTRING_LIST_FREE(a) \
+  pcre2_substring_list_free_8((PCRE2_SPTR8 *)a)
+#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \
+  a = pcre2_substring_number_from_name_8(G(b,8),G(c,8));
+#define PTR(x) (void *)G(x,8)
+#define SETFLD(x,y,z) G(x,8)->y = z
+#define SETFLDVEC(x,y,v,z) G(x,8)->y[v] = z
+#define SETOP(x,y,z) G(x,8) z y
+#define SETCASTPTR(x,y) G(x,8) = (uint8_t *)(y)
+#define STRLEN(p) (int)strlen((char *)p)
+#define SUB1(a,b) G(a,8)(G(b,8))
+#define SUB2(a,b,c) G(a,8)(G(b,8),G(c,8))
+#define TEST(x,r,y) (G(x,8) r (y))
+#define TESTFLD(x,f,r,y) (G(x,8)->f r (y))
+
+
+/* ----- Only 16-bit mode is supported ----- */
+
+#elif defined SUPPORT_PCRE2_16
+#define CASTFLD(t,a,b) (t)(G(a,16)->b)
+#define CASTVAR(t,x) (t)G(x,16)
+#define CODE_UNIT(a,b) (uint32_t)(((PCRE2_SPTR16)(a))[b])
+#define CONCTXCPY(a,b) memcpy(G(a,16),G(b,16),sizeof(pcre2_convert_context_16))
+#define CONVERT_COPY(a,b,c) memcpy(G(a,16),(char *)b, (c)*2)
+#define DATCTXCPY(a,b) memcpy(G(a,16),G(b,16),sizeof(pcre2_match_context_16))
+#define FLD(a,b) G(a,16)->b
+#define PATCTXCPY(a,b) memcpy(G(a,16),G(b,16),sizeof(pcre2_compile_context_16))
+#define PCHARS(lv, p, offset, len, utf, f) \
+  lv = pchars16((PCRE2_SPTR16)(p)+offset, len, utf, f)
+#define PCHARSV(p, offset, len, utf, f) \
+  (void)pchars16((PCRE2_SPTR16)(p)+offset, len, utf, f)
+#define PCRE2_CALLOUT_ENUMERATE(a,b,c) \
+   a = pcre2_callout_enumerate_16(compiled_code16, \
+     (int (*)(struct pcre2_callout_enumerate_block_16 *, void *))b,c)
+#define PCRE2_CODE_COPY_FROM_VOID(a,b) G(a,16) = pcre2_code_copy_16(b)
+#define PCRE2_CODE_COPY_TO_VOID(a,b) a = (void *)pcre2_code_copy_16(G(b,16))
+#define PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(a,b) a = (void *)pcre2_code_copy_with_tables_16(G(b,16))
+#define PCRE2_COMPILE(a,b,c,d,e,f,g) \
+  G(a,16) = pcre2_compile_16(G(b,16),c,d,e,f,g)
+#define PCRE2_CONVERTED_PATTERN_FREE(a) \
+  pcre2_converted_pattern_free_16((PCRE2_UCHAR16 *)a)
+#define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \
+  a = pcre2_dfa_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h,i,j)
+#define PCRE2_GET_ERROR_MESSAGE(r,a,b) \
+  r = pcre2_get_error_message_16(a,G(b,16),G(G(b,16),_size/2))
+#define PCRE2_GET_OVECTOR_COUNT(a,b) a = pcre2_get_ovector_count_16(G(b,16))
+#define PCRE2_GET_STARTCHAR(a,b) a = pcre2_get_startchar_16(G(b,16))
+#define PCRE2_JIT_COMPILE(r,a,b) r = pcre2_jit_compile_16(G(a,16),b)
+#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) pcre2_jit_free_unused_memory_16(G(a,16))
+#define PCRE2_JIT_MATCH(a,b,c,d,e,f,g,h) \
+  a = pcre2_jit_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h)
+#define PCRE2_JIT_STACK_CREATE(a,b,c,d) \
+  a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_16(b,c,d);
+#define PCRE2_JIT_STACK_ASSIGN(a,b,c) \
+  pcre2_jit_stack_assign_16(G(a,16),(pcre2_jit_callback_16)b,c);
+#define PCRE2_JIT_STACK_FREE(a) pcre2_jit_stack_free_16((pcre2_jit_stack_16 *)a);
+#define PCRE2_MAKETABLES(a) a = pcre2_maketables_16(NULL)
+#define PCRE2_MATCH(a,b,c,d,e,f,g,h) \
+  a = pcre2_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h)
+#define PCRE2_MATCH_DATA_CREATE(a,b,c) G(a,16) = pcre2_match_data_create_16(b,c)
+#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \
+  G(a,16) = pcre2_match_data_create_from_pattern_16(G(b,16),c)
+#define PCRE2_MATCH_DATA_FREE(a) pcre2_match_data_free_16(G(a,16))
+#define PCRE2_PATTERN_CONVERT(a,b,c,d,e,f,g) a = pcre2_pattern_convert_16(G(b,16),c,d,(PCRE2_UCHAR16 **)e,f,G(g,16))
+#define PCRE2_PATTERN_INFO(a,b,c,d) a = pcre2_pattern_info_16(G(b,16),c,d)
+#define PCRE2_PRINTINT(a) pcre2_printint_16(compiled_code16,outfile,a)
+#define PCRE2_SERIALIZE_DECODE(r,a,b,c,d) \
+  r = pcre2_serialize_decode_16((pcre2_code_16 **)a,b,c,G(d,16))
+#define PCRE2_SERIALIZE_ENCODE(r,a,b,c,d,e) \
+  r = pcre2_serialize_encode_16((const pcre2_code_16 **)a,b,c,d,G(e,16))
+#define PCRE2_SERIALIZE_FREE(a) pcre2_serialize_free_16(a)
+#define PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(r,a) \
+  r = pcre2_serialize_get_number_of_codes_16(a)
+#define PCRE2_SET_CALLOUT(a,b,c) \
+  pcre2_set_callout_16(G(a,16),(int (*)(pcre2_callout_block_16 *, void *))b,c);
+#define PCRE2_SET_CHARACTER_TABLES(a,b) pcre2_set_character_tables_16(G(a,16),b)
+#define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b,c) \
+  pcre2_set_compile_recursion_guard_16(G(a,16),b,c)
+#define PCRE2_SET_DEPTH_LIMIT(a,b) pcre2_set_depth_limit_16(G(a,16),b)
+#define PCRE2_SET_GLOB_ESCAPE(r,a,b) r = pcre2_set_glob_escape_16(G(a,16),b)
+#define PCRE2_SET_GLOB_SEPARATOR(r,a,b) r = pcre2_set_glob_separator_16(G(a,16),b)
+#define PCRE2_SET_HEAP_LIMIT(a,b) pcre2_set_heap_limit_16(G(a,16),b)
+#define PCRE2_SET_MATCH_LIMIT(a,b) pcre2_set_match_limit_16(G(a,16),b)
+#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) pcre2_set_max_pattern_length_16(G(a,16),b)
+#define PCRE2_SET_OFFSET_LIMIT(a,b) pcre2_set_offset_limit_16(G(a,16),b)
+#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) pcre2_set_parens_nest_limit_16(G(a,16),b)
+#define PCRE2_SET_SUBSTITUTE_CALLOUT(a,b,c) \
+  pcre2_set_substitute_callout_16(G(a,16), \
+    (int (*)(pcre2_substitute_callout_block_16 *, void *))b,c)
+#define PCRE2_SUBSTITUTE(a,b,c,d,e,f,g,h,i,j,k,l) \
+  a = pcre2_substitute_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h, \
+    (PCRE2_SPTR16)i,j,(PCRE2_UCHAR16 *)k,l)
+#define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \
+  a = pcre2_substring_copy_byname_16(G(b,16),G(c,16),(PCRE2_UCHAR16 *)d,e)
+#define PCRE2_SUBSTRING_COPY_BYNUMBER(a,b,c,d,e) \
+  a = pcre2_substring_copy_bynumber_16(G(b,16),c,(PCRE2_UCHAR16 *)d,e)
+#define PCRE2_SUBSTRING_FREE(a) pcre2_substring_free_16((PCRE2_UCHAR16 *)a)
+#define PCRE2_SUBSTRING_GET_BYNAME(a,b,c,d,e) \
+  a = pcre2_substring_get_byname_16(G(b,16),G(c,16),(PCRE2_UCHAR16 **)d,e)
+#define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \
+  a = pcre2_substring_get_bynumber_16(G(b,16),c,(PCRE2_UCHAR16 **)d,e)
+#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \
+    a = pcre2_substring_length_byname_16(G(b,16),G(c,16),d)
+#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \
+    a = pcre2_substring_length_bynumber_16(G(b,16),c,d)
+#define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \
+  a = pcre2_substring_list_get_16(G(b,16),(PCRE2_UCHAR16 ***)c,d)
+#define PCRE2_SUBSTRING_LIST_FREE(a) \
+  pcre2_substring_list_free_16((PCRE2_SPTR16 *)a)
+#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \
+  a = pcre2_substring_number_from_name_16(G(b,16),G(c,16));
+#define PTR(x) (void *)G(x,16)
+#define SETFLD(x,y,z) G(x,16)->y = z
+#define SETFLDVEC(x,y,v,z) G(x,16)->y[v] = z
+#define SETOP(x,y,z) G(x,16) z y
+#define SETCASTPTR(x,y) G(x,16) = (uint16_t *)(y)
+#define STRLEN(p) (int)strlen16((PCRE2_SPTR16)p)
+#define SUB1(a,b) G(a,16)(G(b,16))
+#define SUB2(a,b,c) G(a,16)(G(b,16),G(c,16))
+#define TEST(x,r,y) (G(x,16) r (y))
+#define TESTFLD(x,f,r,y) (G(x,16)->f r (y))
+
+
+/* ----- Only 32-bit mode is supported ----- */
+
+#elif defined SUPPORT_PCRE2_32
+#define CASTFLD(t,a,b) (t)(G(a,32)->b)
+#define CASTVAR(t,x) (t)G(x,32)
+#define CODE_UNIT(a,b) (uint32_t)(((PCRE2_SPTR32)(a))[b])
+#define CONCTXCPY(a,b) memcpy(G(a,32),G(b,32),sizeof(pcre2_convert_context_32))
+#define CONVERT_COPY(a,b,c) memcpy(G(a,32),(char *)b, (c)*4)
+#define DATCTXCPY(a,b) memcpy(G(a,32),G(b,32),sizeof(pcre2_match_context_32))
+#define FLD(a,b) G(a,32)->b
+#define PATCTXCPY(a,b) memcpy(G(a,32),G(b,32),sizeof(pcre2_compile_context_32))
+#define PCHARS(lv, p, offset, len, utf, f) \
+  lv = pchars32((PCRE2_SPTR32)(p)+offset, len, utf, f)
+#define PCHARSV(p, offset, len, utf, f) \
+  (void)pchars32((PCRE2_SPTR32)(p)+offset, len, utf, f)
+#define PCRE2_CALLOUT_ENUMERATE(a,b,c) \
+   a = pcre2_callout_enumerate_32(compiled_code32, \
+     (int (*)(struct pcre2_callout_enumerate_block_32 *, void *))b,c)
+#define PCRE2_CODE_COPY_FROM_VOID(a,b) G(a,32) = pcre2_code_copy_32(b)
+#define PCRE2_CODE_COPY_TO_VOID(a,b) a = (void *)pcre2_code_copy_32(G(b,32))
+#define PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(a,b) a = (void *)pcre2_code_copy_with_tables_32(G(b,32))
+#define PCRE2_COMPILE(a,b,c,d,e,f,g) \
+  G(a,32) = pcre2_compile_32(G(b,32),c,d,e,f,g)
+#define PCRE2_CONVERTED_PATTERN_FREE(a) \
+  pcre2_converted_pattern_free_32((PCRE2_UCHAR32 *)a)
+#define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \
+  a = pcre2_dfa_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h,i,j)
+#define PCRE2_GET_ERROR_MESSAGE(r,a,b) \
+  r = pcre2_get_error_message_32(a,G(b,32),G(G(b,32),_size/4))
+#define PCRE2_GET_OVECTOR_COUNT(a,b) a = pcre2_get_ovector_count_32(G(b,32))
+#define PCRE2_GET_STARTCHAR(a,b) a = pcre2_get_startchar_32(G(b,32))
+#define PCRE2_JIT_COMPILE(r,a,b) r = pcre2_jit_compile_32(G(a,32),b)
+#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) pcre2_jit_free_unused_memory_32(G(a,32))
+#define PCRE2_JIT_MATCH(a,b,c,d,e,f,g,h) \
+  a = pcre2_jit_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h)
+#define PCRE2_JIT_STACK_CREATE(a,b,c,d) \
+  a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_32(b,c,d);
+#define PCRE2_JIT_STACK_ASSIGN(a,b,c) \
+  pcre2_jit_stack_assign_32(G(a,32),(pcre2_jit_callback_32)b,c);
+#define PCRE2_JIT_STACK_FREE(a) pcre2_jit_stack_free_32((pcre2_jit_stack_32 *)a);
+#define PCRE2_MAKETABLES(a) a = pcre2_maketables_32(NULL)
+#define PCRE2_MATCH(a,b,c,d,e,f,g,h) \
+  a = pcre2_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h)
+#define PCRE2_MATCH_DATA_CREATE(a,b,c) G(a,32) = pcre2_match_data_create_32(b,c)
+#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \
+  G(a,32) = pcre2_match_data_create_from_pattern_32(G(b,32),c)
+#define PCRE2_MATCH_DATA_FREE(a) pcre2_match_data_free_32(G(a,32))
+#define PCRE2_PATTERN_CONVERT(a,b,c,d,e,f,g) a = pcre2_pattern_convert_32(G(b,32),c,d,(PCRE2_UCHAR32 **)e,f,G(g,32))
+#define PCRE2_PATTERN_INFO(a,b,c,d) a = pcre2_pattern_info_32(G(b,32),c,d)
+#define PCRE2_PRINTINT(a) pcre2_printint_32(compiled_code32,outfile,a)
+#define PCRE2_SERIALIZE_DECODE(r,a,b,c,d) \
+  r = pcre2_serialize_decode_32((pcre2_code_32 **)a,b,c,G(d,32))
+#define PCRE2_SERIALIZE_ENCODE(r,a,b,c,d,e) \
+  r = pcre2_serialize_encode_32((const pcre2_code_32 **)a,b,c,d,G(e,32))
+#define PCRE2_SERIALIZE_FREE(a) pcre2_serialize_free_32(a)
+#define PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(r,a) \
+  r = pcre2_serialize_get_number_of_codes_32(a)
+#define PCRE2_SET_CALLOUT(a,b,c) \
+  pcre2_set_callout_32(G(a,32),(int (*)(pcre2_callout_block_32 *, void *))b,c)
+#define PCRE2_SET_CHARACTER_TABLES(a,b) pcre2_set_character_tables_32(G(a,32),b)
+#define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b,c) \
+  pcre2_set_compile_recursion_guard_32(G(a,32),b,c)
+#define PCRE2_SET_DEPTH_LIMIT(a,b) pcre2_set_depth_limit_32(G(a,32),b)
+#define PCRE2_SET_GLOB_ESCAPE(r,a,b) r = pcre2_set_glob_escape_32(G(a,32),b)
+#define PCRE2_SET_GLOB_SEPARATOR(r,a,b) r = pcre2_set_glob_separator_32(G(a,32),b)
+#define PCRE2_SET_HEAP_LIMIT(a,b) pcre2_set_heap_limit_32(G(a,32),b)
+#define PCRE2_SET_MATCH_LIMIT(a,b) pcre2_set_match_limit_32(G(a,32),b)
+#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) pcre2_set_max_pattern_length_32(G(a,32),b)
+#define PCRE2_SET_OFFSET_LIMIT(a,b) pcre2_set_offset_limit_32(G(a,32),b)
+#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) pcre2_set_parens_nest_limit_32(G(a,32),b)
+#define PCRE2_SET_SUBSTITUTE_CALLOUT(a,b,c) \
+  pcre2_set_substitute_callout_32(G(a,32), \
+    (int (*)(pcre2_substitute_callout_block_32 *, void *))b,c)
+#define PCRE2_SUBSTITUTE(a,b,c,d,e,f,g,h,i,j,k,l) \
+  a = pcre2_substitute_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h, \
+    (PCRE2_SPTR32)i,j,(PCRE2_UCHAR32 *)k,l)
+#define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \
+  a = pcre2_substring_copy_byname_32(G(b,32),G(c,32),(PCRE2_UCHAR32 *)d,e)
+#define PCRE2_SUBSTRING_COPY_BYNUMBER(a,b,c,d,e) \
+  a = pcre2_substring_copy_bynumber_32(G(b,32),c,(PCRE2_UCHAR32 *)d,e);
+#define PCRE2_SUBSTRING_FREE(a) pcre2_substring_free_32((PCRE2_UCHAR32 *)a)
+#define PCRE2_SUBSTRING_GET_BYNAME(a,b,c,d,e) \
+  a = pcre2_substring_get_byname_32(G(b,32),G(c,32),(PCRE2_UCHAR32 **)d,e)
+#define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \
+  a = pcre2_substring_get_bynumber_32(G(b,32),c,(PCRE2_UCHAR32 **)d,e)
+#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \
+    a = pcre2_substring_length_byname_32(G(b,32),G(c,32),d)
+#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \
+    a = pcre2_substring_length_bynumber_32(G(b,32),c,d)
+#define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \
+  a = pcre2_substring_list_get_32(G(b,32),(PCRE2_UCHAR32 ***)c,d)
+#define PCRE2_SUBSTRING_LIST_FREE(a) \
+  pcre2_substring_list_free_32((PCRE2_SPTR32 *)a)
+#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \
+  a = pcre2_substring_number_from_name_32(G(b,32),G(c,32));
+#define PTR(x) (void *)G(x,32)
+#define SETFLD(x,y,z) G(x,32)->y = z
+#define SETFLDVEC(x,y,v,z) G(x,32)->y[v] = z
+#define SETOP(x,y,z) G(x,32) z y
+#define SETCASTPTR(x,y) G(x,32) = (uint32_t *)(y)
+#define STRLEN(p) (int)strlen32((PCRE2_SPTR32)p)
+#define SUB1(a,b) G(a,32)(G(b,32))
+#define SUB2(a,b,c) G(a,32)(G(b,32),G(c,32))
+#define TEST(x,r,y) (G(x,32) r (y))
+#define TESTFLD(x,f,r,y) (G(x,32)->f r (y))
+
+#endif
+
+/* ----- End of mode-specific function call macros ----- */
+
+
+
+
+/*************************************************
+*         Alternate character tables             *
+*************************************************/
+
+/* By default, the "tables" pointer in the compile context when calling
+pcre2_compile() is not set (= NULL), thereby using the default tables of the
+library. However, the tables modifier can be used to select alternate sets of
+tables, for different kinds of testing. Note that the locale modifier also
+adjusts the tables. */
+
+/* This is the set of tables distributed as default with PCRE2. It recognizes
+only ASCII characters. */
+
+static const uint8_t tables1[] = {
+
+/* This table is a lower casing table. */
+
+    0,  1,  2,  3,  4,  5,  6,  7,
+    8,  9, 10, 11, 12, 13, 14, 15,
+   16, 17, 18, 19, 20, 21, 22, 23,
+   24, 25, 26, 27, 28, 29, 30, 31,
+   32, 33, 34, 35, 36, 37, 38, 39,
+   40, 41, 42, 43, 44, 45, 46, 47,
+   48, 49, 50, 51, 52, 53, 54, 55,
+   56, 57, 58, 59, 60, 61, 62, 63,
+   64, 97, 98, 99,100,101,102,103,
+  104,105,106,107,108,109,110,111,
+  112,113,114,115,116,117,118,119,
+  120,121,122, 91, 92, 93, 94, 95,
+   96, 97, 98, 99,100,101,102,103,
+  104,105,106,107,108,109,110,111,
+  112,113,114,115,116,117,118,119,
+  120,121,122,123,124,125,126,127,
+  128,129,130,131,132,133,134,135,
+  136,137,138,139,140,141,142,143,
+  144,145,146,147,148,149,150,151,
+  152,153,154,155,156,157,158,159,
+  160,161,162,163,164,165,166,167,
+  168,169,170,171,172,173,174,175,
+  176,177,178,179,180,181,182,183,
+  184,185,186,187,188,189,190,191,
+  192,193,194,195,196,197,198,199,
+  200,201,202,203,204,205,206,207,
+  208,209,210,211,212,213,214,215,
+  216,217,218,219,220,221,222,223,
+  224,225,226,227,228,229,230,231,
+  232,233,234,235,236,237,238,239,
+  240,241,242,243,244,245,246,247,
+  248,249,250,251,252,253,254,255,
+
+/* This table is a case flipping table. */
+
+    0,  1,  2,  3,  4,  5,  6,  7,
+    8,  9, 10, 11, 12, 13, 14, 15,
+   16, 17, 18, 19, 20, 21, 22, 23,
+   24, 25, 26, 27, 28, 29, 30, 31,
+   32, 33, 34, 35, 36, 37, 38, 39,
+   40, 41, 42, 43, 44, 45, 46, 47,
+   48, 49, 50, 51, 52, 53, 54, 55,
+   56, 57, 58, 59, 60, 61, 62, 63,
+   64, 97, 98, 99,100,101,102,103,
+  104,105,106,107,108,109,110,111,
+  112,113,114,115,116,117,118,119,
+  120,121,122, 91, 92, 93, 94, 95,
+   96, 65, 66, 67, 68, 69, 70, 71,
+   72, 73, 74, 75, 76, 77, 78, 79,
+   80, 81, 82, 83, 84, 85, 86, 87,
+   88, 89, 90,123,124,125,126,127,
+  128,129,130,131,132,133,134,135,
+  136,137,138,139,140,141,142,143,
+  144,145,146,147,148,149,150,151,
+  152,153,154,155,156,157,158,159,
+  160,161,162,163,164,165,166,167,
+  168,169,170,171,172,173,174,175,
+  176,177,178,179,180,181,182,183,
+  184,185,186,187,188,189,190,191,
+  192,193,194,195,196,197,198,199,
+  200,201,202,203,204,205,206,207,
+  208,209,210,211,212,213,214,215,
+  216,217,218,219,220,221,222,223,
+  224,225,226,227,228,229,230,231,
+  232,233,234,235,236,237,238,239,
+  240,241,242,243,244,245,246,247,
+  248,249,250,251,252,253,254,255,
+
+/* This table contains bit maps for various character classes. Each map is 32
+bytes long and the bits run from the least significant end of each byte. The
+classes that have their own maps are: space, xdigit, digit, upper, lower, word,
+graph, print, punct, and cntrl. Other classes are built from combinations. */
+
+  0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
+  0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
+  0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc,
+  0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+/* This table identifies various classes of character by individual bits:
+  0x01   white space character
+  0x02   letter
+  0x04   decimal digit
+  0x08   hexadecimal digit
+  0x10   alphanumeric or '_'
+  0x80   regular expression metacharacter or binary zero
+*/
+
+  0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*   0-  7 */
+  0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00, /*   8- 15 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  16- 23 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  24- 31 */
+  0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /*    - '  */
+  0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x00, /*  ( - /  */
+  0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /*  0 - 7  */
+  0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x80, /*  8 - ?  */
+  0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /*  @ - G  */
+  0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /*  H - O  */
+  0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /*  P - W  */
+  0x12,0x12,0x12,0x80,0x80,0x00,0x80,0x10, /*  X - _  */
+  0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /*  ` - g  */
+  0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /*  h - o  */
+  0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /*  p - w  */
+  0x12,0x12,0x12,0x80,0x80,0x00,0x00,0x00, /*  x -127 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */
+
+/* This is a set of tables that came originally from a Windows user. It seems
+to be at least an approximation of ISO 8859. In particular, there are
+characters greater than 128 that are marked as spaces, letters, etc. */
+
+static const uint8_t tables2[] = {
+0,1,2,3,4,5,6,7,
+8,9,10,11,12,13,14,15,
+16,17,18,19,20,21,22,23,
+24,25,26,27,28,29,30,31,
+32,33,34,35,36,37,38,39,
+40,41,42,43,44,45,46,47,
+48,49,50,51,52,53,54,55,
+56,57,58,59,60,61,62,63,
+64,97,98,99,100,101,102,103,
+104,105,106,107,108,109,110,111,
+112,113,114,115,116,117,118,119,
+120,121,122,91,92,93,94,95,
+96,97,98,99,100,101,102,103,
+104,105,106,107,108,109,110,111,
+112,113,114,115,116,117,118,119,
+120,121,122,123,124,125,126,127,
+128,129,130,131,132,133,134,135,
+136,137,138,139,140,141,142,143,
+144,145,146,147,148,149,150,151,
+152,153,154,155,156,157,158,159,
+160,161,162,163,164,165,166,167,
+168,169,170,171,172,173,174,175,
+176,177,178,179,180,181,182,183,
+184,185,186,187,188,189,190,191,
+224,225,226,227,228,229,230,231,
+232,233,234,235,236,237,238,239,
+240,241,242,243,244,245,246,215,
+248,249,250,251,252,253,254,223,
+224,225,226,227,228,229,230,231,
+232,233,234,235,236,237,238,239,
+240,241,242,243,244,245,246,247,
+248,249,250,251,252,253,254,255,
+0,1,2,3,4,5,6,7,
+8,9,10,11,12,13,14,15,
+16,17,18,19,20,21,22,23,
+24,25,26,27,28,29,30,31,
+32,33,34,35,36,37,38,39,
+40,41,42,43,44,45,46,47,
+48,49,50,51,52,53,54,55,
+56,57,58,59,60,61,62,63,
+64,97,98,99,100,101,102,103,
+104,105,106,107,108,109,110,111,
+112,113,114,115,116,117,118,119,
+120,121,122,91,92,93,94,95,
+96,65,66,67,68,69,70,71,
+72,73,74,75,76,77,78,79,
+80,81,82,83,84,85,86,87,
+88,89,90,123,124,125,126,127,
+128,129,130,131,132,133,134,135,
+136,137,138,139,140,141,142,143,
+144,145,146,147,148,149,150,151,
+152,153,154,155,156,157,158,159,
+160,161,162,163,164,165,166,167,
+168,169,170,171,172,173,174,175,
+176,177,178,179,180,181,182,183,
+184,185,186,187,188,189,190,191,
+224,225,226,227,228,229,230,231,
+232,233,234,235,236,237,238,239,
+240,241,242,243,244,245,246,215,
+248,249,250,251,252,253,254,223,
+192,193,194,195,196,197,198,199,
+200,201,202,203,204,205,206,207,
+208,209,210,211,212,213,214,247,
+216,217,218,219,220,221,222,255,
+0,62,0,0,1,0,0,0,
+0,0,0,0,0,0,0,0,
+32,0,0,0,1,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,255,3,
+126,0,0,0,126,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,255,3,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,12,2,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+254,255,255,7,0,0,0,0,
+0,0,0,0,0,0,0,0,
+255,255,127,127,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,254,255,255,7,
+0,0,0,0,0,4,32,4,
+0,0,0,128,255,255,127,255,
+0,0,0,0,0,0,255,3,
+254,255,255,135,254,255,255,7,
+0,0,0,0,0,4,44,6,
+255,255,127,255,255,255,127,255,
+0,0,0,0,254,255,255,255,
+255,255,255,255,255,255,255,127,
+0,0,0,0,254,255,255,255,
+255,255,255,255,255,255,255,255,
+0,2,0,0,255,255,255,255,
+255,255,255,255,255,255,255,127,
+0,0,0,0,255,255,255,255,
+255,255,255,255,255,255,255,255,
+0,0,0,0,254,255,0,252,
+1,0,0,248,1,0,0,120,
+0,0,0,0,254,255,255,255,
+0,0,128,0,0,0,128,0,
+255,255,255,255,0,0,0,0,
+0,0,0,0,0,0,0,128,
+255,255,255,255,0,0,0,0,
+0,0,0,0,0,0,0,0,
+128,0,0,0,0,0,0,0,
+0,1,1,0,1,1,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+1,0,0,0,128,0,0,0,
+128,128,128,128,0,0,128,0,
+28,28,28,28,28,28,28,28,
+28,28,0,0,0,0,0,128,
+0,26,26,26,26,26,26,18,
+18,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,18,
+18,18,18,128,128,0,128,16,
+0,26,26,26,26,26,26,18,
+18,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,18,
+18,18,18,128,128,0,0,0,
+0,0,0,0,0,1,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+1,0,0,0,0,0,0,0,
+0,0,18,0,0,0,0,0,
+0,0,20,20,0,18,0,0,
+0,20,18,0,0,0,0,0,
+18,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,0,
+18,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,0,
+18,18,18,18,18,18,18,18
+};
+
+
+
+#if !defined(VPCOMPAT) && !defined(HAVE_MEMMOVE)
+/*************************************************
+*    Emulated memmove() for systems without it   *
+*************************************************/
+
+/* This function can make use of bcopy() if it is available. Otherwise do it by
+steam, as there are some non-Unix environments that lack both memmove() and
+bcopy(). */
+
+static void *
+emulated_memmove(void *d, const void *s, size_t n)
+{
+#ifdef HAVE_BCOPY
+bcopy(s, d, n);
+return d;
+#else
+size_t i;
+unsigned char *dest = (unsigned char *)d;
+const unsigned char *src = (const unsigned char *)s;
+if (dest > src)
+  {
+  dest += n;
+  src += n;
+  for (i = 0; i < n; ++i) *(--dest) = *(--src);
+  return (void *)dest;
+  }
+else
+  {
+  for (i = 0; i < n; ++i) *dest++ = *src++;
+  return (void *)(dest - n);
+  }
+#endif   /* not HAVE_BCOPY */
+}
+#undef memmove
+#define memmove(d,s,n) emulated_memmove(d,s,n)
+#endif   /* not VPCOMPAT && not HAVE_MEMMOVE */
+
+
+
+#ifndef HAVE_STRERROR
+/*************************************************
+*     Provide strerror() for non-ANSI libraries  *
+*************************************************/
+
+/* Some old-fashioned systems (e.g. SunOS4) didn't have strerror() in their
+libraries. They may no longer be around, but just in case, we can try to
+provide the same facility by this simple alternative function. */
+
+extern int   sys_nerr;
+extern char *sys_errlist[];
+
+char *
+strerror(int n)
+{
+if (n < 0 || n >= sys_nerr) return "unknown error number";
+return sys_errlist[n];
+}
+#endif /* HAVE_STRERROR */
+
+
+
+/*************************************************
+*            Local memory functions              *
+*************************************************/
+
+/* Alternative memory functions, to test functionality. */
+
+static void *my_malloc(PCRE2_SIZE size, void *data)
+{
+void *block = malloc(size);
+(void)data;
+if (show_memory)
+  {
+  if (block == NULL)
+    {
+    fprintf(outfile, "** malloc() failed for %" SIZ_FORM "\n", SIZ_CAST size);
+    }
+  else
+    {
+    fprintf(outfile, "malloc  %5" SIZ_FORM, SIZ_CAST size);
+#ifdef DEBUG_SHOW_MALLOC_ADDRESSES
+    fprintf(outfile, " %p", block);   /* Not portable */
+#endif
+    if (malloclistptr < MALLOCLISTSIZE)
+      {
+      malloclist[malloclistptr] = block;
+      malloclistlength[malloclistptr++] = size;
+      }
+    else
+      fprintf(outfile, " (not remembered)");
+    fprintf(outfile, "\n");
+    }
+  }
+return block;
+}
+
+static void my_free(void *block, void *data)
+{
+(void)data;
+if (show_memory)
+  {
+  uint32_t i, j;
+  BOOL found = FALSE;
+
+  fprintf(outfile, "free");
+  for (i = 0; i < malloclistptr; i++)
+    {
+    if (block == malloclist[i])
+      {
+      fprintf(outfile, "    %5" SIZ_FORM, SIZ_CAST malloclistlength[i]);
+      malloclistptr--;
+      for (j = i; j < malloclistptr; j++)
+        {
+        malloclist[j] = malloclist[j+1];
+        malloclistlength[j] = malloclistlength[j+1];
+        }
+      found = TRUE;
+      break;
+      }
+    }
+  if (!found) fprintf(outfile, " unremembered block");
+#ifdef DEBUG_SHOW_MALLOC_ADDRESSES
+  fprintf(outfile, " %p", block);  /* Not portable */
+#endif
+  fprintf(outfile, "\n");
+  }
+free(block);
+}
+
+
+
+/*************************************************
+*       Callback function for stack guard        *
+*************************************************/
+
+/* This is set up to be called from pcre2_compile() when the stackguard=n
+modifier sets a value greater than zero. The test we do is whether the
+parenthesis nesting depth is greater than the value set by the modifier.
+
+Argument:  the current parenthesis nesting depth
+Returns:   non-zero to kill the compilation
+*/
+
+static int
+stack_guard(uint32_t depth, void *user_data)
+{
+(void)user_data;
+return depth > pat_patctl.stackguard_test;
+}
+
+
+/*************************************************
+*         JIT memory callback                    *
+*************************************************/
+
+static PCRE2_JIT_STACK*
+jit_callback(void *arg)
+{
+jit_was_used = TRUE;
+return (PCRE2_JIT_STACK *)arg;
+}
+
+
+/*************************************************
+*      Convert UTF-8 character to code point     *
+*************************************************/
+
+/* This function reads one or more bytes that represent a UTF-8 character,
+and returns the codepoint of that character. Note that the function supports
+the original UTF-8 definition of RFC 2279, allowing for values in the range 0
+to 0x7fffffff, up to 6 bytes long. This makes it possible to generate
+codepoints greater than 0x10ffff which are useful for testing PCRE2's error
+checking, and also for generating 32-bit non-UTF data values above the UTF
+limit.
+
+Argument:
+  utf8bytes   a pointer to the byte vector
+  vptr        a pointer to an int to receive the value
+
+Returns:      >  0 => the number of bytes consumed
+              -6 to 0 => malformed UTF-8 character at offset = (-return)
+*/
+
+static int
+utf82ord(PCRE2_SPTR8 utf8bytes, uint32_t *vptr)
+{
+uint32_t c = *utf8bytes++;
+uint32_t d = c;
+int i, j, s;
+
+for (i = -1; i < 6; i++)               /* i is number of additional bytes */
+  {
+  if ((d & 0x80) == 0) break;
+  d <<= 1;
+  }
+
+if (i == -1) { *vptr = c; return 1; }  /* ascii character */
+if (i == 0 || i == 6) return 0;        /* invalid UTF-8 */
+
+/* i now has a value in the range 1-5 */
+
+s = 6*i;
+d = (c & utf8_table3[i]) << s;
+
+for (j = 0; j < i; j++)
+  {
+  c = *utf8bytes++;
+  if ((c & 0xc0) != 0x80) return -(j+1);
+  s -= 6;
+  d |= (c & 0x3f) << s;
+  }
+
+/* Check that encoding was the correct unique one */
+
+for (j = 0; j < utf8_table1_size; j++)
+  if (d <= (uint32_t)utf8_table1[j]) break;
+if (j != i) return -(i+1);
+
+/* Valid value */
+
+*vptr = d;
+return i+1;
+}
+
+
+
+/*************************************************
+*             Print one character                *
+*************************************************/
+
+/* Print a single character either literally, or as a hex escape, and count how
+many printed characters are used.
+
+Arguments:
+  c            the character
+  utf          TRUE in UTF mode
+  f            the FILE to print to, or NULL just to count characters
+
+Returns:       number of characters written
+*/
+
+static int
+pchar(uint32_t c, BOOL utf, FILE *f)
+{
+int n = 0;
+char tempbuffer[16];
+
+if (PRINTOK(c))
+  {
+  if (f != NULL) fprintf(f, "%c", c);
+  return 1;
+  }
+
+if (c < 0x100)
+  {
+  if (utf)
+    {
+    if (f != NULL) fprintf(f, "\\x{%02x}", c);
+    return 6;
+    }
+  else
+    {
+    if (f != NULL) fprintf(f, "\\x%02x", c);
+    return 4;
+    }
+  }
+
+if (f != NULL) n = fprintf(f, "\\x{%02x}", c);
+  else n = sprintf(tempbuffer, "\\x{%02x}", c);
+
+return n >= 0 ? n : 0;
+}
+
+
+
+#ifdef SUPPORT_PCRE2_16
+/*************************************************
+*    Find length of 0-terminated 16-bit string   *
+*************************************************/
+
+static size_t strlen16(PCRE2_SPTR16 p)
+{
+PCRE2_SPTR16 pp = p;
+while (*pp != 0) pp++;
+return (int)(pp - p);
+}
+#endif  /* SUPPORT_PCRE2_16 */
+
+
+
+#ifdef SUPPORT_PCRE2_32
+/*************************************************
+*    Find length of 0-terminated 32-bit string   *
+*************************************************/
+
+static size_t strlen32(PCRE2_SPTR32 p)
+{
+PCRE2_SPTR32 pp = p;
+while (*pp != 0) pp++;
+return (int)(pp - p);
+}
+#endif  /* SUPPORT_PCRE2_32 */
+
+
+#ifdef SUPPORT_PCRE2_8
+/*************************************************
+*         Print 8-bit character string           *
+*************************************************/
+
+/* Must handle UTF-8 strings in utf8 mode. Yields number of characters printed.
+For printing *MARK strings, a negative length is given, indicating that the
+length is in the first code unit. If handed a NULL file, this function just
+counts chars without printing (because pchar() does that). */
+
+static int pchars8(PCRE2_SPTR8 p, int length, BOOL utf, FILE *f)
+{
+uint32_t c = 0;
+int yield = 0;
+if (length < 0) length = *p++;
+while (length-- > 0)
+  {
+  if (utf)
+    {
+    int rc = utf82ord(p, &c);
+    if (rc > 0 && rc <= length + 1)   /* Mustn't run over the end */
+      {
+      length -= rc - 1;
+      p += rc;
+      yield += pchar(c, utf, f);
+      continue;
+      }
+    }
+  c = *p++;
+  yield += pchar(c, utf, f);
+  }
+
+return yield;
+}
+#endif
+
+
+#ifdef SUPPORT_PCRE2_16
+/*************************************************
+*           Print 16-bit character string        *
+*************************************************/
+
+/* Must handle UTF-16 strings in utf mode. Yields number of characters printed.
+For printing *MARK strings, a negative length is given, indicating that the
+length is in the first code unit. If handed a NULL file, just counts chars
+without printing. */
+
+static int pchars16(PCRE2_SPTR16 p, int length, BOOL utf, FILE *f)
+{
+int yield = 0;
+if (length < 0) length = *p++;
+while (length-- > 0)
+  {
+  uint32_t c = *p++ & 0xffff;
+  if (utf && c >= 0xD800 && c < 0xDC00 && length > 0)
+    {
+    int d = *p & 0xffff;
+    if (d >= 0xDC00 && d <= 0xDFFF)
+      {
+      c = ((c & 0x3ff) << 10) + (d & 0x3ff) + 0x10000;
+      length--;
+      p++;
+      }
+    }
+  yield += pchar(c, utf, f);
+  }
+return yield;
+}
+#endif  /* SUPPORT_PCRE2_16 */
+
+
+
+#ifdef SUPPORT_PCRE2_32
+/*************************************************
+*           Print 32-bit character string        *
+*************************************************/
+
+/* Must handle UTF-32 strings in utf mode. Yields number of characters printed.
+For printing *MARK strings, a negative length is given, indicating that the
+length is in the first code unit. If handed a NULL file, just counts chars
+without printing. */
+
+static int pchars32(PCRE2_SPTR32 p, int length, BOOL utf, FILE *f)
+{
+int yield = 0;
+(void)(utf);  /* Avoid compiler warning */
+if (length < 0) length = *p++;
+while (length-- > 0)
+  {
+  uint32_t c = *p++;
+  yield += pchar(c, utf, f);
+  }
+return yield;
+}
+#endif  /* SUPPORT_PCRE2_32 */
+
+
+
+
+/*************************************************
+*       Convert character value to UTF-8         *
+*************************************************/
+
+/* This function takes an integer value in the range 0 - 0x7fffffff
+and encodes it as a UTF-8 character in 0 to 6 bytes. It is needed even when the
+8-bit library is not supported, to generate UTF-8 output for non-ASCII
+characters.
+
+Arguments:
+  cvalue     the character value
+  utf8bytes  pointer to buffer for result - at least 6 bytes long
+
+Returns:     number of characters placed in the buffer
+*/
+
+static int
+ord2utf8(uint32_t cvalue, uint8_t *utf8bytes)
+{
+int i, j;
+if (cvalue > 0x7fffffffu)
+  return -1;
+for (i = 0; i < utf8_table1_size; i++)
+  if (cvalue <= (uint32_t)utf8_table1[i]) break;
+utf8bytes += i;
+for (j = i; j > 0; j--)
+ {
+ *utf8bytes-- = 0x80 | (cvalue & 0x3f);
+ cvalue >>= 6;
+ }
+*utf8bytes = utf8_table2[i] | cvalue;
+return i + 1;
+}
+
+
+
+#ifdef SUPPORT_PCRE2_16
+/*************************************************
+*           Convert string to 16-bit             *
+*************************************************/
+
+/* In UTF mode the input is always interpreted as a string of UTF-8 bytes using
+the original UTF-8 definition of RFC 2279, which allows for up to 6 bytes, and
+code values from 0 to 0x7fffffff. However, values greater than the later UTF
+limit of 0x10ffff cause an error. In non-UTF mode the input is interpreted as
+UTF-8 if the utf8_input modifier is set, but an error is generated for values
+greater than 0xffff.
+
+If all the input bytes are ASCII, the space needed for a 16-bit string is
+exactly double the 8-bit size. Otherwise, the size needed for a 16-bit string
+is no more than double, because up to 0xffff uses no more than 3 bytes in UTF-8
+but possibly 4 in UTF-16. Higher values use 4 bytes in UTF-8 and up to 4 bytes
+in UTF-16. The result is always left in pbuffer16. Impose a minimum size to
+save repeated re-sizing.
+
+Note that this function does not object to surrogate values. This is
+deliberate; it makes it possible to construct UTF-16 strings that are invalid,
+for the purpose of testing that they are correctly faulted.
+
+Arguments:
+  p          points to a byte string
+  utf        true in UTF mode
+  lenptr     points to number of bytes in the string (excluding trailing zero)
+
+Returns:     0 on success, with the length updated to the number of 16-bit
+               data items used (excluding the trailing zero)
+             OR -1 if a UTF-8 string is malformed
+             OR -2 if a value > 0x10ffff is encountered in UTF mode
+             OR -3 if a value > 0xffff is encountered when not in UTF mode
+*/
+
+static PCRE2_SIZE
+to16(uint8_t *p, int utf, PCRE2_SIZE *lenptr)
+{
+uint16_t *pp;
+PCRE2_SIZE len = *lenptr;
+
+if (pbuffer16_size < 2*len + 2)
+  {
+  if (pbuffer16 != NULL) free(pbuffer16);
+  pbuffer16_size = 2*len + 2;
+  if (pbuffer16_size < 4096) pbuffer16_size = 4096;
+  pbuffer16 = (uint16_t *)malloc(pbuffer16_size);
+  if (pbuffer16 == NULL)
+    {
+    fprintf(stderr, "pcre2test: malloc(%" SIZ_FORM ") failed for pbuffer16\n",
+      SIZ_CAST pbuffer16_size);
+    exit(1);
+    }
+  }
+
+pp = pbuffer16;
+if (!utf && (pat_patctl.control & CTL_UTF8_INPUT) == 0)
+  {
+  for (; len > 0; len--) *pp++ = *p++;
+  }
+else while (len > 0)
+  {
+  uint32_t c;
+  int chlen = utf82ord(p, &c);
+  if (chlen <= 0) return -1;
+  if (!utf && c > 0xffff) return -3;
+  if (c > 0x10ffff) return -2;
+  p += chlen;
+  len -= chlen;
+  if (c < 0x10000) *pp++ = c; else
+    {
+    c -= 0x10000;
+    *pp++ = 0xD800 | (c >> 10);
+    *pp++ = 0xDC00 | (c & 0x3ff);
+    }
+  }
+
+*pp = 0;
+*lenptr = pp - pbuffer16;
+return 0;
+}
+#endif
+
+
+
+#ifdef SUPPORT_PCRE2_32
+/*************************************************
+*           Convert string to 32-bit             *
+*************************************************/
+
+/* In UTF mode the input is always interpreted as a string of UTF-8 bytes using
+the original UTF-8 definition of RFC 2279, which allows for up to 6 bytes, and
+code values from 0 to 0x7fffffff. However, values greater than the later UTF
+limit of 0x10ffff cause an error.
+
+In non-UTF mode the input is interpreted as UTF-8 if the utf8_input modifier
+is set, and no limit is imposed. There is special interpretation of the 0xff
+byte (which is illegal in UTF-8) in this case: it causes the top bit of the
+next character to be set. This provides a way of generating 32-bit characters
+greater than 0x7fffffff.
+
+If all the input bytes are ASCII, the space needed for a 32-bit string is
+exactly four times the 8-bit size. Otherwise, the size needed for a 32-bit
+string is no more than four times, because the number of characters must be
+less than the number of bytes. The result is always left in pbuffer32. Impose a
+minimum size to save repeated re-sizing.
+
+Note that this function does not object to surrogate values. This is
+deliberate; it makes it possible to construct UTF-32 strings that are invalid,
+for the purpose of testing that they are correctly faulted.
+
+Arguments:
+  p          points to a byte string
+  utf        true in UTF mode
+  lenptr     points to number of bytes in the string (excluding trailing zero)
+
+Returns:     0 on success, with the length updated to the number of 32-bit
+               data items used (excluding the trailing zero)
+             OR -1 if a UTF-8 string is malformed
+             OR -2 if a value > 0x10ffff is encountered in UTF mode
+*/
+
+static PCRE2_SIZE
+to32(uint8_t *p, int utf, PCRE2_SIZE *lenptr)
+{
+uint32_t *pp;
+PCRE2_SIZE len = *lenptr;
+
+if (pbuffer32_size < 4*len + 4)
+  {
+  if (pbuffer32 != NULL) free(pbuffer32);
+  pbuffer32_size = 4*len + 4;
+  if (pbuffer32_size < 8192) pbuffer32_size = 8192;
+  pbuffer32 = (uint32_t *)malloc(pbuffer32_size);
+  if (pbuffer32 == NULL)
+    {
+    fprintf(stderr, "pcre2test: malloc(%" SIZ_FORM ") failed for pbuffer32\n",
+      SIZ_CAST pbuffer32_size);
+    exit(1);
+    }
+  }
+
+pp = pbuffer32;
+
+if (!utf && (pat_patctl.control & CTL_UTF8_INPUT) == 0)
+  {
+  for (; len > 0; len--) *pp++ = *p++;
+  }
+
+else while (len > 0)
+  {
+  int chlen;
+  uint32_t c;
+  uint32_t topbit = 0;
+  if (!utf && *p == 0xff && len > 1)
+    {
+    topbit = 0x80000000u;
+    p++;
+    len--;
+    }
+  chlen = utf82ord(p, &c);
+  if (chlen <= 0) return -1;
+  if (utf && c > 0x10ffff) return -2;
+  p += chlen;
+  len -= chlen;
+  *pp++ = c | topbit;
+  }
+
+*pp = 0;
+*lenptr = pp - pbuffer32;
+return 0;
+}
+#endif /* SUPPORT_PCRE2_32 */
+
+
+
+/* This function is no longer used. Keep it around for a while, just in case it
+needs to be re-instated. */
+
+#ifdef NEVERNEVERNEVER
+
+/*************************************************
+*         Move back by so many characters        *
+*************************************************/
+
+/* Given a code unit offset in a subject string, move backwards by a number of
+characters, and return the resulting offset.
+
+Arguments:
+  subject   pointer to the string
+  offset    start offset
+  count     count to move back by
+  utf       TRUE if in UTF mode
+
+Returns:   a possibly changed offset
+*/
+
+static PCRE2_SIZE
+backchars(uint8_t *subject, PCRE2_SIZE offset, uint32_t count, BOOL utf)
+{
+if (!utf || test_mode == PCRE32_MODE)
+  return (count >= offset)? 0 : (offset - count);
+
+else if (test_mode == PCRE8_MODE)
+  {
+  PCRE2_SPTR8 pp = (PCRE2_SPTR8)subject + offset;
+  for (; count > 0 && pp > (PCRE2_SPTR8)subject; count--)
+    {
+    pp--;
+    while ((*pp & 0xc0) == 0x80) pp--;
+    }
+  return pp - (PCRE2_SPTR8)subject;
+  }
+
+else  /* 16-bit mode */
+  {
+  PCRE2_SPTR16 pp = (PCRE2_SPTR16)subject + offset;
+  for (; count > 0 && pp > (PCRE2_SPTR16)subject; count--)
+    {
+    pp--;
+    if ((*pp & 0xfc00) == 0xdc00) pp--;
+    }
+  return pp - (PCRE2_SPTR16)subject;
+  }
+}
+#endif  /* NEVERNEVERNEVER */
+
+
+
+/*************************************************
+*           Expand input buffers                 *
+*************************************************/
+
+/* This function doubles the size of the input buffer and the buffer for
+keeping an 8-bit copy of patterns (pbuffer8), and copies the current buffers to
+the new ones.
+
+Arguments: none
+Returns:   nothing (aborts if malloc() fails)
+*/
+
+static void
+expand_input_buffers(void)
+{
+int new_pbuffer8_size = 2*pbuffer8_size;
+uint8_t *new_buffer = (uint8_t *)malloc(new_pbuffer8_size);
+uint8_t *new_pbuffer8 = (uint8_t *)malloc(new_pbuffer8_size);
+
+if (new_buffer == NULL || new_pbuffer8 == NULL)
+  {
+  fprintf(stderr, "pcre2test: malloc(%d) failed\n", new_pbuffer8_size);
+  exit(1);
+  }
+
+memcpy(new_buffer, buffer, pbuffer8_size);
+memcpy(new_pbuffer8, pbuffer8, pbuffer8_size);
+
+pbuffer8_size = new_pbuffer8_size;
+
+free(buffer);
+free(pbuffer8);
+
+buffer = new_buffer;
+pbuffer8 = new_pbuffer8;
+}
+
+
+
+/*************************************************
+*        Read or extend an input line            *
+*************************************************/
+
+/* Input lines are read into buffer, but both patterns and data lines can be
+continued over multiple input lines. In addition, if the buffer fills up, we
+want to automatically expand it so as to be able to handle extremely large
+lines that are needed for certain stress tests, although this is less likely
+now that there are repetition features for both patterns and data. When the
+input buffer is expanded, the other two buffers must also be expanded likewise,
+and the contents of pbuffer, which are a copy of the input for callouts, must
+be preserved (for when expansion happens for a data line). This is not the most
+optimal way of handling this, but hey, this is just a test program!
+
+Arguments:
+  f            the file to read
+  start        where in buffer to start (this *must* be within buffer)
+  prompt       for stdin or readline()
+
+Returns:       pointer to the start of new data
+               could be a copy of start, or could be moved
+               NULL if no data read and EOF reached
+*/
+
+static uint8_t *
+extend_inputline(FILE *f, uint8_t *start, const char *prompt)
+{
+uint8_t *here = start;
+
+for (;;)
+  {
+  size_t rlen = (size_t)(pbuffer8_size - (here - buffer));
+
+  if (rlen > 1000)
+    {
+    size_t dlen;
+
+    /* If libreadline or libedit support is required, use readline() to read a
+    line if the input is a terminal. Note that readline() removes the trailing
+    newline, so we must put it back again, to be compatible with fgets(). */
+
+#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT)
+    if (INTERACTIVE(f))
+      {
+      size_t len;
+      char *s = readline(prompt);
+      if (s == NULL) return (here == start)? NULL : start;
+      len = strlen(s);
+      if (len > 0) add_history(s);
+      if (len > rlen - 1) len = rlen - 1;
+      memcpy(here, s, len);
+      here[len] = '\n';
+      here[len+1] = 0;
+      free(s);
+      }
+    else
+#endif
+
+    /* Read the next line by normal means, prompting if the file is a tty. */
+
+      {
+      if (INTERACTIVE(f)) printf("%s", prompt);
+      if (fgets((char *)here, rlen,  f) == NULL)
+        return (here == start)? NULL : start;
+      }
+
+    dlen = strlen((char *)here);
+    here += dlen;
+
+    /* Check for end of line reached. Take care not to read data from before
+    start (dlen will be zero for a file starting with a binary zero). */
+
+    if (here > start && here[-1] == '\n') return start;
+
+    /* If we have not read a newline when reading a file, we have either filled
+    the buffer or reached the end of the file. We can detect the former by
+    checking that the string fills the buffer, and the latter by feof(). If
+    neither of these is true, it means we read a binary zero which has caused
+    strlen() to give a short length. This is a hard error because pcre2test
+    expects to work with C strings. */
+
+    if (!INTERACTIVE(f) && dlen < rlen - 1 && !feof(f))
+      {
+      fprintf(outfile, "** Binary zero encountered in input\n");
+      fprintf(outfile, "** pcre2test run abandoned\n");
+      exit(1);
+      }
+    }
+
+  else
+    {
+    size_t start_offset = start - buffer;
+    size_t here_offset = here - buffer;
+    expand_input_buffers();
+    start = buffer + start_offset;
+    here = buffer + here_offset;
+    }
+  }
+
+/* Control never gets here */
+}
+
+
+
+/*************************************************
+*         Case-independent strncmp() function    *
+*************************************************/
+
+/*
+Arguments:
+  s         first string
+  t         second string
+  n         number of characters to compare
+
+Returns:    < 0, = 0, or > 0, according to the comparison
+*/
+
+static int
+strncmpic(const uint8_t *s, const uint8_t *t, int n)
+{
+while (n--)
+  {
+  int c = tolower(*s++) - tolower(*t++);
+  if (c != 0) return c;
+  }
+return 0;
+}
+
+
+
+/*************************************************
+*          Scan the main modifier list           *
+*************************************************/
+
+/* This function searches the modifier list for a long modifier name.
+
+Argument:
+  p         start of the name
+  lenp      length of the name
+
+Returns:    an index in the modifier list, or -1 on failure
+*/
+
+static int
+scan_modifiers(const uint8_t *p, unsigned int len)
+{
+int bot = 0;
+int top = MODLISTCOUNT;
+
+while (top > bot)
+  {
+  int mid = (bot + top)/2;
+  unsigned int mlen = strlen(modlist[mid].name);
+  int c = strncmp((char *)p, modlist[mid].name, (len < mlen)? len : mlen);
+  if (c == 0)
+    {
+    if (len == mlen) return mid;
+    c = (int)len - (int)mlen;
+    }
+  if (c > 0) bot = mid + 1; else top = mid;
+  }
+
+return -1;
+
+}
+
+
+
+/*************************************************
+*        Check a modifer and find its field      *
+*************************************************/
+
+/* This function is called when a modifier has been identified. We check that
+it is allowed here and find the field that is to be changed.
+
+Arguments:
+  m          the modifier list entry
+  ctx        CTX_PAT     => pattern context
+             CTX_POPPAT  => pattern context for popped pattern
+             CTX_DEFPAT  => default pattern context
+             CTX_DAT     => data context
+             CTX_DEFDAT  => default data context
+  pctl       point to pattern control block
+  dctl       point to data control block
+  c          a single character or 0
+
+Returns:     a field pointer or NULL
+*/
+
+static void *
+check_modifier(modstruct *m, int ctx, patctl *pctl, datctl *dctl, uint32_t c)
+{
+void *field = NULL;
+PCRE2_SIZE offset = m->offset;
+
+if (restrict_for_perl_test) switch(m->which)
+  {
+  case MOD_PNDP:
+  case MOD_PATP:
+  case MOD_PDP:
+  break;
+
+  default:
+  fprintf(outfile, "** '%s' is not allowed in a Perl-compatible test\n",
+    m->name);
+  return NULL;
+  }
+
+switch (m->which)
+  {
+  case MOD_CTC:  /* Compile context modifier */
+  if (ctx == CTX_DEFPAT) field = PTR(default_pat_context);
+    else if (ctx == CTX_PAT) field = PTR(pat_context);
+  break;
+
+  case MOD_CTM:  /* Match context modifier */
+  if (ctx == CTX_DEFDAT) field = PTR(default_dat_context);
+    else if (ctx == CTX_DAT) field = PTR(dat_context);
+  break;
+
+  case MOD_DAT:  /* Data line modifier */
+  if (dctl != NULL) field = dctl;
+  break;
+
+  case MOD_PAT:    /* Pattern modifier */
+  case MOD_PATP:   /* Allowed for Perl test */
+  if (pctl != NULL) field = pctl;
+  break;
+
+  case MOD_PD:   /* Pattern or data line modifier */
+  case MOD_PDP:  /* Ditto, allowed for Perl test */
+  case MOD_PND:  /* Ditto, but not default pattern */
+  case MOD_PNDP: /* Ditto, allowed for Perl test */
+  if (dctl != NULL) field = dctl;
+    else if (pctl != NULL && (m->which == MOD_PD || m->which == MOD_PDP ||
+             ctx != CTX_DEFPAT))
+      field = pctl;
+  break;
+  }
+
+if (field == NULL)
+  {
+  if (c == 0)
+    fprintf(outfile, "** '%s' is not valid here\n", m->name);
+  else
+    fprintf(outfile, "** /%c is not valid here\n", c);
+  return NULL;
+  }
+
+return (char *)field + offset;
+}
+
+
+
+/*************************************************
+*            Decode a modifier list              *
+*************************************************/
+
+/* A pointer to a control block is NULL when called in cases when that block is
+not relevant. They are never all relevant in one call. At least one of patctl
+and datctl is NULL. The second argument specifies which context to use for
+modifiers that apply to contexts.
+
+Arguments:
+  p          point to modifier string
+  ctx        CTX_PAT     => pattern context
+             CTX_POPPAT  => pattern context for popped pattern
+             CTX_DEFPAT  => default pattern context
+             CTX_DAT     => data context
+             CTX_DEFDAT  => default data context
+  pctl       point to pattern control block
+  dctl       point to data control block
+
+Returns: TRUE if successful decode, FALSE otherwise
+*/
+
+static BOOL
+decode_modifiers(uint8_t *p, int ctx, patctl *pctl, datctl *dctl)
+{
+uint8_t *ep, *pp;
+long li;
+unsigned long uli;
+BOOL first = TRUE;
+
+for (;;)
+  {
+  void *field;
+  modstruct *m;
+  BOOL off = FALSE;
+  unsigned int i, len;
+  int index;
+  char *endptr;
+
+  /* Skip white space and commas. */
+
+  while (isspace(*p) || *p == ',') p++;
+  if (*p == 0) break;
+
+  /* Find the end of the item; lose trailing whitespace at end of line. */
+
+  for (ep = p; *ep != 0 && *ep != ','; ep++);
+  if (*ep == 0)
+    {
+    while (ep > p && isspace(ep[-1])) ep--;
+    *ep = 0;
+    }
+
+  /* Remember if the first character is '-'. */
+
+  if (*p == '-')
+    {
+    off = TRUE;
+    p++;
+    }
+
+  /* Find the length of a full-length modifier name, and scan for it. */
+
+  pp = p;
+  while (pp < ep && *pp != '=') pp++;
+  index = scan_modifiers(p, pp - p);
+
+  /* If the first modifier is unrecognized, try to interpret it as a sequence
+  of single-character abbreviated modifiers. None of these modifiers have any
+  associated data. They just set options or control bits. */
+
+  if (index < 0)
+    {
+    uint32_t cc;
+    uint8_t *mp = p;
+
+    if (!first)
+      {
+      fprintf(outfile, "** Unrecognized modifier '%.*s'\n", (int)(ep-p), p);
+      if (ep - p == 1)
+        fprintf(outfile, "** Single-character modifiers must come first\n");
+      return FALSE;
+      }
+
+    for (cc = *p; cc != ',' && cc != '\n' && cc != 0; cc = *(++p))
+      {
+      for (i = 0; i < C1MODLISTCOUNT; i++)
+        if (cc == c1modlist[i].onechar) break;
+
+      if (i >= C1MODLISTCOUNT)
+        {
+        fprintf(outfile, "** Unrecognized modifier '%c' in '%.*s'\n",
+          *p, (int)(ep-mp), mp);
+        return FALSE;
+        }
+
+      if (c1modlist[i].index >= 0)
+        {
+        index = c1modlist[i].index;
+        }
+
+      else
+        {
+        index = scan_modifiers((uint8_t *)(c1modlist[i].fullname),
+          strlen(c1modlist[i].fullname));
+        if (index < 0)
+          {
+          fprintf(outfile, "** Internal error: single-character equivalent "
+            "modifier '%s' not found\n", c1modlist[i].fullname);
+          return FALSE;
+          }
+        c1modlist[i].index = index;     /* Cache for next time */
+        }
+
+      field = check_modifier(modlist + index, ctx, pctl, dctl, *p);
+      if (field == NULL) return FALSE;
+
+      /* /x is a special case; a second appearance changes PCRE2_EXTENDED to
+      PCRE2_EXTENDED_MORE. */
+
+      if (cc == 'x' && (*((uint32_t *)field) & PCRE2_EXTENDED) != 0)
+        {
+        *((uint32_t *)field) &= ~PCRE2_EXTENDED;
+        *((uint32_t *)field) |= PCRE2_EXTENDED_MORE;
+        }
+      else
+        *((uint32_t *)field) |= modlist[index].value;
+      }
+
+    continue;    /* With tne next (fullname) modifier */
+    }
+
+  /* We have a match on a full-name modifier. Check for the existence of data
+  when needed. */
+
+  m = modlist + index;      /* Save typing */
+  if (m->type != MOD_CTL && m->type != MOD_OPT &&
+      (m->type != MOD_IND || *pp == '='))
+    {
+    if (*pp++ != '=')
+      {
+      fprintf(outfile, "** '=' expected after '%s'\n", m->name);
+      return FALSE;
+      }
+    if (off)
+      {
+      fprintf(outfile, "** '-' is not valid for '%s'\n", m->name);
+      return FALSE;
+      }
+    }
+
+  /* These on/off types have no data. */
+
+  else if (*pp != ',' && *pp != '\n' && *pp != ' ' && *pp != 0)
+    {
+    fprintf(outfile, "** Unrecognized modifier '%.*s'\n", (int)(ep-p), p);
+    return FALSE;
+    }
+
+  /* Set the data length for those types that have data. Then find the field
+  that is to be set. If check_modifier() returns NULL, it has already output an
+  error message. */
+
+  len = ep - pp;
+  field = check_modifier(m, ctx, pctl, dctl, 0);
+  if (field == NULL) return FALSE;
+
+  /* Process according to data type. */
+
+  switch (m->type)
+    {
+    case MOD_CTL:
+    case MOD_OPT:
+    if (off) *((uint32_t *)field) &= ~m->value;
+      else *((uint32_t *)field) |= m->value;
+    break;
+
+    case MOD_BSR:
+    if (len == 7 && strncmpic(pp, (const uint8_t *)"default", 7) == 0)
+      {
+#ifdef BSR_ANYCRLF
+      *((uint16_t *)field) = PCRE2_BSR_ANYCRLF;
+#else
+      *((uint16_t *)field) = PCRE2_BSR_UNICODE;
+#endif
+      if (ctx == CTX_PAT || ctx == CTX_DEFPAT) pctl->control2 &= ~CTL2_BSR_SET;
+        else dctl->control2 &= ~CTL2_BSR_SET;
+      }
+    else
+      {
+      if (len == 7 && strncmpic(pp, (const uint8_t *)"anycrlf", 7) == 0)
+        *((uint16_t *)field) = PCRE2_BSR_ANYCRLF;
+      else if (len == 7 && strncmpic(pp, (const uint8_t *)"unicode", 7) == 0)
+        *((uint16_t *)field) = PCRE2_BSR_UNICODE;
+      else goto INVALID_VALUE;
+      if (ctx == CTX_PAT || ctx == CTX_DEFPAT) pctl->control2 |= CTL2_BSR_SET;
+        else dctl->control2 |= CTL2_BSR_SET;
+      }
+    pp = ep;
+    break;
+
+    case MOD_CHR:  /* A single character */
+    *((uint32_t *)field) = *pp++;
+    break;
+
+    case MOD_CON:  /* A convert type/options list */
+    for (;; pp++)
+      {
+      uint8_t *colon = (uint8_t *)strchr((const char *)pp, ':');
+      len = ((colon != NULL && colon < ep)? colon:ep) - pp;
+      for (i = 0; i < convertlistcount; i++)
+        {
+        if (strncmpic(pp, (const uint8_t *)convertlist[i].name, len) == 0)
+          {
+          if (*((uint32_t *)field) == CONVERT_UNSET)
+            *((uint32_t *)field) = convertlist[i].option;
+          else
+            *((uint32_t *)field) |= convertlist[i].option;
+          break;
+          }
+        }
+      if (i >= convertlistcount) goto INVALID_VALUE;
+      pp += len;
+      if (*pp != ':') break;
+      }
+    break;
+
+    case MOD_IN2:    /* One or two unsigned integers */
+    if (!isdigit(*pp)) goto INVALID_VALUE;
+    uli = strtoul((const char *)pp, &endptr, 10);
+    if (U32OVERFLOW(uli)) goto INVALID_VALUE;
+    ((uint32_t *)field)[0] = (uint32_t)uli;
+    if (*endptr == ':')
+      {
+      uli = strtoul((const char *)endptr+1, &endptr, 10);
+      if (U32OVERFLOW(uli)) goto INVALID_VALUE;
+      ((uint32_t *)field)[1] = (uint32_t)uli;
+      }
+    else ((uint32_t *)field)[1] = 0;
+    pp = (uint8_t *)endptr;
+    break;
+
+    /* PCRE2_SIZE_MAX is usually SIZE_MAX, which may be greater, equal to, or
+    less than ULONG_MAX. So first test for overflowing the long int, and then
+    test for overflowing PCRE2_SIZE_MAX if it is smaller than ULONG_MAX. */
+
+    case MOD_SIZ:    /* PCRE2_SIZE value */
+    if (!isdigit(*pp)) goto INVALID_VALUE;
+    uli = strtoul((const char *)pp, &endptr, 10);
+    if (uli == ULONG_MAX) goto INVALID_VALUE;
+#if ULONG_MAX > PCRE2_SIZE_MAX
+    if (uli > PCRE2_SIZE_MAX) goto INVALID_VALUE;
+#endif
+    *((PCRE2_SIZE *)field) = (PCRE2_SIZE)uli;
+    pp = (uint8_t *)endptr;
+    break;
+
+    case MOD_IND:    /* Unsigned integer with default */
+    if (len == 0)
+      {
+      *((uint32_t *)field) = (uint32_t)(m->value);
+      break;
+      }
+    /* Fall through */
+
+    case MOD_INT:    /* Unsigned integer */
+    if (!isdigit(*pp)) goto INVALID_VALUE;
+    uli = strtoul((const char *)pp, &endptr, 10);
+    if (U32OVERFLOW(uli)) goto INVALID_VALUE;
+    *((uint32_t *)field) = (uint32_t)uli;
+    pp = (uint8_t *)endptr;
+    break;
+
+    case MOD_INS:   /* Signed integer */
+    if (!isdigit(*pp) && *pp != '-') goto INVALID_VALUE;
+    li = strtol((const char *)pp, &endptr, 10);
+    if (S32OVERFLOW(li)) goto INVALID_VALUE;
+    *((int32_t *)field) = (int32_t)li;
+    pp = (uint8_t *)endptr;
+    break;
+
+    case MOD_NL:
+    for (i = 0; i < sizeof(newlines)/sizeof(char *); i++)
+      if (len == strlen(newlines[i]) &&
+        strncmpic(pp, (const uint8_t *)newlines[i], len) == 0) break;
+    if (i >= sizeof(newlines)/sizeof(char *)) goto INVALID_VALUE;
+    if (i == 0)
+      {
+      *((uint16_t *)field) = NEWLINE_DEFAULT;
+      if (ctx == CTX_PAT || ctx == CTX_DEFPAT) pctl->control2 &= ~CTL2_NL_SET;
+        else dctl->control2 &= ~CTL2_NL_SET;
+      }
+    else
+      {
+      *((uint16_t *)field) = i;
+      if (ctx == CTX_PAT || ctx == CTX_DEFPAT) pctl->control2 |= CTL2_NL_SET;
+        else dctl->control2 |= CTL2_NL_SET;
+      }
+    pp = ep;
+    break;
+
+    case MOD_NN:              /* Name or (signed) number; may be several */
+    if (isdigit(*pp) || *pp == '-')
+      {
+      int ct = MAXCPYGET - 1;
+      int32_t value;
+      li = strtol((const char *)pp, &endptr, 10);
+      if (S32OVERFLOW(li)) goto INVALID_VALUE;
+      value = (int32_t)li;
+      field = (char *)field - m->offset + m->value;      /* Adjust field ptr */
+      if (value >= 0)                                    /* Add new number */
+        {
+        while (*((int32_t *)field) >= 0 && ct-- > 0)   /* Skip previous */
+          field = (char *)field + sizeof(int32_t);
+        if (ct <= 0)
+          {
+          fprintf(outfile, "** Too many numeric '%s' modifiers\n", m->name);
+          return FALSE;
+          }
+        }
+      *((int32_t *)field) = value;
+      if (ct > 0) ((int32_t *)field)[1] = -1;
+      pp = (uint8_t *)endptr;
+      }
+
+    /* Multiple strings are put end to end. */
+
+    else
+      {
+      char *nn = (char *)field;
+      if (len > 0)                    /* Add new name */
+        {
+        if (len > MAX_NAME_SIZE)
+          {
+          fprintf(outfile, "** Group name in '%s' is too long\n", m->name);
+          return FALSE;
+          }
+        while (*nn != 0) nn += strlen(nn) + 1;
+        if (nn + len + 2 - (char *)field > LENCPYGET)
+          {
+          fprintf(outfile, "** Too many characters in named '%s' modifiers\n",
+            m->name);
+          return FALSE;
+          }
+        memcpy(nn, pp, len);
+        }
+      nn[len] = 0 ;
+      nn[len+1] = 0;
+      pp = ep;
+      }
+    break;
+
+    case MOD_STR:
+    if (len + 1 > m->value)
+      {
+      fprintf(outfile, "** Overlong value for '%s' (max %d code units)\n",
+        m->name, m->value - 1);
+      return FALSE;
+      }
+    memcpy(field, pp, len);
+    ((uint8_t *)field)[len] = 0;
+    pp = ep;
+    break;
+    }
+
+  if (*pp != ',' && *pp != '\n' && *pp != ' ' && *pp != 0)
+    {
+    fprintf(outfile, "** Comma expected after modifier item '%s'\n", m->name);
+    return FALSE;
+    }
+
+  p = pp;
+  first = FALSE;
+
+  if (ctx == CTX_POPPAT &&
+     (pctl->options != 0 ||
+      pctl->tables_id != 0 ||
+      pctl->locale[0] != 0 ||
+      (pctl->control & NOTPOP_CONTROLS) != 0))
+    {
+    fprintf(outfile, "** '%s' is not valid here\n", m->name);
+    return FALSE;
+    }
+  }
+
+return TRUE;
+
+INVALID_VALUE:
+fprintf(outfile, "** Invalid value in '%.*s'\n", (int)(ep-p), p);
+return FALSE;
+}
+
+
+/*************************************************
+*             Get info from a pattern            *
+*************************************************/
+
+/* A wrapped call to pcre2_pattern_info(), applied to the current compiled
+pattern.
+
+Arguments:
+  what        code for the required information
+  where       where to put the answer
+  unsetok     PCRE2_ERROR_UNSET is an "expected" result
+
+Returns:      the return from pcre2_pattern_info()
+*/
+
+static int
+pattern_info(int what, void *where, BOOL unsetok)
+{
+int rc;
+PCRE2_PATTERN_INFO(rc, compiled_code, what, NULL);  /* Exercise the code */
+PCRE2_PATTERN_INFO(rc, compiled_code, what, where);
+if (rc >= 0) return 0;
+if (rc != PCRE2_ERROR_UNSET || !unsetok)
+  {
+  fprintf(outfile, "Error %d from pcre2_pattern_info_%d(%d)\n", rc, test_mode,
+    what);
+  if (rc == PCRE2_ERROR_BADMODE)
+    fprintf(outfile, "Running in %d-bit mode but pattern was compiled in "
+      "%d-bit mode\n", test_mode,
+      8 * (FLD(compiled_code, flags) & PCRE2_MODE_MASK));
+  }
+return rc;
+}
+
+
+
+#ifdef SUPPORT_PCRE2_8
+/*************************************************
+*             Show something in a list           *
+*************************************************/
+
+/* This function just helps to keep the code that uses it tidier. It's used for
+various lists of things where there needs to be introductory text before the
+first item. As these calls are all in the POSIX-support code, they happen only
+when 8-bit mode is supported. */
+
+static void
+prmsg(const char **msg, const char *s)
+{
+fprintf(outfile, "%s %s", *msg, s);
+*msg = "";
+}
+#endif  /* SUPPORT_PCRE2_8 */
+
+
+
+/*************************************************
+*                Show control bits               *
+*************************************************/
+
+/* Called for mutually exclusive controls and for unsupported POSIX controls.
+Because the bits are unique, this can be used for both pattern and data control
+words.
+
+Arguments:
+  controls    control bits
+  controls2   more control bits
+  before      text to print before
+
+Returns:      nothing
+*/
+
+static void
+show_controls(uint32_t controls, uint32_t controls2, const char *before)
+{
+fprintf(outfile, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+  before,
+  ((controls & CTL_AFTERTEXT) != 0)? " aftertext" : "",
+  ((controls & CTL_ALLAFTERTEXT) != 0)? " allaftertext" : "",
+  ((controls & CTL_ALLCAPTURES) != 0)? " allcaptures" : "",
+  ((controls & CTL_ALLUSEDTEXT) != 0)? " allusedtext" : "",
+  ((controls2 & CTL2_ALLVECTOR) != 0)? " allvector" : "",
+  ((controls & CTL_ALTGLOBAL) != 0)? " altglobal" : "",
+  ((controls & CTL_BINCODE) != 0)? " bincode" : "",
+  ((controls2 & CTL2_BSR_SET) != 0)? " bsr" : "",
+  ((controls & CTL_CALLOUT_CAPTURE) != 0)? " callout_capture" : "",
+  ((controls2 & CTL2_CALLOUT_EXTRA) != 0)? " callout_extra" : "",
+  ((controls & CTL_CALLOUT_INFO) != 0)? " callout_info" : "",
+  ((controls & CTL_CALLOUT_NONE) != 0)? " callout_none" : "",
+  ((controls2 & CTL2_CALLOUT_NO_WHERE) != 0)? " callout_no_where" : "",
+  ((controls & CTL_DFA) != 0)? " dfa" : "",
+  ((controls & CTL_EXPAND) != 0)? " expand" : "",
+  ((controls & CTL_FINDLIMITS) != 0)? " find_limits" : "",
+  ((controls & CTL_FRAMESIZE) != 0)? " framesize" : "",
+  ((controls & CTL_FULLBINCODE) != 0)? " fullbincode" : "",
+  ((controls & CTL_GETALL) != 0)? " getall" : "",
+  ((controls & CTL_GLOBAL) != 0)? " global" : "",
+  ((controls & CTL_HEXPAT) != 0)? " hex" : "",
+  ((controls & CTL_INFO) != 0)? " info" : "",
+  ((controls & CTL_JITFAST) != 0)? " jitfast" : "",
+  ((controls & CTL_JITVERIFY) != 0)? " jitverify" : "",
+  ((controls & CTL_MARK) != 0)? " mark" : "",
+  ((controls & CTL_MEMORY) != 0)? " memory" : "",
+  ((controls2 & CTL2_NL_SET) != 0)? " newline" : "",
+  ((controls & CTL_NULLCONTEXT) != 0)? " null_context" : "",
+  ((controls & CTL_POSIX) != 0)? " posix" : "",
+  ((controls & CTL_POSIX_NOSUB) != 0)? " posix_nosub" : "",
+  ((controls & CTL_PUSH) != 0)? " push" : "",
+  ((controls & CTL_PUSHCOPY) != 0)? " pushcopy" : "",
+  ((controls & CTL_PUSHTABLESCOPY) != 0)? " pushtablescopy" : "",
+  ((controls & CTL_STARTCHAR) != 0)? " startchar" : "",
+  ((controls2 & CTL2_SUBSTITUTE_CALLOUT) != 0)? " substitute_callout" : "",
+  ((controls2 & CTL2_SUBSTITUTE_EXTENDED) != 0)? " substitute_extended" : "",
+  ((controls2 & CTL2_SUBSTITUTE_LITERAL) != 0)? " substitute_literal" : "",
+  ((controls2 & CTL2_SUBSTITUTE_MATCHED) != 0)? " substitute_matched" : "",
+  ((controls2 & CTL2_SUBSTITUTE_OVERFLOW_LENGTH) != 0)? " substitute_overflow_length" : "",
+  ((controls2 & CTL2_SUBSTITUTE_REPLACEMENT_ONLY) != 0)? " substitute_replacement_only" : "",
+  ((controls2 & CTL2_SUBSTITUTE_UNKNOWN_UNSET) != 0)? " substitute_unknown_unset" : "",
+  ((controls2 & CTL2_SUBSTITUTE_UNSET_EMPTY) != 0)? " substitute_unset_empty" : "",
+  ((controls & CTL_USE_LENGTH) != 0)? " use_length" : "",
+  ((controls & CTL_UTF8_INPUT) != 0)? " utf8_input" : "",
+  ((controls & CTL_ZERO_TERMINATE) != 0)? " zero_terminate" : "");
+}
+
+
+
+/*************************************************
+*                Show compile options            *
+*************************************************/
+
+/* Called from show_pattern_info() and for unsupported POSIX options.
+
+Arguments:
+  options     an options word
+  before      text to print before
+  after       text to print after
+
+Returns:      nothing
+*/
+
+static void
+show_compile_options(uint32_t options, const char *before, const char *after)
+{
+if (options == 0) fprintf(outfile, "%s <none>%s", before, after);
+else fprintf(outfile, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+  before,
+  ((options & PCRE2_ALT_BSUX) != 0)? " alt_bsux" : "",
+  ((options & PCRE2_ALT_CIRCUMFLEX) != 0)? " alt_circumflex" : "",
+  ((options & PCRE2_ALT_VERBNAMES) != 0)? " alt_verbnames" : "",
+  ((options & PCRE2_ALLOW_EMPTY_CLASS) != 0)? " allow_empty_class" : "",
+  ((options & PCRE2_ANCHORED) != 0)? " anchored" : "",
+  ((options & PCRE2_AUTO_CALLOUT) != 0)? " auto_callout" : "",
+  ((options & PCRE2_CASELESS) != 0)? " caseless" : "",
+  ((options & PCRE2_DOLLAR_ENDONLY) != 0)? " dollar_endonly" : "",
+  ((options & PCRE2_DOTALL) != 0)? " dotall" : "",
+  ((options & PCRE2_DUPNAMES) != 0)? " dupnames" : "",
+  ((options & PCRE2_ENDANCHORED) != 0)? " endanchored" : "",
+  ((options & PCRE2_EXTENDED) != 0)? " extended" : "",
+  ((options & PCRE2_EXTENDED_MORE) != 0)? " extended_more" : "",
+  ((options & PCRE2_FIRSTLINE) != 0)? " firstline" : "",
+  ((options & PCRE2_LITERAL) != 0)? " literal" : "",
+  ((options & PCRE2_MATCH_INVALID_UTF) != 0)? " match_invalid_utf" : "",
+  ((options & PCRE2_MATCH_UNSET_BACKREF) != 0)? " match_unset_backref" : "",
+  ((options & PCRE2_MULTILINE) != 0)? " multiline" : "",
+  ((options & PCRE2_NEVER_BACKSLASH_C) != 0)? " never_backslash_c" : "",
+  ((options & PCRE2_NEVER_UCP) != 0)? " never_ucp" : "",
+  ((options & PCRE2_NEVER_UTF) != 0)? " never_utf" : "",
+  ((options & PCRE2_NO_AUTO_CAPTURE) != 0)? " no_auto_capture" : "",
+  ((options & PCRE2_NO_AUTO_POSSESS) != 0)? " no_auto_possess" : "",
+  ((options & PCRE2_NO_DOTSTAR_ANCHOR) != 0)? " no_dotstar_anchor" : "",
+  ((options & PCRE2_NO_UTF_CHECK) != 0)? " no_utf_check" : "",
+  ((options & PCRE2_NO_START_OPTIMIZE) != 0)? " no_start_optimize" : "",
+  ((options & PCRE2_UCP) != 0)? " ucp" : "",
+  ((options & PCRE2_UNGREEDY) != 0)? " ungreedy" : "",
+  ((options & PCRE2_USE_OFFSET_LIMIT) != 0)? " use_offset_limit" : "",
+  ((options & PCRE2_UTF) != 0)? " utf" : "",
+  after);
+}
+
+
+/*************************************************
+*           Show compile extra options           *
+*************************************************/
+
+/* Called from show_pattern_info() and for unsupported POSIX options.
+
+Arguments:
+  options     an options word
+  before      text to print before
+  after       text to print after
+
+Returns:      nothing
+*/
+
+static void
+show_compile_extra_options(uint32_t options, const char *before,
+  const char *after)
+{
+if (options == 0) fprintf(outfile, "%s <none>%s", before, after);
+else fprintf(outfile, "%s%s%s%s%s%s%s%s",
+  before,
+  ((options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) != 0)? " allow_surrogate_escapes" : "",
+  ((options & PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL) != 0)? " bad_escape_is_literal" : "",
+  ((options & PCRE2_EXTRA_ALT_BSUX) != 0)? " extra_alt_bsux" : "",
+  ((options & PCRE2_EXTRA_MATCH_WORD) != 0)? " match_word" : "",
+  ((options & PCRE2_EXTRA_MATCH_LINE) != 0)? " match_line" : "",
+  ((options & PCRE2_EXTRA_ESCAPED_CR_IS_LF) != 0)? " escaped_cr_is_lf" : "",
+  after);
+}
+
+
+
+#ifdef SUPPORT_PCRE2_8
+/*************************************************
+*                Show match options              *
+*************************************************/
+
+/* Called for unsupported POSIX options. */
+
+static void
+show_match_options(uint32_t options)
+{
+fprintf(outfile, "%s%s%s%s%s%s%s%s%s%s%s%s%s",
+  ((options & PCRE2_ANCHORED) != 0)? " anchored" : "",
+  ((options & PCRE2_COPY_MATCHED_SUBJECT) != 0)? " copy_matched_subject" : "",
+  ((options & PCRE2_DFA_RESTART) != 0)? " dfa_restart" : "",
+  ((options & PCRE2_DFA_SHORTEST) != 0)? " dfa_shortest" : "",
+  ((options & PCRE2_ENDANCHORED) != 0)? " endanchored" : "",
+  ((options & PCRE2_NO_JIT) != 0)? " no_jit" : "",
+  ((options & PCRE2_NO_UTF_CHECK) != 0)? " no_utf_check" : "",
+  ((options & PCRE2_NOTBOL) != 0)? " notbol" : "",
+  ((options & PCRE2_NOTEMPTY) != 0)? " notempty" : "",
+  ((options & PCRE2_NOTEMPTY_ATSTART) != 0)? " notempty_atstart" : "",
+  ((options & PCRE2_NOTEOL) != 0)? " noteol" : "",
+  ((options & PCRE2_PARTIAL_HARD) != 0)? " partial_hard" : "",
+  ((options & PCRE2_PARTIAL_SOFT) != 0)? " partial_soft" : "");
+}
+#endif  /* SUPPORT_PCRE2_8 */
+
+
+
+/*************************************************
+*      Show memory usage info for a pattern      *
+*************************************************/
+
+static void
+show_memory_info(void)
+{
+uint32_t name_count, name_entry_size;
+size_t size, cblock_size;
+
+/* One of the test_mode values will always be true, but to stop a compiler
+warning we must initialize cblock_size. */
+
+cblock_size = 0;
+#ifdef SUPPORT_PCRE2_8
+if (test_mode == PCRE8_MODE) cblock_size = sizeof(pcre2_real_code_8);
+#endif
+#ifdef SUPPORT_PCRE2_16
+if (test_mode == PCRE16_MODE) cblock_size = sizeof(pcre2_real_code_16);
+#endif
+#ifdef SUPPORT_PCRE2_32
+if (test_mode == PCRE32_MODE) cblock_size = sizeof(pcre2_real_code_32);
+#endif
+
+(void)pattern_info(PCRE2_INFO_SIZE, &size, FALSE);
+(void)pattern_info(PCRE2_INFO_NAMECOUNT, &name_count, FALSE);
+(void)pattern_info(PCRE2_INFO_NAMEENTRYSIZE, &name_entry_size, FALSE);
+fprintf(outfile, "Memory allocation (code space): %d\n",
+  (int)(size - name_count*name_entry_size*code_unit_size - cblock_size));
+if (pat_patctl.jit != 0)
+  {
+  (void)pattern_info(PCRE2_INFO_JITSIZE, &size, FALSE);
+  fprintf(outfile, "Memory allocation (JIT code): %d\n", (int)size);
+  }
+}
+
+
+
+/*************************************************
+*       Show frame size info for a pattern       *
+*************************************************/
+
+static void
+show_framesize(void)
+{
+size_t frame_size;
+(void)pattern_info(PCRE2_INFO_FRAMESIZE, &frame_size, FALSE);
+fprintf(outfile, "Frame size for pcre2_match(): %d\n", (int)frame_size);
+}
+
+
+
+/*************************************************
+*         Get and output an error message        *
+*************************************************/
+
+static BOOL
+print_error_message(int errorcode, const char *before, const char *after)
+{
+int len;
+PCRE2_GET_ERROR_MESSAGE(len, errorcode, pbuffer);
+if (len < 0)
+  {
+  fprintf(outfile, "\n** pcre2test internal error: cannot interpret error "
+    "number\n** Unexpected return (%d) from pcre2_get_error_message()\n", len);
+  }
+else
+  {
+  fprintf(outfile, "%s", before);
+  PCHARSV(CASTVAR(void *, pbuffer), 0, len, FALSE, outfile);
+  fprintf(outfile, "%s", after);
+  }
+return len >= 0;
+}
+
+
+/*************************************************
+*     Callback function for callout enumeration  *
+*************************************************/
+
+/* The only differences in the callout emumeration block for different code
+unit widths are that the pointers to the subject, the most recent MARK, and a
+callout argument string point to strings of the appropriate width. Casts can be
+used to deal with this.
+
+Argument:
+  cb            pointer to enumerate block
+  callout_data  user data
+
+Returns:    0
+*/
+
+static int callout_callback(pcre2_callout_enumerate_block_8 *cb,
+  void *callout_data)
+{
+uint32_t i;
+BOOL utf = (FLD(compiled_code, overall_options) & PCRE2_UTF) != 0;
+
+(void)callout_data;  /* Not currently displayed */
+
+fprintf(outfile, "Callout ");
+if (cb->callout_string != NULL)
+  {
+  uint32_t delimiter = CODE_UNIT(cb->callout_string, -1);
+  fprintf(outfile, "%c", delimiter);
+  PCHARSV(cb->callout_string, 0,
+    cb->callout_string_length, utf, outfile);
+  for (i = 0; callout_start_delims[i] != 0; i++)
+    if (delimiter == callout_start_delims[i])
+      {
+      delimiter = callout_end_delims[i];
+      break;
+      }
+  fprintf(outfile, "%c  ", delimiter);
+  }
+else fprintf(outfile, "%d  ", cb->callout_number);
+
+fprintf(outfile, "%.*s\n",
+  (int)((cb->next_item_length == 0)? 1 : cb->next_item_length),
+  pbuffer8 + cb->pattern_position);
+
+return 0;
+}
+
+
+
+/*************************************************
+*        Show information about a pattern        *
+*************************************************/
+
+/* This function is called after a pattern has been compiled if any of the
+information-requesting controls have been set.
+
+Arguments:  none
+
+Returns:    PR_OK     continue processing next line
+            PR_SKIP   skip to a blank line
+            PR_ABEND  abort the pcre2test run
+*/
+
+static int
+show_pattern_info(void)
+{
+uint32_t compile_options, overall_options, extra_options;
+BOOL utf = (FLD(compiled_code, overall_options) & PCRE2_UTF) != 0;
+
+if ((pat_patctl.control & (CTL_BINCODE|CTL_FULLBINCODE)) != 0)
+  {
+  fprintf(outfile, "------------------------------------------------------------------\n");
+  PCRE2_PRINTINT((pat_patctl.control & CTL_FULLBINCODE) != 0);
+  }
+
+if ((pat_patctl.control & CTL_INFO) != 0)
+  {
+  int rc;
+  void *nametable;
+  uint8_t *start_bits;
+  BOOL heap_limit_set, match_limit_set, depth_limit_set;
+  uint32_t backrefmax, bsr_convention, capture_count, first_ctype, first_cunit,
+    hasbackslashc, hascrorlf, jchanged, last_ctype, last_cunit, match_empty,
+    depth_limit, heap_limit, match_limit, minlength, nameentrysize, namecount,
+    newline_convention;
+
+  /* Exercise the error route. */
+
+  PCRE2_PATTERN_INFO(rc, compiled_code, 999, NULL);
+  (void)rc;
+
+  /* These info requests may return PCRE2_ERROR_UNSET. */
+
+  switch(pattern_info(PCRE2_INFO_HEAPLIMIT, &heap_limit, TRUE))
+    {
+    case 0:
+    heap_limit_set = TRUE;
+    break;
+
+    case PCRE2_ERROR_UNSET:
+    heap_limit_set = FALSE;
+    break;
+
+    default:
+    return PR_ABEND;
+    }
+
+  switch(pattern_info(PCRE2_INFO_MATCHLIMIT, &match_limit, TRUE))
+    {
+    case 0:
+    match_limit_set = TRUE;
+    break;
+
+    case PCRE2_ERROR_UNSET:
+    match_limit_set = FALSE;
+    break;
+
+    default:
+    return PR_ABEND;
+    }
+
+  switch(pattern_info(PCRE2_INFO_DEPTHLIMIT, &depth_limit, TRUE))
+    {
+    case 0:
+    depth_limit_set = TRUE;
+    break;
+
+    case PCRE2_ERROR_UNSET:
+    depth_limit_set = FALSE;
+    break;
+
+    default:
+    return PR_ABEND;
+    }
+
+  /* These info requests should always succeed. */
+
+  if (pattern_info(PCRE2_INFO_BACKREFMAX, &backrefmax, FALSE) +
+      pattern_info(PCRE2_INFO_BSR, &bsr_convention, FALSE) +
+      pattern_info(PCRE2_INFO_CAPTURECOUNT, &capture_count, FALSE) +
+      pattern_info(PCRE2_INFO_FIRSTBITMAP, &start_bits, FALSE) +
+      pattern_info(PCRE2_INFO_FIRSTCODEUNIT, &first_cunit, FALSE) +
+      pattern_info(PCRE2_INFO_FIRSTCODETYPE, &first_ctype, FALSE) +
+      pattern_info(PCRE2_INFO_HASBACKSLASHC, &hasbackslashc, FALSE) +
+      pattern_info(PCRE2_INFO_HASCRORLF, &hascrorlf, FALSE) +
+      pattern_info(PCRE2_INFO_JCHANGED, &jchanged, FALSE) +
+      pattern_info(PCRE2_INFO_LASTCODEUNIT, &last_cunit, FALSE) +
+      pattern_info(PCRE2_INFO_LASTCODETYPE, &last_ctype, FALSE) +
+      pattern_info(PCRE2_INFO_MATCHEMPTY, &match_empty, FALSE) +
+      pattern_info(PCRE2_INFO_MINLENGTH, &minlength, FALSE) +
+      pattern_info(PCRE2_INFO_NAMECOUNT, &namecount, FALSE) +
+      pattern_info(PCRE2_INFO_NAMEENTRYSIZE, &nameentrysize, FALSE) +
+      pattern_info(PCRE2_INFO_NAMETABLE, &nametable, FALSE) +
+      pattern_info(PCRE2_INFO_NEWLINE, &newline_convention, FALSE)
+      != 0)
+    return PR_ABEND;
+
+  fprintf(outfile, "Capture group count = %d\n", capture_count);
+
+  if (backrefmax > 0)
+    fprintf(outfile, "Max back reference = %d\n", backrefmax);
+
+  if (maxlookbehind > 0)
+    fprintf(outfile, "Max lookbehind = %d\n", maxlookbehind);
+
+  if (heap_limit_set)
+    fprintf(outfile, "Heap limit = %u\n", heap_limit);
+
+  if (match_limit_set)
+    fprintf(outfile, "Match limit = %u\n", match_limit);
+
+  if (depth_limit_set)
+    fprintf(outfile, "Depth limit = %u\n", depth_limit);
+
+  if (namecount > 0)
+    {
+    fprintf(outfile, "Named capture groups:\n");
+    for (; namecount > 0; namecount--)
+      {
+      int imm2_size = test_mode == PCRE8_MODE ? 2 : 1;
+      uint32_t length = (uint32_t)STRLEN(nametable + imm2_size);
+      fprintf(outfile, "  ");
+
+      /* In UTF mode the name may be a UTF string containing non-ASCII
+      letters and digits. We must output it as a UTF-8 string. In non-UTF mode,
+      use the normal string printing functions, which use escapes for all
+      non-ASCII characters. */
+
+      if (utf)
+        {
+#ifdef SUPPORT_PCRE2_32
+        if (test_mode == PCRE32_MODE)
+          {
+          PCRE2_SPTR32 nameptr = (PCRE2_SPTR32)nametable + imm2_size;
+          while (*nameptr != 0)
+            {
+            uint8_t u8buff[6];
+            int len = ord2utf8(*nameptr++, u8buff);
+            fprintf(outfile, "%.*s", len, u8buff);
+            }
+          }
+#endif
+#ifdef SUPPORT_PCRE2_16
+        if (test_mode == PCRE16_MODE)
+          {
+          PCRE2_SPTR16 nameptr = (PCRE2_SPTR16)nametable + imm2_size;
+          while (*nameptr != 0)
+            {
+            int len;
+            uint8_t u8buff[6];
+            uint32_t c = *nameptr++ & 0xffff;
+            if (c >= 0xD800 && c < 0xDC00)
+              c = ((c & 0x3ff) << 10) + (*nameptr++ & 0x3ff) + 0x10000;
+            len = ord2utf8(c, u8buff);
+            fprintf(outfile, "%.*s", len, u8buff);
+            }
+          }
+#endif
+#ifdef SUPPORT_PCRE2_8
+        if (test_mode == PCRE8_MODE)
+          fprintf(outfile, "%s", (PCRE2_SPTR8)nametable + imm2_size);
+#endif
+        }
+      else  /* Not UTF mode */
+        {
+        PCHARSV(nametable, imm2_size, length, FALSE, outfile);
+        }
+
+      while (length++ < nameentrysize - imm2_size) putc(' ', outfile);
+
+#ifdef SUPPORT_PCRE2_32
+      if (test_mode == PCRE32_MODE)
+        fprintf(outfile, "%3d\n", (int)(((PCRE2_SPTR32)nametable)[0]));
+#endif
+#ifdef SUPPORT_PCRE2_16
+      if (test_mode == PCRE16_MODE)
+        fprintf(outfile, "%3d\n", (int)(((PCRE2_SPTR16)nametable)[0]));
+#endif
+#ifdef SUPPORT_PCRE2_8
+      if (test_mode == PCRE8_MODE)
+        fprintf(outfile, "%3d\n", (int)(
+        ((((PCRE2_SPTR8)nametable)[0]) << 8) | ((PCRE2_SPTR8)nametable)[1]));
+#endif
+
+      nametable = (void*)((PCRE2_SPTR8)nametable + nameentrysize * code_unit_size);
+      }
+    }
+
+  if (hascrorlf)     fprintf(outfile, "Contains explicit CR or LF match\n");
+  if (hasbackslashc) fprintf(outfile, "Contains \\C\n");
+  if (match_empty)   fprintf(outfile, "May match empty string\n");
+
+  pattern_info(PCRE2_INFO_ARGOPTIONS, &compile_options, FALSE);
+  pattern_info(PCRE2_INFO_ALLOPTIONS, &overall_options, FALSE);
+  pattern_info(PCRE2_INFO_EXTRAOPTIONS, &extra_options, FALSE);
+
+  /* Remove UTF/UCP if they were there only because of forbid_utf. This saves
+  cluttering up the verification output of non-UTF test files. */
+
+  if ((pat_patctl.options & PCRE2_NEVER_UTF) == 0)
+    {
+    compile_options &= ~PCRE2_NEVER_UTF;
+    overall_options &= ~PCRE2_NEVER_UTF;
+    }
+
+  if ((pat_patctl.options & PCRE2_NEVER_UCP) == 0)
+    {
+    compile_options &= ~PCRE2_NEVER_UCP;
+    overall_options &= ~PCRE2_NEVER_UCP;
+    }
+
+  if ((compile_options|overall_options) != 0)
+    {
+    if (compile_options == overall_options)
+      show_compile_options(compile_options, "Options:", "\n");
+    else
+      {
+      show_compile_options(compile_options, "Compile options:", "\n");
+      show_compile_options(overall_options, "Overall options:", "\n");
+      }
+    }
+
+  if (extra_options != 0)
+    show_compile_extra_options(extra_options, "Extra options:", "\n");
+
+  if (jchanged) fprintf(outfile, "Duplicate name status changes\n");
+
+  if ((pat_patctl.control2 & CTL2_BSR_SET) != 0 ||
+      (FLD(compiled_code, flags) & PCRE2_BSR_SET) != 0)
+    fprintf(outfile, "\\R matches %s\n", (bsr_convention == PCRE2_BSR_UNICODE)?
+      "any Unicode newline" : "CR, LF, or CRLF");
+
+  if ((FLD(compiled_code, flags) & PCRE2_NL_SET) != 0)
+    {
+    switch (newline_convention)
+      {
+      case PCRE2_NEWLINE_CR:
+      fprintf(outfile, "Forced newline is CR\n");
+      break;
+
+      case PCRE2_NEWLINE_LF:
+      fprintf(outfile, "Forced newline is LF\n");
+      break;
+
+      case PCRE2_NEWLINE_CRLF:
+      fprintf(outfile, "Forced newline is CRLF\n");
+      break;
+
+      case PCRE2_NEWLINE_ANYCRLF:
+      fprintf(outfile, "Forced newline is CR, LF, or CRLF\n");
+      break;
+
+      case PCRE2_NEWLINE_ANY:
+      fprintf(outfile, "Forced newline is any Unicode newline\n");
+      break;
+
+      case PCRE2_NEWLINE_NUL:
+      fprintf(outfile, "Forced newline is NUL\n");
+      break;
+
+      default:
+      break;
+      }
+    }
+
+  if (first_ctype == 2)
+    {
+    fprintf(outfile, "First code unit at start or follows newline\n");
+    }
+  else if (first_ctype == 1)
+    {
+    const char *caseless =
+      ((FLD(compiled_code, flags) & PCRE2_FIRSTCASELESS) == 0)?
+      "" : " (caseless)";
+    if (PRINTOK(first_cunit))
+      fprintf(outfile, "First code unit = \'%c\'%s\n", first_cunit, caseless);
+    else
+      {
+      fprintf(outfile, "First code unit = ");
+      pchar(first_cunit, FALSE, outfile);
+      fprintf(outfile, "%s\n", caseless);
+      }
+    }
+  else if (start_bits != NULL)
+    {
+    int i;
+    int c = 24;
+    fprintf(outfile, "Starting code units: ");
+    for (i = 0; i < 256; i++)
+      {
+      if ((start_bits[i/8] & (1u << (i&7))) != 0)
+        {
+        if (c > 75)
+          {
+          fprintf(outfile, "\n  ");
+          c = 2;
+          }
+        if (PRINTOK(i) && i != ' ')
+          {
+          fprintf(outfile, "%c ", i);
+          c += 2;
+          }
+        else
+          {
+          fprintf(outfile, "\\x%02x ", i);
+          c += 5;
+          }
+        }
+      }
+    fprintf(outfile, "\n");
+    }
+
+  if (last_ctype != 0)
+    {
+    const char *caseless =
+      ((FLD(compiled_code, flags) & PCRE2_LASTCASELESS) == 0)?
+      "" : " (caseless)";
+    if (PRINTOK(last_cunit))
+      fprintf(outfile, "Last code unit = \'%c\'%s\n", last_cunit, caseless);
+    else
+      {
+      fprintf(outfile, "Last code unit = ");
+      pchar(last_cunit, FALSE, outfile);
+      fprintf(outfile, "%s\n", caseless);
+      }
+    }
+
+  if ((FLD(compiled_code, overall_options) & PCRE2_NO_START_OPTIMIZE) == 0)
+    fprintf(outfile, "Subject length lower bound = %d\n", minlength);
+
+  if (pat_patctl.jit != 0 && (pat_patctl.control & CTL_JITVERIFY) != 0)
+    {
+    if (FLD(compiled_code, executable_jit) != NULL)
+      fprintf(outfile, "JIT compilation was successful\n");
+    else
+      {
+#ifdef SUPPORT_JIT
+      fprintf(outfile, "JIT compilation was not successful");
+      if (jitrc != 0 && !print_error_message(jitrc, " (", ")"))
+        return PR_ABEND;
+      fprintf(outfile, "\n");
+#else
+      fprintf(outfile, "JIT support is not available in this version of PCRE2\n");
+#endif
+      }
+    }
+  }
+
+if ((pat_patctl.control & CTL_CALLOUT_INFO) != 0)
+  {
+  int errorcode;
+  PCRE2_CALLOUT_ENUMERATE(errorcode, callout_callback, 0);
+  if (errorcode != 0)
+    {
+    fprintf(outfile, "Callout enumerate failed: error %d: ", errorcode);
+    if (errorcode < 0 && !print_error_message(errorcode, "", "\n"))
+      return PR_ABEND;
+    return PR_SKIP;
+    }
+  }
+
+return PR_OK;
+}
+
+
+
+/*************************************************
+*              Handle serialization error        *
+*************************************************/
+
+/* Print an error message after a serialization failure.
+
+Arguments:
+  rc         the error code
+  msg        an initial message for what failed
+
+Returns:     FALSE if print_error_message() fails
+*/
+
+static BOOL
+serial_error(int rc, const char *msg)
+{
+fprintf(outfile, "%s failed: error %d: ", msg, rc);
+return print_error_message(rc, "", "\n");
+}
+
+
+
+/*************************************************
+*        Open file for save/load commands        *
+*************************************************/
+
+/* This function decodes the file name and opens the file.
+
+Arguments:
+  buffptr     point after the #command
+  mode        open mode
+  fptr        points to the FILE variable
+  name        name of # command
+
+Returns:      PR_OK or PR_ABEND
+*/
+
+static int
+open_file(uint8_t *buffptr, const char *mode, FILE **fptr, const char *name)
+{
+char *endf;
+char *filename = (char *)buffptr;
+while (isspace(*filename)) filename++;
+endf = filename + strlen8(filename);
+while (endf > filename && isspace(endf[-1])) endf--;
+
+if (endf == filename)
+  {
+  fprintf(outfile, "** File name expected after %s\n", name);
+  return PR_ABEND;
+  }
+
+*endf = 0;
+*fptr = fopen((const char *)filename, mode);
+if (*fptr == NULL)
+  {
+  fprintf(outfile, "** Failed to open '%s': %s\n", filename, strerror(errno));
+  return PR_ABEND;
+  }
+
+return PR_OK;
+}
+
+
+
+/*************************************************
+*               Process command line             *
+*************************************************/
+
+/* This function is called for lines beginning with # and a character that is
+not ! or whitespace, when encountered between tests, which means that there is
+no compiled pattern (compiled_code is NULL). The line is in buffer.
+
+Arguments:  none
+
+Returns:    PR_OK     continue processing next line
+            PR_SKIP   skip to a blank line
+            PR_ABEND  abort the pcre2test run
+*/
+
+static int
+process_command(void)
+{
+FILE *f;
+PCRE2_SIZE serial_size;
+size_t i;
+int rc, cmd, cmdlen, yield;
+uint16_t first_listed_newline;
+const char *cmdname;
+uint8_t *argptr, *serial;
+
+yield = PR_OK;
+cmd = CMD_UNKNOWN;
+cmdlen = 0;
+
+for (i = 0; i < cmdlistcount; i++)
+  {
+  cmdname = cmdlist[i].name;
+  cmdlen = strlen(cmdname);
+  if (strncmp((char *)(buffer+1), cmdname, cmdlen) == 0 &&
+      isspace(buffer[cmdlen+1]))
+    {
+    cmd = cmdlist[i].value;
+    break;
+    }
+  }
+
+argptr = buffer + cmdlen + 1;
+
+if (restrict_for_perl_test && cmd != CMD_PATTERN && cmd != CMD_SUBJECT)
+  {
+  fprintf(outfile, "** #%s is not allowed after #perltest\n", cmdname);
+  return PR_ABEND;
+  }
+
+switch(cmd)
+  {
+  case CMD_UNKNOWN:
+  fprintf(outfile, "** Unknown command: %s", buffer);
+  break;
+
+  case CMD_FORBID_UTF:
+  forbid_utf = PCRE2_NEVER_UTF|PCRE2_NEVER_UCP;
+  break;
+
+  case CMD_PERLTEST:
+  restrict_for_perl_test = TRUE;
+  break;
+
+  /* Set default pattern modifiers */
+
+  case CMD_PATTERN:
+  (void)decode_modifiers(argptr, CTX_DEFPAT, &def_patctl, NULL);
+  if (def_patctl.jit == 0 && (def_patctl.control & CTL_JITVERIFY) != 0)
+    def_patctl.jit = JIT_DEFAULT;
+  break;
+
+  /* Set default subject modifiers */
+
+  case CMD_SUBJECT:
+  (void)decode_modifiers(argptr, CTX_DEFDAT, NULL, &def_datctl);
+  break;
+
+  /* Check the default newline, and if not one of those listed, set up the
+  first one to be forced. An empty list unsets. */
+
+  case CMD_NEWLINE_DEFAULT:
+  local_newline_default = 0;   /* Unset */
+  first_listed_newline = 0;
+  for (;;)
+    {
+    while (isspace(*argptr)) argptr++;
+    if (*argptr == 0) break;
+    for (i = 1; i < sizeof(newlines)/sizeof(char *); i++)
+      {
+      size_t nlen = strlen(newlines[i]);
+      if (strncmpic(argptr, (const uint8_t *)newlines[i], nlen) == 0 &&
+          isspace(argptr[nlen]))
+        {
+        if (i == NEWLINE_DEFAULT) return PR_OK;  /* Default is valid */
+        if (first_listed_newline == 0) first_listed_newline = i;
+        }
+      }
+    while (*argptr != 0 && !isspace(*argptr)) argptr++;
+    }
+  local_newline_default = first_listed_newline;
+  break;
+
+  /* Pop or copy a compiled pattern off the stack. Modifiers that do not affect
+  the compiled pattern (e.g. to give information) are permitted. The default
+  pattern modifiers are ignored. */
+
+  case CMD_POP:
+  case CMD_POPCOPY:
+  if (patstacknext <= 0)
+    {
+    fprintf(outfile, "** Can't pop off an empty stack\n");
+    return PR_SKIP;
+    }
+  memset(&pat_patctl, 0, sizeof(patctl));   /* Completely unset */
+  if (!decode_modifiers(argptr, CTX_POPPAT, &pat_patctl, NULL))
+    return PR_SKIP;
+
+  if (cmd == CMD_POP)
+    {
+    SET(compiled_code, patstack[--patstacknext]);
+    }
+  else
+    {
+    PCRE2_CODE_COPY_FROM_VOID(compiled_code, patstack[patstacknext - 1]);
+    }
+
+  if (pat_patctl.jit != 0)
+    {
+    PCRE2_JIT_COMPILE(jitrc, compiled_code, pat_patctl.jit);
+    }
+  if ((pat_patctl.control & CTL_MEMORY) != 0) show_memory_info();
+  if ((pat_patctl.control & CTL_FRAMESIZE) != 0) show_framesize();
+  if ((pat_patctl.control & CTL_ANYINFO) != 0)
+    {
+    rc = show_pattern_info();
+    if (rc != PR_OK) return rc;
+    }
+  break;
+
+  /* Save the stack of compiled patterns to a file, then empty the stack. */
+
+  case CMD_SAVE:
+  if (patstacknext <= 0)
+    {
+    fprintf(outfile, "** No stacked patterns to save\n");
+    return PR_OK;
+    }
+
+  rc = open_file(argptr+1, BINARY_OUTPUT_MODE, &f, "#save");
+  if (rc != PR_OK) return rc;
+
+  PCRE2_SERIALIZE_ENCODE(rc, patstack, patstacknext, &serial, &serial_size,
+    general_context);
+  if (rc < 0)
+    {
+    fclose(f);
+    if (!serial_error(rc, "Serialization")) return PR_ABEND;
+    break;
+    }
+
+  /* Write the length at the start of the file to make it straightforward to
+  get the right memory when re-loading. This saves having to read the file size
+  in different operating systems. To allow for different endianness (even
+  though reloading with the opposite endianness does not work), write the
+  length byte-by-byte. */
+
+  for (i = 0; i < 4; i++) fputc((serial_size >> (i*8)) & 255, f);
+  if (fwrite(serial, 1, serial_size, f) != serial_size)
+    {
+    fprintf(outfile, "** Wrong return from fwrite()\n");
+    fclose(f);
+    return PR_ABEND;
+    }
+
+  fclose(f);
+  PCRE2_SERIALIZE_FREE(serial);
+  while(patstacknext > 0)
+    {
+    SET(compiled_code, patstack[--patstacknext]);
+    SUB1(pcre2_code_free, compiled_code);
+    }
+  SET(compiled_code, NULL);
+  break;
+
+  /* Load a set of compiled patterns from a file onto the stack */
+
+  case CMD_LOAD:
+  rc = open_file(argptr+1, BINARY_INPUT_MODE, &f, "#load");
+  if (rc != PR_OK) return rc;
+
+  serial_size = 0;
+  for (i = 0; i < 4; i++) serial_size |= fgetc(f) << (i*8);
+
+  serial = malloc(serial_size);
+  if (serial == NULL)
+    {
+    fprintf(outfile, "** Failed to get memory (size %" SIZ_FORM ") for #load\n",
+      SIZ_CAST serial_size);
+    fclose(f);
+    return PR_ABEND;
+    }
+
+  i = fread(serial, 1, serial_size, f);
+  fclose(f);
+
+  if (i != serial_size)
+    {
+    fprintf(outfile, "** Wrong return from fread()\n");
+    yield = PR_ABEND;
+    }
+  else
+    {
+    PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(rc, serial);
+    if (rc < 0)
+      {
+      if (!serial_error(rc, "Get number of codes")) yield = PR_ABEND;
+      }
+    else
+      {
+      if (rc + patstacknext > PATSTACKSIZE)
+        {
+        fprintf(outfile, "** Not enough space on pattern stack for %d pattern%s\n",
+          rc, (rc == 1)? "" : "s");
+        rc = PATSTACKSIZE - patstacknext;
+        fprintf(outfile, "** Decoding %d pattern%s\n", rc,
+          (rc == 1)? "" : "s");
+        }
+      PCRE2_SERIALIZE_DECODE(rc, patstack + patstacknext, rc, serial,
+        general_context);
+      if (rc < 0)
+        {
+        if (!serial_error(rc, "Deserialization")) yield = PR_ABEND;
+        }
+      else patstacknext += rc;
+      }
+    }
+
+  free(serial);
+  break;
+
+  /* Load a set of binary tables into tables3. */
+
+  case CMD_LOADTABLES:
+  rc = open_file(argptr+1, BINARY_INPUT_MODE, &f, "#loadtables");
+  if (rc != PR_OK) return rc;
+
+  if (tables3 == NULL)
+    {
+    (void)PCRE2_CONFIG(PCRE2_CONFIG_TABLES_LENGTH, &loadtables_length);
+    tables3 = malloc(loadtables_length);
+    }
+
+  if (tables3 == NULL)
+    {
+    fprintf(outfile, "** Failed: malloc failed for #loadtables\n");
+    yield = PR_ABEND;
+    }
+  else if (fread(tables3, 1, loadtables_length, f) != loadtables_length)
+    {
+    fprintf(outfile, "** Wrong return from fread()\n");
+    yield = PR_ABEND;
+    }
+
+  fclose(f);
+  break;
+  }
+
+return yield;
+}
+
+
+
+/*************************************************
+*               Process pattern line             *
+*************************************************/
+
+/* This function is called when the input buffer contains the start of a
+pattern. The first character is known to be a valid delimiter. The pattern is
+read, modifiers are interpreted, and a suitable local context is set up for
+this test. The pattern is then compiled.
+
+Arguments:  none
+
+Returns:    PR_OK     continue processing next line
+            PR_SKIP   skip to a blank line
+            PR_ABEND  abort the pcre2test run
+*/
+
+static int
+process_pattern(void)
+{
+BOOL utf;
+uint32_t k;
+uint8_t *p = buffer;
+unsigned int delimiter = *p++;
+int errorcode;
+void *use_pat_context;
+uint32_t use_forbid_utf = forbid_utf;
+PCRE2_SIZE patlen;
+PCRE2_SIZE valgrind_access_length;
+PCRE2_SIZE erroroffset;
+
+/* The perltest.sh script supports only / as a delimiter. */
+
+if (restrict_for_perl_test && delimiter != '/')
+  {
+  fprintf(outfile, "** The only allowed delimiter after #perltest is '/'\n");
+  return PR_ABEND;  
+  } 
+
+/* Initialize the context and pattern/data controls for this test from the
+defaults. */
+
+PATCTXCPY(pat_context, default_pat_context);
+memcpy(&pat_patctl, &def_patctl, sizeof(patctl));
+
+/* Find the end of the pattern, reading more lines if necessary. */
+
+for(;;)
+  {
+  while (*p != 0)
+    {
+    if (*p == '\\' && p[1] != 0) p++;
+      else if (*p == delimiter) break;
+    p++;
+    }
+  if (*p != 0) break;
+  if ((p = extend_inputline(infile, p, "    > ")) == NULL)
+    {
+    fprintf(outfile, "** Unexpected EOF\n");
+    return PR_ABEND;
+    }
+  if (!INTERACTIVE(infile)) fprintf(outfile, "%s", (char *)p);
+  }
+
+/* If the first character after the delimiter is backslash, make the pattern
+end with backslash. This is purely to provide a way of testing for the error
+message when a pattern ends with backslash. */
+
+if (p[1] == '\\') *p++ = '\\';
+
+/* Terminate the pattern at the delimiter, and compute the length. */
+
+*p++ = 0;
+patlen = p - buffer - 2;
+
+/* Look for modifiers and options after the final delimiter. */
+
+if (!decode_modifiers(p, CTX_PAT, &pat_patctl, NULL)) return PR_SKIP;
+
+/* Note that the match_invalid_utf option also sets utf when passed to
+pcre2_compile(). */
+
+utf = (pat_patctl.options & (PCRE2_UTF|PCRE2_MATCH_INVALID_UTF)) != 0;
+
+/* The utf8_input modifier is not allowed in 8-bit mode, and is mutually
+exclusive with the utf modifier. */
+
+if ((pat_patctl.control & CTL_UTF8_INPUT) != 0)
+  {
+  if (test_mode == PCRE8_MODE)
+    {
+    fprintf(outfile, "** The utf8_input modifier is not allowed in 8-bit mode\n");
+    return PR_SKIP;
+    }
+  if (utf)
+    {
+    fprintf(outfile, "** The utf and utf8_input modifiers are mutually exclusive\n");
+    return PR_SKIP;
+    }
+  }
+
+/* The convert and posix modifiers are mutually exclusive. */
+
+if (pat_patctl.convert_type != CONVERT_UNSET &&
+    (pat_patctl.control & CTL_POSIX) != 0)
+  {
+  fprintf(outfile, "** The convert and posix modifiers are mutually exclusive\n");
+  return PR_SKIP;
+  }
+
+/* Check for mutually exclusive control modifiers. At present, these are all in
+the first control word. */
+
+for (k = 0; k < sizeof(exclusive_pat_controls)/sizeof(uint32_t); k++)
+  {
+  uint32_t c = pat_patctl.control & exclusive_pat_controls[k];
+  if (c != 0 && c != (c & (~c+1)))
+    {
+    show_controls(c, 0, "** Not allowed together:");
+    fprintf(outfile, "\n");
+    return PR_SKIP;
+    }
+  }
+
+/* Assume full JIT compile for jitverify and/or jitfast if nothing else was
+specified. */
+
+if (pat_patctl.jit == 0 &&
+    (pat_patctl.control & (CTL_JITVERIFY|CTL_JITFAST)) != 0)
+  pat_patctl.jit = JIT_DEFAULT;
+
+/* Now copy the pattern to pbuffer8 for use in 8-bit testing and for reflecting
+in callouts. Convert from hex if requested (literal strings in quotes may be
+present within the hexadecimal pairs). The result must necessarily be fewer
+characters so will always fit in pbuffer8. */
+
+if ((pat_patctl.control & CTL_HEXPAT) != 0)
+  {
+  uint8_t *pp, *pt;
+  uint32_t c, d;
+
+  pt = pbuffer8;
+  for (pp = buffer + 1; *pp != 0; pp++)
+    {
+    if (isspace(*pp)) continue;
+    c = *pp++;
+
+    /* Handle a literal substring */
+
+    if (c == '\'' || c == '"')
+      {
+      uint8_t *pq = pp;
+      for (;; pp++)
+        {
+        d = *pp;
+        if (d == 0)
+          {
+          fprintf(outfile, "** Missing closing quote in hex pattern: "
+            "opening quote is at offset %" PTR_FORM ".\n", pq - buffer - 2);
+          return PR_SKIP;
+          }
+        if (d == c) break;
+        *pt++ = d;
+        }
+      }
+
+    /* Expect a hex pair */
+
+    else
+      {
+      if (!isxdigit(c))
+        {
+        fprintf(outfile, "** Unexpected non-hex-digit '%c' at offset %"
+          PTR_FORM " in hex pattern: quote missing?\n", c, pp - buffer - 2);
+        return PR_SKIP;
+        }
+      if (*pp == 0)
+        {
+        fprintf(outfile, "** Odd number of digits in hex pattern\n");
+        return PR_SKIP;
+        }
+      d = *pp;
+      if (!isxdigit(d))
+        {
+        fprintf(outfile, "** Unexpected non-hex-digit '%c' at offset %"
+          PTR_FORM " in hex pattern: quote missing?\n", d, pp - buffer - 1);
+        return PR_SKIP;
+        }
+      c = toupper(c);
+      d = toupper(d);
+      *pt++ = ((isdigit(c)? (c - '0') : (c - 'A' + 10)) << 4) +
+               (isdigit(d)? (d - '0') : (d - 'A' + 10));
+      }
+    }
+  *pt = 0;
+  patlen = pt - pbuffer8;
+  }
+
+/* If not a hex string, process for repetition expansion if requested. */
+
+else if ((pat_patctl.control & CTL_EXPAND) != 0)
+  {
+  uint8_t *pp, *pt;
+
+  pt = pbuffer8;
+  for (pp = buffer + 1; *pp != 0; pp++)
+    {
+    uint8_t *pc = pp;
+    uint32_t count = 1;
+    size_t length = 1;
+
+    /* Check for replication syntax; if not found, the defaults just set will
+    prevail and one character will be copied. */
+
+    if (pp[0] == '\\' && pp[1] == '[')
+      {
+      uint8_t *pe;
+      for (pe = pp + 2; *pe != 0; pe++)
+        {
+        if (pe[0] == ']' && pe[1] == '{')
+          {
+          uint32_t clen = pe - pc - 2;
+          uint32_t i = 0;
+          unsigned long uli;
+          char *endptr;
+
+          pe += 2;
+          uli = strtoul((const char *)pe, &endptr, 10);
+          if (U32OVERFLOW(uli))
+            {
+            fprintf(outfile, "** Pattern repeat count too large\n");
+            return PR_SKIP;
+            }
+
+          i = (uint32_t)uli;
+          pe = (uint8_t *)endptr;
+          if (*pe == '}')
+            {
+            if (i == 0)
+              {
+              fprintf(outfile, "** Zero repeat not allowed\n");
+              return PR_SKIP;
+              }
+            pc += 2;
+            count = i;
+            length = clen;
+            pp = pe;
+            break;
+            }
+          }
+        }
+      }
+
+    /* Add to output. If the buffer is too small expand it. The function for
+    expanding buffers always keeps buffer and pbuffer8 in step as far as their
+    size goes. */
+
+    while (pt + count * length > pbuffer8 + pbuffer8_size)
+      {
+      size_t pc_offset = pc - buffer;
+      size_t pp_offset = pp - buffer;
+      size_t pt_offset = pt - pbuffer8;
+      expand_input_buffers();
+      pc = buffer + pc_offset;
+      pp = buffer + pp_offset;
+      pt = pbuffer8 + pt_offset;
+      }
+
+    for (; count > 0; count--)
+      {
+      memcpy(pt, pc, length);
+      pt += length;
+      }
+    }
+
+  *pt = 0;
+  patlen = pt - pbuffer8;
+
+  if ((pat_patctl.control & CTL_INFO) != 0)
+    fprintf(outfile, "Expanded: %s\n", pbuffer8);
+  }
+
+/* Neither hex nor expanded, just copy the input verbatim. */
+
+else
+  {
+  strncpy((char *)pbuffer8, (char *)(buffer+1), patlen + 1);
+  }
+
+/* Sort out character tables */
+
+if (pat_patctl.locale[0] != 0)
+  {
+  if (pat_patctl.tables_id != 0)
+    {
+    fprintf(outfile, "** 'Locale' and 'tables' must not both be set\n");
+    return PR_SKIP;
+    }
+  if (setlocale(LC_CTYPE, (const char *)pat_patctl.locale) == NULL)
+    {
+    fprintf(outfile, "** Failed to set locale '%s'\n", pat_patctl.locale);
+    return PR_SKIP;
+    }
+  if (strcmp((const char *)pat_patctl.locale, (const char *)locale_name) != 0)
+    {
+    strcpy((char *)locale_name, (char *)pat_patctl.locale);
+    if (locale_tables != NULL) free((void *)locale_tables);
+    PCRE2_MAKETABLES(locale_tables);
+    }
+  use_tables = locale_tables;
+  }
+
+else switch (pat_patctl.tables_id)
+  {
+  case 0: use_tables = NULL; break;
+  case 1: use_tables = tables1; break;
+  case 2: use_tables = tables2; break;
+
+  case 3:
+  if (tables3 == NULL)
+    {
+    fprintf(outfile, "** 'Tables = 3' is invalid: binary tables have not "
+      "been loaded\n");
+    return PR_SKIP;
+    }
+  use_tables = tables3;
+  break;
+
+  default:
+  fprintf(outfile, "** 'Tables' must specify 0, 1, 2, or 3.\n");
+  return PR_SKIP;
+  }
+
+PCRE2_SET_CHARACTER_TABLES(pat_context, use_tables);
+
+/* Set up for the stackguard test. */
+
+if (pat_patctl.stackguard_test != 0)
+  {
+  PCRE2_SET_COMPILE_RECURSION_GUARD(pat_context, stack_guard, NULL);
+  }
+
+/* Handle compiling via the POSIX interface, which doesn't support the
+timing, showing, or debugging options, nor the ability to pass over
+local character tables. Neither does it have 16-bit or 32-bit support. */
+
+if ((pat_patctl.control & CTL_POSIX) != 0)
+  {
+#ifdef SUPPORT_PCRE2_8
+  int rc;
+  int cflags = 0;
+  const char *msg = "** Ignored with POSIX interface:";
+#endif
+
+  if (test_mode != PCRE8_MODE)
+    {
+    fprintf(outfile, "** The POSIX interface is available only in 8-bit mode\n");
+    return PR_SKIP;
+    }
+
+#ifdef SUPPORT_PCRE2_8
+  /* Check for features that the POSIX interface does not support. */
+
+  if (pat_patctl.locale[0] != 0) prmsg(&msg, "locale");
+  if (pat_patctl.replacement[0] != 0) prmsg(&msg, "replace");
+  if (pat_patctl.tables_id != 0) prmsg(&msg, "tables");
+  if (pat_patctl.stackguard_test != 0) prmsg(&msg, "stackguard");
+  if (timeit > 0) prmsg(&msg, "timing");
+  if (pat_patctl.jit != 0) prmsg(&msg, "JIT");
+
+  if ((pat_patctl.options & ~POSIX_SUPPORTED_COMPILE_OPTIONS) != 0)
+    {
+    show_compile_options(
+      pat_patctl.options & ~POSIX_SUPPORTED_COMPILE_OPTIONS, msg, "");
+    msg = "";
+    }
+
+  if ((FLD(pat_context, extra_options) &
+       ~POSIX_SUPPORTED_COMPILE_EXTRA_OPTIONS) != 0)
+    {
+    show_compile_extra_options(
+      FLD(pat_context, extra_options) & ~POSIX_SUPPORTED_COMPILE_EXTRA_OPTIONS,
+        msg, "");
+    msg = "";
+    }
+
+  if ((pat_patctl.control & ~POSIX_SUPPORTED_COMPILE_CONTROLS) != 0 ||
+      (pat_patctl.control2 & ~POSIX_SUPPORTED_COMPILE_CONTROLS2) != 0)
+    {
+    show_controls(pat_patctl.control & ~POSIX_SUPPORTED_COMPILE_CONTROLS,
+      pat_patctl.control2 & ~POSIX_SUPPORTED_COMPILE_CONTROLS2, msg);
+    msg = "";
+    }
+
+  if (local_newline_default != 0) prmsg(&msg, "#newline_default");
+  if (FLD(pat_context, max_pattern_length) != PCRE2_UNSET)
+    prmsg(&msg, "max_pattern_length");
+  if (FLD(pat_context, parens_nest_limit) != PARENS_NEST_DEFAULT)
+    prmsg(&msg, "parens_nest_limit");
+
+  if (msg[0] == 0) fprintf(outfile, "\n");
+
+  /* Translate PCRE2 options to POSIX options and then compile. */
+
+  if (utf) cflags |= REG_UTF;
+  if ((pat_patctl.control & CTL_POSIX_NOSUB) != 0) cflags |= REG_NOSUB;
+  if ((pat_patctl.options & PCRE2_UCP) != 0) cflags |= REG_UCP;
+  if ((pat_patctl.options & PCRE2_CASELESS) != 0) cflags |= REG_ICASE;
+  if ((pat_patctl.options & PCRE2_LITERAL) != 0) cflags |= REG_NOSPEC;
+  if ((pat_patctl.options & PCRE2_MULTILINE) != 0) cflags |= REG_NEWLINE;
+  if ((pat_patctl.options & PCRE2_DOTALL) != 0) cflags |= REG_DOTALL;
+  if ((pat_patctl.options & PCRE2_UNGREEDY) != 0) cflags |= REG_UNGREEDY;
+
+  if ((pat_patctl.control & (CTL_HEXPAT|CTL_USE_LENGTH)) != 0)
+    {
+    preg.re_endp = (char *)pbuffer8 + patlen;
+    cflags |= REG_PEND;
+    }
+
+  rc = regcomp(&preg, (char *)pbuffer8, cflags);
+
+  /* Compiling failed */
+
+  if (rc != 0)
+    {
+    size_t bsize, usize;
+    int psize;
+
+    preg.re_pcre2_code = NULL;     /* In case something was left in there */
+    preg.re_match_data = NULL;
+
+    bsize = (pat_patctl.regerror_buffsize != 0)?
+      pat_patctl.regerror_buffsize : pbuffer8_size;
+    if (bsize + 8 < pbuffer8_size)
+      memcpy(pbuffer8 + bsize, "DEADBEEF", 8);
+    usize = regerror(rc, &preg, (char *)pbuffer8, bsize);
+
+    /* Inside regerror(), snprintf() is used. If the buffer is too small, some
+    versions of snprintf() put a zero byte at the end, but others do not.
+    Therefore, we print a maximum of one less than the size of the buffer. */
+
+    psize = (int)bsize - 1;
+    fprintf(outfile, "Failed: POSIX code %d: %.*s\n", rc, psize, pbuffer8);
+    if (usize > bsize)
+      {
+      fprintf(outfile, "** regerror() message truncated\n");
+      if (memcmp(pbuffer8 + bsize, "DEADBEEF", 8) != 0)
+        fprintf(outfile, "** regerror() buffer overflow\n");
+      }
+    return PR_SKIP;
+    }
+
+  /* Compiling succeeded. Check that the values in the preg block are sensible.
+  It can happen that pcre2test is accidentally linked with a different POSIX
+  library which succeeds, but of course puts different things into preg. In
+  this situation, calling regfree() may cause a segfault (or invalid free() in
+  valgrind), so ensure that preg.re_pcre2_code is NULL, which suppresses the
+  calling of regfree() on exit. */
+
+  if (preg.re_pcre2_code == NULL ||
+      ((pcre2_real_code_8 *)preg.re_pcre2_code)->magic_number != MAGIC_NUMBER ||
+      ((pcre2_real_code_8 *)preg.re_pcre2_code)->top_bracket != preg.re_nsub ||
+      preg.re_match_data == NULL ||
+      preg.re_cflags != cflags)
+    {
+    fprintf(outfile,
+      "** The regcomp() function returned zero (success), but the values set\n"
+      "** in the preg block are not valid for PCRE2. Check that pcre2test is\n"
+      "** linked with PCRE2's pcre2posix module (-lpcre2-posix) and not with\n"
+      "** some other POSIX regex library.\n**\n");
+    preg.re_pcre2_code = NULL;
+    return PR_ABEND;
+    }
+
+  return PR_OK;
+#endif  /* SUPPORT_PCRE2_8 */
+  }
+
+/* Handle compiling via the native interface. Controls that act later are
+ignored with "push". Replacements are locked out. */
+
+if ((pat_patctl.control & (CTL_PUSH|CTL_PUSHCOPY|CTL_PUSHTABLESCOPY)) != 0)
+  {
+  if (pat_patctl.replacement[0] != 0)
+    {
+    fprintf(outfile, "** Replacement text is not supported with 'push'.\n");
+    return PR_OK;
+    }
+  if ((pat_patctl.control & ~PUSH_SUPPORTED_COMPILE_CONTROLS) != 0 ||
+      (pat_patctl.control2 & ~PUSH_SUPPORTED_COMPILE_CONTROLS2) != 0)
+    {
+    show_controls(pat_patctl.control & ~PUSH_SUPPORTED_COMPILE_CONTROLS,
+                  pat_patctl.control2 & ~PUSH_SUPPORTED_COMPILE_CONTROLS2,
+      "** Ignored when compiled pattern is stacked with 'push':");
+    fprintf(outfile, "\n");
+    }
+  if ((pat_patctl.control & PUSH_COMPILE_ONLY_CONTROLS) != 0 ||
+      (pat_patctl.control2 & PUSH_COMPILE_ONLY_CONTROLS2) != 0)
+    {
+    show_controls(pat_patctl.control & PUSH_COMPILE_ONLY_CONTROLS,
+                  pat_patctl.control2 & PUSH_COMPILE_ONLY_CONTROLS2,
+      "** Applies only to compile when pattern is stacked with 'push':");
+    fprintf(outfile, "\n");
+    }
+  }
+
+/* Convert the input in non-8-bit modes. */
+
+errorcode = 0;
+
+#ifdef SUPPORT_PCRE2_16
+if (test_mode == PCRE16_MODE) errorcode = to16(pbuffer8, utf, &patlen);
+#endif
+
+#ifdef SUPPORT_PCRE2_32
+if (test_mode == PCRE32_MODE) errorcode = to32(pbuffer8, utf, &patlen);
+#endif
+
+switch(errorcode)
+  {
+  case -1:
+  fprintf(outfile, "** Failed: invalid UTF-8 string cannot be "
+    "converted to %d-bit string\n", (test_mode == PCRE16_MODE)? 16:32);
+  return PR_SKIP;
+
+  case -2:
+  fprintf(outfile, "** Failed: character value greater than 0x10ffff "
+    "cannot be converted to UTF\n");
+  return PR_SKIP;
+
+  case -3:
+  fprintf(outfile, "** Failed: character value greater than 0xffff "
+    "cannot be converted to 16-bit in non-UTF mode\n");
+  return PR_SKIP;
+
+  default:
+  break;
+  }
+
+/* The pattern is now in pbuffer[8|16|32], with the length in code units in
+patlen. If it is to be converted, copy the result back afterwards so that it
+ends up back in the usual place. */
+
+if (pat_patctl.convert_type != CONVERT_UNSET)
+  {
+  int rc;
+  int convert_return = PR_OK;
+  uint32_t convert_options = pat_patctl.convert_type;
+  void *converted_pattern;
+  PCRE2_SIZE converted_length;
+
+  if (pat_patctl.convert_length != 0)
+    {
+    converted_length = pat_patctl.convert_length;
+    converted_pattern = malloc(converted_length * code_unit_size);
+    if (converted_pattern == NULL)
+      {
+      fprintf(outfile, "** Failed: malloc failed for converted pattern\n");
+      return PR_SKIP;
+      }
+    }
+  else converted_pattern = NULL;  /* Let the library allocate */
+
+  if (utf) convert_options |= PCRE2_CONVERT_UTF;
+  if ((pat_patctl.options & PCRE2_NO_UTF_CHECK) != 0)
+    convert_options |= PCRE2_CONVERT_NO_UTF_CHECK;
+
+  CONCTXCPY(con_context, default_con_context);
+
+  if (pat_patctl.convert_glob_escape != 0)
+    {
+    uint32_t escape = (pat_patctl.convert_glob_escape == '0')? 0 :
+      pat_patctl.convert_glob_escape;
+    PCRE2_SET_GLOB_ESCAPE(rc, con_context, escape);
+    if (rc != 0)
+      {
+      fprintf(outfile, "** Invalid glob escape '%c'\n",
+        pat_patctl.convert_glob_escape);
+      convert_return = PR_SKIP;
+      goto CONVERT_FINISH;
+      }
+    }
+
+  if (pat_patctl.convert_glob_separator != 0)
+    {
+    PCRE2_SET_GLOB_SEPARATOR(rc, con_context, pat_patctl.convert_glob_separator);
+    if (rc != 0)
+      {
+      fprintf(outfile, "** Invalid glob separator '%c'\n",
+        pat_patctl.convert_glob_separator);
+      convert_return = PR_SKIP;
+      goto CONVERT_FINISH;
+      }
+    }
+
+  PCRE2_PATTERN_CONVERT(rc, pbuffer, patlen, convert_options,
+    &converted_pattern, &converted_length, con_context);
+
+  if (rc != 0)
+    {
+    fprintf(outfile, "** Pattern conversion error at offset %" SIZ_FORM ": ",
+      SIZ_CAST converted_length);
+    convert_return = print_error_message(rc, "", "\n")? PR_SKIP:PR_ABEND;
+    }
+
+  /* Output the converted pattern, then copy it. */
+
+  else
+    {
+    PCHARSV(converted_pattern, 0, converted_length, utf, outfile);
+    fprintf(outfile, "\n");
+    patlen = converted_length;
+    CONVERT_COPY(pbuffer, converted_pattern, converted_length + 1);
+    }
+
+  /* Free the converted pattern. */
+
+  CONVERT_FINISH:
+  if (pat_patctl.convert_length != 0)
+    free(converted_pattern);
+  else
+    PCRE2_CONVERTED_PATTERN_FREE(converted_pattern);
+
+  /* Return if conversion was unsuccessful. */
+
+  if (convert_return != PR_OK) return convert_return;
+  }
+
+/* By default we pass a zero-terminated pattern, but a length is passed if
+"use_length" was specified or this is a hex pattern (which might contain binary
+zeros). When valgrind is supported, arrange for the unused part of the buffer
+to be marked as no access. */
+
+valgrind_access_length = patlen;
+if ((pat_patctl.control & (CTL_HEXPAT|CTL_USE_LENGTH)) == 0)
+  {
+  patlen = PCRE2_ZERO_TERMINATED;
+  valgrind_access_length += 1;  /* For the terminating zero */
+  }
+
+#ifdef SUPPORT_VALGRIND
+#ifdef SUPPORT_PCRE2_8
+if (test_mode == PCRE8_MODE && pbuffer8 != NULL)
+  {
+  VALGRIND_MAKE_MEM_NOACCESS(pbuffer8 + valgrind_access_length,
+    pbuffer8_size - valgrind_access_length);
+  }
+#endif
+#ifdef SUPPORT_PCRE2_16
+if (test_mode == PCRE16_MODE && pbuffer16 != NULL)
+  {
+  VALGRIND_MAKE_MEM_NOACCESS(pbuffer16 + valgrind_access_length,
+    pbuffer16_size - valgrind_access_length*sizeof(uint16_t));
+  }
+#endif
+#ifdef SUPPORT_PCRE2_32
+if (test_mode == PCRE32_MODE && pbuffer32 != NULL)
+  {
+  VALGRIND_MAKE_MEM_NOACCESS(pbuffer32 + valgrind_access_length,
+    pbuffer32_size - valgrind_access_length*sizeof(uint32_t));
+  }
+#endif
+#else  /* Valgrind not supported */
+(void)valgrind_access_length;  /* Avoid compiler warning */
+#endif
+
+/* If #newline_default has been used and the library was not compiled with an
+appropriate default newline setting, local_newline_default will be non-zero. We
+use this if there is no explicit newline modifier. */
+
+if ((pat_patctl.control2 & CTL2_NL_SET) == 0 && local_newline_default != 0)
+  {
+  SETFLD(pat_context, newline_convention, local_newline_default);
+  }
+
+/* The null_context modifier is used to test calling pcre2_compile() with a
+NULL context. */
+
+use_pat_context = ((pat_patctl.control & CTL_NULLCONTEXT) != 0)?
+  NULL : PTR(pat_context);
+
+/* If PCRE2_LITERAL is set, set use_forbid_utf zero because PCRE2_NEVER_UTF
+and PCRE2_NEVER_UCP are invalid with it. */
+
+if ((pat_patctl.options & PCRE2_LITERAL) != 0) use_forbid_utf = 0;
+
+/* Compile many times when timing. */
+
+if (timeit > 0)
+  {
+  int i;
+  clock_t time_taken = 0;
+  for (i = 0; i < timeit; i++)
+    {
+    clock_t start_time = clock();
+    PCRE2_COMPILE(compiled_code, pbuffer, patlen,
+      pat_patctl.options|use_forbid_utf, &errorcode, &erroroffset,
+        use_pat_context);
+    time_taken += clock() - start_time;
+    if (TEST(compiled_code, !=, NULL))
+      { SUB1(pcre2_code_free, compiled_code); }
+    }
+  total_compile_time += time_taken;
+  fprintf(outfile, "Compile time %.4f milliseconds\n",
+    (((double)time_taken * 1000.0) / (double)timeit) /
+      (double)CLOCKS_PER_SEC);
+  }
+
+/* A final compile that is used "for real". */
+
+PCRE2_COMPILE(compiled_code, pbuffer, patlen, pat_patctl.options|use_forbid_utf,
+  &errorcode, &erroroffset, use_pat_context);
+
+/* Call the JIT compiler if requested. When timing, we must free and recompile
+the pattern each time because that is the only way to free the JIT compiled
+code. We know that compilation will always succeed. */
+
+if (TEST(compiled_code, !=, NULL) && pat_patctl.jit != 0)
+  {
+  if (timeit > 0)
+    {
+    int i;
+    clock_t time_taken = 0;
+
+    for (i = 0; i < timeit; i++)
+      {
+      clock_t start_time;
+      SUB1(pcre2_code_free, compiled_code);
+      PCRE2_COMPILE(compiled_code, pbuffer, patlen,
+        pat_patctl.options|use_forbid_utf, &errorcode, &erroroffset,
+        use_pat_context);
+      start_time = clock();
+      PCRE2_JIT_COMPILE(jitrc, compiled_code, pat_patctl.jit);
+      time_taken += clock() - start_time;
+      }
+    total_jit_compile_time += time_taken;
+    fprintf(outfile, "JIT compile  %.4f milliseconds\n",
+      (((double)time_taken * 1000.0) / (double)timeit) /
+        (double)CLOCKS_PER_SEC);
+    }
+  else
+    {
+    PCRE2_JIT_COMPILE(jitrc, compiled_code, pat_patctl.jit);
+    }
+  }
+
+/* If valgrind is supported, mark the pbuffer as accessible again. The 16-bit
+and 32-bit buffers can be marked completely undefined, but we must leave the
+pattern in the 8-bit buffer defined because it may be read from a callout
+during matching. */
+
+#ifdef SUPPORT_VALGRIND
+#ifdef SUPPORT_PCRE2_8
+if (test_mode == PCRE8_MODE)
+  {
+  VALGRIND_MAKE_MEM_UNDEFINED(pbuffer8 + valgrind_access_length,
+    pbuffer8_size - valgrind_access_length);
+  }
+#endif
+#ifdef SUPPORT_PCRE2_16
+if (test_mode == PCRE16_MODE)
+  {
+  VALGRIND_MAKE_MEM_UNDEFINED(pbuffer16, pbuffer16_size);
+  }
+#endif
+#ifdef SUPPORT_PCRE2_32
+if (test_mode == PCRE32_MODE)
+  {
+  VALGRIND_MAKE_MEM_UNDEFINED(pbuffer32, pbuffer32_size);
+  }
+#endif
+#endif
+
+/* Compilation failed; go back for another re, skipping to blank line
+if non-interactive. */
+
+if (TEST(compiled_code, ==, NULL))
+  {
+  fprintf(outfile, "Failed: error %d at offset %d: ", errorcode,
+    (int)erroroffset);
+  if (!print_error_message(errorcode, "", "\n")) return PR_ABEND;
+  return PR_SKIP;
+  }
+
+/* If forbid_utf is non-zero, we are running a non-UTF test. UTF and UCP are
+locked out at compile time, but we must also check for occurrences of \P, \p,
+and \X, which are only supported when Unicode is supported. */
+
+if (forbid_utf != 0)
+  {
+  if ((FLD(compiled_code, flags) & PCRE2_HASBKPORX) != 0)
+    {
+    fprintf(outfile, "** \\P, \\p, and \\X are not allowed after the "
+      "#forbid_utf command\n");
+    return PR_SKIP;
+    }
+  }
+
+/* Remember the maximum lookbehind, for partial matching. */
+
+if (pattern_info(PCRE2_INFO_MAXLOOKBEHIND, &maxlookbehind, FALSE) != 0)
+  return PR_ABEND;
+
+/* Remember the number of captures. */
+
+if (pattern_info(PCRE2_INFO_CAPTURECOUNT, &maxcapcount, FALSE) < 0)
+  return PR_ABEND;
+
+/* If an explicit newline modifier was given, set the information flag in the
+pattern so that it is preserved over push/pop. */
+
+if ((pat_patctl.control2 & CTL2_NL_SET) != 0)
+  {
+  SETFLD(compiled_code, flags, FLD(compiled_code, flags) | PCRE2_NL_SET);
+  }
+
+/* Output code size and other information if requested. */
+
+if ((pat_patctl.control & CTL_MEMORY) != 0) show_memory_info();
+if ((pat_patctl.control & CTL_FRAMESIZE) != 0) show_framesize();
+if ((pat_patctl.control & CTL_ANYINFO) != 0)
+  {
+  int rc = show_pattern_info();
+  if (rc != PR_OK) return rc;
+  }
+
+/* The "push" control requests that the compiled pattern be remembered on a
+stack. This is mainly for testing the serialization functionality. */
+
+if ((pat_patctl.control & CTL_PUSH) != 0)
+  {
+  if (patstacknext >= PATSTACKSIZE)
+    {
+    fprintf(outfile, "** Too many pushed patterns (max %d)\n", PATSTACKSIZE);
+    return PR_ABEND;
+    }
+  patstack[patstacknext++] = PTR(compiled_code);
+  SET(compiled_code, NULL);
+  }
+
+/* The "pushcopy" and "pushtablescopy" controls are similar, but push a
+copy of the pattern, the latter with a copy of its character tables. This tests
+the pcre2_code_copy() and pcre2_code_copy_with_tables() functions. */
+
+if ((pat_patctl.control & (CTL_PUSHCOPY|CTL_PUSHTABLESCOPY)) != 0)
+  {
+  if (patstacknext >= PATSTACKSIZE)
+    {
+    fprintf(outfile, "** Too many pushed patterns (max %d)\n", PATSTACKSIZE);
+    return PR_ABEND;
+    }
+  if ((pat_patctl.control & CTL_PUSHCOPY) != 0)
+    {
+    PCRE2_CODE_COPY_TO_VOID(patstack[patstacknext++], compiled_code);
+    }
+  else
+    {
+    PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(patstack[patstacknext++],
+      compiled_code); }
+  }
+
+return PR_OK;
+}
+
+
+
+/*************************************************
+*          Check heap, match or depth limit      *
+*************************************************/
+
+/* This is used for DFA, normal, and JIT fast matching. For DFA matching it
+should only be called with the third argument set to PCRE2_ERROR_DEPTHLIMIT.
+
+Arguments:
+  pp        the subject string
+  ulen      length of subject or PCRE2_ZERO_TERMINATED
+  errnumber defines which limit to test
+  msg       string to include in final message
+
+Returns:    the return from the final match function call
+*/
+
+static int
+check_match_limit(uint8_t *pp, PCRE2_SIZE ulen, int errnumber, const char *msg)
+{
+int capcount;
+uint32_t min = 0;
+uint32_t mid = 64;
+uint32_t max = UINT32_MAX;
+
+PCRE2_SET_MATCH_LIMIT(dat_context, max);
+PCRE2_SET_DEPTH_LIMIT(dat_context, max);
+PCRE2_SET_HEAP_LIMIT(dat_context, max);
+
+for (;;)
+  {
+  uint32_t stack_start = 0;
+
+  if (errnumber == PCRE2_ERROR_HEAPLIMIT)
+    {
+    PCRE2_SET_HEAP_LIMIT(dat_context, mid);
+    }
+  else if (errnumber == PCRE2_ERROR_MATCHLIMIT)
+    {
+    PCRE2_SET_MATCH_LIMIT(dat_context, mid);
+    }
+  else
+    {
+    PCRE2_SET_DEPTH_LIMIT(dat_context, mid);
+    }
+
+  if ((dat_datctl.control & CTL_DFA) != 0)
+    {
+    stack_start = DFA_START_RWS_SIZE/1024;
+    if (dfa_workspace == NULL)
+      dfa_workspace = (int *)malloc(DFA_WS_DIMENSION*sizeof(int));
+    if (dfa_matched++ == 0)
+      dfa_workspace[0] = -1;  /* To catch bad restart */
+    PCRE2_DFA_MATCH(capcount, compiled_code, pp, ulen, dat_datctl.offset,
+      dat_datctl.options, match_data,
+      PTR(dat_context), dfa_workspace, DFA_WS_DIMENSION);
+    }
+
+  else if ((pat_patctl.control & CTL_JITFAST) != 0)
+    PCRE2_JIT_MATCH(capcount, compiled_code, pp, ulen, dat_datctl.offset,
+      dat_datctl.options, match_data, PTR(dat_context));
+
+  else
+    {
+    stack_start = START_FRAMES_SIZE/1024;
+    PCRE2_MATCH(capcount, compiled_code, pp, ulen, dat_datctl.offset,
+      dat_datctl.options, match_data, PTR(dat_context));
+    }
+
+  if (capcount == errnumber)
+    {
+    if ((mid & 0x80000000u) != 0)
+      {
+      fprintf(outfile, "Can't find minimum %s limit: check pattern for "
+        "restriction\n", msg);
+      break;
+      }
+
+    min = mid;
+    mid = (mid == max - 1)? max : (max != UINT32_MAX)? (min + max)/2 : mid*2;
+    }
+  else if (capcount >= 0 ||
+           capcount == PCRE2_ERROR_NOMATCH ||
+           capcount == PCRE2_ERROR_PARTIAL)
+    {
+    /* If we've not hit the error with a heap limit less than the size of the
+    initial stack frame vector (for pcre2_match()) or the initial stack
+    workspace vector (for pcre2_dfa_match()), the heap is not being used, so
+    the minimum limit is zero; there's no need to go on. The other limits are
+    always greater than zero. */
+
+    if (errnumber == PCRE2_ERROR_HEAPLIMIT && mid < stack_start)
+      {
+      fprintf(outfile, "Minimum %s limit = 0\n", msg);
+      break;
+      }
+    if (mid == min + 1)
+      {
+      fprintf(outfile, "Minimum %s limit = %d\n", msg, mid);
+      break;
+      }
+    max = mid;
+    mid = (min + max)/2;
+    }
+  else break;    /* Some other error */
+  }
+
+return capcount;
+}
+
+
+
+/*************************************************
+*        Substitute callout function             *
+*************************************************/
+
+/* Called from pcre2_substitute() when the substitute_callout modifier is set.
+Print out the data that is passed back. The substitute callout block is
+identical for all code unit widths, so we just pick one.
+
+Arguments:
+  scb         pointer to substitute callout block
+  data_ptr    callout data
+
+Returns:      nothing
+*/
+
+static int
+substitute_callout_function(pcre2_substitute_callout_block_8 *scb,
+  void *data_ptr)
+{
+int yield = 0;
+BOOL utf = (FLD(compiled_code, overall_options) & PCRE2_UTF) != 0;
+(void)data_ptr;   /* Not used */
+
+fprintf(outfile, "%2d(%d) Old %" SIZ_FORM " %" SIZ_FORM " \"",
+  scb->subscount, scb->oveccount,
+  SIZ_CAST scb->ovector[0], SIZ_CAST scb->ovector[1]);
+
+PCHARSV(scb->input, scb->ovector[0], scb->ovector[1] - scb->ovector[0],
+  utf, outfile);
+
+fprintf(outfile, "\" New %" SIZ_FORM " %" SIZ_FORM " \"",
+  SIZ_CAST scb->output_offsets[0], SIZ_CAST scb->output_offsets[1]);
+
+PCHARSV(scb->output, scb->output_offsets[0],
+  scb->output_offsets[1] - scb->output_offsets[0], utf, outfile);
+
+if (scb->subscount == dat_datctl.substitute_stop)
+  {
+  yield = -1;
+  fprintf(outfile, " STOPPED");
+  }
+else if (scb->subscount == dat_datctl.substitute_skip)
+  {
+  yield = +1;
+  fprintf(outfile, " SKIPPED");
+  }
+
+fprintf(outfile, "\"\n");
+return yield;
+}
+
+
+/*************************************************
+*              Callout function                  *
+*************************************************/
+
+/* Called from a PCRE2 library as a result of the (?C) item. We print out where
+we are in the match (unless suppressed). Yield zero unless more callouts than
+the fail count, or the callout data is not zero. The only differences in the
+callout block for different code unit widths are that the pointers to the
+subject, the most recent MARK, and a callout argument string point to strings
+of the appropriate width. Casts can be used to deal with this.
+
+Arguments:
+  cb                a pointer to a callout block
+  callout_data_ptr  the provided callout data
+
+Returns:            0 or 1 or an error, as determined by settings
+*/
+
+static int
+callout_function(pcre2_callout_block_8 *cb, void *callout_data_ptr)
+{
+FILE *f, *fdefault;
+uint32_t i, pre_start, post_start, subject_length;
+PCRE2_SIZE current_position;
+BOOL utf = (FLD(compiled_code, overall_options) & PCRE2_UTF) != 0;
+BOOL callout_capture = (dat_datctl.control & CTL_CALLOUT_CAPTURE) != 0;
+BOOL callout_where = (dat_datctl.control2 & CTL2_CALLOUT_NO_WHERE) == 0;
+
+/* The FILE f is used for echoing the subject string if it is non-NULL. This
+happens only once in simple cases, but we want to repeat after any additional
+output caused by CALLOUT_EXTRA. */
+
+fdefault = (!first_callout && !callout_capture && cb->callout_string == NULL)?
+  NULL : outfile;
+
+if ((dat_datctl.control2 & CTL2_CALLOUT_EXTRA) != 0)
+  {
+  f = outfile;
+  switch (cb->callout_flags)
+    {
+    case PCRE2_CALLOUT_BACKTRACK:
+    fprintf(f, "Backtrack\n");
+    break;
+
+    case PCRE2_CALLOUT_STARTMATCH|PCRE2_CALLOUT_BACKTRACK:
+    fprintf(f, "Backtrack\nNo other matching paths\n");
+    /* Fall through */
+
+    case PCRE2_CALLOUT_STARTMATCH:
+    fprintf(f, "New match attempt\n");
+    break;
+
+    default:
+    f = fdefault;
+    break;
+    }
+  }
+else f = fdefault;
+
+/* For a callout with a string argument, show the string first because there
+isn't a tidy way to fit it in the rest of the data. */
+
+if (cb->callout_string != NULL)
+  {
+  uint32_t delimiter = CODE_UNIT(cb->callout_string, -1);
+  fprintf(outfile, "Callout (%" SIZ_FORM "): %c",
+    SIZ_CAST cb->callout_string_offset, delimiter);
+  PCHARSV(cb->callout_string, 0,
+    cb->callout_string_length, utf, outfile);
+  for (i = 0; callout_start_delims[i] != 0; i++)
+    if (delimiter == callout_start_delims[i])
+      {
+      delimiter = callout_end_delims[i];
+      break;
+      }
+  fprintf(outfile, "%c", delimiter);
+  if (!callout_capture) fprintf(outfile, "\n");
+  }
+
+/* Show captured strings if required */
+
+if (callout_capture)
+  {
+  if (cb->callout_string == NULL)
+    fprintf(outfile, "Callout %d:", cb->callout_number);
+  fprintf(outfile, " last capture = %d\n", cb->capture_last);
+  for (i = 2; i < cb->capture_top * 2; i += 2)
+    {
+    fprintf(outfile, "%2d: ", i/2);
+    if (cb->offset_vector[i] == PCRE2_UNSET)
+      fprintf(outfile, "<unset>");
+    else
+      {
+      PCHARSV(cb->subject, cb->offset_vector[i],
+        cb->offset_vector[i+1] - cb->offset_vector[i], utf, f);
+      }
+    fprintf(outfile, "\n");
+    }
+  }
+
+/* Unless suppressed, re-print the subject in canonical form (with escapes for
+non-printing characters), the first time, or if giving full details. On
+subsequent calls in the same match, we use PCHARS() just to find the printed
+lengths of the substrings. */
+
+if (callout_where)
+  {
+  if (f != NULL) fprintf(f, "--->");
+
+  /* The subject before the match start. */
+
+  PCHARS(pre_start, cb->subject, 0, cb->start_match, utf, f);
+
+  /* If a lookbehind is involved, the current position may be earlier than the
+  match start. If so, use the match start instead. */
+
+  current_position = (cb->current_position >= cb->start_match)?
+    cb->current_position : cb->start_match;
+
+  /* The subject between the match start and the current position. */
+
+  PCHARS(post_start, cb->subject, cb->start_match,
+    current_position - cb->start_match, utf, f);
+
+  /* Print from the current position to the end. */
+
+  PCHARSV(cb->subject, current_position, cb->subject_length - current_position,
+    utf, f);
+
+  /* Calculate the total subject printed length (no print). */
+
+  PCHARS(subject_length, cb->subject, 0, cb->subject_length, utf, NULL);
+
+  if (f != NULL) fprintf(f, "\n");
+
+  /* For automatic callouts, show the pattern offset. Otherwise, for a
+  numerical callout whose number has not already been shown with captured
+  strings, show the number here. A callout with a string argument has been
+  displayed above. */
+
+  if (cb->callout_number == 255)
+    {
+    fprintf(outfile, "%+3d ", (int)cb->pattern_position);
+    if (cb->pattern_position > 99) fprintf(outfile, "\n    ");
+    }
+  else
+    {
+    if (callout_capture || cb->callout_string != NULL) fprintf(outfile, "    ");
+      else fprintf(outfile, "%3d ", cb->callout_number);
+    }
+
+  /* Now show position indicators */
+
+  for (i = 0; i < pre_start; i++) fprintf(outfile, " ");
+  fprintf(outfile, "^");
+
+  if (post_start > 0)
+    {
+    for (i = 0; i < post_start - 1; i++) fprintf(outfile, " ");
+    fprintf(outfile, "^");
+    }
+
+  for (i = 0; i < subject_length - pre_start - post_start + 4; i++)
+    fprintf(outfile, " ");
+
+  if (cb->next_item_length != 0)
+    fprintf(outfile, "%.*s", (int)(cb->next_item_length),
+      pbuffer8 + cb->pattern_position);
+  else
+    fprintf(outfile, "End of pattern");
+
+  fprintf(outfile, "\n");
+  }
+
+first_callout = FALSE;
+
+/* Show any mark info */
+
+if (cb->mark != last_callout_mark)
+  {
+  if (cb->mark == NULL)
+    fprintf(outfile, "Latest Mark: <unset>\n");
+  else
+    {
+    fprintf(outfile, "Latest Mark: ");
+    PCHARSV(cb->mark, -1, -1, utf, outfile);
+    putc('\n', outfile);
+    }
+  last_callout_mark = cb->mark;
+  }
+
+/* Show callout data */
+
+if (callout_data_ptr != NULL)
+  {
+  int callout_data = *((int32_t *)callout_data_ptr);
+  if (callout_data != 0)
+    {
+    fprintf(outfile, "Callout data = %d\n", callout_data);
+    return callout_data;
+    }
+  }
+
+/* Keep count and give the appropriate return code */
+
+callout_count++;
+
+if (cb->callout_number == dat_datctl.cerror[0] &&
+    callout_count >= dat_datctl.cerror[1])
+  return PCRE2_ERROR_CALLOUT;
+
+if (cb->callout_number == dat_datctl.cfail[0] &&
+    callout_count >= dat_datctl.cfail[1])
+  return 1;
+
+return 0;
+}
+
+
+
+/*************************************************
+*       Handle *MARK and copy/get tests          *
+*************************************************/
+
+/* This function is called after complete and partial matches. It runs the
+tests for substring extraction.
+
+Arguments:
+  utf       TRUE for utf
+  capcount  return from pcre2_match()
+
+Returns:    FALSE if print_error_message() fails
+*/
+
+static BOOL
+copy_and_get(BOOL utf, int capcount)
+{
+int i;
+uint8_t *nptr;
+
+/* Test copy strings by number */
+
+for (i = 0; i < MAXCPYGET && dat_datctl.copy_numbers[i] >= 0; i++)
+  {
+  int rc;
+  PCRE2_SIZE length, length2;
+  uint32_t copybuffer[256];
+  uint32_t n = (uint32_t)(dat_datctl.copy_numbers[i]);
+  length = sizeof(copybuffer)/code_unit_size;
+  PCRE2_SUBSTRING_COPY_BYNUMBER(rc, match_data, n, copybuffer, &length);
+  if (rc < 0)
+    {
+    fprintf(outfile, "Copy substring %d failed (%d): ", n, rc);
+    if (!print_error_message(rc, "", "\n")) return FALSE;
+    }
+  else
+    {
+    PCRE2_SUBSTRING_LENGTH_BYNUMBER(rc, match_data, n, &length2);
+    if (rc < 0)
+      {
+      fprintf(outfile, "Get substring %d length failed (%d): ", n, rc);
+      if (!print_error_message(rc, "", "\n")) return FALSE;
+      }
+    else if (length2 != length)
+      {
+      fprintf(outfile, "Mismatched substring lengths: %"
+        SIZ_FORM " %" SIZ_FORM "\n", SIZ_CAST length, SIZ_CAST length2);
+      }
+    fprintf(outfile, "%2dC ", n);
+    PCHARSV(copybuffer, 0, length, utf, outfile);
+    fprintf(outfile, " (%" SIZ_FORM ")\n", SIZ_CAST length);
+    }
+  }
+
+/* Test copy strings by name */
+
+nptr = dat_datctl.copy_names;
+for (;;)
+  {
+  int rc;
+  int groupnumber;
+  PCRE2_SIZE length, length2;
+  uint32_t copybuffer[256];
+  int namelen = strlen((const char *)nptr);
+#if defined SUPPORT_PCRE2_16 || defined SUPPORT_PCRE2_32
+  PCRE2_SIZE cnl = namelen;
+#endif
+  if (namelen == 0) break;
+
+#ifdef SUPPORT_PCRE2_8
+  if (test_mode == PCRE8_MODE) strcpy((char *)pbuffer8, (char *)nptr);
+#endif
+#ifdef SUPPORT_PCRE2_16
+  if (test_mode == PCRE16_MODE)(void)to16(nptr, utf, &cnl);
+#endif
+#ifdef SUPPORT_PCRE2_32
+  if (test_mode == PCRE32_MODE)(void)to32(nptr, utf, &cnl);
+#endif
+
+  PCRE2_SUBSTRING_NUMBER_FROM_NAME(groupnumber, compiled_code, pbuffer);
+  if (groupnumber < 0 && groupnumber != PCRE2_ERROR_NOUNIQUESUBSTRING)
+    fprintf(outfile, "Number not found for group '%s'\n", nptr);
+
+  length = sizeof(copybuffer)/code_unit_size;
+  PCRE2_SUBSTRING_COPY_BYNAME(rc, match_data, pbuffer, copybuffer, &length);
+  if (rc < 0)
+    {
+    fprintf(outfile, "Copy substring '%s' failed (%d): ", nptr, rc);
+    if (!print_error_message(rc, "", "\n")) return FALSE;
+    }
+  else
+    {
+    PCRE2_SUBSTRING_LENGTH_BYNAME(rc, match_data, pbuffer, &length2);
+    if (rc < 0)
+      {
+      fprintf(outfile, "Get substring '%s' length failed (%d): ", nptr, rc);
+      if (!print_error_message(rc, "", "\n")) return FALSE;
+      }
+    else if (length2 != length)
+      {
+      fprintf(outfile, "Mismatched substring lengths: %"
+        SIZ_FORM " %" SIZ_FORM "\n", SIZ_CAST length, SIZ_CAST length2);
+      }
+    fprintf(outfile, "  C ");
+    PCHARSV(copybuffer, 0, length, utf, outfile);
+    fprintf(outfile, " (%" SIZ_FORM ") %s", SIZ_CAST length, nptr);
+    if (groupnumber >= 0) fprintf(outfile, " (group %d)\n", groupnumber);
+      else fprintf(outfile, " (non-unique)\n");
+    }
+  nptr += namelen + 1;
+  }
+
+/* Test get strings by number */
+
+for (i = 0; i < MAXCPYGET && dat_datctl.get_numbers[i] >= 0; i++)
+  {
+  int rc;
+  PCRE2_SIZE length;
+  void *gotbuffer;
+  uint32_t n = (uint32_t)(dat_datctl.get_numbers[i]);
+  PCRE2_SUBSTRING_GET_BYNUMBER(rc, match_data, n, &gotbuffer, &length);
+  if (rc < 0)
+    {
+    fprintf(outfile, "Get substring %d failed (%d): ", n, rc);
+    if (!print_error_message(rc, "", "\n")) return FALSE;
+    }
+  else
+    {
+    fprintf(outfile, "%2dG ", n);
+    PCHARSV(gotbuffer, 0, length, utf, outfile);
+    fprintf(outfile, " (%" SIZ_FORM ")\n", SIZ_CAST length);
+    PCRE2_SUBSTRING_FREE(gotbuffer);
+    }
+  }
+
+/* Test get strings by name */
+
+nptr = dat_datctl.get_names;
+for (;;)
+  {
+  PCRE2_SIZE length;
+  void *gotbuffer;
+  int rc;
+  int groupnumber;
+  int namelen = strlen((const char *)nptr);
+#if defined SUPPORT_PCRE2_16 || defined SUPPORT_PCRE2_32
+  PCRE2_SIZE cnl = namelen;
+#endif
+  if (namelen == 0) break;
+
+#ifdef SUPPORT_PCRE2_8
+  if (test_mode == PCRE8_MODE) strcpy((char *)pbuffer8, (char *)nptr);
+#endif
+#ifdef SUPPORT_PCRE2_16
+  if (test_mode == PCRE16_MODE)(void)to16(nptr, utf, &cnl);
+#endif
+#ifdef SUPPORT_PCRE2_32
+  if (test_mode == PCRE32_MODE)(void)to32(nptr, utf, &cnl);
+#endif
+
+  PCRE2_SUBSTRING_NUMBER_FROM_NAME(groupnumber, compiled_code, pbuffer);
+  if (groupnumber < 0 && groupnumber != PCRE2_ERROR_NOUNIQUESUBSTRING)
+    fprintf(outfile, "Number not found for group '%s'\n", nptr);
+
+  PCRE2_SUBSTRING_GET_BYNAME(rc, match_data, pbuffer, &gotbuffer, &length);
+  if (rc < 0)
+    {
+    fprintf(outfile, "Get substring '%s' failed (%d): ", nptr, rc);
+    if (!print_error_message(rc, "", "\n")) return FALSE;
+    }
+  else
+    {
+    fprintf(outfile, "  G ");
+    PCHARSV(gotbuffer, 0, length, utf, outfile);
+    fprintf(outfile, " (%" SIZ_FORM ") %s", SIZ_CAST length, nptr);
+    if (groupnumber >= 0) fprintf(outfile, " (group %d)\n", groupnumber);
+      else fprintf(outfile, " (non-unique)\n");
+    PCRE2_SUBSTRING_FREE(gotbuffer);
+    }
+  nptr += namelen + 1;
+  }
+
+/* Test getting the complete list of captured strings. */
+
+if ((dat_datctl.control & CTL_GETALL) != 0)
+  {
+  int rc;
+  void **stringlist;
+  PCRE2_SIZE *lengths;
+  PCRE2_SUBSTRING_LIST_GET(rc, match_data, &stringlist, &lengths);
+  if (rc < 0)
+    {
+    fprintf(outfile, "get substring list failed (%d): ", rc);
+    if (!print_error_message(rc, "", "\n")) return FALSE;
+    }
+  else
+    {
+    for (i = 0; i < capcount; i++)
+      {
+      fprintf(outfile, "%2dL ", i);
+      PCHARSV(stringlist[i], 0, lengths[i], utf, outfile);
+      putc('\n', outfile);
+      }
+    if (stringlist[i] != NULL)
+      fprintf(outfile, "string list not terminated by NULL\n");
+    PCRE2_SUBSTRING_LIST_FREE(stringlist);
+    }
+  }
+
+return TRUE;
+}
+
+
+
+/*************************************************
+*            Show an entire ovector              *
+*************************************************/
+
+/* This function is called after partial matching or match failure, when the
+"allvector" modifier is set. It is a means of checking the contents of the
+entire ovector, to ensure no modification of fields that should be unchanged.
+
+Arguments:
+  ovector      points to the ovector
+  oveccount    number of pairs
+
+Returns:       nothing
+*/
+
+static void
+show_ovector(PCRE2_SIZE *ovector, uint32_t oveccount)
+{
+uint32_t i;
+for (i = 0; i < 2*oveccount; i += 2)
+  {
+  PCRE2_SIZE start = ovector[i];
+  PCRE2_SIZE end = ovector[i+1];
+
+  fprintf(outfile, "%2d: ", i/2);
+  if (start == PCRE2_UNSET && end == PCRE2_UNSET)
+    fprintf(outfile, "<unset>\n");
+  else if (start == JUNK_OFFSET && end == JUNK_OFFSET)
+    fprintf(outfile, "<unchanged>\n");
+  else
+    fprintf(outfile, "%ld %ld\n", (unsigned long int)start,
+      (unsigned long int)end);
+  }
+}
+
+
+/*************************************************
+*               Process a data line              *
+*************************************************/
+
+/* The line is in buffer; it will not be empty.
+
+Arguments:  none
+
+Returns:    PR_OK     continue processing next line
+            PR_SKIP   skip to a blank line
+            PR_ABEND  abort the pcre2test run
+*/
+
+static int
+process_data(void)
+{
+PCRE2_SIZE len, ulen, arg_ulen;
+uint32_t gmatched;
+uint32_t c, k;
+uint32_t g_notempty = 0;
+uint8_t *p, *pp, *start_rep;
+size_t needlen;
+void *use_dat_context;
+BOOL utf;
+BOOL subject_literal;
+
+PCRE2_SIZE *ovector;
+PCRE2_SIZE ovecsave[3];
+uint32_t oveccount;
+
+#ifdef SUPPORT_PCRE2_8
+uint8_t *q8 = NULL;
+#endif
+#ifdef SUPPORT_PCRE2_16
+uint16_t *q16 = NULL;
+#endif
+#ifdef SUPPORT_PCRE2_32
+uint32_t *q32 = NULL;
+#endif
+
+subject_literal = (pat_patctl.control2 & CTL2_SUBJECT_LITERAL) != 0;
+
+/* Copy the default context and data control blocks to the active ones. Then
+copy from the pattern the controls that can be set in either the pattern or the
+data. This allows them to be overridden in the data line. We do not do this for
+options because those that are common apply separately to compiling and
+matching. */
+
+DATCTXCPY(dat_context, default_dat_context);
+memcpy(&dat_datctl, &def_datctl, sizeof(datctl));
+dat_datctl.control |= (pat_patctl.control & CTL_ALLPD);
+dat_datctl.control2 |= (pat_patctl.control2 & CTL2_ALLPD);
+strcpy((char *)dat_datctl.replacement, (char *)pat_patctl.replacement);
+if (dat_datctl.jitstack == 0) dat_datctl.jitstack = pat_patctl.jitstack;
+
+if (dat_datctl.substitute_skip == 0)
+    dat_datctl.substitute_skip = pat_patctl.substitute_skip;
+if (dat_datctl.substitute_stop == 0)
+    dat_datctl.substitute_stop = pat_patctl.substitute_stop;
+
+/* Initialize for scanning the data line. */
+
+#ifdef SUPPORT_PCRE2_8
+utf = ((((pat_patctl.control & CTL_POSIX) != 0)?
+  ((pcre2_real_code_8 *)preg.re_pcre2_code)->overall_options :
+  FLD(compiled_code, overall_options)) & PCRE2_UTF) != 0;
+#else
+utf = (FLD(compiled_code, overall_options) & PCRE2_UTF) != 0;
+#endif
+
+start_rep = NULL;
+len = strlen((const char *)buffer);
+while (len > 0 && isspace(buffer[len-1])) len--;
+buffer[len] = 0;
+p = buffer;
+while (isspace(*p)) p++;
+
+/* Check that the data is well-formed UTF-8 if we're in UTF mode. To create
+invalid input to pcre2_match(), you must use \x?? or \x{} sequences. */
+
+if (utf)
+  {
+  uint8_t *q;
+  uint32_t cc;
+  int n = 1;
+  for (q = p; n > 0 && *q; q += n) n = utf82ord(q, &cc);
+  if (n <= 0)
+    {
+    fprintf(outfile, "** Failed: invalid UTF-8 string cannot be used as input "
+      "in UTF mode\n");
+    return PR_OK;
+    }
+  }
+
+#ifdef SUPPORT_VALGRIND
+/* Mark the dbuffer as addressable but undefined again. */
+if (dbuffer != NULL)
+  {
+  VALGRIND_MAKE_MEM_UNDEFINED(dbuffer, dbuffer_size);
+  }
+#endif
+
+/* Allocate a buffer to hold the data line; len+1 is an upper bound on
+the number of code units that will be needed (though the buffer may have to be
+extended if replication is involved). */
+
+needlen = (size_t)((len+1) * code_unit_size);
+if (dbuffer == NULL || needlen >= dbuffer_size)
+  {
+  while (needlen >= dbuffer_size) dbuffer_size *= 2;
+  dbuffer = (uint8_t *)realloc(dbuffer, dbuffer_size);
+  if (dbuffer == NULL)
+    {
+    fprintf(stderr, "pcre2test: realloc(%d) failed\n", (int)dbuffer_size);
+    exit(1);
+    }
+  }
+SETCASTPTR(q, dbuffer);  /* Sets q8, q16, or q32, as appropriate. */
+
+/* Scan the data line, interpreting data escapes, and put the result into a
+buffer of the appropriate width. In UTF mode, input is always UTF-8; otherwise,
+in 16- and 32-bit modes, it can be forced to UTF-8 by the utf8_input modifier.
+*/
+
+while ((c = *p++) != 0)
+  {
+  int32_t i = 0;
+  size_t replen;
+
+  /* ] may mark the end of a replicated sequence */
+
+  if (c == ']' && start_rep != NULL)
+    {
+    long li;
+    char *endptr;
+    size_t qoffset = CAST8VAR(q) - dbuffer;
+    size_t rep_offset = start_rep - dbuffer;
+
+    if (*p++ != '{')
+      {
+      fprintf(outfile, "** Expected '{' after \\[....]\n");
+      return PR_OK;
+      }
+
+    li = strtol((const char *)p, &endptr, 10);
+    if (S32OVERFLOW(li))
+      {
+      fprintf(outfile, "** Repeat count too large\n");
+      return PR_OK;
+      }
+
+    p = (uint8_t *)endptr;
+    if (*p++ != '}')
+      {
+      fprintf(outfile, "** Expected '}' after \\[...]{...\n");
+      return PR_OK;
+      }
+
+    i = (int32_t)li;
+    if (i-- == 0)
+      {
+      fprintf(outfile, "** Zero repeat not allowed\n");
+      return PR_OK;
+      }
+
+    replen = CAST8VAR(q) - start_rep;
+    needlen += replen * i;
+
+    if (needlen >= dbuffer_size)
+      {
+      while (needlen >= dbuffer_size) dbuffer_size *= 2;
+      dbuffer = (uint8_t *)realloc(dbuffer, dbuffer_size);
+      if (dbuffer == NULL)
+        {
+        fprintf(stderr, "pcre2test: realloc(%d) failed\n", (int)dbuffer_size);
+        exit(1);
+        }
+      SETCASTPTR(q, dbuffer + qoffset);
+      start_rep = dbuffer + rep_offset;
+      }
+
+    while (i-- > 0)
+      {
+      memcpy(CAST8VAR(q), start_rep, replen);
+      SETPLUS(q, replen/code_unit_size);
+      }
+
+    start_rep = NULL;
+    continue;
+    }
+
+  /* Handle a non-escaped character. In non-UTF 32-bit mode with utf8_input
+  set, do the fudge for setting the top bit. */
+
+  if (c != '\\' || subject_literal)
+    {
+    uint32_t topbit = 0;
+    if (test_mode == PCRE32_MODE && c == 0xff && *p != 0)
+      {
+      topbit = 0x80000000;
+      c = *p++;
+      }
+    if ((utf || (pat_patctl.control & CTL_UTF8_INPUT) != 0) &&
+      HASUTF8EXTRALEN(c)) { GETUTF8INC(c, p); }
+    c |= topbit;
+    }
+
+  /* Handle backslash escapes */
+
+  else switch ((c = *p++))
+    {
+    case '\\': break;
+    case 'a': c = CHAR_BEL; break;
+    case 'b': c = '\b'; break;
+    case 'e': c = CHAR_ESC; break;
+    case 'f': c = '\f'; break;
+    case 'n': c = '\n'; break;
+    case 'r': c = '\r'; break;
+    case 't': c = '\t'; break;
+    case 'v': c = '\v'; break;
+
+    case '0': case '1': case '2': case '3':
+    case '4': case '5': case '6': case '7':
+    c -= '0';
+    while (i++ < 2 && isdigit(*p) && *p != '8' && *p != '9')
+      c = c * 8 + *p++ - '0';
+    break;
+
+    case 'o':
+    if (*p == '{')
+      {
+      uint8_t *pt = p;
+      c = 0;
+      for (pt++; isdigit(*pt) && *pt != '8' && *pt != '9'; pt++)
+        {
+        if (++i == 12)
+          fprintf(outfile, "** Too many octal digits in \\o{...} item; "
+                           "using only the first twelve.\n");
+        else c = c * 8 + *pt - '0';
+        }
+      if (*pt == '}') p = pt + 1;
+        else fprintf(outfile, "** Missing } after \\o{ (assumed)\n");
+      }
+    break;
+
+    case 'x':
+    if (*p == '{')
+      {
+      uint8_t *pt = p;
+      c = 0;
+
+      /* We used to have "while (isxdigit(*(++pt)))" here, but it fails
+      when isxdigit() is a macro that refers to its argument more than
+      once. This is banned by the C Standard, but apparently happens in at
+      least one MacOS environment. */
+
+      for (pt++; isxdigit(*pt); pt++)
+        {
+        if (++i == 9)
+          fprintf(outfile, "** Too many hex digits in \\x{...} item; "
+                           "using only the first eight.\n");
+        else c = c * 16 + tolower(*pt) - ((isdigit(*pt))? '0' : 'a' - 10);
+        }
+      if (*pt == '}')
+        {
+        p = pt + 1;
+        break;
+        }
+      /* Not correct form for \x{...}; fall through */
+      }
+
+    /* \x without {} always defines just one byte in 8-bit mode. This
+    allows UTF-8 characters to be constructed byte by byte, and also allows
+    invalid UTF-8 sequences to be made. Just copy the byte in UTF-8 mode.
+    Otherwise, pass it down as data. */
+
+    c = 0;
+    while (i++ < 2 && isxdigit(*p))
+      {
+      c = c * 16 + tolower(*p) - ((isdigit(*p))? '0' : 'a' - 10);
+      p++;
+      }
+#if defined SUPPORT_PCRE2_8
+    if (utf && (test_mode == PCRE8_MODE))
+      {
+      *q8++ = c;
+      continue;
+      }
+#endif
+    break;
+
+    case 0:     /* \ followed by EOF allows for an empty line */
+    p--;
+    continue;
+
+    case '=':   /* \= terminates the data, starts modifiers */
+    goto ENDSTRING;
+
+    case '[':   /* \[ introduces a replicated character sequence */
+    if (start_rep != NULL)
+      {
+      fprintf(outfile, "** Nested replication is not supported\n");
+      return PR_OK;
+      }
+    start_rep = CAST8VAR(q);
+    continue;
+
+    default:
+    if (isalnum(c))
+      {
+      fprintf(outfile, "** Unrecognized escape sequence \"\\%c\"\n", c);
+      return PR_OK;
+      }
+    }
+
+  /* We now have a character value in c that may be greater than 255.
+  In 8-bit mode we convert to UTF-8 if we are in UTF mode. Values greater
+  than 127 in UTF mode must have come from \x{...} or octal constructs
+  because values from \x.. get this far only in non-UTF mode. */
+
+#ifdef SUPPORT_PCRE2_8
+  if (test_mode == PCRE8_MODE)
+    {
+    if (utf)
+      {
+      if (c > 0x7fffffff)
+        {
+        fprintf(outfile, "** Character \\x{%x} is greater than 0x7fffffff "
+          "and so cannot be converted to UTF-8\n", c);
+        return PR_OK;
+        }
+      q8 += ord2utf8(c, q8);
+      }
+    else
+      {
+      if (c > 0xffu)
+        {
+        fprintf(outfile, "** Character \\x{%x} is greater than 255 "
+          "and UTF-8 mode is not enabled.\n", c);
+        fprintf(outfile, "** Truncation will probably give the wrong "
+          "result.\n");
+        }
+      *q8++ = (uint8_t)c;
+      }
+    }
+#endif
+#ifdef SUPPORT_PCRE2_16
+  if (test_mode == PCRE16_MODE)
+    {
+    if (utf)
+      {
+      if (c > 0x10ffffu)
+        {
+        fprintf(outfile, "** Failed: character \\x{%x} is greater than "
+          "0x10ffff and so cannot be converted to UTF-16\n", c);
+        return PR_OK;
+        }
+      else if (c >= 0x10000u)
+        {
+        c-= 0x10000u;
+        *q16++ = 0xD800 | (c >> 10);
+        *q16++ = 0xDC00 | (c & 0x3ff);
+        }
+      else
+        *q16++ = c;
+      }
+    else
+      {
+      if (c > 0xffffu)
+        {
+        fprintf(outfile, "** Character \\x{%x} is greater than 0xffff "
+          "and UTF-16 mode is not enabled.\n", c);
+        fprintf(outfile, "** Truncation will probably give the wrong "
+          "result.\n");
+        }
+
+      *q16++ = (uint16_t)c;
+      }
+    }
+#endif
+#ifdef SUPPORT_PCRE2_32
+  if (test_mode == PCRE32_MODE)
+    {
+    *q32++ = c;
+    }
+#endif
+  }
+
+ENDSTRING:
+SET(*q, 0);
+len = CASTVAR(uint8_t *, q) - dbuffer;    /* Length in bytes */
+ulen = len/code_unit_size;                /* Length in code units */
+arg_ulen = ulen;                          /* Value to use in match arg */
+
+/* If the string was terminated by \= we must now interpret modifiers. */
+
+if (p[-1] != 0 && !decode_modifiers(p, CTX_DAT, NULL, &dat_datctl))
+  return PR_OK;
+
+/* Setting substitute_{skip,fail} implies a substitute callout. */
+
+if (dat_datctl.substitute_skip != 0 || dat_datctl.substitute_stop != 0)
+  dat_datctl.control2 |= CTL2_SUBSTITUTE_CALLOUT;
+
+/* Check for mutually exclusive modifiers. At present, these are all in the
+first control word. */
+
+for (k = 0; k < sizeof(exclusive_dat_controls)/sizeof(uint32_t); k++)
+  {
+  c = dat_datctl.control & exclusive_dat_controls[k];
+  if (c != 0 && c != (c & (~c+1)))
+    {
+    show_controls(c, 0, "** Not allowed together:");
+    fprintf(outfile, "\n");
+    return PR_OK;
+    }
+  }
+
+if (pat_patctl.replacement[0] != 0)
+  {
+  if ((dat_datctl.control2 & CTL2_SUBSTITUTE_CALLOUT) != 0 &&
+      (dat_datctl.control & CTL_NULLCONTEXT) != 0)
+    {
+    fprintf(outfile, "** Replacement callouts are not supported with null_context.\n");
+    return PR_OK;
+    }
+
+  if ((dat_datctl.control & CTL_ALLCAPTURES) != 0)
+    fprintf(outfile, "** Ignored with replacement text: allcaptures\n");
+  }
+
+/* Warn for modifiers that are ignored for DFA. */
+
+if ((dat_datctl.control & CTL_DFA) != 0)
+  {
+  if ((dat_datctl.control & CTL_ALLCAPTURES) != 0)
+    fprintf(outfile, "** Ignored after DFA matching: allcaptures\n");
+  }
+
+/* We now have the subject in dbuffer, with len containing the byte length, and
+ulen containing the code unit length, with a copy in arg_ulen for use in match
+function arguments (this gets changed to PCRE2_ZERO_TERMINATED when the
+zero_terminate modifier is present).
+
+Move the data to the end of the buffer so that a read over the end can be
+caught by valgrind or other means. If we have explicit valgrind support, mark
+the unused start of the buffer unaddressable. If we are using the POSIX
+interface, or testing zero-termination, we must include the terminating zero in
+the usable data. */
+
+c = code_unit_size * (((pat_patctl.control & CTL_POSIX) +
+                       (dat_datctl.control & CTL_ZERO_TERMINATE) != 0)? 1:0);
+pp = memmove(dbuffer + dbuffer_size - len - c, dbuffer, len + c);
+#ifdef SUPPORT_VALGRIND
+  VALGRIND_MAKE_MEM_NOACCESS(dbuffer, dbuffer_size - (len + c));
+#endif
+
+/* Now pp points to the subject string. POSIX matching is only possible in
+8-bit mode, and it does not support timing or other fancy features. Some were
+checked at compile time, but we need to check the match-time settings here. */
+
+#ifdef SUPPORT_PCRE2_8
+if ((pat_patctl.control & CTL_POSIX) != 0)
+  {
+  int rc;
+  int eflags = 0;
+  regmatch_t *pmatch = NULL;
+  const char *msg = "** Ignored with POSIX interface:";
+
+  if (dat_datctl.cerror[0] != CFORE_UNSET || dat_datctl.cerror[1] != CFORE_UNSET)
+    prmsg(&msg, "callout_error");
+  if (dat_datctl.cfail[0] != CFORE_UNSET || dat_datctl.cfail[1] != CFORE_UNSET)
+    prmsg(&msg, "callout_fail");
+  if (dat_datctl.copy_numbers[0] >= 0 || dat_datctl.copy_names[0] != 0)
+    prmsg(&msg, "copy");
+  if (dat_datctl.get_numbers[0] >= 0 || dat_datctl.get_names[0] != 0)
+    prmsg(&msg, "get");
+  if (dat_datctl.jitstack != 0) prmsg(&msg, "jitstack");
+  if (dat_datctl.offset != 0) prmsg(&msg, "offset");
+
+  if ((dat_datctl.options & ~POSIX_SUPPORTED_MATCH_OPTIONS) != 0)
+    {
+    fprintf(outfile, "%s", msg);
+    show_match_options(dat_datctl.options & ~POSIX_SUPPORTED_MATCH_OPTIONS);
+    msg = "";
+    }
+  if ((dat_datctl.control & ~POSIX_SUPPORTED_MATCH_CONTROLS) != 0 ||
+      (dat_datctl.control2 & ~POSIX_SUPPORTED_MATCH_CONTROLS2) != 0)
+    {
+    show_controls(dat_datctl.control & ~POSIX_SUPPORTED_MATCH_CONTROLS,
+                  dat_datctl.control2 & ~POSIX_SUPPORTED_MATCH_CONTROLS2, msg);
+    msg = "";
+    }
+
+  if (msg[0] == 0) fprintf(outfile, "\n");
+
+  if (dat_datctl.oveccount > 0)
+    {
+    pmatch = (regmatch_t *)malloc(sizeof(regmatch_t) * dat_datctl.oveccount);
+    if (pmatch == NULL)
+      {
+      fprintf(outfile, "** Failed to get memory for recording matching "
+        "information (size set = %du)\n", dat_datctl.oveccount);
+      return PR_OK;
+      }
+    }
+
+  if (dat_datctl.startend[0] != CFORE_UNSET)
+    {
+    pmatch[0].rm_so = dat_datctl.startend[0];
+    pmatch[0].rm_eo = (dat_datctl.startend[1] != 0)?
+      dat_datctl.startend[1] : len;
+    eflags |= REG_STARTEND;
+    }
+
+  if ((dat_datctl.options & PCRE2_NOTBOL) != 0) eflags |= REG_NOTBOL;
+  if ((dat_datctl.options & PCRE2_NOTEOL) != 0) eflags |= REG_NOTEOL;
+  if ((dat_datctl.options & PCRE2_NOTEMPTY) != 0) eflags |= REG_NOTEMPTY;
+
+  rc = regexec(&preg, (const char *)pp, dat_datctl.oveccount, pmatch, eflags);
+  if (rc != 0)
+    {
+    (void)regerror(rc, &preg, (char *)pbuffer8, pbuffer8_size);
+    fprintf(outfile, "No match: POSIX code %d: %s\n", rc, pbuffer8);
+    }
+  else if ((pat_patctl.control & CTL_POSIX_NOSUB) != 0)
+    fprintf(outfile, "Matched with REG_NOSUB\n");
+  else if (dat_datctl.oveccount == 0)
+    fprintf(outfile, "Matched without capture\n");
+  else
+    {
+    size_t i, j;
+    size_t last_printed = (size_t)dat_datctl.oveccount;
+    for (i = 0; i < (size_t)dat_datctl.oveccount; i++)
+      {
+      if (pmatch[i].rm_so >= 0)
+        {
+        PCRE2_SIZE start = pmatch[i].rm_so;
+        PCRE2_SIZE end = pmatch[i].rm_eo;
+        for (j = last_printed + 1; j < i; j++)
+          fprintf(outfile, "%2d: <unset>\n", (int)j);
+        last_printed = i;
+        if (start > end)
+          {
+          start = pmatch[i].rm_eo;
+          end = pmatch[i].rm_so;
+          fprintf(outfile, "Start of matched string is beyond its end - "
+            "displaying from end to start.\n");
+          }
+        fprintf(outfile, "%2d: ", (int)i);
+        PCHARSV(pp, start, end - start, utf, outfile);
+        fprintf(outfile, "\n");
+
+        if ((i == 0 && (dat_datctl.control & CTL_AFTERTEXT) != 0) ||
+            (dat_datctl.control & CTL_ALLAFTERTEXT) != 0)
+          {
+          fprintf(outfile, "%2d+ ", (int)i);
+          /* Note: don't use the start/end variables here because we want to
+          show the text from what is reported as the end. */
+          PCHARSV(pp, pmatch[i].rm_eo, len - pmatch[i].rm_eo, utf, outfile);
+          fprintf(outfile, "\n"); }
+        }
+      }
+    }
+  free(pmatch);
+  return PR_OK;
+  }
+#endif  /* SUPPORT_PCRE2_8 */
+
+ /* Handle matching via the native interface. Check for consistency of
+modifiers. */
+
+if (dat_datctl.startend[0] != CFORE_UNSET)
+  fprintf(outfile, "** \\=posix_startend ignored for non-POSIX matching\n");
+
+/* ALLUSEDTEXT is not supported with JIT, but JIT is not used with DFA
+matching, even if the JIT compiler was used. */
+
+if ((dat_datctl.control & (CTL_ALLUSEDTEXT|CTL_DFA)) == CTL_ALLUSEDTEXT &&
+    FLD(compiled_code, executable_jit) != NULL)
+  {
+  fprintf(outfile, "** Showing all consulted text is not supported by JIT: ignored\n");
+  dat_datctl.control &= ~CTL_ALLUSEDTEXT;
+  }
+
+/* Handle passing the subject as zero-terminated. */
+
+if ((dat_datctl.control & CTL_ZERO_TERMINATE) != 0)
+  arg_ulen = PCRE2_ZERO_TERMINATED;
+
+/* The nullcontext modifier is used to test calling pcre2_[jit_]match() with a
+NULL context. */
+
+use_dat_context = ((dat_datctl.control & CTL_NULLCONTEXT) != 0)?
+  NULL : PTR(dat_context);
+
+/* Enable display of malloc/free if wanted. We can do this only if either the
+pattern or the subject is processed with a context. */
+
+show_memory = (dat_datctl.control & CTL_MEMORY) != 0;
+
+if (show_memory &&
+    (pat_patctl.control & dat_datctl.control & CTL_NULLCONTEXT) != 0)
+  fprintf(outfile, "** \\=memory requires either a pattern or a subject "
+    "context: ignored\n");
+
+/* Create and assign a JIT stack if requested. */
+
+if (dat_datctl.jitstack != 0)
+  {
+  if (dat_datctl.jitstack != jit_stack_size)
+    {
+    PCRE2_JIT_STACK_FREE(jit_stack);
+    PCRE2_JIT_STACK_CREATE(jit_stack, 1, dat_datctl.jitstack * 1024, NULL);
+    jit_stack_size = dat_datctl.jitstack;
+    }
+  PCRE2_JIT_STACK_ASSIGN(dat_context, jit_callback, jit_stack);
+  }
+
+/* Or de-assign */
+
+else if (jit_stack != NULL)
+  {
+  PCRE2_JIT_STACK_ASSIGN(dat_context, NULL, NULL);
+  PCRE2_JIT_STACK_FREE(jit_stack);
+  jit_stack = NULL;
+  jit_stack_size = 0;
+  }
+
+/* When no JIT stack is assigned, we must ensure that there is a JIT callback
+if we want to verify that JIT was actually used. */
+
+if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_stack == NULL)
+   {
+   PCRE2_JIT_STACK_ASSIGN(dat_context, jit_callback, NULL);
+   }
+
+/* Adjust match_data according to size of offsets required. A size of zero
+causes a new match data block to be obtained that exactly fits the pattern. */
+
+if (dat_datctl.oveccount == 0)
+  {
+  PCRE2_MATCH_DATA_FREE(match_data);
+  PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(match_data, compiled_code, NULL);
+  PCRE2_GET_OVECTOR_COUNT(max_oveccount, match_data);
+  }
+else if (dat_datctl.oveccount <= max_oveccount)
+  {
+  SETFLD(match_data, oveccount, dat_datctl.oveccount);
+  }
+else
+  {
+  max_oveccount = dat_datctl.oveccount;
+  PCRE2_MATCH_DATA_FREE(match_data);
+  PCRE2_MATCH_DATA_CREATE(match_data, max_oveccount, NULL);
+  }
+
+if (CASTVAR(void *, match_data) == NULL)
+  {
+  fprintf(outfile, "** Failed to get memory for recording matching "
+    "information (size requested: %d)\n", dat_datctl.oveccount);
+  max_oveccount = 0;
+  return PR_OK;
+  }
+
+ovector = FLD(match_data, ovector);
+PCRE2_GET_OVECTOR_COUNT(oveccount, match_data);
+
+/* Replacement processing is ignored for DFA matching. */
+
+if (dat_datctl.replacement[0] != 0 && (dat_datctl.control & CTL_DFA) != 0)
+  {
+  fprintf(outfile, "** Ignored for DFA matching: replace\n");
+  dat_datctl.replacement[0] = 0;
+  }
+
+/* If a replacement string is provided, call pcre2_substitute() instead of one
+of the matching functions. First we have to convert the replacement string to
+the appropriate width. */
+
+if (dat_datctl.replacement[0] != 0)
+  {
+  int rc;
+  uint8_t *pr;
+  uint8_t rbuffer[REPLACE_BUFFSIZE];
+  uint8_t nbuffer[REPLACE_BUFFSIZE];
+  uint32_t xoptions;
+  uint32_t emoption;  /* External match option */
+  PCRE2_SIZE j, rlen, nsize, erroroffset;
+  BOOL badutf = FALSE;
+
+#ifdef SUPPORT_PCRE2_8
+  uint8_t *r8 = NULL;
+#endif
+#ifdef SUPPORT_PCRE2_16
+  uint16_t *r16 = NULL;
+#endif
+#ifdef SUPPORT_PCRE2_32
+  uint32_t *r32 = NULL;
+#endif
+
+  /* Fill the ovector with junk to detect elements that do not get set
+  when they should be (relevant only when "allvector" is specified). */
+
+  for (j = 0; j < 2*oveccount; j++) ovector[j] = JUNK_OFFSET;
+
+  if (timeitm)
+    fprintf(outfile, "** Timing is not supported with replace: ignored\n");
+
+  if ((dat_datctl.control & CTL_ALTGLOBAL) != 0)
+    fprintf(outfile, "** Altglobal is not supported with replace: ignored\n");
+
+  /* Check for a test that does substitution after an initial external match.
+  If this is set, we run the external match, but leave the interpretation of
+  its output to pcre2_substitute(). */
+
+  emoption = ((dat_datctl.control2 & CTL2_SUBSTITUTE_MATCHED) == 0)? 0 :
+    PCRE2_SUBSTITUTE_MATCHED;
+
+  if (emoption != 0)
+    {
+    PCRE2_MATCH(rc, compiled_code, pp, arg_ulen, dat_datctl.offset,
+      dat_datctl.options, match_data, use_dat_context);
+    }
+
+  xoptions = emoption |
+             (((dat_datctl.control & CTL_GLOBAL) == 0)? 0 :
+                PCRE2_SUBSTITUTE_GLOBAL) |
+             (((dat_datctl.control2 & CTL2_SUBSTITUTE_EXTENDED) == 0)? 0 :
+                PCRE2_SUBSTITUTE_EXTENDED) |
+             (((dat_datctl.control2 & CTL2_SUBSTITUTE_LITERAL) == 0)? 0 :
+                PCRE2_SUBSTITUTE_LITERAL) |
+             (((dat_datctl.control2 & CTL2_SUBSTITUTE_OVERFLOW_LENGTH) == 0)? 0 :
+                PCRE2_SUBSTITUTE_OVERFLOW_LENGTH) |
+             (((dat_datctl.control2 & CTL2_SUBSTITUTE_REPLACEMENT_ONLY) == 0)? 0 :
+                PCRE2_SUBSTITUTE_REPLACEMENT_ONLY) |
+             (((dat_datctl.control2 & CTL2_SUBSTITUTE_UNKNOWN_UNSET) == 0)? 0 :
+                PCRE2_SUBSTITUTE_UNKNOWN_UNSET) |
+             (((dat_datctl.control2 & CTL2_SUBSTITUTE_UNSET_EMPTY) == 0)? 0 :
+                PCRE2_SUBSTITUTE_UNSET_EMPTY);
+
+  SETCASTPTR(r, rbuffer);  /* Sets r8, r16, or r32, as appropriate. */
+  pr = dat_datctl.replacement;
+
+  /* If the replacement starts with '[<number>]' we interpret that as length
+  value for the replacement buffer. */
+
+  nsize = REPLACE_BUFFSIZE/code_unit_size;
+  if (*pr == '[')
+    {
+    PCRE2_SIZE n = 0;
+    while ((c = *(++pr)) >= CHAR_0 && c <= CHAR_9) n = n * 10 + c - CHAR_0;
+    if (*pr++ != ']')
+      {
+      fprintf(outfile, "Bad buffer size in replacement string\n");
+      return PR_OK;
+      }
+    if (n > nsize)
+      {
+      fprintf(outfile, "Replacement buffer setting (%" SIZ_FORM ") is too "
+        "large (max %" SIZ_FORM ")\n", SIZ_CAST n, SIZ_CAST nsize);
+      return PR_OK;
+      }
+    nsize = n;
+    }
+
+  /* Now copy the replacement string to a buffer of the appropriate width. No
+  escape processing is done for replacements. In UTF mode, check for an invalid
+  UTF-8 input string, and if it is invalid, just copy its code units without
+  UTF interpretation. This provides a means of checking that an invalid string
+  is detected. Otherwise, UTF-8 can be used to include wide characters in a
+  replacement. */
+
+  if (utf) badutf = valid_utf(pr, strlen((const char *)pr), &erroroffset);
+
+  /* Not UTF or invalid UTF-8: just copy the code units. */
+
+  if (!utf || badutf)
+    {
+    while ((c = *pr++) != 0)
+      {
+#ifdef SUPPORT_PCRE2_8
+      if (test_mode == PCRE8_MODE) *r8++ = c;
+#endif
+#ifdef SUPPORT_PCRE2_16
+      if (test_mode == PCRE16_MODE) *r16++ = c;
+#endif
+#ifdef SUPPORT_PCRE2_32
+      if (test_mode == PCRE32_MODE) *r32++ = c;
+#endif
+      }
+    }
+
+  /* Valid UTF-8 replacement string */
+
+  else while ((c = *pr++) != 0)
+    {
+    if (HASUTF8EXTRALEN(c)) { GETUTF8INC(c, pr); }
+
+#ifdef SUPPORT_PCRE2_8
+    if (test_mode == PCRE8_MODE) r8 += ord2utf8(c, r8);
+#endif
+
+#ifdef SUPPORT_PCRE2_16
+    if (test_mode == PCRE16_MODE)
+      {
+      if (c >= 0x10000u)
+        {
+        c-= 0x10000u;
+        *r16++ = 0xD800 | (c >> 10);
+        *r16++ = 0xDC00 | (c & 0x3ff);
+        }
+      else *r16++ = c;
+      }
+#endif
+
+#ifdef SUPPORT_PCRE2_32
+    if (test_mode == PCRE32_MODE) *r32++ = c;
+#endif
+    }
+
+  SET(*r, 0);
+  if ((dat_datctl.control & CTL_ZERO_TERMINATE) != 0)
+    rlen = PCRE2_ZERO_TERMINATED;
+  else
+    rlen = (CASTVAR(uint8_t *, r) - rbuffer)/code_unit_size;
+
+  if ((dat_datctl.control2 & CTL2_SUBSTITUTE_CALLOUT) != 0)
+    {
+    PCRE2_SET_SUBSTITUTE_CALLOUT(dat_context, substitute_callout_function, NULL);
+    }
+  else
+    {
+    PCRE2_SET_SUBSTITUTE_CALLOUT(dat_context, NULL, NULL);  /* No callout */
+    }
+
+  PCRE2_SUBSTITUTE(rc, compiled_code, pp, arg_ulen, dat_datctl.offset,
+    dat_datctl.options|xoptions, match_data, use_dat_context,
+    rbuffer, rlen, nbuffer, &nsize);
+
+  if (rc < 0)
+    {
+    fprintf(outfile, "Failed: error %d", rc);
+    if (rc != PCRE2_ERROR_NOMEMORY && nsize != PCRE2_UNSET)
+      fprintf(outfile, " at offset %ld in replacement", (long int)nsize);
+    fprintf(outfile, ": ");
+    if (!print_error_message(rc, "", "")) return PR_ABEND;
+    if (rc == PCRE2_ERROR_NOMEMORY &&
+        (xoptions & PCRE2_SUBSTITUTE_OVERFLOW_LENGTH) != 0)
+      fprintf(outfile, ": %ld code units are needed", (long int)nsize);
+    }
+  else
+    {
+    fprintf(outfile, "%2d: ", rc);
+    PCHARSV(nbuffer, 0, nsize, utf, outfile);
+    }
+
+  fprintf(outfile, "\n");
+  show_memory = FALSE;
+
+  /* Show final ovector contents if requested. */
+
+  if ((dat_datctl.control2 & CTL2_ALLVECTOR) != 0)
+    show_ovector(ovector, oveccount);
+
+  return PR_OK;
+  }   /* End of substitution handling */
+
+/* When a replacement string is not provided, run a loop for global matching
+with one of the basic matching functions. For altglobal (or first time round
+the loop), set an "unset" value for the previous match info. */
+
+ovecsave[0] = ovecsave[1] = ovecsave[2] = PCRE2_UNSET;
+
+for (gmatched = 0;; gmatched++)
+  {
+  PCRE2_SIZE j;
+  int capcount;
+
+  /* Fill the ovector with junk to detect elements that do not get set
+  when they should be. */
+
+  for (j = 0; j < 2*oveccount; j++) ovector[j] = JUNK_OFFSET;
+
+  /* When matching is via pcre2_match(), we will detect the use of JIT via the
+  stack callback function. */
+
+  jit_was_used = (pat_patctl.control & CTL_JITFAST) != 0;
+
+  /* Do timing if required. */
+
+  if (timeitm > 0)
+    {
+    int i;
+    clock_t start_time, time_taken;
+
+    if ((dat_datctl.control & CTL_DFA) != 0)
+      {
+      if ((dat_datctl.options & PCRE2_DFA_RESTART) != 0)
+        {
+        fprintf(outfile, "Timing DFA restarts is not supported\n");
+        return PR_OK;
+        }
+      if (dfa_workspace == NULL)
+        dfa_workspace = (int *)malloc(DFA_WS_DIMENSION*sizeof(int));
+      start_time = clock();
+      for (i = 0; i < timeitm; i++)
+        {
+        PCRE2_DFA_MATCH(capcount, compiled_code, pp, arg_ulen,
+          dat_datctl.offset, dat_datctl.options | g_notempty, match_data,
+          use_dat_context, dfa_workspace, DFA_WS_DIMENSION);
+        }
+      }
+
+    else if ((pat_patctl.control & CTL_JITFAST) != 0)
+      {
+      start_time = clock();
+      for (i = 0; i < timeitm; i++)
+        {
+        PCRE2_JIT_MATCH(capcount, compiled_code, pp, arg_ulen,
+          dat_datctl.offset, dat_datctl.options | g_notempty, match_data,
+          use_dat_context);
+        }
+      }
+
+    else
+      {
+      start_time = clock();
+      for (i = 0; i < timeitm; i++)
+        {
+        PCRE2_MATCH(capcount, compiled_code, pp, arg_ulen,
+          dat_datctl.offset, dat_datctl.options | g_notempty, match_data,
+          use_dat_context);
+        }
+      }
+    total_match_time += (time_taken = clock() - start_time);
+    fprintf(outfile, "Match time %.4f milliseconds\n",
+      (((double)time_taken * 1000.0) / (double)timeitm) /
+        (double)CLOCKS_PER_SEC);
+    }
+
+  /* Find the heap, match and depth limits if requested. The depth and heap
+  limits are not relevant for JIT. The return from check_match_limit() is the
+  return from the final call to pcre2_match() or pcre2_dfa_match(). */
+
+  if ((dat_datctl.control & CTL_FINDLIMITS) != 0)
+    {
+    capcount = 0;  /* This stops compiler warnings */
+
+    if (FLD(compiled_code, executable_jit) == NULL ||
+          (dat_datctl.options & PCRE2_NO_JIT) != 0)
+      {
+      (void)check_match_limit(pp, arg_ulen, PCRE2_ERROR_HEAPLIMIT, "heap");
+      }
+
+    capcount = check_match_limit(pp, arg_ulen, PCRE2_ERROR_MATCHLIMIT,
+      "match");
+
+    if (FLD(compiled_code, executable_jit) == NULL ||
+        (dat_datctl.options & PCRE2_NO_JIT) != 0 ||
+        (dat_datctl.control & CTL_DFA) != 0)
+      {
+      capcount = check_match_limit(pp, arg_ulen, PCRE2_ERROR_DEPTHLIMIT,
+        "depth");
+      }
+
+    if (capcount == 0)
+      {
+      fprintf(outfile, "Matched, but offsets vector is too small to show all matches\n");
+      capcount = dat_datctl.oveccount;
+      }
+    }
+
+  /* Otherwise just run a single match, setting up a callout if required (the
+  default). There is a copy of the pattern in pbuffer8 for use by callouts. */
+
+  else
+    {
+    if ((dat_datctl.control & CTL_CALLOUT_NONE) == 0)
+      {
+      PCRE2_SET_CALLOUT(dat_context, callout_function,
+        (void *)(&dat_datctl.callout_data));
+      first_callout = TRUE;
+      last_callout_mark = NULL;
+      callout_count = 0;
+      }
+    else
+      {
+      PCRE2_SET_CALLOUT(dat_context, NULL, NULL);  /* No callout */
+      }
+
+    /* Run a single DFA or NFA match. */
+
+    if ((dat_datctl.control & CTL_DFA) != 0)
+      {
+      if (dfa_workspace == NULL)
+        dfa_workspace = (int *)malloc(DFA_WS_DIMENSION*sizeof(int));
+      if (dfa_matched++ == 0)
+        dfa_workspace[0] = -1;  /* To catch bad restart */
+      PCRE2_DFA_MATCH(capcount, compiled_code, pp, arg_ulen,
+        dat_datctl.offset, dat_datctl.options | g_notempty, match_data,
+        use_dat_context, dfa_workspace, DFA_WS_DIMENSION);
+      if (capcount == 0)
+        {
+        fprintf(outfile, "Matched, but offsets vector is too small to show all matches\n");
+        capcount = dat_datctl.oveccount;
+        }
+      }
+    else
+      {
+      if ((pat_patctl.control & CTL_JITFAST) != 0)
+        PCRE2_JIT_MATCH(capcount, compiled_code, pp, arg_ulen, dat_datctl.offset,
+          dat_datctl.options | g_notempty, match_data, use_dat_context);
+      else
+        PCRE2_MATCH(capcount, compiled_code, pp, arg_ulen, dat_datctl.offset,
+          dat_datctl.options | g_notempty, match_data, use_dat_context);
+      if (capcount == 0)
+        {
+        fprintf(outfile, "Matched, but too many substrings\n");
+        capcount = dat_datctl.oveccount;
+        }
+      }
+    }
+
+  /* The result of the match is now in capcount. First handle a successful
+  match. */
+
+  if (capcount >= 0)
+    {
+    int i;
+
+    if (capcount > (int)oveccount)   /* Check for lunatic return value */
+      {
+      fprintf(outfile,
+        "** PCRE2 error: returned count %d is too big for ovector count %d\n",
+        capcount, oveccount);
+      capcount = oveccount;
+      if ((dat_datctl.control & CTL_ANYGLOB) != 0)
+        {
+        fprintf(outfile, "** Global loop abandoned\n");
+        dat_datctl.control &= ~CTL_ANYGLOB;        /* Break g/G loop */
+        }
+      }
+
+    /* If PCRE2_COPY_MATCHED_SUBJECT was set, check that things are as they
+    should be, but not for fast JIT, where it isn't supported. */
+
+    if ((dat_datctl.options & PCRE2_COPY_MATCHED_SUBJECT) != 0 &&
+        (pat_patctl.control & CTL_JITFAST) == 0)
+      {
+      if ((FLD(match_data, flags) & PCRE2_MD_COPIED_SUBJECT) == 0)
+        fprintf(outfile,
+          "** PCRE2 error: flag not set after copy_matched_subject\n");
+
+      if (CASTFLD(void *, match_data, subject) == pp)
+        fprintf(outfile,
+          "** PCRE2 error: copy_matched_subject has not copied\n");
+
+      if (memcmp(CASTFLD(void *, match_data, subject), pp, ulen) != 0)
+        fprintf(outfile,
+          "** PCRE2 error: copy_matched_subject mismatch\n");
+      }
+
+    /* If this is not the first time round a global loop, check that the
+    returned string has changed. If it has not, check for an empty string match
+    at different starting offset from the previous match. This is a failed test
+    retry for null-matching patterns that don't match at their starting offset,
+    for example /(?<=\G.)/. A repeated match at the same point is not such a
+    pattern, and must be discarded, and we then proceed to seek a non-null
+    match at the current point. For any other repeated match, there is a bug
+    somewhere and we must break the loop because it will go on for ever. We
+    know that there are always at least two elements in the ovector. */
+
+    if (gmatched > 0 && ovecsave[0] == ovector[0] && ovecsave[1] == ovector[1])
+      {
+      if (ovector[0] == ovector[1] && ovecsave[2] != dat_datctl.offset)
+        {
+        g_notempty = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED;
+        ovecsave[2] = dat_datctl.offset;
+        continue;    /* Back to the top of the loop */
+        }
+      fprintf(outfile,
+        "** PCRE2 error: global repeat returned the same string as previous\n");
+      fprintf(outfile, "** Global loop abandoned\n");
+      dat_datctl.control &= ~CTL_ANYGLOB;        /* Break g/G loop */
+      }
+
+    /* "allcaptures" requests showing of all captures in the pattern, to check
+    unset ones at the end. It may be set on the pattern or the data. Implement
+    by setting capcount to the maximum. This is not relevant for DFA matching,
+    so ignore it (warning given above). */
+
+    if ((dat_datctl.control & (CTL_ALLCAPTURES|CTL_DFA)) == CTL_ALLCAPTURES)
+      {
+      capcount = maxcapcount + 1;   /* Allow for full match */
+      if (capcount > (int)oveccount) capcount = oveccount;
+      }
+
+    /* "allvector" request showing the entire ovector. */
+
+    if ((dat_datctl.control2 & CTL2_ALLVECTOR) != 0) capcount = oveccount;
+
+    /* Output the captured substrings. Note that, for the matched string,
+    the use of \K in an assertion can make the start later than the end. */
+
+    for (i = 0; i < 2*capcount; i += 2)
+      {
+      PCRE2_SIZE lleft, lmiddle, lright;
+      PCRE2_SIZE start = ovector[i];
+      PCRE2_SIZE end = ovector[i+1];
+
+      if (start > end)
+        {
+        start = ovector[i+1];
+        end = ovector[i];
+        fprintf(outfile, "Start of matched string is beyond its end - "
+          "displaying from end to start.\n");
+        }
+
+      fprintf(outfile, "%2d: ", i/2);
+
+      /* Check for an unset group */
+
+      if (start == PCRE2_UNSET && end == PCRE2_UNSET)
+        {
+        fprintf(outfile, "<unset>\n");
+        continue;
+        }
+
+      /* Check for silly offsets, in particular, values that have not been
+      set when they should have been. However, if we are past the end of the
+      captures for this pattern ("allvector" causes this), or if we are DFA
+      matching, it isn't an error if the entry is unchanged. */
+
+      if (start > ulen || end > ulen)
+        {
+        if (((dat_datctl.control & CTL_DFA) != 0 ||
+              i >= (int)(2*maxcapcount + 2)) &&
+            start == JUNK_OFFSET && end == JUNK_OFFSET)
+          fprintf(outfile, "<unchanged>\n");
+        else
+          fprintf(outfile, "ERROR: bad value(s) for offset(s): 0x%lx 0x%lx\n",
+            (unsigned long int)start, (unsigned long int)end);
+        continue;
+        }
+
+      /* When JIT is not being used, ALLUSEDTEXT may be set. (It if is set with
+      JIT, it is disabled above, with a comment.) When the match is done by the
+      interpreter, leftchar and rightchar are available, and if ALLUSEDTEXT is
+      set, and if the leftmost consulted character is before the start of the
+      match or the rightmost consulted character is past the end of the match,
+      we want to show all consulted characters for the main matched string, and
+      indicate which were lookarounds. */
+
+      if (i == 0)
+        {
+        BOOL showallused;
+        PCRE2_SIZE leftchar, rightchar;
+
+        if ((dat_datctl.control & CTL_ALLUSEDTEXT) != 0)
+          {
+          leftchar = FLD(match_data, leftchar);
+          rightchar = FLD(match_data, rightchar);
+          showallused = i == 0 && (leftchar < start || rightchar > end);
+          }
+        else showallused = FALSE;
+
+        if (showallused)
+          {
+          PCHARS(lleft, pp, leftchar, start - leftchar, utf, outfile);
+          PCHARS(lmiddle, pp, start, end - start, utf, outfile);
+          PCHARS(lright, pp, end, rightchar - end, utf, outfile);
+          if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used)
+            fprintf(outfile, " (JIT)");
+          fprintf(outfile, "\n    ");
+          for (j = 0; j < lleft; j++) fprintf(outfile, "<");
+          for (j = 0; j < lmiddle; j++) fprintf(outfile, " ");
+          for (j = 0; j < lright; j++) fprintf(outfile, ">");
+          }
+
+        /* When a pattern contains \K, the start of match position may be
+        different to the start of the matched string. When this is the case,
+        show it when requested. */
+
+        else if ((dat_datctl.control & CTL_STARTCHAR) != 0)
+          {
+          PCRE2_SIZE startchar;
+          PCRE2_GET_STARTCHAR(startchar, match_data);
+          PCHARS(lleft, pp, startchar, start - startchar, utf, outfile);
+          PCHARSV(pp, start, end - start, utf, outfile);
+          if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used)
+            fprintf(outfile, " (JIT)");
+          if (startchar != start)
+            {
+            fprintf(outfile, "\n    ");
+            for (j = 0; j < lleft; j++) fprintf(outfile, "^");
+            }
+          }
+
+        /* Otherwise, just show the matched string. */
+
+        else
+          {
+          PCHARSV(pp, start, end - start, utf, outfile);
+          if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used)
+            fprintf(outfile, " (JIT)");
+          }
+        }
+
+      /* Not the main matched string. Just show it unadorned. */
+
+      else
+        {
+        PCHARSV(pp, start, end - start, utf, outfile);
+        }
+
+      fprintf(outfile, "\n");
+
+      /* Note: don't use the start/end variables here because we want to
+      show the text from what is reported as the end. */
+
+      if ((dat_datctl.control & CTL_ALLAFTERTEXT) != 0 ||
+          (i == 0 && (dat_datctl.control & CTL_AFTERTEXT) != 0))
+        {
+        fprintf(outfile, "%2d+ ", i/2);
+        PCHARSV(pp, ovector[i+1], ulen - ovector[i+1], utf, outfile);
+        fprintf(outfile, "\n");
+        }
+      }
+
+    /* Output (*MARK) data if requested */
+
+    if ((dat_datctl.control & CTL_MARK) != 0 &&
+         TESTFLD(match_data, mark, !=, NULL))
+      {
+      fprintf(outfile, "MK: ");
+      PCHARSV(CASTFLD(void *, match_data, mark), -1, -1, utf, outfile);
+      fprintf(outfile, "\n");
+      }
+
+    /* Process copy/get strings */
+
+    if (!copy_and_get(utf, capcount)) return PR_ABEND;
+
+    }    /* End of handling a successful match */
+
+  /* There was a partial match. The value of ovector[0] is the bumpalong point,
+  that is, startchar, not any \K point that might have been passed. When JIT is
+  not in use, "allusedtext" may be set, in which case we indicate the leftmost
+  consulted character. */
+
+  else if (capcount == PCRE2_ERROR_PARTIAL)
+    {
+    PCRE2_SIZE leftchar;
+    int backlength;
+    int rubriclength = 0;
+
+    if ((dat_datctl.control & CTL_ALLUSEDTEXT) != 0)
+      {
+      leftchar = FLD(match_data, leftchar);
+      }
+    else leftchar = ovector[0];
+
+    fprintf(outfile, "Partial match");
+    if ((dat_datctl.control & CTL_MARK) != 0 &&
+         TESTFLD(match_data, mark, !=, NULL))
+      {
+      fprintf(outfile, ", mark=");
+      PCHARS(rubriclength, CASTFLD(void *, match_data, mark), -1, -1, utf,
+        outfile);
+      rubriclength += 7;
+      }
+    fprintf(outfile, ": ");
+    rubriclength += 15;
+
+    PCHARS(backlength, pp, leftchar, ovector[0] - leftchar, utf, outfile);
+    PCHARSV(pp, ovector[0], ulen - ovector[0], utf, outfile);
+
+    if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used)
+      fprintf(outfile, " (JIT)");
+    fprintf(outfile, "\n");
+
+    if (backlength != 0)
+      {
+      int i;
+      for (i = 0; i < rubriclength; i++) fprintf(outfile, " ");
+      for (i = 0; i < backlength; i++) fprintf(outfile, "<");
+      fprintf(outfile, "\n");
+      }
+
+    if (ulen != ovector[1])
+      fprintf(outfile, "** ovector[1] is not equal to the subject length: "
+        "%ld != %ld\n", (unsigned long int)ovector[1], (unsigned long int)ulen);
+
+    /* Process copy/get strings */
+
+    if (!copy_and_get(utf, 1)) return PR_ABEND;
+
+    /* "allvector" outputs the entire vector */
+
+    if ((dat_datctl.control2 & CTL2_ALLVECTOR) != 0)
+      show_ovector(ovector, oveccount);
+
+    break;  /* Out of the /g loop */
+    }       /* End of handling partial match */
+
+  /* Failed to match. If this is a /g or /G loop, we might previously have
+  set g_notempty (to PCRE2_NOTEMPTY_ATSTART|PCRE2_ANCHORED) after a null match.
+  If that is the case, this is not necessarily the end. We want to advance the
+  start offset, and continue. We won't be at the end of the string - that was
+  checked before setting g_notempty. We achieve the effect by pretending that a
+  single character was matched.
+
+  Complication arises in the case when the newline convention is "any", "crlf",
+  or "anycrlf". If the previous match was at the end of a line terminated by
+  CRLF, an advance of one character just passes the CR, whereas we should
+  prefer the longer newline sequence, as does the code in pcre2_match().
+
+  Otherwise, in the case of UTF-8 or UTF-16 matching, the advance must be one
+  character, not one byte. */
+
+  else if (g_notempty != 0)   /* There was a previous null match */
+    {
+    uint16_t nl = FLD(compiled_code, newline_convention);
+    PCRE2_SIZE start_offset = dat_datctl.offset;    /* Where the match was */
+    PCRE2_SIZE end_offset = start_offset + 1;
+
+    if ((nl == PCRE2_NEWLINE_CRLF || nl == PCRE2_NEWLINE_ANY ||
+         nl == PCRE2_NEWLINE_ANYCRLF) &&
+        start_offset < ulen - 1 &&
+        CODE_UNIT(pp, start_offset) == '\r' &&
+        CODE_UNIT(pp, end_offset) == '\n')
+      end_offset++;
+
+    else if (utf && test_mode != PCRE32_MODE)
+      {
+      if (test_mode == PCRE8_MODE)
+        {
+        for (; end_offset < ulen; end_offset++)
+          if ((((PCRE2_SPTR8)pp)[end_offset] & 0xc0) != 0x80) break;
+        }
+      else  /* 16-bit mode */
+        {
+        for (; end_offset < ulen; end_offset++)
+          if ((((PCRE2_SPTR16)pp)[end_offset] & 0xfc00) != 0xdc00) break;
+        }
+      }
+
+    SETFLDVEC(match_data, ovector, 0, start_offset);
+    SETFLDVEC(match_data, ovector, 1, end_offset);
+    }  /* End of handling null match in a global loop */
+
+  /* A "normal" match failure. There will be a negative error number in
+  capcount. */
+
+  else
+    {
+    switch(capcount)
+      {
+      case PCRE2_ERROR_NOMATCH:
+      if (gmatched == 0)
+        {
+        fprintf(outfile, "No match");
+        if ((dat_datctl.control & CTL_MARK) != 0 &&
+             TESTFLD(match_data, mark, !=, NULL))
+          {
+          fprintf(outfile, ", mark = ");
+          PCHARSV(CASTFLD(void *, match_data, mark), -1, -1, utf, outfile);
+          }
+        if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used)
+          fprintf(outfile, " (JIT)");
+        fprintf(outfile, "\n");
+
+        /* "allvector" outputs the entire vector */
+
+        if ((dat_datctl.control2 & CTL2_ALLVECTOR) != 0)
+          show_ovector(ovector, oveccount);
+        }
+      break;
+
+      case PCRE2_ERROR_BADUTFOFFSET:
+      fprintf(outfile, "Error %d (bad UTF-%d offset)\n", capcount, test_mode);
+      break;
+
+      default:
+      fprintf(outfile, "Failed: error %d: ", capcount);
+      if (!print_error_message(capcount, "", "")) return PR_ABEND;
+      if (capcount <= PCRE2_ERROR_UTF8_ERR1 &&
+          capcount >= PCRE2_ERROR_UTF32_ERR2)
+        {
+        PCRE2_SIZE startchar;
+        PCRE2_GET_STARTCHAR(startchar, match_data);
+        fprintf(outfile, " at offset %" SIZ_FORM, SIZ_CAST startchar);
+        }
+      fprintf(outfile, "\n");
+      break;
+      }
+
+    break;  /* Out of the /g loop */
+    }       /* End of failed match handling */
+
+  /* Control reaches here in two circumstances: (a) after a match, and (b)
+  after a non-match that immediately followed a match on an empty string when
+  doing a global search. Such a match is done with PCRE2_NOTEMPTY_ATSTART and
+  PCRE2_ANCHORED set in g_notempty. The code above turns it into a fake match
+  of one character. So effectively we get here only after a match. If we
+  are not doing a global search, we are done. */
+
+  if ((dat_datctl.control & CTL_ANYGLOB) == 0) break; else
+    {
+    PCRE2_SIZE match_offset = FLD(match_data, ovector)[0];
+    PCRE2_SIZE end_offset = FLD(match_data, ovector)[1];
+
+    /* We must now set up for the next iteration of a global search. If we have
+    matched an empty string, first check to see if we are at the end of the
+    subject. If so, the loop is over. Otherwise, mimic what Perl's /g option
+    does. Set PCRE2_NOTEMPTY_ATSTART and PCRE2_ANCHORED and try the match again
+    at the same point. If this fails it will be picked up above, where a fake
+    match is set up so that at this point we advance to the next character.
+
+    However, in order to cope with patterns that never match at their starting
+    offset (e.g. /(?<=\G.)/) we don't do this when the match offset is greater
+    than the starting offset. This means there will be a retry with the
+    starting offset at the match offset. If this returns the same match again,
+    it is picked up above and ignored, and the special action is then taken. */
+
+    if (match_offset == end_offset)
+      {
+      if (end_offset == ulen) break;           /* End of subject */
+      if (match_offset <= dat_datctl.offset)
+        g_notempty = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED;
+      }
+
+    /* However, even after matching a non-empty string, there is still one
+    tricky case. If a pattern contains \K within a lookbehind assertion at the
+    start, the end of the matched string can be at the offset where the match
+    started. In the case of a normal /g iteration without special action, this
+    leads to a loop that keeps on returning the same substring. The loop would
+    be caught above, but we really want to move on to the next match. */
+
+    else
+      {
+      g_notempty = 0;   /* Set for a "normal" repeat */
+      if ((dat_datctl.control & CTL_GLOBAL) != 0)
+        {
+        PCRE2_SIZE startchar;
+        PCRE2_GET_STARTCHAR(startchar, match_data);
+        if (end_offset <= startchar)
+          {
+          if (startchar >= ulen) break;       /* End of subject */
+          end_offset = startchar + 1;
+          if (utf && test_mode != PCRE32_MODE)
+            {
+            if (test_mode == PCRE8_MODE)
+              {
+              for (; end_offset < ulen; end_offset++)
+                if ((((PCRE2_SPTR8)pp)[end_offset] & 0xc0) != 0x80) break;
+              }
+            else  /* 16-bit mode */
+              {
+              for (; end_offset < ulen; end_offset++)
+                if ((((PCRE2_SPTR16)pp)[end_offset] & 0xfc00) != 0xdc00) break;
+              }
+            }
+          }
+        }
+      }
+
+    /* For a normal global (/g) iteration, save the current ovector[0,1] and
+    the starting offset so that we can check that they do change each time.
+    Otherwise a matching bug that returns the same string causes an infinite
+    loop. It has happened! Then update the start offset, leaving other
+    parameters alone. */
+
+    if ((dat_datctl.control & CTL_GLOBAL) != 0)
+      {
+      ovecsave[0] = ovector[0];
+      ovecsave[1] = ovector[1];
+      ovecsave[2] = dat_datctl.offset;
+      dat_datctl.offset = end_offset;
+      }
+
+    /* For altglobal, just update the pointer and length. */
+
+    else
+      {
+      pp += end_offset * code_unit_size;
+      len -= end_offset * code_unit_size;
+      ulen -= end_offset;
+      if (arg_ulen != PCRE2_ZERO_TERMINATED) arg_ulen -= end_offset;
+      }
+    }
+  }  /* End of global loop */
+
+show_memory = FALSE;
+return PR_OK;
+}
+
+
+
+
+/*************************************************
+*               Print PCRE2 version              *
+*************************************************/
+
+static void
+print_version(FILE *f)
+{
+VERSION_TYPE *vp;
+fprintf(f, "PCRE2 version ");
+for (vp = version; *vp != 0; vp++) fprintf(f, "%c", *vp);
+fprintf(f, "\n");
+}
+
+
+
+/*************************************************
+*               Print Unicode version            *
+*************************************************/
+
+static void
+print_unicode_version(FILE *f)
+{
+VERSION_TYPE *vp;
+fprintf(f, "Unicode version ");
+for (vp = uversion; *vp != 0; vp++) fprintf(f, "%c", *vp);
+}
+
+
+
+/*************************************************
+*               Print JIT target                 *
+*************************************************/
+
+static void
+print_jit_target(FILE *f)
+{
+VERSION_TYPE *vp;
+for (vp = jittarget; *vp != 0; vp++) fprintf(f, "%c", *vp);
+}
+
+
+
+/*************************************************
+*       Print newline configuration              *
+*************************************************/
+
+/* Output is always to stdout.
+
+Arguments:
+  rc         the return code from PCRE2_CONFIG_NEWLINE
+  isc        TRUE if called from "-C newline"
+Returns:     nothing
+*/
+
+static void
+print_newline_config(uint32_t optval, BOOL isc)
+{
+if (!isc) printf("  Default newline sequence is ");
+if (optval < sizeof(newlines)/sizeof(char *))
+  printf("%s\n", newlines[optval]);
+else
+  printf("a non-standard value: %d\n", optval);
+}
+
+
+
+/*************************************************
+*             Usage function                     *
+*************************************************/
+
+static void
+usage(void)
+{
+printf("Usage:     pcre2test [options] [<input file> [<output file>]]\n\n");
+printf("Input and output default to stdin and stdout.\n");
+#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT)
+printf("If input is a terminal, readline() is used to read from it.\n");
+#else
+printf("This version of pcre2test is not linked with readline().\n");
+#endif
+printf("\nOptions:\n");
+#ifdef SUPPORT_PCRE2_8
+printf("  -8            use the 8-bit library\n");
+#endif
+#ifdef SUPPORT_PCRE2_16
+printf("  -16           use the 16-bit library\n");
+#endif
+#ifdef SUPPORT_PCRE2_32
+printf("  -32           use the 32-bit library\n");
+#endif
+printf("  -ac           set default pattern modifier PCRE2_AUTO_CALLOUT\n");
+printf("  -AC           as -ac, but also set subject 'callout_extra' modifier\n");
+printf("  -b            set default pattern modifier 'fullbincode'\n");
+printf("  -C            show PCRE2 compile-time options and exit\n");
+printf("  -C arg        show a specific compile-time option and exit with its\n");
+printf("                  value if numeric (else 0). The arg can be:\n");
+printf("     backslash-C    use of \\C is enabled [0, 1]\n");
+printf("     bsr            \\R type [ANYCRLF, ANY]\n");
+printf("     ebcdic         compiled for EBCDIC character code [0,1]\n");
+printf("     ebcdic-nl      NL code if compiled for EBCDIC\n");
+printf("     jit            just-in-time compiler supported [0, 1]\n");
+printf("     linksize       internal link size [2, 3, 4]\n");
+printf("     newline        newline type [CR, LF, CRLF, ANYCRLF, ANY, NUL]\n");
+printf("     pcre2-8        8 bit library support enabled [0, 1]\n");
+printf("     pcre2-16       16 bit library support enabled [0, 1]\n");
+printf("     pcre2-32       32 bit library support enabled [0, 1]\n");
+printf("     unicode        Unicode and UTF support enabled [0, 1]\n");
+printf("  -d            set default pattern modifier 'debug'\n");
+printf("  -dfa          set default subject modifier 'dfa'\n");
+printf("  -error <n,m,..>  show messages for error numbers, then exit\n");
+printf("  -help         show usage information\n");
+printf("  -i            set default pattern modifier 'info'\n");
+printf("  -jit          set default pattern modifier 'jit'\n");
+printf("  -jitfast      set default pattern modifier 'jitfast'\n");
+printf("  -jitverify    set default pattern modifier 'jitverify'\n");
+printf("  -LM           list pattern and subject modifiers, then exit\n");
+printf("  -q            quiet: do not output PCRE2 version number at start\n");
+printf("  -pattern <s>  set default pattern modifier fields\n");
+printf("  -subject <s>  set default subject modifier fields\n");
+printf("  -S <n>        set stack size to <n> mebibytes\n");
+printf("  -t [<n>]      time compilation and execution, repeating <n> times\n");
+printf("  -tm [<n>]     time execution (matching) only, repeating <n> times\n");
+printf("  -T            same as -t, but show total times at the end\n");
+printf("  -TM           same as -tm, but show total time at the end\n");
+printf("  -version      show PCRE2 version and exit\n");
+}
+
+
+
+/*************************************************
+*             Handle -C option                   *
+*************************************************/
+
+/* This option outputs configuration options and sets an appropriate return
+code when asked for a single option. The code is abstracted into a separate
+function because of its size. Use whichever pcre2_config() function is
+available.
+
+Argument:   an option name or NULL
+Returns:    the return code
+*/
+
+static int
+c_option(const char *arg)
+{
+uint32_t optval;
+unsigned int i = COPTLISTCOUNT;
+int yield = 0;
+
+if (arg != NULL && arg[0] != CHAR_MINUS)
+  {
+  for (i = 0; i < COPTLISTCOUNT; i++)
+    if (strcmp(arg, coptlist[i].name) == 0) break;
+
+  if (i >= COPTLISTCOUNT)
+    {
+    fprintf(stderr, "** Unknown -C option '%s'\n", arg);
+    return 0;
+    }
+
+  switch (coptlist[i].type)
+    {
+    case CONF_BSR:
+    (void)PCRE2_CONFIG(coptlist[i].value, &optval);
+    printf("%s\n", (optval == PCRE2_BSR_ANYCRLF)? "ANYCRLF" : "ANY");
+    break;
+
+    case CONF_FIX:
+    yield = coptlist[i].value;
+    printf("%d\n", yield);
+    break;
+
+    case CONF_FIZ:
+    optval = coptlist[i].value;
+    printf("%d\n", optval);
+    break;
+
+    case CONF_INT:
+    (void)PCRE2_CONFIG(coptlist[i].value, &yield);
+    printf("%d\n", yield);
+    break;
+
+    case CONF_NL:
+    (void)PCRE2_CONFIG(coptlist[i].value, &optval);
+    print_newline_config(optval, TRUE);
+    break;
+    }
+
+/* For VMS, return the value by setting a symbol, for certain values only. This
+is contributed code which the PCRE2 developers have no means of testing. */
+
+#ifdef __VMS
+
+/* This is the original code provided by the first VMS contributor. */
+#ifdef NEVER
+  if (copytlist[i].type == CONF_FIX || coptlist[i].type == CONF_INT)
+    {
+    char ucname[16];
+    strcpy(ucname, coptlist[i].name);
+    for (i = 0; ucname[i] != 0; i++) ucname[i] = toupper[ucname[i]];
+    vms_setsymbol(ucname, 0, optval);
+    }
+#endif
+
+/* This is the new code, provided by a second VMS contributor. */
+
+  if (coptlist[i].type == CONF_FIX || coptlist[i].type == CONF_INT)
+    {
+    char nam_buf[22], val_buf[4];
+    $DESCRIPTOR(nam, nam_buf);
+    $DESCRIPTOR(val, val_buf);
+
+    strcpy(nam_buf, coptlist[i].name);
+    nam.dsc$w_length = strlen(nam_buf);
+    sprintf(val_buf, "%d", yield);
+    val.dsc$w_length = strlen(val_buf);
+    lib$set_symbol(&nam, &val);
+    }
+#endif  /* __VMS */
+
+  return yield;
+  }
+
+/* No argument for -C: output all configuration information. */
+
+print_version(stdout);
+printf("Compiled with\n");
+
+#ifdef EBCDIC
+printf("  EBCDIC code support: LF is 0x%02x\n", CHAR_LF);
+#if defined NATIVE_ZOS
+printf("  EBCDIC code page %s or similar\n", pcrz_cpversion());
+#endif
+#endif
+
+(void)PCRE2_CONFIG(PCRE2_CONFIG_COMPILED_WIDTHS, &optval);
+if (optval & 1) printf("  8-bit support\n");
+if (optval & 2) printf("  16-bit support\n");
+if (optval & 4) printf("  32-bit support\n");
+
+#ifdef SUPPORT_VALGRIND
+printf("  Valgrind support\n");
+#endif
+
+(void)PCRE2_CONFIG(PCRE2_CONFIG_UNICODE, &optval);
+if (optval != 0)
+  {
+  printf("  UTF and UCP support (");
+  print_unicode_version(stdout);
+  printf(")\n");
+  }
+else printf("  No Unicode support\n");
+
+(void)PCRE2_CONFIG(PCRE2_CONFIG_JIT, &optval);
+if (optval != 0)
+  {
+  printf("  Just-in-time compiler support: ");
+  print_jit_target(stdout);
+  printf("\n");
+  }
+else
+  {
+  printf("  No just-in-time compiler support\n");
+  }
+
+(void)PCRE2_CONFIG(PCRE2_CONFIG_NEWLINE, &optval);
+print_newline_config(optval, FALSE);
+(void)PCRE2_CONFIG(PCRE2_CONFIG_BSR, &optval);
+printf("  \\R matches %s\n",
+  (optval == PCRE2_BSR_ANYCRLF)? "CR, LF, or CRLF only" :
+                                 "all Unicode newlines");
+(void)PCRE2_CONFIG(PCRE2_CONFIG_NEVER_BACKSLASH_C, &optval);
+printf("  \\C is %ssupported\n", optval? "not ":"");
+(void)PCRE2_CONFIG(PCRE2_CONFIG_LINKSIZE, &optval);
+printf("  Internal link size = %d\n", optval);
+(void)PCRE2_CONFIG(PCRE2_CONFIG_PARENSLIMIT, &optval);
+printf("  Parentheses nest limit = %d\n", optval);
+(void)PCRE2_CONFIG(PCRE2_CONFIG_HEAPLIMIT, &optval);
+printf("  Default heap limit = %d kibibytes\n", optval);
+(void)PCRE2_CONFIG(PCRE2_CONFIG_MATCHLIMIT, &optval);
+printf("  Default match limit = %d\n", optval);
+(void)PCRE2_CONFIG(PCRE2_CONFIG_DEPTHLIMIT, &optval);
+printf("  Default depth limit = %d\n", optval);
+
+#if defined SUPPORT_LIBREADLINE
+printf("  pcre2test has libreadline support\n");
+#elif defined SUPPORT_LIBEDIT
+printf("  pcre2test has libedit support\n");
+#else
+printf("  pcre2test has neither libreadline nor libedit support\n");
+#endif
+
+return 0;
+}
+
+
+
+/*************************************************
+*              Display one modifier              *
+*************************************************/
+
+static void
+display_one_modifier(modstruct *m, BOOL for_pattern)
+{
+uint32_t c = (!for_pattern && (m->which == MOD_PND || m->which == MOD_PNDP))?
+  '*' : ' ';
+printf("%c%s", c, m->name);
+}
+
+
+
+/*************************************************
+*       Display pattern or subject modifiers     *
+*************************************************/
+
+/* In order to print in two columns, first scan without printing to get a list
+of the modifiers that are required.
+
+Arguments:
+  for_pattern   TRUE for pattern modifiers, FALSE for subject modifiers
+  title         string to be used in title
+
+Returns:        nothing
+*/
+
+static void
+display_selected_modifiers(BOOL for_pattern, const char *title)
+{
+uint32_t i, j;
+uint32_t n = 0;
+uint32_t list[MODLISTCOUNT];
+
+for (i = 0; i < MODLISTCOUNT; i++)
+  {
+  BOOL is_pattern = TRUE;
+  modstruct *m = modlist + i;
+
+  switch (m->which)
+    {
+    case MOD_CTC:       /* Compile context */
+    case MOD_PAT:       /* Pattern */
+    case MOD_PATP:      /* Pattern, OK for Perl-compatible test */
+    break;
+
+    /* The MOD_PND and MOD_PNDP modifiers are precisely those that affect
+    subjects, but can be given with a pattern. We list them as subject
+    modifiers, but marked with an asterisk.*/
+
+    case MOD_CTM:       /* Match context */
+    case MOD_DAT:       /* Subject line */
+    case MOD_PND:       /* As PD, but not default pattern */
+    case MOD_PNDP:      /* As PND, OK for Perl-compatible test */
+    is_pattern = FALSE;
+    break;
+
+    default: printf("** Unknown type for modifier '%s'\n", m->name);
+    /* Fall through */
+    case MOD_PD:        /* Pattern or subject */
+    case MOD_PDP:       /* As PD, OK for Perl-compatible test */
+    is_pattern = for_pattern;
+    break;
+    }
+
+  if (for_pattern == is_pattern) list[n++] = i;
+  }
+
+/* Now print from the list in two columns. */
+
+printf("-------------- %s MODIFIERS --------------\n", title);
+
+for (i = 0, j = (n+1)/2; i < (n+1)/2; i++, j++)
+  {
+  modstruct *m = modlist + list[i];
+  display_one_modifier(m, for_pattern);
+  if (j < n)
+    {
+    uint32_t k = 27 - strlen(m->name);
+    while (k-- > 0) printf(" ");
+    display_one_modifier(modlist + list[j], for_pattern);
+    }
+  printf("\n");
+  }
+}
+
+
+
+/*************************************************
+*          Display the list of modifiers         *
+*************************************************/
+
+static void
+display_modifiers(void)
+{
+printf(
+  "An asterisk on a subject modifier means that it may be given on a pattern\n"
+  "line, in order to apply to all subjects matched by that pattern. Modifiers\n"
+  "that are listed for both patterns and subjects have different effects in\n"
+  "each case.\n\n");
+display_selected_modifiers(TRUE, "PATTERN");
+printf("\n");
+display_selected_modifiers(FALSE, "SUBJECT");
+}
+
+
+
+/*************************************************
+*                Main Program                    *
+*************************************************/
+
+int
+main(int argc, char **argv)
+{
+uint32_t temp;
+uint32_t yield = 0;
+uint32_t op = 1;
+BOOL notdone = TRUE;
+BOOL quiet = FALSE;
+BOOL showtotaltimes = FALSE;
+BOOL skipping = FALSE;
+char *arg_subject = NULL;
+char *arg_pattern = NULL;
+char *arg_error = NULL;
+
+/* The offsets to the options and control bits fields of the pattern and data
+control blocks must be the same so that common options and controls such as
+"anchored" or "memory" can work for either of them from a single table entry.
+We cannot test this till runtime because "offsetof" does not work in the
+preprocessor. */
+
+if (PO(options) != DO(options) || PO(control) != DO(control) ||
+    PO(control2) != DO(control2))
+  {
+  fprintf(stderr, "** Coding error: "
+    "options and control offsets for pattern and data must be the same.\n");
+  return 1;
+  }
+
+/* Get the PCRE2 and Unicode version number and JIT target information, at the
+same time checking that a request for the length gives the same answer. Also
+check lengths for non-string items. */
+
+if (PCRE2_CONFIG(PCRE2_CONFIG_VERSION, NULL) !=
+    PCRE2_CONFIG(PCRE2_CONFIG_VERSION, version) ||
+
+    PCRE2_CONFIG(PCRE2_CONFIG_UNICODE_VERSION, NULL) !=
+    PCRE2_CONFIG(PCRE2_CONFIG_UNICODE_VERSION, uversion) ||
+
+    PCRE2_CONFIG(PCRE2_CONFIG_JITTARGET, NULL) !=
+    PCRE2_CONFIG(PCRE2_CONFIG_JITTARGET, jittarget) ||
+
+    PCRE2_CONFIG(PCRE2_CONFIG_UNICODE, NULL) != sizeof(uint32_t) ||
+    PCRE2_CONFIG(PCRE2_CONFIG_MATCHLIMIT, NULL) != sizeof(uint32_t))
+  {
+  fprintf(stderr, "** Error in pcre2_config(): bad length\n");
+  return 1;
+  }
+
+/* Check that bad options are diagnosed. */
+
+if (PCRE2_CONFIG(999, NULL) != PCRE2_ERROR_BADOPTION ||
+    PCRE2_CONFIG(999, &temp) != PCRE2_ERROR_BADOPTION)
+  {
+  fprintf(stderr, "** Error in pcre2_config(): bad option not diagnosed\n");
+  return 1;
+  }
+
+/* This configuration option is now obsolete, but running a quick check ensures
+that its code is covered. */
+
+(void)PCRE2_CONFIG(PCRE2_CONFIG_STACKRECURSE, &temp);
+
+/* Get buffers from malloc() so that valgrind will check their misuse when
+debugging. They grow automatically when very long lines are read. The 16-
+and 32-bit buffers (pbuffer16, pbuffer32) are obtained only if needed. */
+
+buffer = (uint8_t *)malloc(pbuffer8_size);
+pbuffer8 = (uint8_t *)malloc(pbuffer8_size);
+
+/* The following  _setmode() stuff is some Windows magic that tells its runtime
+library to translate CRLF into a single LF character. At least, that's what
+I've been told: never having used Windows I take this all on trust. Originally
+it set 0x8000, but then I was advised that _O_BINARY was better. */
+
+#if defined(_WIN32) || defined(WIN32)
+_setmode( _fileno( stdout ), _O_BINARY );
+#endif
+
+/* Initialization that does not depend on the running mode. */
+
+locale_name[0] = 0;
+
+memset(&def_patctl, 0, sizeof(patctl));
+def_patctl.convert_type = CONVERT_UNSET;
+
+memset(&def_datctl, 0, sizeof(datctl));
+def_datctl.oveccount = DEFAULT_OVECCOUNT;
+def_datctl.copy_numbers[0] = -1;
+def_datctl.get_numbers[0] = -1;
+def_datctl.startend[0] = def_datctl.startend[1] = CFORE_UNSET;
+def_datctl.cerror[0] = def_datctl.cerror[1] = CFORE_UNSET;
+def_datctl.cfail[0] = def_datctl.cfail[1] = CFORE_UNSET;
+
+/* Scan command line options. */
+
+while (argc > 1 && argv[op][0] == '-' && argv[op][1] != 0)
+  {
+  char *endptr;
+  char *arg = argv[op];
+  unsigned long uli;
+
+  /* List modifiers and exit. */
+
+  if (strcmp(arg, "-LM") == 0)
+    {
+    display_modifiers();
+    goto EXIT;
+    }
+
+  /* Display and/or set return code for configuration options. */
+
+  if (strcmp(arg, "-C") == 0)
+    {
+    yield = c_option(argv[op + 1]);
+    goto EXIT;
+    }
+
+  /* Select operating mode. Ensure that pcre2_config() is called in 16-bit
+  and 32-bit modes because that won't happen naturally when 8-bit is also
+  configured. Also call some other functions that are not otherwise used. This
+  means that a coverage report won't claim there are uncalled functions. */
+
+  if (strcmp(arg, "-8") == 0)
+    {
+#ifdef SUPPORT_PCRE2_8
+    test_mode = PCRE8_MODE;
+    (void)pcre2_set_bsr_8(pat_context8, 999);
+    (void)pcre2_set_newline_8(pat_context8, 999);
+#else
+    fprintf(stderr,
+      "** This version of PCRE2 was built without 8-bit support\n");
+    exit(1);
+#endif
+    }
+
+  else if (strcmp(arg, "-16") == 0)
+    {
+#ifdef SUPPORT_PCRE2_16
+    test_mode = PCRE16_MODE;
+    (void)pcre2_config_16(PCRE2_CONFIG_VERSION, NULL);
+    (void)pcre2_set_bsr_16(pat_context16, 999);
+    (void)pcre2_set_newline_16(pat_context16, 999);
+#else
+    fprintf(stderr,
+      "** This version of PCRE2 was built without 16-bit support\n");
+    exit(1);
+#endif
+    }
+
+  else if (strcmp(arg, "-32") == 0)
+    {
+#ifdef SUPPORT_PCRE2_32
+    test_mode = PCRE32_MODE;
+    (void)pcre2_config_32(PCRE2_CONFIG_VERSION, NULL);
+    (void)pcre2_set_bsr_32(pat_context32, 999);
+    (void)pcre2_set_newline_32(pat_context32, 999);
+#else
+    fprintf(stderr,
+      "** This version of PCRE2 was built without 32-bit support\n");
+    exit(1);
+#endif
+    }
+
+  /* Set quiet (no version verification) */
+
+  else if (strcmp(arg, "-q") == 0) quiet = TRUE;
+
+  /* Set system stack size */
+
+  else if (strcmp(arg, "-S") == 0 && argc > 2 &&
+      ((uli = strtoul(argv[op+1], &endptr, 10)), *endptr == 0))
+    {
+#if defined(_WIN32) || defined(WIN32) || defined(__minix) || defined(NATIVE_ZOS) || defined(__VMS)
+    fprintf(stderr, "pcre2test: -S is not supported on this OS\n");
+    exit(1);
+#else
+    int rc;
+    uint32_t stack_size;
+    struct rlimit rlim;
+    if (U32OVERFLOW(uli))
+      {
+      fprintf(stderr, "** Argument for -S is too big\n");
+      exit(1);
+      }
+    stack_size = (uint32_t)uli;
+    getrlimit(RLIMIT_STACK, &rlim);
+    rlim.rlim_cur = stack_size * 1024 * 1024;
+    if (rlim.rlim_cur > rlim.rlim_max)
+      {
+      fprintf(stderr,
+        "pcre2test: requested stack size %luMiB is greater than hard limit "
+          "%luMiB\n", (unsigned long int)stack_size,
+          (unsigned long int)(rlim.rlim_max));
+      exit(1);
+      }
+    rc = setrlimit(RLIMIT_STACK, &rlim);
+    if (rc != 0)
+      {
+      fprintf(stderr, "pcre2test: setting stack size %luMiB failed: %s\n",
+        (unsigned long int)stack_size, strerror(errno));
+      exit(1);
+      }
+    op++;
+    argc--;
+#endif
+    }
+
+  /* Set some common pattern and subject controls */
+
+  else if (strcmp(arg, "-AC") == 0)
+    {
+    def_patctl.options |= PCRE2_AUTO_CALLOUT;
+    def_datctl.control2 |= CTL2_CALLOUT_EXTRA;
+    }
+  else if (strcmp(arg, "-ac") == 0)  def_patctl.options |= PCRE2_AUTO_CALLOUT;
+  else if (strcmp(arg, "-b") == 0)   def_patctl.control |= CTL_FULLBINCODE;
+  else if (strcmp(arg, "-d") == 0)   def_patctl.control |= CTL_DEBUG;
+  else if (strcmp(arg, "-dfa") == 0) def_datctl.control |= CTL_DFA;
+  else if (strcmp(arg, "-i") == 0)   def_patctl.control |= CTL_INFO;
+  else if (strcmp(arg, "-jit") == 0 || strcmp(arg, "-jitverify") == 0 ||
+           strcmp(arg, "-jitfast") == 0)
+    {
+    if (arg[4] == 'v') def_patctl.control |= CTL_JITVERIFY;
+      else if (arg[4] == 'f') def_patctl.control |= CTL_JITFAST;
+    def_patctl.jit = JIT_DEFAULT;  /* full & partial */
+#ifndef SUPPORT_JIT
+    fprintf(stderr, "** Warning: JIT support is not available: "
+                    "-jit[fast|verify] calls functions that do nothing.\n");
+#endif
+    }
+
+  /* Set timing parameters */
+
+  else if (strcmp(arg, "-t") == 0 || strcmp(arg, "-tm") == 0 ||
+           strcmp(arg, "-T") == 0 || strcmp(arg, "-TM") == 0)
+    {
+    int both = arg[2] == 0;
+    showtotaltimes = arg[1] == 'T';
+    if (argc > 2 && (uli = strtoul(argv[op+1], &endptr, 10), *endptr == 0))
+      {
+      if (uli == 0)
+        {
+        fprintf(stderr, "** Argument for %s must not be zero\n", arg);
+        exit(1);
+        }
+      if (U32OVERFLOW(uli))
+        {
+        fprintf(stderr, "** Argument for %s is too big\n", arg);
+        exit(1);
+        }
+      timeitm = (int)uli;
+      op++;
+      argc--;
+      }
+    else timeitm = LOOPREPEAT;
+    if (both) timeit = timeitm;
+    }
+
+  /* Give help */
+
+  else if (strcmp(arg, "-help") == 0 ||
+           strcmp(arg, "--help") == 0)
+    {
+    usage();
+    goto EXIT;
+    }
+
+  /* Show version */
+
+  else if (strcmp(arg, "-version") == 0 ||
+           strcmp(arg, "--version") == 0)
+    {
+    print_version(stdout);
+    goto EXIT;
+    }
+
+  /* The following options save their data for processing once we know what
+  the running mode is. */
+
+  else if (strcmp(arg, "-error") == 0)
+    {
+    arg_error = argv[op+1];
+    goto CHECK_VALUE_EXISTS;
+    }
+
+  else if (strcmp(arg, "-subject") == 0)
+    {
+    arg_subject = argv[op+1];
+    goto CHECK_VALUE_EXISTS;
+    }
+
+  else if (strcmp(arg, "-pattern") == 0)
+    {
+    arg_pattern = argv[op+1];
+    CHECK_VALUE_EXISTS:
+    if (argc <= 2)
+      {
+      fprintf(stderr, "** Missing value for %s\n", arg);
+      yield = 1;
+      goto EXIT;
+      }
+    op++;
+    argc--;
+    }
+
+  /* Unrecognized option */
+
+  else
+    {
+    fprintf(stderr, "** Unknown or malformed option '%s'\n", arg);
+    usage();
+    yield = 1;
+    goto EXIT;
+    }
+  op++;
+  argc--;
+  }
+
+/* If -error was present, get the error numbers, show the messages, and exit.
+We wait to do this until we know which mode we are in. */
+
+if (arg_error != NULL)
+  {
+  int len;
+  int errcode;
+  char *endptr;
+
+/* Ensure the relevant non-8-bit buffer is available. Ensure that it is at
+least 128 code units, because it is used for retrieving error messages. */
+
+#ifdef SUPPORT_PCRE2_16
+  if (test_mode == PCRE16_MODE)
+    {
+    pbuffer16_size = 256;
+    pbuffer16 = (uint16_t *)malloc(pbuffer16_size);
+    if (pbuffer16 == NULL)
+      {
+      fprintf(stderr, "pcre2test: malloc(%" SIZ_FORM ") failed for pbuffer16\n",
+        SIZ_CAST pbuffer16_size);
+      yield = 1;
+      goto EXIT;
+      }
+    }
+#endif
+
+#ifdef SUPPORT_PCRE2_32
+  if (test_mode == PCRE32_MODE)
+    {
+    pbuffer32_size = 512;
+    pbuffer32 = (uint32_t *)malloc(pbuffer32_size);
+    if (pbuffer32 == NULL)
+      {
+      fprintf(stderr, "pcre2test: malloc(%" SIZ_FORM ") failed for pbuffer32\n",
+        SIZ_CAST pbuffer32_size);
+      yield = 1;
+      goto EXIT;
+      }
+    }
+#endif
+
+  /* Loop along a list of error numbers. */
+
+  for (;;)
+    {
+    errcode = strtol(arg_error, &endptr, 10);
+    if (*endptr != 0 && *endptr != CHAR_COMMA)
+      {
+      fprintf(stderr, "** '%s' is not a valid error number list\n", arg_error);
+      yield = 1;
+      goto EXIT;
+      }
+    printf("Error %d: ", errcode);
+    PCRE2_GET_ERROR_MESSAGE(len, errcode, pbuffer);
+    if (len < 0)
+      {
+      switch (len)
+        {
+        case PCRE2_ERROR_BADDATA:
+        printf("PCRE2_ERROR_BADDATA (unknown error number)");
+        break;
+
+        case PCRE2_ERROR_NOMEMORY:
+        printf("PCRE2_ERROR_NOMEMORY (buffer too small)");
+        break;
+
+        default:
+        printf("Unexpected return (%d) from pcre2_get_error_message()", len);
+        break;
+        }
+      }
+    else
+      {
+      PCHARSV(CASTVAR(void *, pbuffer), 0, len, FALSE, stdout);
+      }
+    printf("\n");
+    if (*endptr == 0) goto EXIT;
+    arg_error = endptr + 1;
+    }
+  /* Control never reaches here */
+  }  /* End of -error handling */
+
+/* Initialize things that cannot be done until we know which test mode we are
+running in. Exercise the general context copying and match data size functions,
+which are not otherwise used. */
+
+code_unit_size = test_mode/8;
+max_oveccount = DEFAULT_OVECCOUNT;
+
+/* Use macros to save a lot of duplication. */
+
+#define CREATECONTEXTS \
+  G(general_context,BITS) = G(pcre2_general_context_create_,BITS)(&my_malloc, &my_free, NULL); \
+  G(general_context_copy,BITS) = G(pcre2_general_context_copy_,BITS)(G(general_context,BITS)); \
+  G(default_pat_context,BITS) = G(pcre2_compile_context_create_,BITS)(G(general_context,BITS)); \
+  G(pat_context,BITS) = G(pcre2_compile_context_copy_,BITS)(G(default_pat_context,BITS)); \
+  G(default_dat_context,BITS) = G(pcre2_match_context_create_,BITS)(G(general_context,BITS)); \
+  G(dat_context,BITS) = G(pcre2_match_context_copy_,BITS)(G(default_dat_context,BITS)); \
+  G(default_con_context,BITS) = G(pcre2_convert_context_create_,BITS)(G(general_context,BITS)); \
+  G(con_context,BITS) = G(pcre2_convert_context_copy_,BITS)(G(default_con_context,BITS)); \
+  G(match_data,BITS) = G(pcre2_match_data_create_,BITS)(max_oveccount, G(general_context,BITS))
+
+#define CONTEXTTESTS \
+  (void)G(pcre2_set_compile_extra_options_,BITS)(G(pat_context,BITS), 0); \
+  (void)G(pcre2_set_max_pattern_length_,BITS)(G(pat_context,BITS), 0); \
+  (void)G(pcre2_set_offset_limit_,BITS)(G(dat_context,BITS), 0); \
+  (void)G(pcre2_set_recursion_memory_management_,BITS)(G(dat_context,BITS), my_malloc, my_free, NULL); \
+  (void)G(pcre2_get_match_data_size_,BITS)(G(match_data,BITS))
+
+
+/* Call the appropriate functions for the current mode, and exercise some
+functions that are not otherwise called. */
+
+#ifdef SUPPORT_PCRE2_8
+#undef BITS
+#define BITS 8
+if (test_mode == PCRE8_MODE)
+  {
+  CREATECONTEXTS;
+  CONTEXTTESTS;
+  }
+#endif
+
+#ifdef SUPPORT_PCRE2_16
+#undef BITS
+#define BITS 16
+if (test_mode == PCRE16_MODE)
+  {
+  CREATECONTEXTS;
+  CONTEXTTESTS;
+  }
+#endif
+
+#ifdef SUPPORT_PCRE2_32
+#undef BITS
+#define BITS 32
+if (test_mode == PCRE32_MODE)
+  {
+  CREATECONTEXTS;
+  CONTEXTTESTS;
+  }
+#endif
+
+/* Set a default parentheses nest limit that is large enough to run the
+standard tests (this also exercises the function). */
+
+PCRE2_SET_PARENS_NEST_LIMIT(default_pat_context, PARENS_NEST_DEFAULT);
+
+/* Handle command line modifier settings, sending any error messages to
+stderr. We need to know the mode before modifying the context, and it is tidier
+to do them all in the same way. */
+
+outfile = stderr;
+if ((arg_pattern != NULL &&
+    !decode_modifiers((uint8_t *)arg_pattern, CTX_DEFPAT, &def_patctl, NULL)) ||
+    (arg_subject != NULL &&
+    !decode_modifiers((uint8_t *)arg_subject, CTX_DEFDAT, NULL, &def_datctl)))
+  {
+  yield = 1;
+  goto EXIT;
+  }
+
+/* Sort out the input and output files, defaulting to stdin/stdout. */
+
+infile = stdin;
+outfile = stdout;
+
+if (argc > 1 && strcmp(argv[op], "-") != 0)
+  {
+  infile = fopen(argv[op], INPUT_MODE);
+  if (infile == NULL)
+    {
+    printf("** Failed to open '%s': %s\n", argv[op], strerror(errno));
+    yield = 1;
+    goto EXIT;
+    }
+  }
+
+#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT)
+if (INTERACTIVE(infile)) using_history();
+#endif
+
+if (argc > 2)
+  {
+  outfile = fopen(argv[op+1], OUTPUT_MODE);
+  if (outfile == NULL)
+    {
+    printf("** Failed to open '%s': %s\n", argv[op+1], strerror(errno));
+    yield = 1;
+    goto EXIT;
+    }
+  }
+
+/* Output a heading line unless quiet, then process input lines. */
+
+if (!quiet) print_version(outfile);
+
+SET(compiled_code, NULL);
+
+#ifdef SUPPORT_PCRE2_8
+preg.re_pcre2_code = NULL;
+preg.re_match_data = NULL;
+#endif
+
+while (notdone)
+  {
+  uint8_t *p;
+  int rc = PR_OK;
+  BOOL expectdata = TEST(compiled_code, !=, NULL);
+#ifdef SUPPORT_PCRE2_8
+  expectdata |= preg.re_pcre2_code != NULL;
+#endif
+
+  if (extend_inputline(infile, buffer, expectdata? "data> " : "  re> ") == NULL)
+    break;
+  if (!INTERACTIVE(infile)) fprintf(outfile, "%s", (char *)buffer);
+  fflush(outfile);
+  p = buffer;
+
+  /* If we have a pattern set up for testing, or we are skipping after a
+  compile failure, a blank line terminates this test. */
+
+  if (expectdata || skipping)
+    {
+    while (isspace(*p)) p++;
+    if (*p == 0)
+      {
+#ifdef SUPPORT_PCRE2_8
+      if (preg.re_pcre2_code != NULL)
+        {
+        regfree(&preg);
+        preg.re_pcre2_code = NULL;
+        preg.re_match_data = NULL;
+        }
+#endif  /* SUPPORT_PCRE2_8 */
+      if (TEST(compiled_code, !=, NULL))
+        {
+        SUB1(pcre2_code_free, compiled_code);
+        SET(compiled_code, NULL);
+        }
+      skipping = FALSE;
+      setlocale(LC_CTYPE, "C");
+      }
+
+    /* Otherwise, if we are not skipping, and the line is not a data comment
+    line starting with "\=", process a data line. */
+
+    else if (!skipping && !(p[0] == '\\' && p[1] == '=' && isspace(p[2])))
+      {
+      rc = process_data();
+      }
+    }
+
+  /* We do not have a pattern set up for testing. Lines starting with # are
+  either comments or special commands. Blank lines are ignored. Otherwise, the
+  line must start with a valid delimiter. It is then processed as a pattern
+  line. A copy of the pattern is left in pbuffer8 for use by callouts. Under
+  valgrind, make the unused part of the buffer undefined, to catch overruns. */
+
+  else if (*p == '#')
+    {
+    if (isspace(p[1]) || p[1] == '!' || p[1] == 0) continue;
+    rc = process_command();
+    }
+
+  else if (strchr("/!\"'`%&-=_:;,@~", *p) != NULL)
+    {
+    rc = process_pattern();
+    dfa_matched = 0;
+    }
+
+  else
+    {
+    while (isspace(*p)) p++;
+    if (*p != 0)
+      {
+      fprintf(outfile, "** Invalid pattern delimiter '%c' (x%x).\n", *buffer,
+        *buffer);
+      rc = PR_SKIP;
+      }
+    }
+
+  if (rc == PR_SKIP && !INTERACTIVE(infile)) skipping = TRUE;
+  else if (rc == PR_ABEND)
+    {
+    fprintf(outfile, "** pcre2test run abandoned\n");
+    yield = 1;
+    goto EXIT;
+    }
+  }
+
+/* Finish off a normal run. */
+
+if (INTERACTIVE(infile)) fprintf(outfile, "\n");
+
+if (showtotaltimes)
+  {
+  const char *pad = "";
+  fprintf(outfile, "--------------------------------------\n");
+  if (timeit > 0)
+    {
+    fprintf(outfile, "Total compile time %.4f milliseconds\n",
+      (((double)total_compile_time * 1000.0) / (double)timeit) /
+        (double)CLOCKS_PER_SEC);
+    if (total_jit_compile_time > 0)
+      fprintf(outfile, "Total JIT compile  %.4f milliseconds\n",
+        (((double)total_jit_compile_time * 1000.0) / (double)timeit) /
+          (double)CLOCKS_PER_SEC);
+    pad = "  ";
+    }
+  fprintf(outfile, "Total match time %s%.4f milliseconds\n", pad,
+    (((double)total_match_time * 1000.0) / (double)timeitm) /
+      (double)CLOCKS_PER_SEC);
+  }
+
+
+EXIT:
+
+#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT)
+if (infile != NULL && INTERACTIVE(infile)) clear_history();
+#endif
+
+if (infile != NULL && infile != stdin) fclose(infile);
+if (outfile != NULL && outfile != stdout) fclose(outfile);
+
+free(buffer);
+free(dbuffer);
+free(pbuffer8);
+free(dfa_workspace);
+free((void *)locale_tables);
+free(tables3);
+PCRE2_MATCH_DATA_FREE(match_data);
+SUB1(pcre2_code_free, compiled_code);
+
+while(patstacknext-- > 0)
+  {
+  SET(compiled_code, patstack[patstacknext]);
+  SUB1(pcre2_code_free, compiled_code);
+  }
+
+PCRE2_JIT_FREE_UNUSED_MEMORY(general_context);
+if (jit_stack != NULL)
+  {
+  PCRE2_JIT_STACK_FREE(jit_stack);
+  }
+
+#define FREECONTEXTS \
+  G(pcre2_general_context_free_,BITS)(G(general_context,BITS)); \
+  G(pcre2_general_context_free_,BITS)(G(general_context_copy,BITS)); \
+  G(pcre2_compile_context_free_,BITS)(G(pat_context,BITS)); \
+  G(pcre2_compile_context_free_,BITS)(G(default_pat_context,BITS)); \
+  G(pcre2_match_context_free_,BITS)(G(dat_context,BITS)); \
+  G(pcre2_match_context_free_,BITS)(G(default_dat_context,BITS)); \
+  G(pcre2_convert_context_free_,BITS)(G(default_con_context,BITS)); \
+  G(pcre2_convert_context_free_,BITS)(G(con_context,BITS));
+
+#ifdef SUPPORT_PCRE2_8
+#undef BITS
+#define BITS 8
+if (preg.re_pcre2_code != NULL) regfree(&preg);
+FREECONTEXTS;
+#endif
+
+#ifdef SUPPORT_PCRE2_16
+#undef BITS
+#define BITS 16
+free(pbuffer16);
+FREECONTEXTS;
+#endif
+
+#ifdef SUPPORT_PCRE2_32
+#undef BITS
+#define BITS 32
+free(pbuffer32);
+FREECONTEXTS;
+#endif
+
+#if defined(__VMS)
+  yield = SS$_NORMAL;  /* Return values via DCL symbols */
+#endif
+
+return yield;
+}
+
+/* End of pcre2test.c */
diff --git a/src/c/pcre2/src/sljit/sljitConfig.h b/src/c/pcre2/src/sljit/sljitConfig.h
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitConfig.h
@@ -0,0 +1,172 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SLJIT_CONFIG_H_
+#define SLJIT_CONFIG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+  This file contains the basic configuration options for the SLJIT compiler
+  and their default values. These options can be overridden in the
+  sljitConfigPre.h header file when SLJIT_HAVE_CONFIG_PRE is set to a
+  non-zero value.
+*/
+
+/* --------------------------------------------------------------------- */
+/*  Architecture                                                         */
+/* --------------------------------------------------------------------- */
+
+/* Architecture selection. */
+/* #define SLJIT_CONFIG_X86_32 1 */
+/* #define SLJIT_CONFIG_X86_64 1 */
+/* #define SLJIT_CONFIG_ARM_V5 1 */
+/* #define SLJIT_CONFIG_ARM_V7 1 */
+/* #define SLJIT_CONFIG_ARM_THUMB2 1 */
+/* #define SLJIT_CONFIG_ARM_64 1 */
+/* #define SLJIT_CONFIG_PPC_32 1 */
+/* #define SLJIT_CONFIG_PPC_64 1 */
+/* #define SLJIT_CONFIG_MIPS_32 1 */
+/* #define SLJIT_CONFIG_MIPS_64 1 */
+/* #define SLJIT_CONFIG_SPARC_32 1 */
+/* #define SLJIT_CONFIG_TILEGX 1 */
+
+/* #define SLJIT_CONFIG_AUTO 1 */
+/* #define SLJIT_CONFIG_UNSUPPORTED 1 */
+
+/* --------------------------------------------------------------------- */
+/*  Utilities                                                            */
+/* --------------------------------------------------------------------- */
+
+/* Implements a stack like data structure (by using mmap / VirtualAlloc  */
+/* or a custom allocator). */
+#ifndef SLJIT_UTIL_STACK
+/* Enabled by default */
+#define SLJIT_UTIL_STACK 1
+#endif
+
+/* Uses user provided allocator to allocate the stack (see SLJIT_UTIL_STACK) */
+#ifndef SLJIT_UTIL_SIMPLE_STACK_ALLOCATION
+/* Disabled by default */
+#define SLJIT_UTIL_SIMPLE_STACK_ALLOCATION 0
+#endif
+
+/* Single threaded application. Does not require any locks. */
+#ifndef SLJIT_SINGLE_THREADED
+/* Disabled by default. */
+#define SLJIT_SINGLE_THREADED 0
+#endif
+
+/* --------------------------------------------------------------------- */
+/*  Configuration                                                        */
+/* --------------------------------------------------------------------- */
+
+/* If SLJIT_STD_MACROS_DEFINED is not defined, the application should
+   define SLJIT_MALLOC, SLJIT_FREE, SLJIT_MEMCPY, and NULL. */
+#ifndef SLJIT_STD_MACROS_DEFINED
+/* Disabled by default. */
+#define SLJIT_STD_MACROS_DEFINED 0
+#endif
+
+/* Executable code allocation:
+   If SLJIT_EXECUTABLE_ALLOCATOR is not defined, the application should
+   define SLJIT_MALLOC_EXEC, SLJIT_FREE_EXEC, and SLJIT_EXEC_OFFSET. */
+#ifndef SLJIT_EXECUTABLE_ALLOCATOR
+/* Enabled by default. */
+#define SLJIT_EXECUTABLE_ALLOCATOR 1
+
+/* When SLJIT_PROT_EXECUTABLE_ALLOCATOR is enabled SLJIT uses
+   an allocator which does not set writable and executable
+   permission flags at the same time.
+   Instead, it creates a shared memory segment (usually backed by a file)
+   and maps it twice, with different permissions, depending on the use
+   case.
+   The trade-off is increased use of virtual memory, incompatibility with
+   fork(), and some possible additional security risks by the use of
+   publicly accessible files for the generated code. */
+#ifndef SLJIT_PROT_EXECUTABLE_ALLOCATOR
+/* Disabled by default. */
+#define SLJIT_PROT_EXECUTABLE_ALLOCATOR 0
+#endif
+
+/* When SLJIT_WX_EXECUTABLE_ALLOCATOR is enabled SLJIT uses an
+   allocator which does not set writable and executable permission
+   flags at the same time.
+   Instead, it creates a new independent map on each invocation and
+   switches permissions at the underlying pages as needed.
+   The trade-off is increased memory use and degraded performance. */
+#ifndef SLJIT_WX_EXECUTABLE_ALLOCATOR
+/* Disabled by default. */
+#define SLJIT_WX_EXECUTABLE_ALLOCATOR 0
+#endif
+
+#endif /* !SLJIT_EXECUTABLE_ALLOCATOR */
+
+/* Force cdecl calling convention even if a better calling
+   convention (e.g. fastcall) is supported by the C compiler.
+   If this option is disabled (this is the default), functions
+   called from JIT should be defined with SLJIT_FUNC attribute.
+   Standard C functions can still be called by using the
+   SLJIT_CALL_CDECL jump type. */
+#ifndef SLJIT_USE_CDECL_CALLING_CONVENTION
+/* Disabled by default */
+#define SLJIT_USE_CDECL_CALLING_CONVENTION 0
+#endif
+
+/* Return with error when an invalid argument is passed. */
+#ifndef SLJIT_ARGUMENT_CHECKS
+/* Disabled by default */
+#define SLJIT_ARGUMENT_CHECKS 0
+#endif
+
+/* Debug checks (assertions, etc.). */
+#ifndef SLJIT_DEBUG
+/* Enabled by default */
+#define SLJIT_DEBUG 1
+#endif
+
+/* Verbose operations. */
+#ifndef SLJIT_VERBOSE
+/* Enabled by default */
+#define SLJIT_VERBOSE 1
+#endif
+
+/*
+  SLJIT_IS_FPU_AVAILABLE
+    The availability of the FPU can be controlled by SLJIT_IS_FPU_AVAILABLE.
+      zero value - FPU is NOT present.
+      nonzero value - FPU is present.
+*/
+
+/* For further configurations, see the beginning of sljitConfigInternal.h */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SLJIT_CONFIG_H_ */
diff --git a/src/c/pcre2/src/sljit/sljitConfigInternal.h b/src/c/pcre2/src/sljit/sljitConfigInternal.h
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitConfigInternal.h
@@ -0,0 +1,800 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SLJIT_CONFIG_INTERNAL_H_
+#define SLJIT_CONFIG_INTERNAL_H_
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+	|| (defined SLJIT_DEBUG && SLJIT_DEBUG && (!defined(SLJIT_ASSERT) || !defined(SLJIT_UNREACHABLE)))
+#include <stdio.h>
+#endif
+
+#if (defined SLJIT_DEBUG && SLJIT_DEBUG \
+	&& (!defined(SLJIT_ASSERT) || !defined(SLJIT_UNREACHABLE) || !defined(SLJIT_HALT_PROCESS)))
+#include <stdlib.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+   SLJIT defines the following architecture dependent types and macros:
+
+   Types:
+     sljit_s8, sljit_u8   : signed and unsigned 8 bit integer type
+     sljit_s16, sljit_u16 : signed and unsigned 16 bit integer type
+     sljit_s32, sljit_u32 : signed and unsigned 32 bit integer type
+     sljit_sw, sljit_uw   : signed and unsigned machine word, enough to store a pointer
+     sljit_p              : unsgined pointer value (usually the same as sljit_uw, but
+                            some 64 bit ABIs may use 32 bit pointers)
+     sljit_f32            : 32 bit single precision floating point value
+     sljit_f64            : 64 bit double precision floating point value
+
+   Macros for feature detection (boolean):
+     SLJIT_32BIT_ARCHITECTURE : 32 bit architecture
+     SLJIT_64BIT_ARCHITECTURE : 64 bit architecture
+     SLJIT_LITTLE_ENDIAN : little endian architecture
+     SLJIT_BIG_ENDIAN : big endian architecture
+     SLJIT_UNALIGNED : allows unaligned memory accesses for non-fpu operations (only!)
+     SLJIT_INDIRECT_CALL : see SLJIT_FUNC_OFFSET() for more information
+
+   Constants:
+     SLJIT_NUMBER_OF_REGISTERS : number of available registers
+     SLJIT_NUMBER_OF_SCRATCH_REGISTERS : number of available scratch registers
+     SLJIT_NUMBER_OF_SAVED_REGISTERS : number of available saved registers
+     SLJIT_NUMBER_OF_FLOAT_REGISTERS : number of available floating point registers
+     SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS : number of available floating point scratch registers
+     SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS : number of available floating point saved registers
+     SLJIT_WORD_SHIFT : the shift required to apply when accessing a sljit_sw/sljit_uw array by index
+     SLJIT_F32_SHIFT : the shift required to apply when accessing
+                       a single precision floating point array by index
+     SLJIT_F64_SHIFT : the shift required to apply when accessing
+                       a double precision floating point array by index
+     SLJIT_PREF_SHIFT_REG : x86 systems prefers ecx for shifting by register
+                            the scratch register index of ecx is stored in this variable
+     SLJIT_LOCALS_OFFSET : local space starting offset (SLJIT_SP + SLJIT_LOCALS_OFFSET)
+     SLJIT_RETURN_ADDRESS_OFFSET : a return instruction always adds this offset to the return address
+
+   Other macros:
+     SLJIT_FUNC : calling convention attribute for both calling JIT from C and C calling back from JIT
+     SLJIT_W(number) : defining 64 bit constants on 64 bit architectures (platform independent helper)
+*/
+
+/*****************/
+/* Sanity check. */
+/*****************/
+
+#if !((defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
+	|| (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
+	|| (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) \
+	|| (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
+	|| (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
+	|| (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
+	|| (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
+	|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
+	|| (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
+	|| (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
+	|| (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) \
+	|| (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) \
+	|| (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \
+	|| (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED))
+#error "An architecture must be selected"
+#endif
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
+	+ (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
+	+ (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) \
+	+ (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
+	+ (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
+	+ (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
+	+ (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
+	+ (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
+	+ (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) \
+	+ (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
+	+ (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
+	+ (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) \
+	+ (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \
+	+ (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) >= 2
+#error "Multiple architectures are selected"
+#endif
+
+/********************************************************/
+/* Automatic CPU detection (requires compiler support). */
+/********************************************************/
+
+#if (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO)
+
+#ifndef _WIN32
+
+#if defined(__i386__) || defined(__i386)
+#define SLJIT_CONFIG_X86_32 1
+#elif defined(__x86_64__)
+#define SLJIT_CONFIG_X86_64 1
+#elif defined(__arm__) || defined(__ARM__)
+#ifdef __thumb2__
+#define SLJIT_CONFIG_ARM_THUMB2 1
+#elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__)
+#define SLJIT_CONFIG_ARM_V7 1
+#else
+#define SLJIT_CONFIG_ARM_V5 1
+#endif
+#elif defined (__aarch64__)
+#define SLJIT_CONFIG_ARM_64 1
+#elif defined(__ppc64__) || defined(__powerpc64__) || defined(_ARCH_PPC64) || (defined(_POWER) && defined(__64BIT__))
+#define SLJIT_CONFIG_PPC_64 1
+#elif defined(__ppc__) || defined(__powerpc__) || defined(_ARCH_PPC) || defined(_ARCH_PWR) || defined(_ARCH_PWR2) || defined(_POWER)
+#define SLJIT_CONFIG_PPC_32 1
+#elif defined(__mips__) && !defined(_LP64)
+#define SLJIT_CONFIG_MIPS_32 1
+#elif defined(__mips64)
+#define SLJIT_CONFIG_MIPS_64 1
+#elif defined(__sparc__) || defined(__sparc)
+#define SLJIT_CONFIG_SPARC_32 1
+#elif defined(__tilegx__)
+#define SLJIT_CONFIG_TILEGX 1
+#else
+/* Unsupported architecture */
+#define SLJIT_CONFIG_UNSUPPORTED 1
+#endif
+
+#else /* _WIN32 */
+
+#if defined(_M_X64) || defined(__x86_64__)
+#define SLJIT_CONFIG_X86_64 1
+#elif (defined(_M_ARM) && _M_ARM >= 7 && defined(_M_ARMT)) || defined(__thumb2__)
+#define SLJIT_CONFIG_ARM_THUMB2 1
+#elif (defined(_M_ARM) && _M_ARM >= 7)
+#define SLJIT_CONFIG_ARM_V7 1
+#elif defined(_ARM_)
+#define SLJIT_CONFIG_ARM_V5 1
+#elif defined(_M_ARM64) || defined(__aarch64__)
+#define SLJIT_CONFIG_ARM_64 1
+#else
+#define SLJIT_CONFIG_X86_32 1
+#endif
+
+#endif /* !_WIN32 */
+#endif /* SLJIT_CONFIG_AUTO */
+
+#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
+#undef SLJIT_EXECUTABLE_ALLOCATOR
+#endif
+
+/******************************/
+/* CPU family type detection. */
+/******************************/
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
+	|| (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
+#define SLJIT_CONFIG_ARM_32 1
+#endif
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+#define SLJIT_CONFIG_X86 1
+#elif (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) || (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
+#define SLJIT_CONFIG_ARM 1
+#elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+#define SLJIT_CONFIG_PPC 1
+#elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) || (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+#define SLJIT_CONFIG_MIPS 1
+#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) || (defined SLJIT_CONFIG_SPARC_64 && SLJIT_CONFIG_SPARC_64)
+#define SLJIT_CONFIG_SPARC 1
+#endif
+
+/***********************************************************/
+/* Intel Control-flow Enforcement Technology (CET) spport. */
+/***********************************************************/
+
+#ifdef SLJIT_CONFIG_X86
+
+#if defined(__CET__) && !(defined SLJIT_CONFIG_X86_CET && SLJIT_CONFIG_X86_CET)
+#define SLJIT_CONFIG_X86_CET 1
+#endif
+
+#if (defined SLJIT_CONFIG_X86_CET && SLJIT_CONFIG_X86_CET) && defined(__GNUC__)
+#include <x86intrin.h>
+#endif
+
+#endif /* SLJIT_CONFIG_X86 */
+
+/**********************************/
+/* External function definitions. */
+/**********************************/
+
+/* General macros:
+   Note: SLJIT is designed to be independent from them as possible.
+
+   In release mode (SLJIT_DEBUG is not defined) only the following
+   external functions are needed:
+*/
+
+#ifndef SLJIT_MALLOC
+#define SLJIT_MALLOC(size, allocator_data) malloc(size)
+#endif
+
+#ifndef SLJIT_FREE
+#define SLJIT_FREE(ptr, allocator_data) free(ptr)
+#endif
+
+#ifndef SLJIT_MEMCPY
+#define SLJIT_MEMCPY(dest, src, len) memcpy(dest, src, len)
+#endif
+
+#ifndef SLJIT_MEMMOVE
+#define SLJIT_MEMMOVE(dest, src, len) memmove(dest, src, len)
+#endif
+
+#ifndef SLJIT_ZEROMEM
+#define SLJIT_ZEROMEM(dest, len) memset(dest, 0, len)
+#endif
+
+/***************************/
+/* Compiler helper macros. */
+/***************************/
+
+#if !defined(SLJIT_LIKELY) && !defined(SLJIT_UNLIKELY)
+
+#if defined(__GNUC__) && (__GNUC__ >= 3)
+#define SLJIT_LIKELY(x)		__builtin_expect((x), 1)
+#define SLJIT_UNLIKELY(x)	__builtin_expect((x), 0)
+#else
+#define SLJIT_LIKELY(x)		(x)
+#define SLJIT_UNLIKELY(x)	(x)
+#endif
+
+#endif /* !defined(SLJIT_LIKELY) && !defined(SLJIT_UNLIKELY) */
+
+#ifndef SLJIT_INLINE
+/* Inline functions. Some old compilers do not support them. */
+#if defined(__SUNPRO_C) && __SUNPRO_C <= 0x510
+#define SLJIT_INLINE
+#else
+#define SLJIT_INLINE __inline
+#endif
+#endif /* !SLJIT_INLINE */
+
+#ifndef SLJIT_NOINLINE
+/* Not inline functions. */
+#if defined(__GNUC__)
+#define SLJIT_NOINLINE __attribute__ ((noinline))
+#else
+#define SLJIT_NOINLINE
+#endif
+#endif /* !SLJIT_INLINE */
+
+#ifndef SLJIT_UNUSED_ARG
+/* Unused arguments. */
+#define SLJIT_UNUSED_ARG(arg) (void)arg
+#endif
+
+/*********************************/
+/* Type of public API functions. */
+/*********************************/
+
+#ifndef SLJIT_API_FUNC_ATTRIBUTE 
+#if (defined SLJIT_CONFIG_STATIC && SLJIT_CONFIG_STATIC)
+/* Static ABI functions. For all-in-one programs. */
+
+#if defined(__GNUC__)
+/* Disable unused warnings in gcc. */
+#define SLJIT_API_FUNC_ATTRIBUTE static __attribute__((unused))
+#else
+#define SLJIT_API_FUNC_ATTRIBUTE static
+#endif
+
+#else
+#define SLJIT_API_FUNC_ATTRIBUTE
+#endif /* (defined SLJIT_CONFIG_STATIC && SLJIT_CONFIG_STATIC) */
+#endif /* defined SLJIT_API_FUNC_ATTRIBUTE */
+
+/****************************/
+/* Instruction cache flush. */
+/****************************/
+
+#if (!defined SLJIT_CACHE_FLUSH && defined __has_builtin)
+#if __has_builtin(__builtin___clear_cache)
+
+#define SLJIT_CACHE_FLUSH(from, to) \
+	__builtin___clear_cache((char*)(from), (char*)(to))
+
+#endif /* __has_builtin(__builtin___clear_cache) */
+#endif /* (!defined SLJIT_CACHE_FLUSH && defined __has_builtin) */
+
+#ifndef SLJIT_CACHE_FLUSH
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+
+/* Not required to implement on archs with unified caches. */
+#define SLJIT_CACHE_FLUSH(from, to)
+
+#elif defined __APPLE__
+
+/* Supported by all macs since Mac OS 10.5.
+   However, it does not work on non-jailbroken iOS devices,
+   although the compilation is successful. */
+
+#define SLJIT_CACHE_FLUSH(from, to) \
+	sys_icache_invalidate((char*)(from), (char*)(to) - (char*)(from))
+
+#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
+
+/* The __clear_cache() implementation of GCC is a dummy function on PowerPC. */
+#define SLJIT_CACHE_FLUSH(from, to) \
+	ppc_cache_flush((from), (to))
+#define SLJIT_CACHE_FLUSH_OWN_IMPL 1
+
+#elif (defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
+
+#define SLJIT_CACHE_FLUSH(from, to) \
+	__builtin___clear_cache((char*)(from), (char*)(to))
+
+#elif defined __ANDROID__
+
+/* Android lacks __clear_cache; instead, cacheflush should be used. */
+
+#define SLJIT_CACHE_FLUSH(from, to) \
+    cacheflush((long)(from), (long)(to), 0)
+
+#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+
+/* The __clear_cache() implementation of GCC is a dummy function on Sparc. */
+#define SLJIT_CACHE_FLUSH(from, to) \
+	sparc_cache_flush((from), (to))
+#define SLJIT_CACHE_FLUSH_OWN_IMPL 1
+
+#elif defined _WIN32
+
+#define SLJIT_CACHE_FLUSH(from, to) \
+	FlushInstructionCache(GetCurrentProcess(), (char*)(from), (char*)(to) - (char*)(from))
+
+#else
+
+/* Calls __ARM_NR_cacheflush on ARM-Linux. */
+#define SLJIT_CACHE_FLUSH(from, to) \
+	__clear_cache((char*)(from), (char*)(to))
+
+#endif
+
+#endif /* !SLJIT_CACHE_FLUSH */
+
+/******************************************************/
+/*    Integer and floating point type definitions.    */
+/******************************************************/
+
+/* 8 bit byte type. */
+typedef unsigned char sljit_u8;
+typedef signed char sljit_s8;
+
+/* 16 bit half-word type. */
+typedef unsigned short int sljit_u16;
+typedef signed short int sljit_s16;
+
+/* 32 bit integer type. */
+typedef unsigned int sljit_u32;
+typedef signed int sljit_s32;
+
+/* Machine word type. Enough for storing a pointer.
+     32 bit for 32 bit machines.
+     64 bit for 64 bit machines. */
+#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
+/* Just to have something. */
+#define SLJIT_WORD_SHIFT 0
+typedef unsigned long int sljit_uw;
+typedef long int sljit_sw;
+#elif !(defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
+	&& !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
+	&& !(defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
+	&& !(defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
+	&& !(defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX)
+#define SLJIT_32BIT_ARCHITECTURE 1
+#define SLJIT_WORD_SHIFT 2
+typedef unsigned int sljit_uw;
+typedef int sljit_sw;
+#else
+#define SLJIT_64BIT_ARCHITECTURE 1
+#define SLJIT_WORD_SHIFT 3
+#ifdef _WIN32
+#ifdef __GNUC__
+/* These types do not require windows.h */
+typedef unsigned long long sljit_uw;
+typedef long long sljit_sw;
+#else
+typedef unsigned __int64 sljit_uw;
+typedef __int64 sljit_sw;
+#endif
+#else /* !_WIN32 */
+typedef unsigned long int sljit_uw;
+typedef long int sljit_sw;
+#endif /* _WIN32 */
+#endif
+
+typedef sljit_uw sljit_p;
+
+/* Floating point types. */
+typedef float sljit_f32;
+typedef double sljit_f64;
+
+/* Shift for pointer sized data. */
+#define SLJIT_POINTER_SHIFT SLJIT_WORD_SHIFT
+
+/* Shift for double precision sized data. */
+#define SLJIT_F32_SHIFT 2
+#define SLJIT_F64_SHIFT 3
+
+#ifndef SLJIT_W
+
+/* Defining long constants. */
+#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
+#define SLJIT_W(w)	(w##l)
+#elif (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
+#ifdef _WIN64
+#define SLJIT_W(w)	(w##ll)
+#else /* !windows */
+#define SLJIT_W(w)	(w##l)
+#endif /* windows */
+#else /* 32 bit */
+#define SLJIT_W(w)	(w)
+#endif /* unknown */
+
+#endif /* !SLJIT_W */
+
+/*************************/
+/* Endianness detection. */
+/*************************/
+
+#if !defined(SLJIT_BIG_ENDIAN) && !defined(SLJIT_LITTLE_ENDIAN)
+
+/* These macros are mostly useful for the applications. */
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
+	|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+
+#ifdef __LITTLE_ENDIAN__
+#define SLJIT_LITTLE_ENDIAN 1
+#else
+#define SLJIT_BIG_ENDIAN 1
+#endif
+
+#elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
+	|| (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+
+#ifdef __MIPSEL__
+#define SLJIT_LITTLE_ENDIAN 1
+#else
+#define SLJIT_BIG_ENDIAN 1
+#endif
+
+#ifndef SLJIT_MIPS_REV
+
+/* Auto detecting mips revision. */
+#if (defined __mips_isa_rev) && (__mips_isa_rev >= 6)
+#define SLJIT_MIPS_REV 6
+#elif (defined __mips_isa_rev && __mips_isa_rev >= 1) \
+	|| (defined __clang__ && defined _MIPS_ARCH_OCTEON) \
+	|| (defined __clang__ && defined _MIPS_ARCH_P5600)
+/* clang either forgets to define (clang-7) __mips_isa_rev at all
+ * or sets it to zero (clang-8,-9) for -march=octeon (MIPS64 R2+)
+ * and -march=p5600 (MIPS32 R5).
+ * It also sets the __mips macro to 64 or 32 for -mipsN when N <= 5
+ * (should be set to N exactly) so we cannot rely on this too.
+ */
+#define SLJIT_MIPS_REV 1
+#endif
+
+#endif /* !SLJIT_MIPS_REV */
+
+#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+
+#define SLJIT_BIG_ENDIAN 1
+
+#else
+#define SLJIT_LITTLE_ENDIAN 1
+#endif
+
+#endif /* !defined(SLJIT_BIG_ENDIAN) && !defined(SLJIT_LITTLE_ENDIAN) */
+
+/* Sanity check. */
+#if (defined SLJIT_BIG_ENDIAN && SLJIT_BIG_ENDIAN) && (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
+#error "Exactly one endianness must be selected"
+#endif
+
+#if !(defined SLJIT_BIG_ENDIAN && SLJIT_BIG_ENDIAN) && !(defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
+#error "Exactly one endianness must be selected"
+#endif
+
+#ifndef SLJIT_UNALIGNED
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
+	|| (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
+	|| (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
+	|| (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
+	|| (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
+	|| (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
+	|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+#define SLJIT_UNALIGNED 1
+#endif
+
+#endif /* !SLJIT_UNALIGNED */
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+/* Auto detect SSE2 support using CPUID.
+   On 64 bit x86 cpus, sse2 must be present. */
+#define SLJIT_DETECT_SSE2 1
+#endif
+
+/*****************************************************************************************/
+/* Calling convention of functions generated by SLJIT or called from the generated code. */
+/*****************************************************************************************/
+
+#ifndef SLJIT_FUNC
+
+#if (defined SLJIT_USE_CDECL_CALLING_CONVENTION && SLJIT_USE_CDECL_CALLING_CONVENTION) \
+	|| !(defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+
+#define SLJIT_FUNC
+
+#elif defined(__GNUC__) && !defined(__APPLE__)
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#define SLJIT_FUNC __attribute__ ((fastcall))
+#define SLJIT_X86_32_FASTCALL 1
+#else
+#define SLJIT_FUNC
+#endif /* gcc >= 3.4 */
+
+#elif defined(_MSC_VER)
+
+#define SLJIT_FUNC __fastcall
+#define SLJIT_X86_32_FASTCALL 1
+
+#elif defined(__BORLANDC__)
+
+#define SLJIT_FUNC __msfastcall
+#define SLJIT_X86_32_FASTCALL 1
+
+#else /* Unknown compiler. */
+
+/* The cdecl calling convention is usually the x86 default. */
+#define SLJIT_FUNC
+
+#endif /* SLJIT_USE_CDECL_CALLING_CONVENTION */
+
+#endif /* !SLJIT_FUNC */
+
+#ifndef SLJIT_INDIRECT_CALL
+#if ((defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) && (!defined _CALL_ELF || _CALL_ELF == 1)) \
+	|| ((defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) && defined _AIX)
+/* It seems certain ppc compilers use an indirect addressing for functions
+   which makes things complicated. */
+#define SLJIT_INDIRECT_CALL 1
+#endif
+#endif /* SLJIT_INDIRECT_CALL */
+
+/* The offset which needs to be substracted from the return address to
+determine the next executed instruction after return. */
+#ifndef SLJIT_RETURN_ADDRESS_OFFSET
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+#define SLJIT_RETURN_ADDRESS_OFFSET 8
+#else
+#define SLJIT_RETURN_ADDRESS_OFFSET 0
+#endif
+#endif /* SLJIT_RETURN_ADDRESS_OFFSET */
+
+/***************************************************/
+/* Functions of the built-in executable allocator. */
+/***************************************************/
+
+#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size);
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr);
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void);
+#define SLJIT_BUILTIN_MALLOC_EXEC(size, exec_allocator_data) sljit_malloc_exec(size)
+#define SLJIT_BUILTIN_FREE_EXEC(ptr, exec_allocator_data) sljit_free_exec(ptr)
+
+#ifndef SLJIT_MALLOC_EXEC
+#define SLJIT_MALLOC_EXEC(size, exec_allocator_data) SLJIT_BUILTIN_MALLOC_EXEC((size), (exec_allocator_data))
+#endif /* SLJIT_MALLOC_EXEC */
+
+#ifndef SLJIT_FREE_EXEC
+#define SLJIT_FREE_EXEC(ptr, exec_allocator_data) SLJIT_BUILTIN_FREE_EXEC((ptr), (exec_allocator_data))
+#endif /* SLJIT_FREE_EXEC */
+
+#if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR)
+SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
+#define SLJIT_EXEC_OFFSET(ptr) sljit_exec_offset(ptr)
+#else
+#define SLJIT_EXEC_OFFSET(ptr) 0
+#endif
+
+#endif /* SLJIT_EXECUTABLE_ALLOCATOR */
+
+/**********************************************/
+/* Registers and locals offset determination. */
+/**********************************************/
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+
+#define SLJIT_NUMBER_OF_REGISTERS 12
+#define SLJIT_NUMBER_OF_SAVED_REGISTERS 9
+#define SLJIT_LOCALS_OFFSET_BASE (compiler->locals_offset)
+#define SLJIT_PREF_SHIFT_REG SLJIT_R2
+
+#elif (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+
+#define SLJIT_NUMBER_OF_REGISTERS 13
+#ifndef _WIN64
+#define SLJIT_NUMBER_OF_SAVED_REGISTERS 6
+#define SLJIT_LOCALS_OFFSET_BASE 0
+#else /* _WIN64 */
+#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
+#define SLJIT_LOCALS_OFFSET_BASE (compiler->locals_offset)
+#endif /* !_WIN64 */
+#define SLJIT_PREF_SHIFT_REG SLJIT_R3
+
+#elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+
+#define SLJIT_NUMBER_OF_REGISTERS 12
+#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
+#define SLJIT_LOCALS_OFFSET_BASE 0
+
+#elif (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
+
+#define SLJIT_NUMBER_OF_REGISTERS 12
+#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
+#define SLJIT_LOCALS_OFFSET_BASE 0
+
+#elif (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
+
+#define SLJIT_NUMBER_OF_REGISTERS 26
+#define SLJIT_NUMBER_OF_SAVED_REGISTERS 10
+#define SLJIT_LOCALS_OFFSET_BASE 0
+
+#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
+
+#define SLJIT_NUMBER_OF_REGISTERS 23
+#define SLJIT_NUMBER_OF_SAVED_REGISTERS 17
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) || (defined _AIX)
+#define SLJIT_LOCALS_OFFSET_BASE ((6 + 8) * sizeof(sljit_sw))
+#elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+/* Add +1 for double alignment. */
+#define SLJIT_LOCALS_OFFSET_BASE ((3 + 1) * sizeof(sljit_sw))
+#else
+#define SLJIT_LOCALS_OFFSET_BASE (3 * sizeof(sljit_sw))
+#endif /* SLJIT_CONFIG_PPC_64 || _AIX */
+
+#elif (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
+
+#define SLJIT_NUMBER_OF_REGISTERS 21
+#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+#define SLJIT_LOCALS_OFFSET_BASE (4 * sizeof(sljit_sw))
+#else
+#define SLJIT_LOCALS_OFFSET_BASE 0
+#endif
+
+#elif (defined SLJIT_CONFIG_SPARC && SLJIT_CONFIG_SPARC)
+
+#define SLJIT_NUMBER_OF_REGISTERS 18
+#define SLJIT_NUMBER_OF_SAVED_REGISTERS 14
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+/* saved registers (16), return struct pointer (1), space for 6 argument words (1),
+   4th double arg (2), double alignment (1). */
+#define SLJIT_LOCALS_OFFSET_BASE ((16 + 1 + 6 + 2 + 1) * sizeof(sljit_sw))
+#endif
+
+#elif (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX)
+
+#define SLJIT_NUMBER_OF_REGISTERS 10
+#define SLJIT_NUMBER_OF_SAVED_REGISTERS 5
+#define SLJIT_LOCALS_OFFSET_BASE 0
+
+#elif (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
+
+#define SLJIT_NUMBER_OF_REGISTERS 0
+#define SLJIT_NUMBER_OF_SAVED_REGISTERS 0
+#define SLJIT_LOCALS_OFFSET_BASE 0
+
+#endif
+
+#define SLJIT_LOCALS_OFFSET (SLJIT_LOCALS_OFFSET_BASE)
+
+#define SLJIT_NUMBER_OF_SCRATCH_REGISTERS \
+	(SLJIT_NUMBER_OF_REGISTERS - SLJIT_NUMBER_OF_SAVED_REGISTERS)
+
+#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 6
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && (defined _WIN64)
+#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 1
+#else
+#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0
+#endif
+
+#define SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS \
+	(SLJIT_NUMBER_OF_FLOAT_REGISTERS - SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS)
+
+/*************************************/
+/* Debug and verbose related macros. */
+/*************************************/
+
+#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
+
+#if !defined(SLJIT_ASSERT) || !defined(SLJIT_UNREACHABLE)
+
+/* SLJIT_HALT_PROCESS must halt the process. */
+#ifndef SLJIT_HALT_PROCESS
+#define SLJIT_HALT_PROCESS() \
+	abort();
+#endif /* !SLJIT_HALT_PROCESS */
+
+#endif /* !SLJIT_ASSERT || !SLJIT_UNREACHABLE */
+
+/* Feel free to redefine these two macros. */
+#ifndef SLJIT_ASSERT
+
+#define SLJIT_ASSERT(x) \
+	do { \
+		if (SLJIT_UNLIKELY(!(x))) { \
+			printf("Assertion failed at " __FILE__ ":%d\n", __LINE__); \
+			SLJIT_HALT_PROCESS(); \
+		} \
+	} while (0)
+
+#endif /* !SLJIT_ASSERT */
+
+#ifndef SLJIT_UNREACHABLE
+
+#define SLJIT_UNREACHABLE() \
+	do { \
+		printf("Should never been reached " __FILE__ ":%d\n", __LINE__); \
+		SLJIT_HALT_PROCESS(); \
+	} while (0)
+
+#endif /* !SLJIT_UNREACHABLE */
+
+#else /* (defined SLJIT_DEBUG && SLJIT_DEBUG) */
+
+/* Forcing empty, but valid statements. */
+#undef SLJIT_ASSERT
+#undef SLJIT_UNREACHABLE
+
+#define SLJIT_ASSERT(x) \
+	do { } while (0)
+#define SLJIT_UNREACHABLE() \
+	do { } while (0)
+
+#endif /* (defined SLJIT_DEBUG && SLJIT_DEBUG) */
+
+#ifndef SLJIT_COMPILE_ASSERT
+
+#define SLJIT_COMPILE_ASSERT(x, description) \
+	switch(0) { case 0: case ((x) ? 1 : 0): break; }
+
+#endif /* !SLJIT_COMPILE_ASSERT */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SLJIT_CONFIG_INTERNAL_H_ */
diff --git a/src/c/pcre2/src/sljit/sljitExecAllocator.c b/src/c/pcre2/src/sljit/sljitExecAllocator.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitExecAllocator.c
@@ -0,0 +1,385 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+   This file contains a simple executable memory allocator
+
+   It is assumed, that executable code blocks are usually medium (or sometimes
+   large) memory blocks, and the allocator is not too frequently called (less
+   optimized than other allocators). Thus, using it as a generic allocator is
+   not suggested.
+
+   How does it work:
+     Memory is allocated in continuous memory areas called chunks by alloc_chunk()
+     Chunk format:
+     [ block ][ block ] ... [ block ][ block terminator ]
+
+   All blocks and the block terminator is started with block_header. The block
+   header contains the size of the previous and the next block. These sizes
+   can also contain special values.
+     Block size:
+       0 - The block is a free_block, with a different size member.
+       1 - The block is a block terminator.
+       n - The block is used at the moment, and the value contains its size.
+     Previous block size:
+       0 - This is the first block of the memory chunk.
+       n - The size of the previous block.
+
+   Using these size values we can go forward or backward on the block chain.
+   The unused blocks are stored in a chain list pointed by free_blocks. This
+   list is useful if we need to find a suitable memory area when the allocator
+   is called.
+
+   When a block is freed, the new free block is connected to its adjacent free
+   blocks if possible.
+
+     [ free block ][ used block ][ free block ]
+   and "used block" is freed, the three blocks are connected together:
+     [           one big free block           ]
+*/
+
+/* --------------------------------------------------------------------- */
+/*  System (OS) functions                                                */
+/* --------------------------------------------------------------------- */
+
+/* 64 KByte. */
+#define CHUNK_SIZE	0x10000
+
+/*
+   alloc_chunk / free_chunk :
+     * allocate executable system memory chunks
+     * the size is always divisible by CHUNK_SIZE
+   SLJIT_ALLOCATOR_LOCK / SLJIT_ALLOCATOR_UNLOCK :
+     * provided as part of sljitUtils
+     * only the allocator requires this lock, sljit is fully thread safe
+       as it only uses local variables
+*/
+
+#ifdef _WIN32
+
+static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
+{
+	return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+}
+
+static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
+{
+	SLJIT_UNUSED_ARG(size);
+	VirtualFree(chunk, 0, MEM_RELEASE);
+}
+
+#else
+
+#ifdef __APPLE__
+#ifdef MAP_ANON
+/* Configures TARGET_OS_OSX when appropriate */
+#include <TargetConditionals.h>
+
+#if TARGET_OS_OSX && defined(MAP_JIT)
+#include <sys/utsname.h>
+#endif /* TARGET_OS_OSX && MAP_JIT */
+
+#ifdef MAP_JIT
+
+/*
+   On macOS systems, returns MAP_JIT if it is defined _and_ we're running on a
+   version where it's OK to have more than one JIT block.
+   On non-macOS systems, returns MAP_JIT if it is defined.
+*/
+static SLJIT_INLINE int get_map_jit_flag()
+{
+#if TARGET_OS_OSX
+	sljit_sw page_size = get_page_alignment() + 1;
+	void *ptr;
+	static int map_jit_flag = -1;
+
+	/*
+	  The following code is thread safe because multiple initialization
+	  sets map_jit_flag to the same value and the code has no side-effects.
+	  Changing the kernel version witout system restart is (very) unlikely.
+	*/
+	if (map_jit_flag == -1) {
+		struct utsname name;
+
+		map_jit_flag = 0;
+		uname(&name);
+
+		/* Kernel version for 10.14.0 (Mojave) */
+		if (atoi(name.release) >= 18) {
+			/* Only use MAP_JIT if a hardened runtime is used */
+
+			ptr = mmap(NULL, page_size, PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0);
+
+			if (ptr == MAP_FAILED) {
+				map_jit_flag = MAP_JIT;
+			} else {
+				munmap(ptr, page_size);
+			}
+		}
+	}
+
+	return map_jit_flag;
+#else /* !TARGET_OS_OSX */
+	return MAP_JIT;
+#endif /* TARGET_OS_OSX */
+}
+
+#endif /* MAP_JIT */
+#endif /* MAP_ANON */
+#endif /* __APPLE__ */
+
+static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
+{
+	void *retval;
+	const int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+
+#ifdef MAP_ANON
+
+	int flags = MAP_PRIVATE | MAP_ANON;
+
+#ifdef MAP_JIT
+	flags |= get_map_jit_flag();
+#endif
+
+	retval = mmap(NULL, size, prot, flags, -1, 0);
+#else /* !MAP_ANON */
+	if (SLJIT_UNLIKELY((dev_zero < 0) && open_dev_zero()))
+		return NULL;
+
+	retval = mmap(NULL, size, prot, MAP_PRIVATE, dev_zero, 0);
+#endif /* MAP_ANON */
+
+	if (retval == MAP_FAILED)
+		retval = NULL;
+	else {
+		if (mprotect(retval, size, prot) < 0) {
+			munmap(retval, size);
+			retval = NULL;
+		}
+	}
+
+	return retval;
+}
+
+static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
+{
+	munmap(chunk, size);
+}
+
+#endif
+
+/* --------------------------------------------------------------------- */
+/*  Common functions                                                     */
+/* --------------------------------------------------------------------- */
+
+#define CHUNK_MASK	(~(CHUNK_SIZE - 1))
+
+struct block_header {
+	sljit_uw size;
+	sljit_uw prev_size;
+};
+
+struct free_block {
+	struct block_header header;
+	struct free_block *next;
+	struct free_block *prev;
+	sljit_uw size;
+};
+
+#define AS_BLOCK_HEADER(base, offset) \
+	((struct block_header*)(((sljit_u8*)base) + offset))
+#define AS_FREE_BLOCK(base, offset) \
+	((struct free_block*)(((sljit_u8*)base) + offset))
+#define MEM_START(base)		((void*)(((sljit_u8*)base) + sizeof(struct block_header)))
+#define ALIGN_SIZE(size)	(((size) + sizeof(struct block_header) + 7) & ~7)
+
+static struct free_block* free_blocks;
+static sljit_uw allocated_size;
+static sljit_uw total_size;
+
+static SLJIT_INLINE void sljit_insert_free_block(struct free_block *free_block, sljit_uw size)
+{
+	free_block->header.size = 0;
+	free_block->size = size;
+
+	free_block->next = free_blocks;
+	free_block->prev = NULL;
+	if (free_blocks)
+		free_blocks->prev = free_block;
+	free_blocks = free_block;
+}
+
+static SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block)
+{
+	if (free_block->next)
+		free_block->next->prev = free_block->prev;
+
+	if (free_block->prev)
+		free_block->prev->next = free_block->next;
+	else {
+		SLJIT_ASSERT(free_blocks == free_block);
+		free_blocks = free_block->next;
+	}
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
+{
+	struct block_header *header;
+	struct block_header *next_header;
+	struct free_block *free_block;
+	sljit_uw chunk_size;
+
+	SLJIT_ALLOCATOR_LOCK();
+	if (size < (64 - sizeof(struct block_header)))
+		size = (64 - sizeof(struct block_header));
+	size = ALIGN_SIZE(size);
+
+	free_block = free_blocks;
+	while (free_block) {
+		if (free_block->size >= size) {
+			chunk_size = free_block->size;
+			if (chunk_size > size + 64) {
+				/* We just cut a block from the end of the free block. */
+				chunk_size -= size;
+				free_block->size = chunk_size;
+				header = AS_BLOCK_HEADER(free_block, chunk_size);
+				header->prev_size = chunk_size;
+				AS_BLOCK_HEADER(header, size)->prev_size = size;
+			}
+			else {
+				sljit_remove_free_block(free_block);
+				header = (struct block_header*)free_block;
+				size = chunk_size;
+			}
+			allocated_size += size;
+			header->size = size;
+			SLJIT_ALLOCATOR_UNLOCK();
+			return MEM_START(header);
+		}
+		free_block = free_block->next;
+	}
+
+	chunk_size = (size + sizeof(struct block_header) + CHUNK_SIZE - 1) & CHUNK_MASK;
+	header = (struct block_header*)alloc_chunk(chunk_size);
+	if (!header) {
+		SLJIT_ALLOCATOR_UNLOCK();
+		return NULL;
+	}
+
+	chunk_size -= sizeof(struct block_header);
+	total_size += chunk_size;
+
+	header->prev_size = 0;
+	if (chunk_size > size + 64) {
+		/* Cut the allocated space into a free and a used block. */
+		allocated_size += size;
+		header->size = size;
+		chunk_size -= size;
+
+		free_block = AS_FREE_BLOCK(header, size);
+		free_block->header.prev_size = size;
+		sljit_insert_free_block(free_block, chunk_size);
+		next_header = AS_BLOCK_HEADER(free_block, chunk_size);
+	}
+	else {
+		/* All space belongs to this allocation. */
+		allocated_size += chunk_size;
+		header->size = chunk_size;
+		next_header = AS_BLOCK_HEADER(header, chunk_size);
+	}
+	next_header->size = 1;
+	next_header->prev_size = chunk_size;
+	SLJIT_ALLOCATOR_UNLOCK();
+	return MEM_START(header);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
+{
+	struct block_header *header;
+	struct free_block* free_block;
+
+	SLJIT_ALLOCATOR_LOCK();
+	header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header));
+	allocated_size -= header->size;
+
+	/* Connecting free blocks together if possible. */
+
+	/* If header->prev_size == 0, free_block will equal to header.
+	   In this case, free_block->header.size will be > 0. */
+	free_block = AS_FREE_BLOCK(header, -(sljit_sw)header->prev_size);
+	if (SLJIT_UNLIKELY(!free_block->header.size)) {
+		free_block->size += header->size;
+		header = AS_BLOCK_HEADER(free_block, free_block->size);
+		header->prev_size = free_block->size;
+	}
+	else {
+		free_block = (struct free_block*)header;
+		sljit_insert_free_block(free_block, header->size);
+	}
+
+	header = AS_BLOCK_HEADER(free_block, free_block->size);
+	if (SLJIT_UNLIKELY(!header->size)) {
+		free_block->size += ((struct free_block*)header)->size;
+		sljit_remove_free_block((struct free_block*)header);
+		header = AS_BLOCK_HEADER(free_block, free_block->size);
+		header->prev_size = free_block->size;
+	}
+
+	/* The whole chunk is free. */
+	if (SLJIT_UNLIKELY(!free_block->header.prev_size && header->size == 1)) {
+		/* If this block is freed, we still have (allocated_size / 2) free space. */
+		if (total_size - free_block->size > (allocated_size * 3 / 2)) {
+			total_size -= free_block->size;
+			sljit_remove_free_block(free_block);
+			free_chunk(free_block, free_block->size + sizeof(struct block_header));
+		}
+	}
+
+	SLJIT_ALLOCATOR_UNLOCK();
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
+{
+	struct free_block* free_block;
+	struct free_block* next_free_block;
+
+	SLJIT_ALLOCATOR_LOCK();
+
+	free_block = free_blocks;
+	while (free_block) {
+		next_free_block = free_block->next;
+		if (!free_block->header.prev_size && 
+				AS_BLOCK_HEADER(free_block, free_block->size)->size == 1) {
+			total_size -= free_block->size;
+			sljit_remove_free_block(free_block);
+			free_chunk(free_block, free_block->size + sizeof(struct block_header));
+		}
+		free_block = next_free_block;
+	}
+
+	SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks));
+	SLJIT_ALLOCATOR_UNLOCK();
+}
diff --git a/src/c/pcre2/src/sljit/sljitLir.c b/src/c/pcre2/src/sljit/sljitLir.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitLir.c
@@ -0,0 +1,2702 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sljitLir.h"
+
+#ifdef _WIN32
+
+#include <windows.h>
+
+#endif /* _WIN32 */
+
+#if !(defined SLJIT_STD_MACROS_DEFINED && SLJIT_STD_MACROS_DEFINED)
+
+/* These libraries are needed for the macros below. */
+#include <stdlib.h>
+#include <string.h>
+
+#endif /* SLJIT_STD_MACROS_DEFINED */
+
+#define CHECK_ERROR() \
+	do { \
+		if (SLJIT_UNLIKELY(compiler->error)) \
+			return compiler->error; \
+	} while (0)
+
+#define CHECK_ERROR_PTR() \
+	do { \
+		if (SLJIT_UNLIKELY(compiler->error)) \
+			return NULL; \
+	} while (0)
+
+#define FAIL_IF(expr) \
+	do { \
+		if (SLJIT_UNLIKELY(expr)) \
+			return compiler->error; \
+	} while (0)
+
+#define PTR_FAIL_IF(expr) \
+	do { \
+		if (SLJIT_UNLIKELY(expr)) \
+			return NULL; \
+	} while (0)
+
+#define FAIL_IF_NULL(ptr) \
+	do { \
+		if (SLJIT_UNLIKELY(!(ptr))) { \
+			compiler->error = SLJIT_ERR_ALLOC_FAILED; \
+			return SLJIT_ERR_ALLOC_FAILED; \
+		} \
+	} while (0)
+
+#define PTR_FAIL_IF_NULL(ptr) \
+	do { \
+		if (SLJIT_UNLIKELY(!(ptr))) { \
+			compiler->error = SLJIT_ERR_ALLOC_FAILED; \
+			return NULL; \
+		} \
+	} while (0)
+
+#define PTR_FAIL_WITH_EXEC_IF(ptr) \
+	do { \
+		if (SLJIT_UNLIKELY(!(ptr))) { \
+			compiler->error = SLJIT_ERR_EX_ALLOC_FAILED; \
+			return NULL; \
+		} \
+	} while (0)
+
+#if !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
+
+#define VARIABLE_FLAG_SHIFT (10)
+#define VARIABLE_FLAG_MASK (0x3f << VARIABLE_FLAG_SHIFT)
+#define GET_FLAG_TYPE(op) ((op) >> VARIABLE_FLAG_SHIFT)
+
+#define GET_OPCODE(op) \
+	((op) & ~(SLJIT_I32_OP | SLJIT_SET_Z | VARIABLE_FLAG_MASK))
+
+#define HAS_FLAGS(op) \
+	((op) & (SLJIT_SET_Z | VARIABLE_FLAG_MASK))
+
+#define GET_ALL_FLAGS(op) \
+	((op) & (SLJIT_I32_OP | SLJIT_SET_Z | VARIABLE_FLAG_MASK))
+
+#if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
+#define TYPE_CAST_NEEDED(op) \
+	((op) >= SLJIT_MOV_U8 && (op) <= SLJIT_MOV_S32)
+#else
+#define TYPE_CAST_NEEDED(op) \
+	((op) >= SLJIT_MOV_U8 && (op) <= SLJIT_MOV_S16)
+#endif
+
+#define BUF_SIZE	4096
+
+#if (defined SLJIT_32BIT_ARCHITECTURE && SLJIT_32BIT_ARCHITECTURE)
+#define ABUF_SIZE	2048
+#else
+#define ABUF_SIZE	4096
+#endif
+
+/* Parameter parsing. */
+#define REG_MASK		0x3f
+#define OFFS_REG(reg)		(((reg) >> 8) & REG_MASK)
+#define OFFS_REG_MASK		(REG_MASK << 8)
+#define TO_OFFS_REG(reg)	((reg) << 8)
+/* When reg cannot be unused. */
+#define FAST_IS_REG(reg)	((reg) <= REG_MASK)
+/* When reg can be unused. */
+#define SLOW_IS_REG(reg)	((reg) > 0 && (reg) <= REG_MASK)
+
+/* Mask for argument types. */
+#define SLJIT_DEF_MASK ((1 << SLJIT_DEF_SHIFT) - 1)
+
+/* Jump flags. */
+#define JUMP_LABEL	0x1
+#define JUMP_ADDR	0x2
+/* SLJIT_REWRITABLE_JUMP is 0x1000. */
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+#	define PATCH_MB		0x4
+#	define PATCH_MW		0x8
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+#	define PATCH_MD		0x10
+#endif
+#	define TYPE_SHIFT	13
+#endif
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+#	define IS_BL		0x4
+#	define PATCH_B		0x8
+#endif
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#	define CPOOL_SIZE	512
+#endif
+
+#if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
+#	define IS_COND		0x04
+#	define IS_BL		0x08
+	/* conditional + imm8 */
+#	define PATCH_TYPE1	0x10
+	/* conditional + imm20 */
+#	define PATCH_TYPE2	0x20
+	/* IT + imm24 */
+#	define PATCH_TYPE3	0x30
+	/* imm11 */
+#	define PATCH_TYPE4	0x40
+	/* imm24 */
+#	define PATCH_TYPE5	0x50
+	/* BL + imm24 */
+#	define PATCH_BL		0x60
+	/* 0xf00 cc code for branches */
+#endif
+
+#if (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
+#	define IS_COND		0x004
+#	define IS_CBZ		0x008
+#	define IS_BL		0x010
+#	define PATCH_B		0x020
+#	define PATCH_COND	0x040
+#	define PATCH_ABS48	0x080
+#	define PATCH_ABS64	0x100
+#endif
+
+#if (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
+#	define IS_COND		0x004
+#	define IS_CALL		0x008
+#	define PATCH_B		0x010
+#	define PATCH_ABS_B	0x020
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+#	define PATCH_ABS32	0x040
+#	define PATCH_ABS48	0x080
+#endif
+#	define REMOVE_COND	0x100
+#endif
+
+#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
+#	define IS_MOVABLE	0x004
+#	define IS_JAL		0x008
+#	define IS_CALL		0x010
+#	define IS_BIT26_COND	0x020
+#	define IS_BIT16_COND	0x040
+#	define IS_BIT23_COND	0x080
+
+#	define IS_COND		(IS_BIT26_COND | IS_BIT16_COND | IS_BIT23_COND)
+
+#	define PATCH_B		0x100
+#	define PATCH_J		0x200
+
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+#	define PATCH_ABS32	0x400
+#	define PATCH_ABS48	0x800
+#endif
+
+	/* instruction types */
+#	define MOVABLE_INS	0
+	/* 1 - 31 last destination register */
+	/* no destination (i.e: store) */
+#	define UNMOVABLE_INS	32
+	/* FPU status register */
+#	define FCSR_FCC		33
+#endif
+
+#if (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX)
+#	define IS_JAL		0x04
+#	define IS_COND		0x08
+
+#	define PATCH_B		0x10
+#	define PATCH_J		0x20
+#endif
+
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+#	define IS_MOVABLE	0x04
+#	define IS_COND		0x08
+#	define IS_CALL		0x10
+
+#	define PATCH_B		0x20
+#	define PATCH_CALL	0x40
+
+	/* instruction types */
+#	define MOVABLE_INS	0
+	/* 1 - 31 last destination register */
+	/* no destination (i.e: store) */
+#	define UNMOVABLE_INS	32
+
+#	define DST_INS_MASK	0xff
+
+	/* ICC_SET is the same as SET_FLAGS. */
+#	define ICC_IS_SET	(1 << 23)
+#	define FCC_IS_SET	(1 << 24)
+#endif
+
+/* Stack management. */
+
+#define GET_SAVED_REGISTERS_SIZE(scratches, saveds, extra) \
+	(((scratches < SLJIT_NUMBER_OF_SCRATCH_REGISTERS ? 0 : (scratches - SLJIT_NUMBER_OF_SCRATCH_REGISTERS)) + \
+		(saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? saveds : SLJIT_NUMBER_OF_SAVED_REGISTERS) + \
+		extra) * sizeof(sljit_sw))
+
+#define ADJUST_LOCAL_OFFSET(p, i) \
+	if ((p) == (SLJIT_MEM1(SLJIT_SP))) \
+		(i) += SLJIT_LOCALS_OFFSET;
+
+#endif /* !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) */
+
+/* Utils can still be used even if SLJIT_CONFIG_UNSUPPORTED is set. */
+#include "sljitUtils.c"
+
+#if !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
+
+#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
+
+#if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR)
+#include "sljitProtExecAllocator.c"
+#elif (defined SLJIT_WX_EXECUTABLE_ALLOCATOR && SLJIT_WX_EXECUTABLE_ALLOCATOR)
+#include "sljitWXExecAllocator.c"
+#else
+#include "sljitExecAllocator.c"
+#endif
+
+#endif
+
+#if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR)
+#define SLJIT_ADD_EXEC_OFFSET(ptr, exec_offset) ((sljit_u8 *)(ptr) + (exec_offset))
+#else
+#define SLJIT_ADD_EXEC_OFFSET(ptr, exec_offset) ((sljit_u8 *)(ptr))
+#endif
+
+#ifndef SLJIT_UPDATE_WX_FLAGS
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
+#endif
+
+/* Argument checking features. */
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+
+/* Returns with error when an invalid argument is passed. */
+
+#define CHECK_ARGUMENT(x) \
+	do { \
+		if (SLJIT_UNLIKELY(!(x))) \
+			return 1; \
+	} while (0)
+
+#define CHECK_RETURN_TYPE sljit_s32
+#define CHECK_RETURN_OK return 0
+
+#define CHECK(x) \
+	do { \
+		if (SLJIT_UNLIKELY(x)) { \
+			compiler->error = SLJIT_ERR_BAD_ARGUMENT; \
+			return SLJIT_ERR_BAD_ARGUMENT; \
+		} \
+	} while (0)
+
+#define CHECK_PTR(x) \
+	do { \
+		if (SLJIT_UNLIKELY(x)) { \
+			compiler->error = SLJIT_ERR_BAD_ARGUMENT; \
+			return NULL; \
+		} \
+	} while (0)
+
+#define CHECK_REG_INDEX(x) \
+	do { \
+		if (SLJIT_UNLIKELY(x)) { \
+			return -2; \
+		} \
+	} while (0)
+
+#elif (defined SLJIT_DEBUG && SLJIT_DEBUG)
+
+/* Assertion failure occures if an invalid argument is passed. */
+#undef SLJIT_ARGUMENT_CHECKS
+#define SLJIT_ARGUMENT_CHECKS 1
+
+#define CHECK_ARGUMENT(x) SLJIT_ASSERT(x)
+#define CHECK_RETURN_TYPE void
+#define CHECK_RETURN_OK return
+#define CHECK(x) x
+#define CHECK_PTR(x) x
+#define CHECK_REG_INDEX(x) x
+
+#elif (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+
+/* Arguments are not checked. */
+#define CHECK_RETURN_TYPE void
+#define CHECK_RETURN_OK return
+#define CHECK(x) x
+#define CHECK_PTR(x) x
+#define CHECK_REG_INDEX(x) x
+
+#else
+
+/* Arguments are not checked. */
+#define CHECK(x)
+#define CHECK_PTR(x)
+#define CHECK_REG_INDEX(x)
+
+#endif /* SLJIT_ARGUMENT_CHECKS */
+
+/* --------------------------------------------------------------------- */
+/*  Public functions                                                     */
+/* --------------------------------------------------------------------- */
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+#define SLJIT_NEEDS_COMPILER_INIT 1
+static sljit_s32 compiler_initialized = 0;
+/* A thread safe initialization. */
+static void init_compiler(void);
+#endif
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data, void *exec_allocator_data)
+{
+	struct sljit_compiler *compiler = (struct sljit_compiler*)SLJIT_MALLOC(sizeof(struct sljit_compiler), allocator_data);
+	if (!compiler)
+		return NULL;
+	SLJIT_ZEROMEM(compiler, sizeof(struct sljit_compiler));
+
+	SLJIT_COMPILE_ASSERT(
+		sizeof(sljit_s8) == 1 && sizeof(sljit_u8) == 1
+		&& sizeof(sljit_s16) == 2 && sizeof(sljit_u16) == 2
+		&& sizeof(sljit_s32) == 4 && sizeof(sljit_u32) == 4
+		&& (sizeof(sljit_p) == 4 || sizeof(sljit_p) == 8)
+		&& sizeof(sljit_p) <= sizeof(sljit_sw)
+		&& (sizeof(sljit_sw) == 4 || sizeof(sljit_sw) == 8)
+		&& (sizeof(sljit_uw) == 4 || sizeof(sljit_uw) == 8),
+		invalid_integer_types);
+	SLJIT_COMPILE_ASSERT(SLJIT_I32_OP == SLJIT_F32_OP,
+		int_op_and_single_op_must_be_the_same);
+	SLJIT_COMPILE_ASSERT(SLJIT_REWRITABLE_JUMP != SLJIT_F32_OP,
+		rewritable_jump_and_single_op_must_not_be_the_same);
+	SLJIT_COMPILE_ASSERT(!(SLJIT_EQUAL & 0x1) && !(SLJIT_LESS & 0x1) && !(SLJIT_EQUAL_F64 & 0x1) && !(SLJIT_JUMP & 0x1),
+		conditional_flags_must_be_even_numbers);
+
+	/* Only the non-zero members must be set. */
+	compiler->error = SLJIT_SUCCESS;
+
+	compiler->allocator_data = allocator_data;
+	compiler->exec_allocator_data = exec_allocator_data;
+	compiler->buf = (struct sljit_memory_fragment*)SLJIT_MALLOC(BUF_SIZE, allocator_data);
+	compiler->abuf = (struct sljit_memory_fragment*)SLJIT_MALLOC(ABUF_SIZE, allocator_data);
+
+	if (!compiler->buf || !compiler->abuf) {
+		if (compiler->buf)
+			SLJIT_FREE(compiler->buf, allocator_data);
+		if (compiler->abuf)
+			SLJIT_FREE(compiler->abuf, allocator_data);
+		SLJIT_FREE(compiler, allocator_data);
+		return NULL;
+	}
+
+	compiler->buf->next = NULL;
+	compiler->buf->used_size = 0;
+	compiler->abuf->next = NULL;
+	compiler->abuf->used_size = 0;
+
+	compiler->scratches = -1;
+	compiler->saveds = -1;
+	compiler->fscratches = -1;
+	compiler->fsaveds = -1;
+	compiler->local_size = -1;
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+	compiler->args = -1;
+#endif
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+	compiler->cpool = (sljit_uw*)SLJIT_MALLOC(CPOOL_SIZE * sizeof(sljit_uw)
+		+ CPOOL_SIZE * sizeof(sljit_u8), allocator_data);
+	if (!compiler->cpool) {
+		SLJIT_FREE(compiler->buf, allocator_data);
+		SLJIT_FREE(compiler->abuf, allocator_data);
+		SLJIT_FREE(compiler, allocator_data);
+		return NULL;
+	}
+	compiler->cpool_unique = (sljit_u8*)(compiler->cpool + CPOOL_SIZE);
+	compiler->cpool_diff = 0xffffffff;
+#endif
+
+#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
+	compiler->delay_slot = UNMOVABLE_INS;
+#endif
+
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+	compiler->delay_slot = UNMOVABLE_INS;
+#endif
+
+#if (defined SLJIT_NEEDS_COMPILER_INIT && SLJIT_NEEDS_COMPILER_INIT)
+	if (!compiler_initialized) {
+		init_compiler();
+		compiler_initialized = 1;
+	}
+#endif
+
+	return compiler;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compiler)
+{
+	struct sljit_memory_fragment *buf;
+	struct sljit_memory_fragment *curr;
+	void *allocator_data = compiler->allocator_data;
+	SLJIT_UNUSED_ARG(allocator_data);
+
+	buf = compiler->buf;
+	while (buf) {
+		curr = buf;
+		buf = buf->next;
+		SLJIT_FREE(curr, allocator_data);
+	}
+
+	buf = compiler->abuf;
+	while (buf) {
+		curr = buf;
+		buf = buf->next;
+		SLJIT_FREE(curr, allocator_data);
+	}
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+	SLJIT_FREE(compiler->cpool, allocator_data);
+#endif
+	SLJIT_FREE(compiler, allocator_data);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compiler *compiler)
+{
+	if (compiler->error == SLJIT_SUCCESS)
+		compiler->error = SLJIT_ERR_ALLOC_FAILED;
+}
+
+#if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code, void *exec_allocator_data)
+{
+	/* Remove thumb mode flag. */
+	SLJIT_FREE_EXEC((void*)((sljit_uw)code & ~0x1), exec_allocator_data);
+}
+#elif (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code, void *exec_allocator_data)
+{
+	/* Resolve indirection. */
+	code = (void*)(*(sljit_uw*)code);
+	SLJIT_FREE_EXEC(code, exec_allocator_data);
+}
+#else
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code, void *exec_allocator_data)
+{
+	SLJIT_FREE_EXEC(code, exec_allocator_data);
+}
+#endif
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_label(struct sljit_jump *jump, struct sljit_label* label)
+{
+	if (SLJIT_LIKELY(!!jump) && SLJIT_LIKELY(!!label)) {
+		jump->flags &= ~JUMP_ADDR;
+		jump->flags |= JUMP_LABEL;
+		jump->u.label = label;
+	}
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_target(struct sljit_jump *jump, sljit_uw target)
+{
+	if (SLJIT_LIKELY(!!jump)) {
+		jump->flags &= ~JUMP_LABEL;
+		jump->flags |= JUMP_ADDR;
+		jump->u.target = target;
+	}
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_put_label(struct sljit_put_label *put_label, struct sljit_label *label)
+{
+	if (SLJIT_LIKELY(!!put_label))
+		put_label->label = label;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler, sljit_s32 current_flags)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(current_flags);
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	if ((current_flags & ~(VARIABLE_FLAG_MASK | SLJIT_I32_OP | SLJIT_SET_Z)) == 0) {
+		compiler->last_flags = GET_FLAG_TYPE(current_flags) | (current_flags & (SLJIT_I32_OP | SLJIT_SET_Z));
+	}
+#endif
+}
+
+/* --------------------------------------------------------------------- */
+/*  Private functions                                                    */
+/* --------------------------------------------------------------------- */
+
+static void* ensure_buf(struct sljit_compiler *compiler, sljit_uw size)
+{
+	sljit_u8 *ret;
+	struct sljit_memory_fragment *new_frag;
+
+	SLJIT_ASSERT(size <= 256);
+	if (compiler->buf->used_size + size <= (BUF_SIZE - (sljit_uw)SLJIT_OFFSETOF(struct sljit_memory_fragment, memory))) {
+		ret = compiler->buf->memory + compiler->buf->used_size;
+		compiler->buf->used_size += size;
+		return ret;
+	}
+	new_frag = (struct sljit_memory_fragment*)SLJIT_MALLOC(BUF_SIZE, compiler->allocator_data);
+	PTR_FAIL_IF_NULL(new_frag);
+	new_frag->next = compiler->buf;
+	compiler->buf = new_frag;
+	new_frag->used_size = size;
+	return new_frag->memory;
+}
+
+static void* ensure_abuf(struct sljit_compiler *compiler, sljit_uw size)
+{
+	sljit_u8 *ret;
+	struct sljit_memory_fragment *new_frag;
+
+	SLJIT_ASSERT(size <= 256);
+	if (compiler->abuf->used_size + size <= (ABUF_SIZE - (sljit_uw)SLJIT_OFFSETOF(struct sljit_memory_fragment, memory))) {
+		ret = compiler->abuf->memory + compiler->abuf->used_size;
+		compiler->abuf->used_size += size;
+		return ret;
+	}
+	new_frag = (struct sljit_memory_fragment*)SLJIT_MALLOC(ABUF_SIZE, compiler->allocator_data);
+	PTR_FAIL_IF_NULL(new_frag);
+	new_frag->next = compiler->abuf;
+	compiler->abuf = new_frag;
+	new_frag->used_size = size;
+	return new_frag->memory;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_s32 size)
+{
+	CHECK_ERROR_PTR();
+
+#if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
+	if (size <= 0 || size > 128)
+		return NULL;
+	size = (size + 7) & ~7;
+#else
+	if (size <= 0 || size > 64)
+		return NULL;
+	size = (size + 3) & ~3;
+#endif
+	return ensure_abuf(compiler, size);
+}
+
+static SLJIT_INLINE void reverse_buf(struct sljit_compiler *compiler)
+{
+	struct sljit_memory_fragment *buf = compiler->buf;
+	struct sljit_memory_fragment *prev = NULL;
+	struct sljit_memory_fragment *tmp;
+
+	do {
+		tmp = buf->next;
+		buf->next = prev;
+		prev = buf;
+		buf = tmp;
+	} while (buf != NULL);
+
+	compiler->buf = prev;
+}
+
+static SLJIT_INLINE sljit_s32 get_arg_count(sljit_s32 arg_types)
+{
+	sljit_s32 arg_count = 0;
+
+	arg_types >>= SLJIT_DEF_SHIFT;
+	while (arg_types) {
+		arg_count++;
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	return arg_count;
+}
+
+#if !(defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+
+static SLJIT_INLINE sljit_uw compute_next_addr(struct sljit_label *label, struct sljit_jump *jump,
+	struct sljit_const *const_, struct sljit_put_label *put_label)
+{
+	sljit_uw result = ~(sljit_uw)0;
+
+	if (label)
+		result = label->size;
+
+	if (jump && jump->addr < result)
+		result = jump->addr;
+
+	if (const_ && const_->addr < result)
+		result = const_->addr;
+
+	if (put_label && put_label->addr < result)
+		result = put_label->addr;
+
+	return result;
+}
+
+#endif /* !SLJIT_CONFIG_X86 */
+
+static SLJIT_INLINE void set_emit_enter(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	SLJIT_UNUSED_ARG(args);
+	SLJIT_UNUSED_ARG(local_size);
+
+	compiler->options = options;
+	compiler->scratches = scratches;
+	compiler->saveds = saveds;
+	compiler->fscratches = fscratches;
+	compiler->fsaveds = fsaveds;
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->logical_local_size = local_size;
+#endif
+}
+
+static SLJIT_INLINE void set_set_context(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	SLJIT_UNUSED_ARG(args);
+	SLJIT_UNUSED_ARG(local_size);
+
+	compiler->options = options;
+	compiler->scratches = scratches;
+	compiler->saveds = saveds;
+	compiler->fscratches = fscratches;
+	compiler->fsaveds = fsaveds;
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->logical_local_size = local_size;
+#endif
+}
+
+static SLJIT_INLINE void set_label(struct sljit_label *label, struct sljit_compiler *compiler)
+{
+	label->next = NULL;
+	label->size = compiler->size;
+	if (compiler->last_label)
+		compiler->last_label->next = label;
+	else
+		compiler->labels = label;
+	compiler->last_label = label;
+}
+
+static SLJIT_INLINE void set_jump(struct sljit_jump *jump, struct sljit_compiler *compiler, sljit_s32 flags)
+{
+	jump->next = NULL;
+	jump->flags = flags;
+	if (compiler->last_jump)
+		compiler->last_jump->next = jump;
+	else
+		compiler->jumps = jump;
+	compiler->last_jump = jump;
+}
+
+static SLJIT_INLINE void set_const(struct sljit_const *const_, struct sljit_compiler *compiler)
+{
+	const_->next = NULL;
+	const_->addr = compiler->size;
+	if (compiler->last_const)
+		compiler->last_const->next = const_;
+	else
+		compiler->consts = const_;
+	compiler->last_const = const_;
+}
+
+static SLJIT_INLINE void set_put_label(struct sljit_put_label *put_label, struct sljit_compiler *compiler, sljit_uw offset)
+{
+	put_label->next = NULL;
+	put_label->label = NULL;
+	put_label->addr = compiler->size - offset;
+	put_label->flags = 0;
+	if (compiler->last_put_label)
+		compiler->last_put_label->next = put_label;
+	else
+		compiler->put_labels = put_label;
+	compiler->last_put_label = put_label;
+}
+
+#define ADDRESSING_DEPENDS_ON(exp, reg) \
+	(((exp) & SLJIT_MEM) && (((exp) & REG_MASK) == reg || OFFS_REG(exp) == reg))
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+
+#define FUNCTION_CHECK_IS_REG(r) \
+	(((r) >= SLJIT_R0 && (r) < (SLJIT_R0 + compiler->scratches)) \
+	|| ((r) > (SLJIT_S0 - compiler->saveds) && (r) <= SLJIT_S0))
+
+#define FUNCTION_CHECK_IS_FREG(fr) \
+	(((fr) >= SLJIT_FR0 && (fr) < (SLJIT_FR0 + compiler->fscratches)) \
+	|| ((fr) > (SLJIT_FS0 - compiler->fsaveds) && (fr) <= SLJIT_FS0))
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+#define CHECK_IF_VIRTUAL_REGISTER(p) ((p) <= SLJIT_S3 && (p) >= SLJIT_S8)
+#else
+#define CHECK_IF_VIRTUAL_REGISTER(p) 0
+#endif
+
+static sljit_s32 function_check_src_mem(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i)
+{
+	if (compiler->scratches == -1 || compiler->saveds == -1)
+		return 0;
+
+	if (!(p & SLJIT_MEM))
+		return 0;
+
+	if (!((p & REG_MASK) == SLJIT_UNUSED || FUNCTION_CHECK_IS_REG(p & REG_MASK)))
+		return 0;
+
+	if (CHECK_IF_VIRTUAL_REGISTER(p & REG_MASK))
+		return 0;
+
+	if (p & OFFS_REG_MASK) {
+		if ((p & REG_MASK) == SLJIT_UNUSED)
+			return 0;
+
+		if (!(FUNCTION_CHECK_IS_REG(OFFS_REG(p))))
+			return 0;
+
+		if (CHECK_IF_VIRTUAL_REGISTER(OFFS_REG(p)))
+			return 0;
+
+		if ((i & ~0x3) != 0)
+			return 0;
+	}
+
+	return (p & ~(SLJIT_MEM | REG_MASK | OFFS_REG_MASK)) == 0;
+}
+
+#define FUNCTION_CHECK_SRC_MEM(p, i) \
+	CHECK_ARGUMENT(function_check_src_mem(compiler, p, i));
+
+static sljit_s32 function_check_src(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i)
+{
+	if (compiler->scratches == -1 || compiler->saveds == -1)
+		return 0;
+
+	if (FUNCTION_CHECK_IS_REG(p))
+		return (i == 0);
+
+	if (p == SLJIT_IMM)
+		return 1;
+
+	if (p == SLJIT_MEM1(SLJIT_SP))
+		return (i >= 0 && i < compiler->logical_local_size);
+
+	return function_check_src_mem(compiler, p, i);
+}
+
+#define FUNCTION_CHECK_SRC(p, i) \
+	CHECK_ARGUMENT(function_check_src(compiler, p, i));
+
+static sljit_s32 function_check_dst(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i, sljit_s32 unused)
+{
+	if (compiler->scratches == -1 || compiler->saveds == -1)
+		return 0;
+
+	if (FUNCTION_CHECK_IS_REG(p) || ((unused) && (p) == SLJIT_UNUSED))
+		return (i == 0);
+
+	if (p == SLJIT_MEM1(SLJIT_SP))
+		return (i >= 0 && i < compiler->logical_local_size);
+
+	return function_check_src_mem(compiler, p, i);
+}
+
+#define FUNCTION_CHECK_DST(p, i, unused) \
+	CHECK_ARGUMENT(function_check_dst(compiler, p, i, unused));
+
+static sljit_s32 function_fcheck(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i)
+{
+	if (compiler->scratches == -1 || compiler->saveds == -1)
+		return 0;
+
+	if (FUNCTION_CHECK_IS_FREG(p))
+		return (i == 0);
+
+	if (p == SLJIT_MEM1(SLJIT_SP))
+		return (i >= 0 && i < compiler->logical_local_size);
+
+	return function_check_src_mem(compiler, p, i);
+}
+
+#define FUNCTION_FCHECK(p, i) \
+	CHECK_ARGUMENT(function_fcheck(compiler, p, i));
+
+#endif /* SLJIT_ARGUMENT_CHECKS */
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_compiler_verbose(struct sljit_compiler *compiler, FILE* verbose)
+{
+	compiler->verbose = verbose;
+}
+
+#if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
+#ifdef _WIN64
+#	define SLJIT_PRINT_D	"I64"
+#else
+#	define SLJIT_PRINT_D	"l"
+#endif
+#else
+#	define SLJIT_PRINT_D	""
+#endif
+
+static void sljit_verbose_reg(struct sljit_compiler *compiler, sljit_s32 r)
+{
+	if (r < (SLJIT_R0 + compiler->scratches))
+		fprintf(compiler->verbose, "r%d", r - SLJIT_R0);
+	else if (r != SLJIT_SP)
+		fprintf(compiler->verbose, "s%d", SLJIT_NUMBER_OF_REGISTERS - r);
+	else
+		fprintf(compiler->verbose, "sp");
+}
+
+static void sljit_verbose_freg(struct sljit_compiler *compiler, sljit_s32 r)
+{
+	if (r < (SLJIT_FR0 + compiler->fscratches))
+		fprintf(compiler->verbose, "fr%d", r - SLJIT_FR0);
+	else
+		fprintf(compiler->verbose, "fs%d", SLJIT_NUMBER_OF_FLOAT_REGISTERS - r);
+}
+
+static void sljit_verbose_param(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i)
+{
+	if ((p) & SLJIT_IMM)
+		fprintf(compiler->verbose, "#%" SLJIT_PRINT_D "d", (i));
+	else if ((p) & SLJIT_MEM) {
+		if ((p) & REG_MASK) {
+			fputc('[', compiler->verbose);
+			sljit_verbose_reg(compiler, (p) & REG_MASK);
+			if ((p) & OFFS_REG_MASK) {
+				fprintf(compiler->verbose, " + ");
+				sljit_verbose_reg(compiler, OFFS_REG(p));
+				if (i)
+					fprintf(compiler->verbose, " * %d", 1 << (i));
+			}
+			else if (i)
+				fprintf(compiler->verbose, " + %" SLJIT_PRINT_D "d", (i));
+			fputc(']', compiler->verbose);
+		}
+		else
+			fprintf(compiler->verbose, "[#%" SLJIT_PRINT_D "d]", (i));
+	} else if (p)
+		sljit_verbose_reg(compiler, p);
+	else
+		fprintf(compiler->verbose, "unused");
+}
+
+static void sljit_verbose_fparam(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i)
+{
+	if ((p) & SLJIT_MEM) {
+		if ((p) & REG_MASK) {
+			fputc('[', compiler->verbose);
+			sljit_verbose_reg(compiler, (p) & REG_MASK);
+			if ((p) & OFFS_REG_MASK) {
+				fprintf(compiler->verbose, " + ");
+				sljit_verbose_reg(compiler, OFFS_REG(p));
+				if (i)
+					fprintf(compiler->verbose, "%d", 1 << (i));
+			}
+			else if (i)
+				fprintf(compiler->verbose, " + %" SLJIT_PRINT_D "d", (i));
+			fputc(']', compiler->verbose);
+		}
+		else
+			fprintf(compiler->verbose, "[#%" SLJIT_PRINT_D "d]", (i));
+	}
+	else
+		sljit_verbose_freg(compiler, p);
+}
+
+static const char* op0_names[] = {
+	(char*)"breakpoint", (char*)"nop", (char*)"lmul.uw", (char*)"lmul.sw",
+	(char*)"divmod.u", (char*)"divmod.s", (char*)"div.u", (char*)"div.s",
+	(char*)"endbr", (char*)"skip_frames_before_return"
+};
+
+static const char* op1_names[] = {
+	(char*)"", (char*)".u8", (char*)".s8", (char*)".u16",
+	(char*)".s16", (char*)".u32", (char*)".s32", (char*)".p",
+	(char*)"", (char*)".u8", (char*)".s8", (char*)".u16",
+	(char*)".s16", (char*)".u32", (char*)".s32", (char*)".p",
+	(char*)"not", (char*)"neg", (char*)"clz",
+};
+
+static const char* op2_names[] = {
+	(char*)"add", (char*)"addc", (char*)"sub", (char*)"subc",
+	(char*)"mul", (char*)"and", (char*)"or", (char*)"xor",
+	(char*)"shl", (char*)"lshr", (char*)"ashr",
+};
+
+static const char* op_src_names[] = {
+	(char*)"fast_return", (char*)"skip_frames_before_fast_return",
+	(char*)"prefetch_l1", (char*)"prefetch_l2",
+	(char*)"prefetch_l3", (char*)"prefetch_once",
+};
+
+static const char* fop1_names[] = {
+	(char*)"mov", (char*)"conv", (char*)"conv", (char*)"conv",
+	(char*)"conv", (char*)"conv", (char*)"cmp", (char*)"neg",
+	(char*)"abs",
+};
+
+static const char* fop2_names[] = {
+	(char*)"add", (char*)"sub", (char*)"mul", (char*)"div"
+};
+
+#define JUMP_POSTFIX(type) \
+	((type & 0xff) <= SLJIT_MUL_NOT_OVERFLOW ? ((type & SLJIT_I32_OP) ? "32" : "") \
+	: ((type & 0xff) <= SLJIT_ORDERED_F64 ? ((type & SLJIT_F32_OP) ? ".f32" : ".f64") : ""))
+
+static char* jump_names[] = {
+	(char*)"equal", (char*)"not_equal",
+	(char*)"less", (char*)"greater_equal",
+	(char*)"greater", (char*)"less_equal",
+	(char*)"sig_less", (char*)"sig_greater_equal",
+	(char*)"sig_greater", (char*)"sig_less_equal",
+	(char*)"overflow", (char*)"not_overflow",
+	(char*)"mul_overflow", (char*)"mul_not_overflow",
+	(char*)"carry", (char*)"",
+	(char*)"equal", (char*)"not_equal",
+	(char*)"less", (char*)"greater_equal",
+	(char*)"greater", (char*)"less_equal",
+	(char*)"unordered", (char*)"ordered",
+	(char*)"jump", (char*)"fast_call",
+	(char*)"call", (char*)"call.cdecl"
+};
+
+static char* call_arg_names[] = {
+	(char*)"void", (char*)"sw", (char*)"uw", (char*)"s32", (char*)"u32", (char*)"f32", (char*)"f64"
+};
+
+#endif /* SLJIT_VERBOSE */
+
+/* --------------------------------------------------------------------- */
+/*  Arch dependent                                                       */
+/* --------------------------------------------------------------------- */
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
+	|| (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_generate_code(struct sljit_compiler *compiler)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	struct sljit_jump *jump;
+#endif
+
+	SLJIT_UNUSED_ARG(compiler);
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(compiler->size > 0);
+	jump = compiler->jumps;
+	while (jump) {
+		/* All jumps have target. */
+		CHECK_ARGUMENT(jump->flags & (JUMP_LABEL | JUMP_ADDR));
+		jump = jump->next;
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_enter(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	sljit_s32 types, arg_count, curr_type;
+#endif
+
+	SLJIT_UNUSED_ARG(compiler);
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(!(options & ~SLJIT_F64_ALIGNMENT));
+	CHECK_ARGUMENT(scratches >= 0 && scratches <= SLJIT_NUMBER_OF_REGISTERS);
+	CHECK_ARGUMENT(saveds >= 0 && saveds <= SLJIT_NUMBER_OF_REGISTERS);
+	CHECK_ARGUMENT(scratches + saveds <= SLJIT_NUMBER_OF_REGISTERS);
+	CHECK_ARGUMENT(fscratches >= 0 && fscratches <= SLJIT_NUMBER_OF_FLOAT_REGISTERS);
+	CHECK_ARGUMENT(fsaveds >= 0 && fsaveds <= SLJIT_NUMBER_OF_FLOAT_REGISTERS);
+	CHECK_ARGUMENT(fscratches + fsaveds <= SLJIT_NUMBER_OF_FLOAT_REGISTERS);
+	CHECK_ARGUMENT(local_size >= 0 && local_size <= SLJIT_MAX_LOCAL_SIZE);
+	CHECK_ARGUMENT((arg_types & SLJIT_DEF_MASK) == 0);
+
+	types = (arg_types >> SLJIT_DEF_SHIFT);
+	arg_count = 0;
+	while (types != 0 && arg_count < 3) {
+		curr_type = (types & SLJIT_DEF_MASK);
+		CHECK_ARGUMENT(curr_type == SLJIT_ARG_TYPE_SW || curr_type == SLJIT_ARG_TYPE_UW);
+		arg_count++;
+		types >>= SLJIT_DEF_SHIFT;
+	}
+	CHECK_ARGUMENT(arg_count <= saveds && types == 0);
+
+	compiler->last_flags = 0;
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  enter options:%s args[", (options & SLJIT_F64_ALIGNMENT) ? "f64_align" : "");
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+		while (arg_types) {
+			fprintf(compiler->verbose, "%s", call_arg_names[arg_types & SLJIT_DEF_MASK]);
+			arg_types >>= SLJIT_DEF_SHIFT;
+			if (arg_types)
+				fprintf(compiler->verbose, ",");
+		}
+
+		fprintf(compiler->verbose, "] scratches:%d saveds:%d fscratches:%d fsaveds:%d local_size:%d\n",
+			scratches, saveds, fscratches, fsaveds, local_size);
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_set_context(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	sljit_s32 types, arg_count, curr_type;
+#endif
+
+	SLJIT_UNUSED_ARG(compiler);
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(!(options & ~SLJIT_F64_ALIGNMENT));
+	CHECK_ARGUMENT(scratches >= 0 && scratches <= SLJIT_NUMBER_OF_REGISTERS);
+	CHECK_ARGUMENT(saveds >= 0 && saveds <= SLJIT_NUMBER_OF_REGISTERS);
+	CHECK_ARGUMENT(scratches + saveds <= SLJIT_NUMBER_OF_REGISTERS);
+	CHECK_ARGUMENT(fscratches >= 0 && fscratches <= SLJIT_NUMBER_OF_FLOAT_REGISTERS);
+	CHECK_ARGUMENT(fsaveds >= 0 && fsaveds <= SLJIT_NUMBER_OF_FLOAT_REGISTERS);
+	CHECK_ARGUMENT(fscratches + fsaveds <= SLJIT_NUMBER_OF_FLOAT_REGISTERS);
+	CHECK_ARGUMENT(local_size >= 0 && local_size <= SLJIT_MAX_LOCAL_SIZE);
+
+	types = (arg_types >> SLJIT_DEF_SHIFT);
+	arg_count = 0;
+	while (types != 0 && arg_count < 3) {
+		curr_type = (types & SLJIT_DEF_MASK);
+		CHECK_ARGUMENT(curr_type == SLJIT_ARG_TYPE_SW || curr_type == SLJIT_ARG_TYPE_UW);
+		arg_count++;
+		types >>= SLJIT_DEF_SHIFT;
+	}
+	CHECK_ARGUMENT(arg_count <= saveds && types == 0);
+
+	compiler->last_flags = 0;
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  set_context options:%s args[", (options & SLJIT_F64_ALIGNMENT) ? "f64_align" : "");
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+		while (arg_types) {
+			fprintf(compiler->verbose, "%s", call_arg_names[arg_types & SLJIT_DEF_MASK]);
+			arg_types >>= SLJIT_DEF_SHIFT;
+			if (arg_types)
+				fprintf(compiler->verbose, ",");
+		}
+
+		fprintf(compiler->verbose, "] scratches:%d saveds:%d fscratches:%d fsaveds:%d local_size:%d\n",
+			scratches, saveds, fscratches, fsaveds, local_size);
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(compiler->scratches >= 0);
+	if (op != SLJIT_UNUSED) {
+		CHECK_ARGUMENT(op >= SLJIT_MOV && op <= SLJIT_MOV_P);
+		FUNCTION_CHECK_SRC(src, srcw);
+	}
+	else
+		CHECK_ARGUMENT(src == 0 && srcw == 0);
+	compiler->last_flags = 0;
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		if (op == SLJIT_UNUSED)
+			fprintf(compiler->verbose, "  return\n");
+		else {
+			fprintf(compiler->verbose, "  return%s ", op1_names[op - SLJIT_OP1_BASE]);
+			sljit_verbose_param(compiler, src, srcw);
+			fprintf(compiler->verbose, "\n");
+		}
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	FUNCTION_CHECK_DST(dst, dstw, 0);
+	compiler->last_flags = 0;
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  fast_enter ");
+		sljit_verbose_param(compiler, dst, dstw);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT((op >= SLJIT_BREAKPOINT && op <= SLJIT_LMUL_SW)
+		|| ((op & ~SLJIT_I32_OP) >= SLJIT_DIVMOD_UW && (op & ~SLJIT_I32_OP) <= SLJIT_DIV_SW)
+		|| (op >= SLJIT_ENDBR && op <= SLJIT_SKIP_FRAMES_BEFORE_RETURN));
+	CHECK_ARGUMENT(GET_OPCODE(op) < SLJIT_LMUL_UW || GET_OPCODE(op) >= SLJIT_ENDBR || compiler->scratches >= 2);
+	if ((GET_OPCODE(op) >= SLJIT_LMUL_UW && GET_OPCODE(op) <= SLJIT_DIV_SW) || op == SLJIT_SKIP_FRAMES_BEFORE_RETURN)
+		compiler->last_flags = 0;
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose))
+	{
+		fprintf(compiler->verbose, "  %s", op0_names[GET_OPCODE(op) - SLJIT_OP0_BASE]);
+		if (GET_OPCODE(op) >= SLJIT_DIVMOD_UW && GET_OPCODE(op) <= SLJIT_DIV_SW) {
+			fprintf(compiler->verbose, (op & SLJIT_I32_OP) ? "32" : "w");
+		}
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	if (SLJIT_UNLIKELY(compiler->skip_checks)) {
+		compiler->skip_checks = 0;
+		CHECK_RETURN_OK;
+	}
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_MOV && GET_OPCODE(op) <= SLJIT_CLZ);
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_NOT:
+		/* Only SLJIT_I32_OP and SLJIT_SET_Z are allowed. */
+		CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK));
+		break;
+	case SLJIT_NEG:
+		CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK)
+			|| GET_FLAG_TYPE(op) == SLJIT_OVERFLOW);
+		break;
+	case SLJIT_MOV:
+	case SLJIT_MOV_U32:
+	case SLJIT_MOV_P:
+		/* Nothing allowed */
+		CHECK_ARGUMENT(!(op & (SLJIT_I32_OP | SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
+		break;
+	default:
+		/* Only SLJIT_I32_OP is allowed. */
+		CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
+		break;
+	}
+
+	FUNCTION_CHECK_DST(dst, dstw, HAS_FLAGS(op));
+	FUNCTION_CHECK_SRC(src, srcw);
+
+	if (GET_OPCODE(op) >= SLJIT_NOT) {
+		CHECK_ARGUMENT(src != SLJIT_IMM);
+		compiler->last_flags = GET_FLAG_TYPE(op) | (op & (SLJIT_I32_OP | SLJIT_SET_Z));
+	}
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		if (GET_OPCODE(op) <= SLJIT_MOV_P)
+		{
+			fprintf(compiler->verbose, "  mov%s%s ", !(op & SLJIT_I32_OP) ? "" : "32",
+				(op != SLJIT_MOV32) ? op1_names[GET_OPCODE(op) - SLJIT_OP1_BASE] : "");
+		}
+		else
+		{
+			fprintf(compiler->verbose, "  %s%s%s%s%s ", op1_names[GET_OPCODE(op) - SLJIT_OP1_BASE], !(op & SLJIT_I32_OP) ? "" : "32",
+				!(op & SLJIT_SET_Z) ? "" : ".z", !(op & VARIABLE_FLAG_MASK) ? "" : ".",
+				!(op & VARIABLE_FLAG_MASK) ? "" : jump_names[GET_FLAG_TYPE(op)]);
+		}
+
+		sljit_verbose_param(compiler, dst, dstw);
+		fprintf(compiler->verbose, ", ");
+		sljit_verbose_param(compiler, src, srcw);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	if (SLJIT_UNLIKELY(compiler->skip_checks)) {
+		compiler->skip_checks = 0;
+		CHECK_RETURN_OK;
+	}
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_ADD && GET_OPCODE(op) <= SLJIT_ASHR);
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_AND:
+	case SLJIT_OR:
+	case SLJIT_XOR:
+	case SLJIT_SHL:
+	case SLJIT_LSHR:
+	case SLJIT_ASHR:
+		CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK));
+		break;
+	case SLJIT_MUL:
+		CHECK_ARGUMENT(!(op & SLJIT_SET_Z));
+		CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK)
+			|| GET_FLAG_TYPE(op) == SLJIT_MUL_OVERFLOW);
+		break;
+	case SLJIT_ADD:
+		CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK)
+			|| GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY)
+			|| GET_FLAG_TYPE(op) == SLJIT_OVERFLOW);
+		break;
+	case SLJIT_SUB:
+		CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK)
+			|| (GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_OVERFLOW)
+			|| GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY));
+		break;
+	case SLJIT_ADDC:
+	case SLJIT_SUBC:
+		CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK)
+			|| GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY));
+		CHECK_ARGUMENT((compiler->last_flags & 0xff) == GET_FLAG_TYPE(SLJIT_SET_CARRY));
+		CHECK_ARGUMENT((op & SLJIT_I32_OP) == (compiler->last_flags & SLJIT_I32_OP));
+		break;
+	default:
+		SLJIT_UNREACHABLE();
+		break;
+	}
+
+	FUNCTION_CHECK_DST(dst, dstw, HAS_FLAGS(op));
+	FUNCTION_CHECK_SRC(src1, src1w);
+	FUNCTION_CHECK_SRC(src2, src2w);
+	compiler->last_flags = GET_FLAG_TYPE(op) | (op & (SLJIT_I32_OP | SLJIT_SET_Z));
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  %s%s%s%s%s ", op2_names[GET_OPCODE(op) - SLJIT_OP2_BASE], !(op & SLJIT_I32_OP) ? "" : "32",
+			!(op & SLJIT_SET_Z) ? "" : ".z", !(op & VARIABLE_FLAG_MASK) ? "" : ".",
+			!(op & VARIABLE_FLAG_MASK) ? "" : jump_names[GET_FLAG_TYPE(op)]);
+		sljit_verbose_param(compiler, dst, dstw);
+		fprintf(compiler->verbose, ", ");
+		sljit_verbose_param(compiler, src1, src1w);
+		fprintf(compiler->verbose, ", ");
+		sljit_verbose_param(compiler, src2, src2w);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src, sljit_sw srcw)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(op >= SLJIT_FAST_RETURN && op <= SLJIT_PREFETCH_ONCE);
+	FUNCTION_CHECK_SRC(src, srcw);
+
+	if (op == SLJIT_FAST_RETURN || op == SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN)
+	{
+		CHECK_ARGUMENT(src != SLJIT_IMM);
+		compiler->last_flags = 0;
+	}
+	else if (op >= SLJIT_PREFETCH_L1 && op <= SLJIT_PREFETCH_ONCE)
+	{
+		CHECK_ARGUMENT(src & SLJIT_MEM);
+	}
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  %s ", op_src_names[op - SLJIT_OP_SRC_BASE]);
+		sljit_verbose_param(compiler, src, srcw);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_register_index(sljit_s32 reg)
+{
+	SLJIT_UNUSED_ARG(reg);
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(reg > 0 && reg <= SLJIT_NUMBER_OF_REGISTERS);
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_float_register_index(sljit_s32 reg)
+{
+	SLJIT_UNUSED_ARG(reg);
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(reg > 0 && reg <= SLJIT_NUMBER_OF_FLOAT_REGISTERS);
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_custom(struct sljit_compiler *compiler,
+	void *instruction, sljit_s32 size)
+{
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	int i;
+#endif
+
+	SLJIT_UNUSED_ARG(compiler);
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(instruction);
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+	CHECK_ARGUMENT(size > 0 && size < 16);
+#elif (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
+	CHECK_ARGUMENT((size == 2 && (((sljit_sw)instruction) & 0x1) == 0)
+		|| (size == 4 && (((sljit_sw)instruction) & 0x3) == 0));
+#else
+	CHECK_ARGUMENT(size == 4 && (((sljit_sw)instruction) & 0x3) == 0);
+#endif
+
+	compiler->last_flags = 0;
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  op_custom");
+		for (i = 0; i < size; i++)
+			fprintf(compiler->verbose, " 0x%x", ((sljit_u8*)instruction)[i]);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	if (SLJIT_UNLIKELY(compiler->skip_checks)) {
+		compiler->skip_checks = 0;
+		CHECK_RETURN_OK;
+	}
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
+	CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_MOV_F64 && GET_OPCODE(op) <= SLJIT_ABS_F64);
+	CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
+	FUNCTION_FCHECK(src, srcw);
+	FUNCTION_FCHECK(dst, dstw);
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32)
+			fprintf(compiler->verbose, "  %s%s ", fop1_names[SLJIT_CONV_F64_FROM_F32 - SLJIT_FOP1_BASE],
+				(op & SLJIT_F32_OP) ? ".f32.from.f64" : ".f64.from.f32");
+		else
+			fprintf(compiler->verbose, "  %s%s ", fop1_names[GET_OPCODE(op) - SLJIT_FOP1_BASE],
+				(op & SLJIT_F32_OP) ? ".f32" : ".f64");
+
+		sljit_verbose_fparam(compiler, dst, dstw);
+		fprintf(compiler->verbose, ", ");
+		sljit_verbose_fparam(compiler, src, srcw);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->last_flags = GET_FLAG_TYPE(op) | (op & (SLJIT_I32_OP | SLJIT_SET_Z));
+#endif
+
+	if (SLJIT_UNLIKELY(compiler->skip_checks)) {
+		compiler->skip_checks = 0;
+		CHECK_RETURN_OK;
+	}
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
+	CHECK_ARGUMENT(GET_OPCODE(op) == SLJIT_CMP_F64);
+	CHECK_ARGUMENT(!(op & SLJIT_SET_Z));
+	CHECK_ARGUMENT((op & VARIABLE_FLAG_MASK)
+		|| (GET_FLAG_TYPE(op) >= SLJIT_EQUAL_F64 && GET_FLAG_TYPE(op) <= SLJIT_ORDERED_F64));
+	FUNCTION_FCHECK(src1, src1w);
+	FUNCTION_FCHECK(src2, src2w);
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  %s%s", fop1_names[SLJIT_CMP_F64 - SLJIT_FOP1_BASE], (op & SLJIT_F32_OP) ? ".f32" : ".f64");
+		if (op & VARIABLE_FLAG_MASK) {
+			fprintf(compiler->verbose, ".%s_f", jump_names[GET_FLAG_TYPE(op)]);
+		}
+		fprintf(compiler->verbose, " ");
+		sljit_verbose_fparam(compiler, src1, src1w);
+		fprintf(compiler->verbose, ", ");
+		sljit_verbose_fparam(compiler, src2, src2w);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	if (SLJIT_UNLIKELY(compiler->skip_checks)) {
+		compiler->skip_checks = 0;
+		CHECK_RETURN_OK;
+	}
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
+	CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_CONV_SW_FROM_F64 && GET_OPCODE(op) <= SLJIT_CONV_S32_FROM_F64);
+	CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
+	FUNCTION_FCHECK(src, srcw);
+	FUNCTION_CHECK_DST(dst, dstw, 0);
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  %s%s.from%s ", fop1_names[GET_OPCODE(op) - SLJIT_FOP1_BASE],
+			(GET_OPCODE(op) == SLJIT_CONV_S32_FROM_F64) ? ".s32" : ".sw",
+			(op & SLJIT_F32_OP) ? ".f32" : ".f64");
+		sljit_verbose_param(compiler, dst, dstw);
+		fprintf(compiler->verbose, ", ");
+		sljit_verbose_fparam(compiler, src, srcw);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	if (SLJIT_UNLIKELY(compiler->skip_checks)) {
+		compiler->skip_checks = 0;
+		CHECK_RETURN_OK;
+	}
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
+	CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_CONV_F64_FROM_SW && GET_OPCODE(op) <= SLJIT_CONV_F64_FROM_S32);
+	CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
+	FUNCTION_CHECK_SRC(src, srcw);
+	FUNCTION_FCHECK(dst, dstw);
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  %s%s.from%s ", fop1_names[GET_OPCODE(op) - SLJIT_FOP1_BASE],
+			(op & SLJIT_F32_OP) ? ".f32" : ".f64",
+			(GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) ? ".s32" : ".sw");
+		sljit_verbose_fparam(compiler, dst, dstw);
+		fprintf(compiler->verbose, ", ");
+		sljit_verbose_param(compiler, src, srcw);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
+	CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_ADD_F64 && GET_OPCODE(op) <= SLJIT_DIV_F64);
+	CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
+	FUNCTION_FCHECK(src1, src1w);
+	FUNCTION_FCHECK(src2, src2w);
+	FUNCTION_FCHECK(dst, dstw);
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  %s%s ", fop2_names[GET_OPCODE(op) - SLJIT_FOP2_BASE], (op & SLJIT_F32_OP) ? ".f32" : ".f64");
+		sljit_verbose_fparam(compiler, dst, dstw);
+		fprintf(compiler->verbose, ", ");
+		sljit_verbose_fparam(compiler, src1, src1w);
+		fprintf(compiler->verbose, ", ");
+		sljit_verbose_fparam(compiler, src2, src2w);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_label(struct sljit_compiler *compiler)
+{
+	SLJIT_UNUSED_ARG(compiler);
+
+	if (SLJIT_UNLIKELY(compiler->skip_checks)) {
+		compiler->skip_checks = 0;
+		CHECK_RETURN_OK;
+	}
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->last_flags = 0;
+#endif
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose))
+		fprintf(compiler->verbose, "label:\n");
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
+{
+	if (SLJIT_UNLIKELY(compiler->skip_checks)) {
+		compiler->skip_checks = 0;
+		CHECK_RETURN_OK;
+	}
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP | SLJIT_I32_OP)));
+	CHECK_ARGUMENT((type & 0xff) != GET_FLAG_TYPE(SLJIT_SET_CARRY) && (type & 0xff) != (GET_FLAG_TYPE(SLJIT_SET_CARRY) + 1));
+	CHECK_ARGUMENT((type & 0xff) >= SLJIT_EQUAL && (type & 0xff) <= SLJIT_FAST_CALL);
+	CHECK_ARGUMENT((type & 0xff) < SLJIT_JUMP || !(type & SLJIT_I32_OP));
+
+	if ((type & 0xff) < SLJIT_JUMP) {
+		if ((type & 0xff) <= SLJIT_NOT_ZERO)
+			CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
+		else
+			CHECK_ARGUMENT((type & 0xff) == (compiler->last_flags & 0xff)
+				|| ((type & 0xff) == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW)
+				|| ((type & 0xff) == SLJIT_MUL_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_MUL_OVERFLOW));
+		CHECK_ARGUMENT((type & SLJIT_I32_OP) == (compiler->last_flags & SLJIT_I32_OP));
+	}
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose))
+		fprintf(compiler->verbose, "  jump%s %s%s\n", !(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r",
+			jump_names[type & 0xff], JUMP_POSTFIX(type));
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	sljit_s32 i, types, curr_type, scratches, fscratches;
+
+	CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP)));
+	CHECK_ARGUMENT((type & 0xff) == SLJIT_CALL || (type & 0xff) == SLJIT_CALL_CDECL);
+
+	types = arg_types;
+	scratches = 0;
+	fscratches = 0;
+	for (i = 0; i < 5; i++) {
+		curr_type = (types & SLJIT_DEF_MASK);
+		CHECK_ARGUMENT(curr_type <= SLJIT_ARG_TYPE_F64);
+		if (i > 0) {
+			if (curr_type == 0) {
+				break;
+			}
+			if (curr_type >= SLJIT_ARG_TYPE_F32)
+				fscratches++;
+			else
+				scratches++;
+		} else {
+			if (curr_type >= SLJIT_ARG_TYPE_F32) {
+				CHECK_ARGUMENT(compiler->fscratches > 0);
+			} else if (curr_type >= SLJIT_ARG_TYPE_SW) {
+				CHECK_ARGUMENT(compiler->scratches > 0);
+			}
+		}
+		types >>= SLJIT_DEF_SHIFT;
+	}
+	CHECK_ARGUMENT(compiler->scratches >= scratches);
+	CHECK_ARGUMENT(compiler->fscratches >= fscratches);
+	CHECK_ARGUMENT(types == 0);
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  %s%s ret[%s", jump_names[type & 0xff],
+			!(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r", call_arg_names[arg_types & SLJIT_DEF_MASK]);
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+		if (arg_types) {
+			fprintf(compiler->verbose, "], args[");
+			do {
+				fprintf(compiler->verbose, "%s", call_arg_names[arg_types & SLJIT_DEF_MASK]);
+				arg_types >>= SLJIT_DEF_SHIFT;
+				if (arg_types)
+					fprintf(compiler->verbose, ",");
+			} while (arg_types);
+		}
+		fprintf(compiler->verbose, "]\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_cmp(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP | SLJIT_I32_OP)));
+	CHECK_ARGUMENT((type & 0xff) >= SLJIT_EQUAL && (type & 0xff) <= SLJIT_SIG_LESS_EQUAL);
+	FUNCTION_CHECK_SRC(src1, src1w);
+	FUNCTION_CHECK_SRC(src2, src2w);
+	compiler->last_flags = 0;
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  cmp%s %s%s, ", !(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r",
+			jump_names[type & 0xff], (type & SLJIT_I32_OP) ? "32" : "");
+		sljit_verbose_param(compiler, src1, src1w);
+		fprintf(compiler->verbose, ", ");
+		sljit_verbose_param(compiler, src2, src2w);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
+	CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP | SLJIT_F32_OP)));
+	CHECK_ARGUMENT((type & 0xff) >= SLJIT_EQUAL_F64 && (type & 0xff) <= SLJIT_ORDERED_F64);
+	FUNCTION_FCHECK(src1, src1w);
+	FUNCTION_FCHECK(src2, src2w);
+	compiler->last_flags = 0;
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  fcmp%s %s%s, ", !(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r",
+			jump_names[type & 0xff], (type & SLJIT_F32_OP) ? ".f32" : ".f64");
+		sljit_verbose_fparam(compiler, src1, src1w);
+		fprintf(compiler->verbose, ", ");
+		sljit_verbose_fparam(compiler, src2, src2w);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 src, sljit_sw srcw)
+{
+	if (SLJIT_UNLIKELY(compiler->skip_checks)) {
+		compiler->skip_checks = 0;
+		CHECK_RETURN_OK;
+	}
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(type >= SLJIT_JUMP && type <= SLJIT_FAST_CALL);
+	FUNCTION_CHECK_SRC(src, srcw);
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  ijump.%s ", jump_names[type]);
+		sljit_verbose_param(compiler, src, srcw);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types,
+	sljit_s32 src, sljit_sw srcw)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	sljit_s32 i, types, curr_type, scratches, fscratches;
+
+	CHECK_ARGUMENT(type == SLJIT_CALL || type == SLJIT_CALL_CDECL);
+	FUNCTION_CHECK_SRC(src, srcw);
+
+	types = arg_types;
+	scratches = 0;
+	fscratches = 0;
+	for (i = 0; i < 5; i++) {
+		curr_type = (types & SLJIT_DEF_MASK);
+		CHECK_ARGUMENT(curr_type <= SLJIT_ARG_TYPE_F64);
+		if (i > 0) {
+			if (curr_type == 0) {
+				break;
+			}
+			if (curr_type >= SLJIT_ARG_TYPE_F32)
+				fscratches++;
+			else
+				scratches++;
+		} else {
+			if (curr_type >= SLJIT_ARG_TYPE_F32) {
+				CHECK_ARGUMENT(compiler->fscratches > 0);
+			} else if (curr_type >= SLJIT_ARG_TYPE_SW) {
+				CHECK_ARGUMENT(compiler->scratches > 0);
+			}
+		}
+		types >>= SLJIT_DEF_SHIFT;
+	}
+	CHECK_ARGUMENT(compiler->scratches >= scratches);
+	CHECK_ARGUMENT(compiler->fscratches >= fscratches);
+	CHECK_ARGUMENT(types == 0);
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  i%s%s ret[%s", jump_names[type & 0xff],
+			!(type & SLJIT_REWRITABLE_JUMP) ? "" : ".r", call_arg_names[arg_types & SLJIT_DEF_MASK]);
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+		if (arg_types) {
+			fprintf(compiler->verbose, "], args[");
+			do {
+				fprintf(compiler->verbose, "%s", call_arg_names[arg_types & SLJIT_DEF_MASK]);
+				arg_types >>= SLJIT_DEF_SHIFT;
+				if (arg_types)
+					fprintf(compiler->verbose, ",");
+			} while (arg_types);
+		}
+		fprintf(compiler->verbose, "], ");
+		sljit_verbose_param(compiler, src, srcw);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 type)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_I32_OP)));
+	CHECK_ARGUMENT((type & 0xff) >= SLJIT_EQUAL && (type & 0xff) <= SLJIT_ORDERED_F64);
+	CHECK_ARGUMENT((type & 0xff) != GET_FLAG_TYPE(SLJIT_SET_CARRY) && (type & 0xff) != (GET_FLAG_TYPE(SLJIT_SET_CARRY) + 1));
+	CHECK_ARGUMENT(op == SLJIT_MOV || op == SLJIT_MOV32
+		|| (GET_OPCODE(op) >= SLJIT_AND && GET_OPCODE(op) <= SLJIT_XOR));
+	CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK));
+
+	if ((type & 0xff) <= SLJIT_NOT_ZERO)
+		CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
+	else
+		CHECK_ARGUMENT((type & 0xff) == (compiler->last_flags & 0xff)
+			|| ((type & 0xff) == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW)
+			|| ((type & 0xff) == SLJIT_MUL_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_MUL_OVERFLOW));
+
+	FUNCTION_CHECK_DST(dst, dstw, 0);
+
+	if (GET_OPCODE(op) >= SLJIT_ADD)
+		compiler->last_flags = GET_FLAG_TYPE(op) | (op & (SLJIT_I32_OP | SLJIT_SET_Z));
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  flags%s %s%s, ",
+			!(op & SLJIT_SET_Z) ? "" : ".z",
+			GET_OPCODE(op) < SLJIT_OP2_BASE ? "mov" : op2_names[GET_OPCODE(op) - SLJIT_OP2_BASE],
+			GET_OPCODE(op) < SLJIT_OP2_BASE ? op1_names[GET_OPCODE(op) - SLJIT_OP1_BASE] : ((op & SLJIT_I32_OP) ? "32" : ""));
+		sljit_verbose_param(compiler, dst, dstw);
+		fprintf(compiler->verbose, ", %s%s\n", jump_names[type & 0xff], JUMP_POSTFIX(type));
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 dst_reg,
+	sljit_s32 src, sljit_sw srcw)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_I32_OP)));
+	CHECK_ARGUMENT((type & 0xff) >= SLJIT_EQUAL && (type & 0xff) <= SLJIT_ORDERED_F64);
+
+	CHECK_ARGUMENT(compiler->scratches != -1 && compiler->saveds != -1);
+	CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(dst_reg & ~SLJIT_I32_OP));
+	if (src != SLJIT_IMM) {
+		CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(src));
+		CHECK_ARGUMENT(srcw == 0);
+	}
+
+	if ((type & 0xff) <= SLJIT_NOT_ZERO)
+		CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
+	else
+		CHECK_ARGUMENT((type & 0xff) == (compiler->last_flags & 0xff)
+			|| ((type & 0xff) == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW)
+			|| ((type & 0xff) == SLJIT_MUL_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_MUL_OVERFLOW));
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  cmov%s %s%s, ",
+			!(dst_reg & SLJIT_I32_OP) ? "" : "32",
+			jump_names[type & 0xff], JUMP_POSTFIX(type));
+		sljit_verbose_reg(compiler, dst_reg & ~SLJIT_I32_OP);
+		fprintf(compiler->verbose, ", ");
+		sljit_verbose_param(compiler, src, srcw);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 reg,
+	sljit_s32 mem, sljit_sw memw)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT((type & 0xff) >= SLJIT_MOV && (type & 0xff) <= SLJIT_MOV_P);
+	CHECK_ARGUMENT(!(type & SLJIT_I32_OP) || ((type & 0xff) != SLJIT_MOV && (type & 0xff) != SLJIT_MOV_U32 && (type & 0xff) != SLJIT_MOV_P));
+	CHECK_ARGUMENT((type & SLJIT_MEM_PRE) || (type & SLJIT_MEM_POST));
+	CHECK_ARGUMENT((type & (SLJIT_MEM_PRE | SLJIT_MEM_POST)) != (SLJIT_MEM_PRE | SLJIT_MEM_POST));
+	CHECK_ARGUMENT((type & ~(0xff | SLJIT_I32_OP | SLJIT_MEM_STORE | SLJIT_MEM_SUPP | SLJIT_MEM_PRE | SLJIT_MEM_POST)) == 0);
+
+	FUNCTION_CHECK_SRC_MEM(mem, memw);
+	CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(reg));
+
+	CHECK_ARGUMENT((mem & REG_MASK) != SLJIT_UNUSED && (mem & REG_MASK) != reg);
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (!(type & SLJIT_MEM_SUPP) && SLJIT_UNLIKELY(!!compiler->verbose)) {
+		if (sljit_emit_mem(compiler, type | SLJIT_MEM_SUPP, reg, mem, memw) == SLJIT_ERR_UNSUPPORTED)
+			fprintf(compiler->verbose, "  //");
+
+		fprintf(compiler->verbose, "  mem%s.%s%s%s ",
+			!(type & SLJIT_I32_OP) ? "" : "32",
+			(type & SLJIT_MEM_STORE) ? "st" : "ld",
+			op1_names[(type & 0xff) - SLJIT_OP1_BASE],
+			(type & SLJIT_MEM_PRE) ? ".pre" : ".post");
+		sljit_verbose_reg(compiler, reg);
+		fprintf(compiler->verbose, ", ");
+		sljit_verbose_param(compiler, mem, memw);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fmem(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 freg,
+	sljit_s32 mem, sljit_sw memw)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	CHECK_ARGUMENT((type & 0xff) == SLJIT_MOV_F64);
+	CHECK_ARGUMENT((type & SLJIT_MEM_PRE) || (type & SLJIT_MEM_POST));
+	CHECK_ARGUMENT((type & (SLJIT_MEM_PRE | SLJIT_MEM_POST)) != (SLJIT_MEM_PRE | SLJIT_MEM_POST));
+	CHECK_ARGUMENT((type & ~(0xff | SLJIT_I32_OP | SLJIT_MEM_STORE | SLJIT_MEM_SUPP | SLJIT_MEM_PRE | SLJIT_MEM_POST)) == 0);
+
+	FUNCTION_CHECK_SRC_MEM(mem, memw);
+	CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(freg));
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (!(type & SLJIT_MEM_SUPP) && SLJIT_UNLIKELY(!!compiler->verbose)) {
+		if (sljit_emit_fmem(compiler, type | SLJIT_MEM_SUPP, freg, mem, memw) == SLJIT_ERR_UNSUPPORTED)
+			fprintf(compiler->verbose, "  //");
+
+		fprintf(compiler->verbose, "  fmem.%s%s%s ",
+			(type & SLJIT_MEM_STORE) ? "st" : "ld",
+			!(type & SLJIT_I32_OP) ? ".f64" : ".f32",
+			(type & SLJIT_MEM_PRE) ? ".pre" : ".post");
+		sljit_verbose_freg(compiler, freg);
+		fprintf(compiler->verbose, ", ");
+		sljit_verbose_param(compiler, mem, memw);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset)
+{
+	/* Any offset is allowed. */
+	SLJIT_UNUSED_ARG(offset);
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	FUNCTION_CHECK_DST(dst, dstw, 0);
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  local_base ");
+		sljit_verbose_param(compiler, dst, dstw);
+		fprintf(compiler->verbose, ", #%" SLJIT_PRINT_D "d\n", offset);
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
+{
+	SLJIT_UNUSED_ARG(init_value);
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	FUNCTION_CHECK_DST(dst, dstw, 0);
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  const ");
+		sljit_verbose_param(compiler, dst, dstw);
+		fprintf(compiler->verbose, ", #%" SLJIT_PRINT_D "d\n", init_value);
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	FUNCTION_CHECK_DST(dst, dstw, 0);
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+		fprintf(compiler->verbose, "  put_label ");
+		sljit_verbose_param(compiler, dst, dstw);
+		fprintf(compiler->verbose, "\n");
+	}
+#endif
+	CHECK_RETURN_OK;
+}
+
+#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_VERBOSE */
+
+#define SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw) \
+	SLJIT_COMPILE_ASSERT(!(SLJIT_CONV_SW_FROM_F64 & 0x1) && !(SLJIT_CONV_F64_FROM_SW & 0x1), \
+		invalid_float_opcodes); \
+	if (GET_OPCODE(op) >= SLJIT_CONV_SW_FROM_F64 && GET_OPCODE(op) <= SLJIT_CMP_F64) { \
+		if (GET_OPCODE(op) == SLJIT_CMP_F64) { \
+			CHECK(check_sljit_emit_fop1_cmp(compiler, op, dst, dstw, src, srcw)); \
+			ADJUST_LOCAL_OFFSET(dst, dstw); \
+			ADJUST_LOCAL_OFFSET(src, srcw); \
+			return sljit_emit_fop1_cmp(compiler, op, dst, dstw, src, srcw); \
+		} \
+		if ((GET_OPCODE(op) | 0x1) == SLJIT_CONV_S32_FROM_F64) { \
+			CHECK(check_sljit_emit_fop1_conv_sw_from_f64(compiler, op, dst, dstw, src, srcw)); \
+			ADJUST_LOCAL_OFFSET(dst, dstw); \
+			ADJUST_LOCAL_OFFSET(src, srcw); \
+			return sljit_emit_fop1_conv_sw_from_f64(compiler, op, dst, dstw, src, srcw); \
+		} \
+		CHECK(check_sljit_emit_fop1_conv_f64_from_sw(compiler, op, dst, dstw, src, srcw)); \
+		ADJUST_LOCAL_OFFSET(dst, dstw); \
+		ADJUST_LOCAL_OFFSET(src, srcw); \
+		return sljit_emit_fop1_conv_f64_from_sw(compiler, op, dst, dstw, src, srcw); \
+	} \
+	CHECK(check_sljit_emit_fop1(compiler, op, dst, dstw, src, srcw)); \
+	ADJUST_LOCAL_OFFSET(dst, dstw); \
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+static SLJIT_INLINE sljit_s32 emit_mov_before_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
+{
+	/* Return if don't need to do anything. */
+	if (op == SLJIT_UNUSED)
+		return SLJIT_SUCCESS;
+
+#if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
+	/* At the moment the pointer size is always equal to sljit_sw. May be changed in the future. */
+	if (src == SLJIT_RETURN_REG && (op == SLJIT_MOV || op == SLJIT_MOV_P))
+		return SLJIT_SUCCESS;
+#else
+	if (src == SLJIT_RETURN_REG && (op == SLJIT_MOV || op == SLJIT_MOV_U32 || op == SLJIT_MOV_S32 || op == SLJIT_MOV_P))
+		return SLJIT_SUCCESS;
+#endif
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
+		|| (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	compiler->skip_checks = 1;
+#endif
+	return sljit_emit_op1(compiler, op, SLJIT_RETURN_REG, 0, src, srcw);
+}
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \
+		|| (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) \
+		|| (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) \
+		|| ((defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) && !(defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1))
+
+static SLJIT_INLINE sljit_s32 sljit_emit_cmov_generic(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 dst_reg,
+	sljit_s32 src, sljit_sw srcw)
+{
+	struct sljit_label *label;
+	struct sljit_jump *jump;
+	sljit_s32 op = (dst_reg & SLJIT_I32_OP) ? SLJIT_MOV32 : SLJIT_MOV;
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+	jump = sljit_emit_jump(compiler, type ^ 0x1);
+	FAIL_IF(!jump);
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+	FAIL_IF(sljit_emit_op1(compiler, op, dst_reg & ~SLJIT_I32_OP, 0, src, srcw));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+	label = sljit_emit_label(compiler);
+	FAIL_IF(!label);
+	sljit_set_label(jump, label);
+	return SLJIT_SUCCESS;
+}
+
+#endif
+
+/* CPU description section */
+
+#if (defined SLJIT_32BIT_ARCHITECTURE && SLJIT_32BIT_ARCHITECTURE)
+#define SLJIT_CPUINFO_PART1 " 32bit ("
+#elif (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
+#define SLJIT_CPUINFO_PART1 " 64bit ("
+#else
+#error "Internal error: CPU type info missing"
+#endif
+
+#if (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
+#define SLJIT_CPUINFO_PART2 "little endian + "
+#elif (defined SLJIT_BIG_ENDIAN && SLJIT_BIG_ENDIAN)
+#define SLJIT_CPUINFO_PART2 "big endian + "
+#else
+#error "Internal error: CPU type info missing"
+#endif
+
+#if (defined SLJIT_UNALIGNED && SLJIT_UNALIGNED)
+#define SLJIT_CPUINFO_PART3 "unaligned)"
+#else
+#define SLJIT_CPUINFO_PART3 "aligned)"
+#endif
+
+#define SLJIT_CPUINFO SLJIT_CPUINFO_PART1 SLJIT_CPUINFO_PART2 SLJIT_CPUINFO_PART3
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+#	include "sljitNativeX86_common.c"
+#elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#	include "sljitNativeARM_32.c"
+#elif (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+#	include "sljitNativeARM_32.c"
+#elif (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
+#	include "sljitNativeARM_T2_32.c"
+#elif (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
+#	include "sljitNativeARM_64.c"
+#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
+#	include "sljitNativePPC_common.c"
+#elif (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
+#	include "sljitNativeMIPS_common.c"
+#elif (defined SLJIT_CONFIG_SPARC && SLJIT_CONFIG_SPARC)
+#	include "sljitNativeSPARC_common.c"
+#elif (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX)
+#	include "sljitNativeTILEGX_64.c"
+#endif
+
+#if !(defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	/* Default compare for most architectures. */
+	sljit_s32 flags, tmp_src, condition;
+	sljit_sw tmp_srcw;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_cmp(compiler, type, src1, src1w, src2, src2w));
+
+	condition = type & 0xff;
+#if (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
+	if ((condition == SLJIT_EQUAL || condition == SLJIT_NOT_EQUAL)) {
+		if ((src1 & SLJIT_IMM) && !src1w) {
+			src1 = src2;
+			src1w = src2w;
+			src2 = SLJIT_IMM;
+			src2w = 0;
+		}
+		if ((src2 & SLJIT_IMM) && !src2w)
+			return emit_cmp_to0(compiler, type, src1, src1w);
+	}
+#endif
+
+	if (SLJIT_UNLIKELY((src1 & SLJIT_IMM) && !(src2 & SLJIT_IMM))) {
+		/* Immediate is prefered as second argument by most architectures. */
+		switch (condition) {
+		case SLJIT_LESS:
+			condition = SLJIT_GREATER;
+			break;
+		case SLJIT_GREATER_EQUAL:
+			condition = SLJIT_LESS_EQUAL;
+			break;
+		case SLJIT_GREATER:
+			condition = SLJIT_LESS;
+			break;
+		case SLJIT_LESS_EQUAL:
+			condition = SLJIT_GREATER_EQUAL;
+			break;
+		case SLJIT_SIG_LESS:
+			condition = SLJIT_SIG_GREATER;
+			break;
+		case SLJIT_SIG_GREATER_EQUAL:
+			condition = SLJIT_SIG_LESS_EQUAL;
+			break;
+		case SLJIT_SIG_GREATER:
+			condition = SLJIT_SIG_LESS;
+			break;
+		case SLJIT_SIG_LESS_EQUAL:
+			condition = SLJIT_SIG_GREATER_EQUAL;
+			break;
+		}
+
+		type = condition | (type & (SLJIT_I32_OP | SLJIT_REWRITABLE_JUMP));
+		tmp_src = src1;
+		src1 = src2;
+		src2 = tmp_src;
+		tmp_srcw = src1w;
+		src1w = src2w;
+		src2w = tmp_srcw;
+	}
+
+	if (condition <= SLJIT_NOT_ZERO)
+		flags = SLJIT_SET_Z;
+	else
+		flags = condition << VARIABLE_FLAG_SHIFT;
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+	PTR_FAIL_IF(sljit_emit_op2(compiler, SLJIT_SUB | flags | (type & SLJIT_I32_OP),
+		SLJIT_UNUSED, 0, src1, src1w, src2, src2w));
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+	return sljit_emit_jump(compiler, condition | (type & (SLJIT_REWRITABLE_JUMP | SLJIT_I32_OP)));
+}
+
+#endif
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_fcmp(compiler, type, src1, src1w, src2, src2w));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+	sljit_emit_fop1(compiler, SLJIT_CMP_F64 | ((type & 0xff) << VARIABLE_FLAG_SHIFT) | (type & SLJIT_I32_OP), src1, src1w, src2, src2w);
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+	return sljit_emit_jump(compiler, type);
+}
+
+#if !(defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) \
+	&& !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
+	&& !(defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 reg,
+	sljit_s32 mem, sljit_sw memw)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(type);
+	SLJIT_UNUSED_ARG(reg);
+	SLJIT_UNUSED_ARG(mem);
+	SLJIT_UNUSED_ARG(memw);
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw));
+
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+#endif
+
+#if !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
+	&& !(defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 freg,
+	sljit_s32 mem, sljit_sw memw)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(type);
+	SLJIT_UNUSED_ARG(freg);
+	SLJIT_UNUSED_ARG(mem);
+	SLJIT_UNUSED_ARG(memw);
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fmem(compiler, type, freg, mem, memw));
+
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+#endif
+
+#if !(defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \
+	&& !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_get_local_base(compiler, dst, dstw, offset));
+
+	ADJUST_LOCAL_OFFSET(SLJIT_MEM1(SLJIT_SP), offset);
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+	if (offset != 0)
+		return sljit_emit_op2(compiler, SLJIT_ADD, dst, dstw, SLJIT_SP, 0, SLJIT_IMM, offset);
+	return sljit_emit_op1(compiler, SLJIT_MOV, dst, dstw, SLJIT_SP, 0);
+}
+
+#endif
+
+#else /* SLJIT_CONFIG_UNSUPPORTED */
+
+/* Empty function bodies for those machines, which are not (yet) supported. */
+
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
+{
+	return "unsupported";
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data, void *exec_allocator_data)
+{
+	SLJIT_UNUSED_ARG(allocator_data);
+	SLJIT_UNUSED_ARG(exec_allocator_data);
+	SLJIT_UNREACHABLE();
+	return NULL;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compiler)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNREACHABLE();
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compiler *compiler)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNREACHABLE();
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_s32 size)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(size);
+	SLJIT_UNREACHABLE();
+	return NULL;
+}
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+SLJIT_API_FUNC_ATTRIBUTE void sljit_compiler_verbose(struct sljit_compiler *compiler, FILE* verbose)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(verbose);
+	SLJIT_UNREACHABLE();
+}
+#endif
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNREACHABLE();
+	return NULL;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
+{
+	SLJIT_UNUSED_ARG(feature_type);
+	SLJIT_UNREACHABLE();
+	return 0;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code, void *exec_allocator_data)
+{
+	SLJIT_UNUSED_ARG(code);
+	SLJIT_UNUSED_ARG(exec_allocator_data);
+	SLJIT_UNREACHABLE();
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(options);
+	SLJIT_UNUSED_ARG(arg_types);
+	SLJIT_UNUSED_ARG(scratches);
+	SLJIT_UNUSED_ARG(saveds);
+	SLJIT_UNUSED_ARG(fscratches);
+	SLJIT_UNUSED_ARG(fsaveds);
+	SLJIT_UNUSED_ARG(local_size);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(options);
+	SLJIT_UNUSED_ARG(arg_types);
+	SLJIT_UNUSED_ARG(scratches);
+	SLJIT_UNUSED_ARG(saveds);
+	SLJIT_UNUSED_ARG(fscratches);
+	SLJIT_UNUSED_ARG(fsaveds);
+	SLJIT_UNUSED_ARG(local_size);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(op);
+	SLJIT_UNUSED_ARG(src);
+	SLJIT_UNUSED_ARG(srcw);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(dst);
+	SLJIT_UNUSED_ARG(dstw);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(op);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(op);
+	SLJIT_UNUSED_ARG(dst);
+	SLJIT_UNUSED_ARG(dstw);
+	SLJIT_UNUSED_ARG(src);
+	SLJIT_UNUSED_ARG(srcw);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(op);
+	SLJIT_UNUSED_ARG(dst);
+	SLJIT_UNUSED_ARG(dstw);
+	SLJIT_UNUSED_ARG(src1);
+	SLJIT_UNUSED_ARG(src1w);
+	SLJIT_UNUSED_ARG(src2);
+	SLJIT_UNUSED_ARG(src2w);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src, sljit_sw srcw)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(op);
+	SLJIT_UNUSED_ARG(src);
+	SLJIT_UNUSED_ARG(srcw);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+{
+	SLJIT_UNREACHABLE();
+	return reg;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+	void *instruction, sljit_s32 size)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(instruction);
+	SLJIT_UNUSED_ARG(size);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler, sljit_s32 current_flags)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(current_flags);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(op);
+	SLJIT_UNUSED_ARG(dst);
+	SLJIT_UNUSED_ARG(dstw);
+	SLJIT_UNUSED_ARG(src);
+	SLJIT_UNUSED_ARG(srcw);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(op);
+	SLJIT_UNUSED_ARG(dst);
+	SLJIT_UNUSED_ARG(dstw);
+	SLJIT_UNUSED_ARG(src1);
+	SLJIT_UNUSED_ARG(src1w);
+	SLJIT_UNUSED_ARG(src2);
+	SLJIT_UNUSED_ARG(src2w);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNREACHABLE();
+	return NULL;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(type);
+	SLJIT_UNREACHABLE();
+	return NULL;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(type);
+	SLJIT_UNUSED_ARG(arg_types);
+	SLJIT_UNREACHABLE();
+	return NULL;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(type);
+	SLJIT_UNUSED_ARG(src1);
+	SLJIT_UNUSED_ARG(src1w);
+	SLJIT_UNUSED_ARG(src2);
+	SLJIT_UNUSED_ARG(src2w);
+	SLJIT_UNREACHABLE();
+	return NULL;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(type);
+	SLJIT_UNUSED_ARG(src1);
+	SLJIT_UNUSED_ARG(src1w);
+	SLJIT_UNUSED_ARG(src2);
+	SLJIT_UNUSED_ARG(src2w);
+	SLJIT_UNREACHABLE();
+	return NULL;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_label(struct sljit_jump *jump, struct sljit_label* label)
+{
+	SLJIT_UNUSED_ARG(jump);
+	SLJIT_UNUSED_ARG(label);
+	SLJIT_UNREACHABLE();
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_target(struct sljit_jump *jump, sljit_uw target)
+{
+	SLJIT_UNUSED_ARG(jump);
+	SLJIT_UNUSED_ARG(target);
+	SLJIT_UNREACHABLE();
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_put_label(struct sljit_put_label *put_label, struct sljit_label *label)
+{
+	SLJIT_UNUSED_ARG(put_label);
+	SLJIT_UNUSED_ARG(label);
+	SLJIT_UNREACHABLE();
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(type);
+	SLJIT_UNUSED_ARG(src);
+	SLJIT_UNUSED_ARG(srcw);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types,
+	sljit_s32 src, sljit_sw srcw)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(type);
+	SLJIT_UNUSED_ARG(arg_types);
+	SLJIT_UNUSED_ARG(src);
+	SLJIT_UNUSED_ARG(srcw);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 type)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(op);
+	SLJIT_UNUSED_ARG(dst);
+	SLJIT_UNUSED_ARG(dstw);
+	SLJIT_UNUSED_ARG(type);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 dst_reg,
+	sljit_s32 src, sljit_sw srcw)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(type);
+	SLJIT_UNUSED_ARG(dst_reg);
+	SLJIT_UNUSED_ARG(src);
+	SLJIT_UNUSED_ARG(srcw);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 reg, sljit_s32 mem, sljit_sw memw)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(type);
+	SLJIT_UNUSED_ARG(reg);
+	SLJIT_UNUSED_ARG(mem);
+	SLJIT_UNUSED_ARG(memw);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 freg, sljit_s32 mem, sljit_sw memw)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(type);
+	SLJIT_UNUSED_ARG(freg);
+	SLJIT_UNUSED_ARG(mem);
+	SLJIT_UNUSED_ARG(memw);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(dst);
+	SLJIT_UNUSED_ARG(dstw);
+	SLJIT_UNUSED_ARG(offset);
+	SLJIT_UNREACHABLE();
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw initval)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(dst);
+	SLJIT_UNUSED_ARG(dstw);
+	SLJIT_UNUSED_ARG(initval);
+	SLJIT_UNREACHABLE();
+	return NULL;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(dst);
+	SLJIT_UNUSED_ARG(dstw);
+	return NULL;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
+{
+	SLJIT_UNUSED_ARG(addr);
+	SLJIT_UNUSED_ARG(new_target);
+	SLJIT_UNUSED_ARG(executable_offset);
+	SLJIT_UNREACHABLE();
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
+{
+	SLJIT_UNUSED_ARG(addr);
+	SLJIT_UNUSED_ARG(new_constant);
+	SLJIT_UNUSED_ARG(executable_offset);
+	SLJIT_UNREACHABLE();
+}
+
+#endif /* !SLJIT_CONFIG_UNSUPPORTED */
diff --git a/src/c/pcre2/src/sljit/sljitLir.h b/src/c/pcre2/src/sljit/sljitLir.h
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitLir.h
@@ -0,0 +1,1544 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SLJIT_LIR_H_
+#define SLJIT_LIR_H_
+
+/*
+   ------------------------------------------------------------------------
+    Stack-Less JIT compiler for multiple architectures (x86, ARM, PowerPC)
+   ------------------------------------------------------------------------
+
+   Short description
+    Advantages:
+      - The execution can be continued from any LIR instruction. In other
+        words, it is possible to jump to any label from anywhere, even from
+        a code fragment, which is compiled later, if both compiled code
+        shares the same context. See sljit_emit_enter for more details
+      - Supports self modifying code: target of (conditional) jump and call
+        instructions and some constant values can be dynamically modified
+        during runtime
+        - although it is not suggested to do it frequently
+        - can be used for inline caching: save an important value once
+          in the instruction stream
+        - since this feature limits the optimization possibilities, a
+          special flag must be passed at compile time when these
+          instructions are emitted
+      - A fixed stack space can be allocated for local variables
+      - The compiler is thread-safe
+      - The compiler is highly configurable through preprocessor macros.
+        You can disable unneeded features (multithreading in single
+        threaded applications), and you can use your own system functions
+        (including memory allocators). See sljitConfig.h
+    Disadvantages:
+      - No automatic register allocation, and temporary results are
+        not stored on the stack. (hence the name comes)
+    In practice:
+      - This approach is very effective for interpreters
+        - One of the saved registers typically points to a stack interface
+        - It can jump to any exception handler anytime (even if it belongs
+          to another function)
+        - Hot paths can be modified during runtime reflecting the changes
+          of the fastest execution path of the dynamic language
+        - SLJIT supports complex memory addressing modes
+        - mainly position and context independent code (except some cases)
+
+    For valgrind users:
+      - pass --smc-check=all argument to valgrind, since JIT is a "self-modifying code"
+*/
+
+#if (defined SLJIT_HAVE_CONFIG_PRE && SLJIT_HAVE_CONFIG_PRE)
+#include "sljitConfigPre.h"
+#endif /* SLJIT_HAVE_CONFIG_PRE */
+
+#include "sljitConfig.h"
+
+/* The following header file defines useful macros for fine tuning
+sljit based code generators. They are listed in the beginning
+of sljitConfigInternal.h */
+
+#include "sljitConfigInternal.h"
+
+#if (defined SLJIT_HAVE_CONFIG_POST && SLJIT_HAVE_CONFIG_POST)
+#include "sljitConfigPost.h"
+#endif /* SLJIT_HAVE_CONFIG_POST */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* --------------------------------------------------------------------- */
+/*  Error codes                                                          */
+/* --------------------------------------------------------------------- */
+
+/* Indicates no error. */
+#define SLJIT_SUCCESS			0
+/* After the call of sljit_generate_code(), the error code of the compiler
+   is set to this value to avoid future sljit calls (in debug mode at least).
+   The complier should be freed after sljit_generate_code(). */
+#define SLJIT_ERR_COMPILED		1
+/* Cannot allocate non executable memory. */
+#define SLJIT_ERR_ALLOC_FAILED		2
+/* Cannot allocate executable memory.
+   Only for sljit_generate_code() */
+#define SLJIT_ERR_EX_ALLOC_FAILED	3
+/* Return value for SLJIT_CONFIG_UNSUPPORTED placeholder architecture. */
+#define SLJIT_ERR_UNSUPPORTED		4
+/* An ivalid argument is passed to any SLJIT function. */
+#define SLJIT_ERR_BAD_ARGUMENT		5
+/* Dynamic code modification is not enabled. */
+#define SLJIT_ERR_DYN_CODE_MOD		6
+
+/* --------------------------------------------------------------------- */
+/*  Registers                                                            */
+/* --------------------------------------------------------------------- */
+
+/*
+  Scratch (R) registers: registers whose may not preserve their values
+  across function calls.
+
+  Saved (S) registers: registers whose preserve their values across
+  function calls.
+
+  The scratch and saved register sets are overlap. The last scratch register
+  is the first saved register, the one before the last is the second saved
+  register, and so on.
+
+  If an architecture provides two scratch and three saved registers,
+  its scratch and saved register sets are the following:
+
+     R0   |        |   R0 is always a scratch register
+     R1   |        |   R1 is always a scratch register
+    [R2]  |   S2   |   R2 and S2 represent the same physical register
+    [R3]  |   S1   |   R3 and S1 represent the same physical register
+    [R4]  |   S0   |   R4 and S0 represent the same physical register
+
+  Note: SLJIT_NUMBER_OF_SCRATCH_REGISTERS would be 2 and
+        SLJIT_NUMBER_OF_SAVED_REGISTERS would be 3 for this architecture.
+
+  Note: On all supported architectures SLJIT_NUMBER_OF_REGISTERS >= 12
+        and SLJIT_NUMBER_OF_SAVED_REGISTERS >= 6. However, 6 registers
+        are virtual on x86-32. See below.
+
+  The purpose of this definition is convenience: saved registers can
+  be used as extra scratch registers. For example four registers can
+  be specified as scratch registers and the fifth one as saved register
+  on the CPU above and any user code which requires four scratch
+  registers can run unmodified. The SLJIT compiler automatically saves
+  the content of the two extra scratch register on the stack. Scratch
+  registers can also be preserved by saving their value on the stack
+  but this needs to be done manually.
+
+  Note: To emphasize that registers assigned to R2-R4 are saved
+        registers, they are enclosed by square brackets.
+
+  Note: sljit_emit_enter and sljit_set_context defines whether a register
+        is S or R register. E.g: when 3 scratches and 1 saved is mapped
+        by sljit_emit_enter, the allowed register set will be: R0-R2 and
+        S0. Although S2 is mapped to the same position as R2, it does not
+        available in the current configuration. Furthermore the S1 register
+        is not available at all.
+*/
+
+/* When SLJIT_UNUSED is specified as the destination of sljit_emit_op1
+   or sljit_emit_op2 operations the result is discarded. Some status
+   flags must be set when the destination is SLJIT_UNUSED, because the
+   operation would have no effect otherwise. Other SLJIT operations do
+   not support SLJIT_UNUSED as a destination operand. */
+#define SLJIT_UNUSED		0
+
+/* Scratch registers. */
+#define SLJIT_R0	1
+#define SLJIT_R1	2
+#define SLJIT_R2	3
+/* Note: on x86-32, R3 - R6 (same as S3 - S6) are emulated (they
+   are allocated on the stack). These registers are called virtual
+   and cannot be used for memory addressing (cannot be part of
+   any SLJIT_MEM1, SLJIT_MEM2 construct). There is no such
+   limitation on other CPUs. See sljit_get_register_index(). */
+#define SLJIT_R3	4
+#define SLJIT_R4	5
+#define SLJIT_R5	6
+#define SLJIT_R6	7
+#define SLJIT_R7	8
+#define SLJIT_R8	9
+#define SLJIT_R9	10
+/* All R registers provided by the architecture can be accessed by SLJIT_R(i)
+   The i parameter must be >= 0 and < SLJIT_NUMBER_OF_REGISTERS. */
+#define SLJIT_R(i)	(1 + (i))
+
+/* Saved registers. */
+#define SLJIT_S0	(SLJIT_NUMBER_OF_REGISTERS)
+#define SLJIT_S1	(SLJIT_NUMBER_OF_REGISTERS - 1)
+#define SLJIT_S2	(SLJIT_NUMBER_OF_REGISTERS - 2)
+/* Note: on x86-32, S3 - S6 (same as R3 - R6) are emulated (they
+   are allocated on the stack). These registers are called virtual
+   and cannot be used for memory addressing (cannot be part of
+   any SLJIT_MEM1, SLJIT_MEM2 construct). There is no such
+   limitation on other CPUs. See sljit_get_register_index(). */
+#define SLJIT_S3	(SLJIT_NUMBER_OF_REGISTERS - 3)
+#define SLJIT_S4	(SLJIT_NUMBER_OF_REGISTERS - 4)
+#define SLJIT_S5	(SLJIT_NUMBER_OF_REGISTERS - 5)
+#define SLJIT_S6	(SLJIT_NUMBER_OF_REGISTERS - 6)
+#define SLJIT_S7	(SLJIT_NUMBER_OF_REGISTERS - 7)
+#define SLJIT_S8	(SLJIT_NUMBER_OF_REGISTERS - 8)
+#define SLJIT_S9	(SLJIT_NUMBER_OF_REGISTERS - 9)
+/* All S registers provided by the architecture can be accessed by SLJIT_S(i)
+   The i parameter must be >= 0 and < SLJIT_NUMBER_OF_SAVED_REGISTERS. */
+#define SLJIT_S(i)	(SLJIT_NUMBER_OF_REGISTERS - (i))
+
+/* Registers >= SLJIT_FIRST_SAVED_REG are saved registers. */
+#define SLJIT_FIRST_SAVED_REG (SLJIT_S0 - SLJIT_NUMBER_OF_SAVED_REGISTERS + 1)
+
+/* The SLJIT_SP provides direct access to the linear stack space allocated by
+   sljit_emit_enter. It can only be used in the following form: SLJIT_MEM1(SLJIT_SP).
+   The immediate offset is extended by the relative stack offset automatically.
+   The sljit_get_local_base can be used to obtain the absolute offset. */
+#define SLJIT_SP	(SLJIT_NUMBER_OF_REGISTERS + 1)
+
+/* Return with machine word. */
+
+#define SLJIT_RETURN_REG	SLJIT_R0
+
+/* --------------------------------------------------------------------- */
+/*  Floating point registers                                             */
+/* --------------------------------------------------------------------- */
+
+/* Each floating point register can store a 32 or a 64 bit precision
+   value. The FR and FS register sets are overlap in the same way as R
+   and S register sets. See above. */
+
+/* Note: SLJIT_UNUSED as destination is not valid for floating point
+   operations, since they cannot be used for setting flags. */
+
+/* Floating point scratch registers. */
+#define SLJIT_FR0	1
+#define SLJIT_FR1	2
+#define SLJIT_FR2	3
+#define SLJIT_FR3	4
+#define SLJIT_FR4	5
+#define SLJIT_FR5	6
+/* All FR registers provided by the architecture can be accessed by SLJIT_FR(i)
+   The i parameter must be >= 0 and < SLJIT_NUMBER_OF_FLOAT_REGISTERS. */
+#define SLJIT_FR(i)	(1 + (i))
+
+/* Floating point saved registers. */
+#define SLJIT_FS0	(SLJIT_NUMBER_OF_FLOAT_REGISTERS)
+#define SLJIT_FS1	(SLJIT_NUMBER_OF_FLOAT_REGISTERS - 1)
+#define SLJIT_FS2	(SLJIT_NUMBER_OF_FLOAT_REGISTERS - 2)
+#define SLJIT_FS3	(SLJIT_NUMBER_OF_FLOAT_REGISTERS - 3)
+#define SLJIT_FS4	(SLJIT_NUMBER_OF_FLOAT_REGISTERS - 4)
+#define SLJIT_FS5	(SLJIT_NUMBER_OF_FLOAT_REGISTERS - 5)
+/* All S registers provided by the architecture can be accessed by SLJIT_FS(i)
+   The i parameter must be >= 0 and < SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS. */
+#define SLJIT_FS(i)	(SLJIT_NUMBER_OF_FLOAT_REGISTERS - (i))
+
+/* Float registers >= SLJIT_FIRST_SAVED_FLOAT_REG are saved registers. */
+#define SLJIT_FIRST_SAVED_FLOAT_REG (SLJIT_FS0 - SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS + 1)
+
+/* --------------------------------------------------------------------- */
+/*  Argument type definitions                                            */
+/* --------------------------------------------------------------------- */
+
+/* Argument type definitions.
+   Used by SLJIT_[DEF_]ARGx and SLJIT_[DEF]_RET macros. */
+
+#define SLJIT_ARG_TYPE_VOID 0
+#define SLJIT_ARG_TYPE_SW 1
+#define SLJIT_ARG_TYPE_UW 2
+#define SLJIT_ARG_TYPE_S32 3
+#define SLJIT_ARG_TYPE_U32 4
+#define SLJIT_ARG_TYPE_F32 5
+#define SLJIT_ARG_TYPE_F64 6
+
+/* The following argument type definitions are used by sljit_emit_enter,
+   sljit_set_context, sljit_emit_call, and sljit_emit_icall functions.
+   The following return type definitions are used by sljit_emit_call
+   and sljit_emit_icall functions.
+
+   When a function is called, the first integer argument must be placed
+   in SLJIT_R0, the second in SLJIT_R1, and so on. Similarly the first
+   floating point argument must be placed in SLJIT_FR0, the second in
+   SLJIT_FR1, and so on.
+
+   Example function definition:
+     sljit_f32 SLJIT_FUNC example_c_callback(sljit_sw arg_a,
+         sljit_f64 arg_b, sljit_u32 arg_c, sljit_f32 arg_d);
+
+   Argument type definition:
+     SLJIT_DEF_RET(SLJIT_ARG_TYPE_F32)
+        | SLJIT_DEF_ARG1(SLJIT_ARG_TYPE_SW) | SLJIT_DEF_ARG2(SLJIT_ARG_TYPE_F64)
+        | SLJIT_DEF_ARG3(SLJIT_ARG_TYPE_U32) | SLJIT_DEF_ARG2(SLJIT_ARG_TYPE_F32)
+
+   Short form of argument type definition:
+     SLJIT_RET(F32) | SLJIT_ARG1(SW) | SLJIT_ARG2(F64)
+        | SLJIT_ARG3(S32) | SLJIT_ARG4(F32)
+
+   Argument passing:
+     arg_a must be placed in SLJIT_R0
+     arg_c must be placed in SLJIT_R1
+     arg_b must be placed in SLJIT_FR0
+     arg_d must be placed in SLJIT_FR1
+
+Note:
+   The SLJIT_ARG_TYPE_VOID type is only supported by
+   SLJIT_DEF_RET, and SLJIT_ARG_TYPE_VOID is also the
+   default value when SLJIT_DEF_RET is not specified. */
+#define SLJIT_DEF_SHIFT 4
+#define SLJIT_DEF_RET(type) (type)
+#define SLJIT_DEF_ARG1(type) ((type) << SLJIT_DEF_SHIFT)
+#define SLJIT_DEF_ARG2(type) ((type) << (2 * SLJIT_DEF_SHIFT))
+#define SLJIT_DEF_ARG3(type) ((type) << (3 * SLJIT_DEF_SHIFT))
+#define SLJIT_DEF_ARG4(type) ((type) << (4 * SLJIT_DEF_SHIFT))
+
+/* Short form of the macros above.
+
+   For example the following definition:
+   SLJIT_DEF_RET(SLJIT_ARG_TYPE_SW) | SLJIT_DEF_ARG1(SLJIT_ARG_TYPE_F32)
+
+   can be shortened to:
+   SLJIT_RET(SW) | SLJIT_ARG1(F32)
+
+Note:
+   The VOID type is only supported by SLJIT_RET, and
+   VOID is also the default value when SLJIT_RET is
+   not specified. */
+#define SLJIT_RET(type) SLJIT_DEF_RET(SLJIT_ARG_TYPE_ ## type)
+#define SLJIT_ARG1(type) SLJIT_DEF_ARG1(SLJIT_ARG_TYPE_ ## type)
+#define SLJIT_ARG2(type) SLJIT_DEF_ARG2(SLJIT_ARG_TYPE_ ## type)
+#define SLJIT_ARG3(type) SLJIT_DEF_ARG3(SLJIT_ARG_TYPE_ ## type)
+#define SLJIT_ARG4(type) SLJIT_DEF_ARG4(SLJIT_ARG_TYPE_ ## type)
+
+/* --------------------------------------------------------------------- */
+/*  Main structures and functions                                        */
+/* --------------------------------------------------------------------- */
+
+/*
+	The following structures are private, and can be changed in the
+	future. Keeping them here allows code inlining.
+*/
+
+struct sljit_memory_fragment {
+	struct sljit_memory_fragment *next;
+	sljit_uw used_size;
+	/* Must be aligned to sljit_sw. */
+	sljit_u8 memory[1];
+};
+
+struct sljit_label {
+	struct sljit_label *next;
+	sljit_uw addr;
+	/* The maximum size difference. */
+	sljit_uw size;
+};
+
+struct sljit_jump {
+	struct sljit_jump *next;
+	sljit_uw addr;
+	sljit_uw flags;
+	union {
+		sljit_uw target;
+		struct sljit_label *label;
+	} u;
+};
+
+struct sljit_put_label {
+	struct sljit_put_label *next;
+	struct sljit_label *label;
+	sljit_uw addr;
+	sljit_uw flags;
+};
+
+struct sljit_const {
+	struct sljit_const *next;
+	sljit_uw addr;
+};
+
+struct sljit_compiler {
+	sljit_s32 error;
+	sljit_s32 options;
+
+	struct sljit_label *labels;
+	struct sljit_jump *jumps;
+	struct sljit_put_label *put_labels;
+	struct sljit_const *consts;
+	struct sljit_label *last_label;
+	struct sljit_jump *last_jump;
+	struct sljit_const *last_const;
+	struct sljit_put_label *last_put_label;
+
+	void *allocator_data;
+	void *exec_allocator_data;
+	struct sljit_memory_fragment *buf;
+	struct sljit_memory_fragment *abuf;
+
+	/* Used scratch registers. */
+	sljit_s32 scratches;
+	/* Used saved registers. */
+	sljit_s32 saveds;
+	/* Used float scratch registers. */
+	sljit_s32 fscratches;
+	/* Used float saved registers. */
+	sljit_s32 fsaveds;
+	/* Local stack size. */
+	sljit_s32 local_size;
+	/* Code size. */
+	sljit_uw size;
+	/* Relative offset of the executable mapping from the writable mapping. */
+	sljit_uw executable_offset;
+	/* Executable size for statistical purposes. */
+	sljit_uw executable_size;
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+	sljit_s32 args;
+	sljit_s32 locals_offset;
+	sljit_s32 saveds_offset;
+	sljit_s32 stack_tmp_size;
+#endif
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	sljit_s32 mode32;
+#ifdef _WIN64
+	sljit_s32 locals_offset;
+#endif
+#endif
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+	/* Constant pool handling. */
+	sljit_uw *cpool;
+	sljit_u8 *cpool_unique;
+	sljit_uw cpool_diff;
+	sljit_uw cpool_fill;
+	/* Other members. */
+	/* Contains pointer, "ldr pc, [...]" pairs. */
+	sljit_uw patches;
+#endif
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+	/* Temporary fields. */
+	sljit_uw shift_imm;
+#endif
+
+#if (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
+	sljit_sw imm;
+#endif
+
+#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
+	sljit_s32 delay_slot;
+	sljit_s32 cache_arg;
+	sljit_sw cache_argw;
+#endif
+
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+	sljit_s32 delay_slot;
+	sljit_s32 cache_arg;
+	sljit_sw cache_argw;
+#endif
+
+#if (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX)
+	sljit_s32 cache_arg;
+	sljit_sw cache_argw;
+#endif
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	FILE* verbose;
+#endif
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
+		|| (defined SLJIT_DEBUG && SLJIT_DEBUG)
+	/* Flags specified by the last arithmetic instruction.
+	   It contains the type of the variable flag. */
+	sljit_s32 last_flags;
+	/* Local size passed to the functions. */
+	sljit_s32 logical_local_size;
+#endif
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
+		|| (defined SLJIT_DEBUG && SLJIT_DEBUG) \
+		|| (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+	/* Trust arguments when the API function is called. */
+	sljit_s32 skip_checks;
+#endif
+};
+
+/* --------------------------------------------------------------------- */
+/*  Main functions                                                       */
+/* --------------------------------------------------------------------- */
+
+/* Creates an sljit compiler. The allocator_data is required by some
+   custom memory managers. This pointer is passed to SLJIT_MALLOC
+   and SLJIT_FREE macros. Most allocators (including the default
+   one) ignores this value, and it is recommended to pass NULL
+   as a dummy value for allocator_data. The exec_allocator_data
+   has the same purpose but this one is passed to SLJIT_MALLOC_EXEC /
+   SLJIT_MALLOC_FREE functions.
+
+   Returns NULL if failed. */
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data, void *exec_allocator_data);
+
+/* Frees everything except the compiled machine code. */
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compiler);
+
+/* Returns the current error code. If an error is occurred, future sljit
+   calls which uses the same compiler argument returns early with the same
+   error code. Thus there is no need for checking the error after every
+   call, it is enough to do it before the code is compiled. Removing
+   these checks increases the performance of the compiling process. */
+static SLJIT_INLINE sljit_s32 sljit_get_compiler_error(struct sljit_compiler *compiler) { return compiler->error; }
+
+/* Sets the compiler error code to SLJIT_ERR_ALLOC_FAILED except
+   if an error was detected before. After the error code is set
+   the compiler behaves as if the allocation failure happened
+   during an sljit function call. This can greatly simplify error
+   checking, since only the compiler status needs to be checked
+   after the compilation. */
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compiler *compiler);
+
+/*
+   Allocate a small amount of memory. The size must be <= 64 bytes on 32 bit,
+   and <= 128 bytes on 64 bit architectures. The memory area is owned by the
+   compiler, and freed by sljit_free_compiler. The returned pointer is
+   sizeof(sljit_sw) aligned. Excellent for allocating small blocks during
+   the compiling, and no need to worry about freeing them. The size is
+   enough to contain at most 16 pointers. If the size is outside of the range,
+   the function will return with NULL. However, this return value does not
+   indicate that there is no more memory (does not set the current error code
+   of the compiler to out-of-memory status).
+*/
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_s32 size);
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+/* Passing NULL disables verbose. */
+SLJIT_API_FUNC_ATTRIBUTE void sljit_compiler_verbose(struct sljit_compiler *compiler, FILE* verbose);
+#endif
+
+/*
+   Create executable code from the sljit instruction stream. This is the final step
+   of the code generation so no more instructions can be added after this call.
+*/
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler);
+
+/* Free executable code. */
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code, void *exec_allocator_data);
+
+/*
+   When the protected executable allocator is used the JIT code is mapped
+   twice. The first mapping has read/write and the second mapping has read/exec
+   permissions. This function returns with the relative offset of the executable
+   mapping using the writable mapping as the base after the machine code is
+   successfully generated. The returned value is always 0 for the normal executable
+   allocator, since it uses only one mapping with read/write/exec permissions.
+   Dynamic code modifications requires this value.
+
+   Before a successful code generation, this function returns with 0.
+*/
+static SLJIT_INLINE sljit_sw sljit_get_executable_offset(struct sljit_compiler *compiler) { return compiler->executable_offset; }
+
+/*
+   The executable memory consumption of the generated code can be retrieved by
+   this function. The returned value can be used for statistical purposes.
+
+   Before a successful code generation, this function returns with 0.
+*/
+static SLJIT_INLINE sljit_uw sljit_get_generated_code_size(struct sljit_compiler *compiler) { return compiler->executable_size; }
+
+/* Returns with non-zero if the feature or limitation type passed as its
+   argument is present on the current CPU.
+
+   Some features (e.g. floating point operations) require hardware (CPU)
+   support while others (e.g. move with update) are emulated if not available.
+   However even if a feature is emulated, specialized code paths can be faster
+   than the emulation. Some limitations are emulated as well so their general
+   case is supported but it has extra performance costs. */
+
+/* [Not emulated] Floating-point support is available. */
+#define SLJIT_HAS_FPU			0
+/* [Limitation] Some registers are virtual registers. */
+#define SLJIT_HAS_VIRTUAL_REGISTERS	1
+/* [Emulated] Has zero register (setting a memory location to zero is efficient). */
+#define SLJIT_HAS_ZERO_REGISTER		2
+/* [Emulated] Count leading zero is supported. */
+#define SLJIT_HAS_CLZ			3
+/* [Emulated] Conditional move is supported. */
+#define SLJIT_HAS_CMOV			4
+/* [Emulated] Conditional move is supported. */
+#define SLJIT_HAS_PREFETCH		5
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+/* [Not emulated] SSE2 support is available on x86. */
+#define SLJIT_HAS_SSE2			100
+#endif
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type);
+
+/* Instruction generation. Returns with any error code. If there is no
+   error, they return with SLJIT_SUCCESS. */
+
+/*
+   The executable code is a function from the viewpoint of the C
+   language. The function calls must obey to the ABI (Application
+   Binary Interface) of the platform, which specify the purpose of
+   machine registers and stack handling among other things. The
+   sljit_emit_enter function emits the necessary instructions for
+   setting up a new context for the executable code and moves function
+   arguments to the saved registers. Furthermore the options argument
+   can be used to pass configuration options to the compiler. The
+   available options are listed before sljit_emit_enter.
+
+   The function argument list is the combination of SLJIT_ARGx
+   (SLJIT_DEF_ARG1) macros. Currently maximum 3 SW / UW
+   (SLJIT_ARG_TYPE_SW / LJIT_ARG_TYPE_UW) arguments are supported.
+   The first argument goes to SLJIT_S0, the second goes to SLJIT_S1
+   and so on. The register set used by the function must be declared
+   as well. The number of scratch and saved registers used by the
+   function must be passed to sljit_emit_enter. Only R registers
+   between R0 and "scratches" argument can be used later. E.g. if
+   "scratches" is set to 2, the scratch register set will be limited
+   to SLJIT_R0 and SLJIT_R1. The S registers and the floating point
+   registers ("fscratches" and "fsaveds") are specified in a similar
+   manner. The sljit_emit_enter is also capable of allocating a stack
+   space for local variables. The "local_size" argument contains the
+   size in bytes of this local area and its staring address is stored
+   in SLJIT_SP. The memory area between SLJIT_SP (inclusive) and
+   SLJIT_SP + local_size (exclusive) can be modified freely until
+   the function returns. The stack space is not initialized.
+
+   Note: the following conditions must met:
+         0 <= scratches <= SLJIT_NUMBER_OF_REGISTERS
+         0 <= saveds <= SLJIT_NUMBER_OF_REGISTERS
+         scratches + saveds <= SLJIT_NUMBER_OF_REGISTERS
+         0 <= fscratches <= SLJIT_NUMBER_OF_FLOAT_REGISTERS
+         0 <= fsaveds <= SLJIT_NUMBER_OF_FLOAT_REGISTERS
+         fscratches + fsaveds <= SLJIT_NUMBER_OF_FLOAT_REGISTERS
+
+   Note: every call of sljit_emit_enter and sljit_set_context
+         overwrites the previous context.
+*/
+
+/* The absolute address returned by sljit_get_local_base with
+offset 0 is aligned to sljit_f64. Otherwise it is aligned to sljit_sw. */
+#define SLJIT_F64_ALIGNMENT 0x00000001
+
+/* The local_size must be >= 0 and <= SLJIT_MAX_LOCAL_SIZE. */
+#define SLJIT_MAX_LOCAL_SIZE	65536
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size);
+
+/* The machine code has a context (which contains the local stack space size,
+   number of used registers, etc.) which initialized by sljit_emit_enter. Several
+   functions (like sljit_emit_return) requres this context to be able to generate
+   the appropriate code. However, some code fragments (like inline cache) may have
+   no normal entry point so their context is unknown for the compiler. Their context
+   can be provided to the compiler by the sljit_set_context function.
+
+   Note: every call of sljit_emit_enter and sljit_set_context overwrites
+         the previous context. */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size);
+
+/* Return from machine code.  The op argument can be SLJIT_UNUSED which means the
+   function does not return with anything or any opcode between SLJIT_MOV and
+   SLJIT_MOV_P (see sljit_emit_op1). As for src and srcw they must be 0 if op
+   is SLJIT_UNUSED, otherwise see below the description about source and
+   destination arguments. */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src, sljit_sw srcw);
+
+/* Generating entry and exit points for fast call functions (see SLJIT_FAST_CALL).
+   Both sljit_emit_fast_enter and SLJIT_FAST_RETURN operations preserve the
+   values of all registers and stack frame. The return address is stored in the
+   dst argument of sljit_emit_fast_enter, and this return address can be passed
+   to SLJIT_FAST_RETURN to continue the execution after the fast call.
+
+   Fast calls are cheap operations (usually only a single call instruction is
+   emitted) but they do not preserve any registers. However the callee function
+   can freely use / update any registers and stack values which can be
+   efficiently exploited by various optimizations. Registers can be saved
+   manually by the callee function if needed.
+
+   Although returning to different address by SLJIT_FAST_RETURN is possible,
+   this address usually cannot be predicted by the return address predictor of
+   modern CPUs which may reduce performance. Furthermore certain security
+   enhancement technologies such as Intel Control-flow Enforcement Technology
+   (CET) may disallow returning to a different address.
+
+   Flags: - (does not modify flags). */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw);
+
+/*
+   Source and destination operands for arithmetical instructions
+    imm              - a simple immediate value (cannot be used as a destination)
+    reg              - any of the registers (immediate argument must be 0)
+    [imm]            - absolute immediate memory address
+    [reg+imm]        - indirect memory address
+    [reg+(reg<<imm)] - indirect indexed memory address (shift must be between 0 and 3)
+                       useful for (byte, half, int, sljit_sw) array access
+                       (fully supported by both x86 and ARM architectures, and cheap operation on others)
+*/
+
+/*
+   IMPORTANT NOTE: memory access MUST be naturally aligned unless
+                   SLJIT_UNALIGNED macro is defined and its value is 1.
+
+     length | alignment
+   ---------+-----------
+     byte   | 1 byte (any physical_address is accepted)
+     half   | 2 byte (physical_address & 0x1 == 0)
+     int    | 4 byte (physical_address & 0x3 == 0)
+     word   | 4 byte if SLJIT_32BIT_ARCHITECTURE is defined and its value is 1
+            | 8 byte if SLJIT_64BIT_ARCHITECTURE is defined and its value is 1
+    pointer | size of sljit_p type (4 byte on 32 bit machines, 4 or 8 byte
+            | on 64 bit machines)
+
+   Note:   Different architectures have different addressing limitations.
+           A single instruction is enough for the following addressing
+           modes. Other adrressing modes are emulated by instruction
+           sequences. This information could help to improve those code
+           generators which focuses only a few architectures.
+
+   x86:    [reg+imm], -2^32+1 <= imm <= 2^32-1 (full address space on x86-32)
+           [reg+(reg<<imm)] is supported
+           [imm], -2^32+1 <= imm <= 2^32-1 is supported
+           Write-back is not supported
+   arm:    [reg+imm], -4095 <= imm <= 4095 or -255 <= imm <= 255 for signed
+                bytes, any halfs or floating point values)
+           [reg+(reg<<imm)] is supported
+           Write-back is supported
+   arm-t2: [reg+imm], -255 <= imm <= 4095
+           [reg+(reg<<imm)] is supported
+           Write back is supported only for [reg+imm], where -255 <= imm <= 255
+   arm64:  [reg+imm], -256 <= imm <= 255, 0 <= aligned imm <= 4095 * alignment
+           [reg+(reg<<imm)] is supported
+           Write back is supported only for [reg+imm], where -256 <= imm <= 255
+   ppc:    [reg+imm], -65536 <= imm <= 65535. 64 bit loads/stores and 32 bit
+                signed load on 64 bit requires immediates divisible by 4.
+                [reg+imm] is not supported for signed 8 bit values.
+           [reg+reg] is supported
+           Write-back is supported except for one instruction: 32 bit signed
+                load with [reg+imm] addressing mode on 64 bit.
+   mips:   [reg+imm], -65536 <= imm <= 65535
+   sparc:  [reg+imm], -4096 <= imm <= 4095
+           [reg+reg] is supported
+*/
+
+/* Macros for specifying operand types. */
+#define SLJIT_MEM		0x80
+#define SLJIT_MEM0()		(SLJIT_MEM)
+#define SLJIT_MEM1(r1)		(SLJIT_MEM | (r1))
+#define SLJIT_MEM2(r1, r2)	(SLJIT_MEM | (r1) | ((r2) << 8))
+#define SLJIT_IMM		0x40
+
+/* Set 32 bit operation mode (I) on 64 bit CPUs. This option is ignored on
+   32 bit CPUs. When this option is set for an arithmetic operation, only
+   the lower 32 bit of the input registers are used, and the CPU status
+   flags are set according to the 32 bit result. Although the higher 32 bit
+   of the input and the result registers are not defined by SLJIT, it might
+   be defined by the CPU architecture (e.g. MIPS). To satisfy these CPU
+   requirements all source registers must be the result of those operations
+   where this option was also set. Memory loads read 32 bit values rather
+   than 64 bit ones. In other words 32 bit and 64 bit operations cannot
+   be mixed. The only exception is SLJIT_MOV32 and SLJIT_MOVU32 whose source
+   register can hold any 32 or 64 bit value, and it is converted to a 32 bit
+   compatible format first. This conversion is free (no instructions are
+   emitted) on most CPUs. A 32 bit value can also be converted to a 64 bit
+   value by SLJIT_MOV_S32 (sign extension) or SLJIT_MOV_U32 (zero extension).
+
+   Note: memory addressing always uses 64 bit values on 64 bit systems so
+         the result of a 32 bit operation must not be used with SLJIT_MEMx
+         macros.
+
+   This option is part of the instruction name, so there is no need to
+   manually set it. E.g:
+
+     SLJIT_ADD32 == (SLJIT_ADD | SLJIT_I32_OP) */
+#define SLJIT_I32_OP		0x100
+
+/* Set F32 (single) precision mode for floating-point computation. This
+   option is similar to SLJIT_I32_OP, it just applies to floating point
+   registers. When this option is passed, the CPU performs 32 bit floating
+   point operations, rather than 64 bit one. Similar to SLJIT_I32_OP, all
+   register arguments must be the result of those operations where this
+   option was also set.
+
+   This option is part of the instruction name, so there is no need to
+   manually set it. E.g:
+
+     SLJIT_MOV_F32 = (SLJIT_MOV_F64 | SLJIT_F32_OP)
+ */
+#define SLJIT_F32_OP		SLJIT_I32_OP
+
+/* Many CPUs (x86, ARM, PPC) have status flags which can be set according
+   to the result of an operation. Other CPUs (MIPS) do not have status
+   flags, and results must be stored in registers. To cover both architecture
+   types efficiently only two flags are defined by SLJIT:
+
+    * Zero (equal) flag: it is set if the result is zero
+    * Variable flag: its value is defined by the last arithmetic operation
+
+   SLJIT instructions can set any or both of these flags. The value of
+   these flags is undefined if the instruction does not specify their value.
+   The description of each instruction contains the list of allowed flag
+   types.
+
+   Example: SLJIT_ADD can set the Z, OVERFLOW, CARRY flags hence
+
+     sljit_op2(..., SLJIT_ADD, ...)
+       Both the zero and variable flags are undefined so they can
+       have any value after the operation is completed.
+
+     sljit_op2(..., SLJIT_ADD | SLJIT_SET_Z, ...)
+       Sets the zero flag if the result is zero, clears it otherwise.
+       The variable flag is undefined.
+
+     sljit_op2(..., SLJIT_ADD | SLJIT_SET_OVERFLOW, ...)
+       Sets the variable flag if an integer overflow occurs, clears
+       it otherwise. The zero flag is undefined.
+
+     sljit_op2(..., SLJIT_ADD | SLJIT_SET_Z | SLJIT_SET_CARRY, ...)
+       Sets the zero flag if the result is zero, clears it otherwise.
+       Sets the variable flag if unsigned overflow (carry) occurs,
+       clears it otherwise.
+
+   If an instruction (e.g. SLJIT_MOV) does not modify flags the flags are
+   unchanged.
+
+   Using these flags can reduce the number of emitted instructions. E.g. a
+   fast loop can be implemented by decreasing a counter register and set the
+   zero flag to jump back if the counter register has not reached zero.
+
+   Motivation: although CPUs can set a large number of flags, usually their
+   values are ignored or only one of them is used. Emulating a large number
+   of flags on systems without flag register is complicated so SLJIT
+   instructions must specify the flag they want to use and only that flag
+   will be emulated. The last arithmetic instruction can be repeated if
+   multiple flags need to be checked.
+*/
+
+/* Set Zero status flag. */
+#define SLJIT_SET_Z			0x0200
+/* Set the variable status flag if condition is true.
+   See comparison types. */
+#define SLJIT_SET(condition)			((condition) << 10)
+
+/* Notes:
+     - you cannot postpone conditional jump instructions except if noted that
+       the instruction does not set flags (See: SLJIT_KEEP_FLAGS).
+     - flag combinations: '|' means 'logical or'. */
+
+/* Starting index of opcodes for sljit_emit_op0. */
+#define SLJIT_OP0_BASE			0
+
+/* Flags: - (does not modify flags)
+   Note: breakpoint instruction is not supported by all architectures (e.g. ppc)
+         It falls back to SLJIT_NOP in those cases. */
+#define SLJIT_BREAKPOINT		(SLJIT_OP0_BASE + 0)
+/* Flags: - (does not modify flags)
+   Note: may or may not cause an extra cycle wait
+         it can even decrease the runtime in a few cases. */
+#define SLJIT_NOP			(SLJIT_OP0_BASE + 1)
+/* Flags: - (may destroy flags)
+   Unsigned multiplication of SLJIT_R0 and SLJIT_R1.
+   Result is placed into SLJIT_R1:SLJIT_R0 (high:low) word */
+#define SLJIT_LMUL_UW			(SLJIT_OP0_BASE + 2)
+/* Flags: - (may destroy flags)
+   Signed multiplication of SLJIT_R0 and SLJIT_R1.
+   Result is placed into SLJIT_R1:SLJIT_R0 (high:low) word */
+#define SLJIT_LMUL_SW			(SLJIT_OP0_BASE + 3)
+/* Flags: - (may destroy flags)
+   Unsigned divide of the value in SLJIT_R0 by the value in SLJIT_R1.
+   The result is placed into SLJIT_R0 and the remainder into SLJIT_R1.
+   Note: if SLJIT_R1 is 0, the behaviour is undefined. */
+#define SLJIT_DIVMOD_UW			(SLJIT_OP0_BASE + 4)
+#define SLJIT_DIVMOD_U32		(SLJIT_DIVMOD_UW | SLJIT_I32_OP)
+/* Flags: - (may destroy flags)
+   Signed divide of the value in SLJIT_R0 by the value in SLJIT_R1.
+   The result is placed into SLJIT_R0 and the remainder into SLJIT_R1.
+   Note: if SLJIT_R1 is 0, the behaviour is undefined.
+   Note: if SLJIT_R1 is -1 and SLJIT_R0 is integer min (0x800..00),
+         the behaviour is undefined. */
+#define SLJIT_DIVMOD_SW			(SLJIT_OP0_BASE + 5)
+#define SLJIT_DIVMOD_S32		(SLJIT_DIVMOD_SW | SLJIT_I32_OP)
+/* Flags: - (may destroy flags)
+   Unsigned divide of the value in SLJIT_R0 by the value in SLJIT_R1.
+   The result is placed into SLJIT_R0. SLJIT_R1 preserves its value.
+   Note: if SLJIT_R1 is 0, the behaviour is undefined. */
+#define SLJIT_DIV_UW			(SLJIT_OP0_BASE + 6)
+#define SLJIT_DIV_U32			(SLJIT_DIV_UW | SLJIT_I32_OP)
+/* Flags: - (may destroy flags)
+   Signed divide of the value in SLJIT_R0 by the value in SLJIT_R1.
+   The result is placed into SLJIT_R0. SLJIT_R1 preserves its value.
+   Note: if SLJIT_R1 is 0, the behaviour is undefined.
+   Note: if SLJIT_R1 is -1 and SLJIT_R0 is integer min (0x800..00),
+         the behaviour is undefined. */
+#define SLJIT_DIV_SW			(SLJIT_OP0_BASE + 7)
+#define SLJIT_DIV_S32			(SLJIT_DIV_SW | SLJIT_I32_OP)
+/* Flags: - (does not modify flags)
+   ENDBR32 instruction for x86-32 and ENDBR64 instruction for x86-64
+   when Intel Control-flow Enforcement Technology (CET) is enabled.
+   No instruction for other architectures.  */
+#define SLJIT_ENDBR			(SLJIT_OP0_BASE + 8)
+/* Flags: - (may destroy flags)
+   Skip stack frames before return.  */
+#define SLJIT_SKIP_FRAMES_BEFORE_RETURN	(SLJIT_OP0_BASE + 9)
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op);
+
+/* Starting index of opcodes for sljit_emit_op1. */
+#define SLJIT_OP1_BASE			32
+
+/* The MOV instruction transfers data from source to destination.
+
+   MOV instruction suffixes:
+
+   U8  - unsigned 8 bit data transfer
+   S8  - signed 8 bit data transfer
+   U16 - unsigned 16 bit data transfer
+   S16 - signed 16 bit data transfer
+   U32 - unsigned int (32 bit) data transfer
+   S32 - signed int (32 bit) data transfer
+   P   - pointer (sljit_p) data transfer
+*/
+
+/* Flags: - (does not modify flags) */
+#define SLJIT_MOV			(SLJIT_OP1_BASE + 0)
+/* Flags: - (does not modify flags) */
+#define SLJIT_MOV_U8			(SLJIT_OP1_BASE + 1)
+#define SLJIT_MOV32_U8			(SLJIT_MOV_U8 | SLJIT_I32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_MOV_S8			(SLJIT_OP1_BASE + 2)
+#define SLJIT_MOV32_S8			(SLJIT_MOV_S8 | SLJIT_I32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_MOV_U16			(SLJIT_OP1_BASE + 3)
+#define SLJIT_MOV32_U16			(SLJIT_MOV_U16 | SLJIT_I32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_MOV_S16			(SLJIT_OP1_BASE + 4)
+#define SLJIT_MOV32_S16			(SLJIT_MOV_S16 | SLJIT_I32_OP)
+/* Flags: - (does not modify flags)
+   Note: no SLJIT_MOV32_U32 form, since it is the same as SLJIT_MOV32 */
+#define SLJIT_MOV_U32			(SLJIT_OP1_BASE + 5)
+/* Flags: - (does not modify flags)
+   Note: no SLJIT_MOV32_S32 form, since it is the same as SLJIT_MOV32 */
+#define SLJIT_MOV_S32			(SLJIT_OP1_BASE + 6)
+/* Flags: - (does not modify flags) */
+#define SLJIT_MOV32			(SLJIT_MOV_S32 | SLJIT_I32_OP)
+/* Flags: - (does not modify flags)
+   Note: load a pointer sized data, useful on x32 (a 32 bit mode on x86-64
+         where all x64 features are available, e.g. 16 register) or similar
+         compiling modes */
+#define SLJIT_MOV_P			(SLJIT_OP1_BASE + 7)
+/* Flags: Z
+   Note: immediate source argument is not supported */
+#define SLJIT_NOT			(SLJIT_OP1_BASE + 8)
+#define SLJIT_NOT32			(SLJIT_NOT | SLJIT_I32_OP)
+/* Flags: Z | OVERFLOW
+   Note: immediate source argument is not supported */
+#define SLJIT_NEG			(SLJIT_OP1_BASE + 9)
+#define SLJIT_NEG32			(SLJIT_NEG | SLJIT_I32_OP)
+/* Count leading zeroes
+   Flags: - (may destroy flags)
+   Note: immediate source argument is not supported */
+#define SLJIT_CLZ			(SLJIT_OP1_BASE + 10)
+#define SLJIT_CLZ32			(SLJIT_CLZ | SLJIT_I32_OP)
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw);
+
+/* Starting index of opcodes for sljit_emit_op2. */
+#define SLJIT_OP2_BASE			96
+
+/* Flags: Z | OVERFLOW | CARRY */
+#define SLJIT_ADD			(SLJIT_OP2_BASE + 0)
+#define SLJIT_ADD32			(SLJIT_ADD | SLJIT_I32_OP)
+/* Flags: CARRY */
+#define SLJIT_ADDC			(SLJIT_OP2_BASE + 1)
+#define SLJIT_ADDC32			(SLJIT_ADDC | SLJIT_I32_OP)
+/* Flags: Z | LESS | GREATER_EQUAL | GREATER | LESS_EQUAL
+          SIG_LESS | SIG_GREATER_EQUAL | SIG_GREATER
+          SIG_LESS_EQUAL | CARRY */
+#define SLJIT_SUB			(SLJIT_OP2_BASE + 2)
+#define SLJIT_SUB32			(SLJIT_SUB | SLJIT_I32_OP)
+/* Flags: CARRY */
+#define SLJIT_SUBC			(SLJIT_OP2_BASE + 3)
+#define SLJIT_SUBC32			(SLJIT_SUBC | SLJIT_I32_OP)
+/* Note: integer mul
+   Flags: MUL_OVERFLOW */
+#define SLJIT_MUL			(SLJIT_OP2_BASE + 4)
+#define SLJIT_MUL32			(SLJIT_MUL | SLJIT_I32_OP)
+/* Flags: Z */
+#define SLJIT_AND			(SLJIT_OP2_BASE + 5)
+#define SLJIT_AND32			(SLJIT_AND | SLJIT_I32_OP)
+/* Flags: Z */
+#define SLJIT_OR			(SLJIT_OP2_BASE + 6)
+#define SLJIT_OR32			(SLJIT_OR | SLJIT_I32_OP)
+/* Flags: Z */
+#define SLJIT_XOR			(SLJIT_OP2_BASE + 7)
+#define SLJIT_XOR32			(SLJIT_XOR | SLJIT_I32_OP)
+/* Flags: Z
+   Let bit_length be the length of the shift operation: 32 or 64.
+   If src2 is immediate, src2w is masked by (bit_length - 1).
+   Otherwise, if the content of src2 is outside the range from 0
+   to bit_length - 1, the result is undefined. */
+#define SLJIT_SHL			(SLJIT_OP2_BASE + 8)
+#define SLJIT_SHL32			(SLJIT_SHL | SLJIT_I32_OP)
+/* Flags: Z
+   Let bit_length be the length of the shift operation: 32 or 64.
+   If src2 is immediate, src2w is masked by (bit_length - 1).
+   Otherwise, if the content of src2 is outside the range from 0
+   to bit_length - 1, the result is undefined. */
+#define SLJIT_LSHR			(SLJIT_OP2_BASE + 9)
+#define SLJIT_LSHR32			(SLJIT_LSHR | SLJIT_I32_OP)
+/* Flags: Z
+   Let bit_length be the length of the shift operation: 32 or 64.
+   If src2 is immediate, src2w is masked by (bit_length - 1).
+   Otherwise, if the content of src2 is outside the range from 0
+   to bit_length - 1, the result is undefined. */
+#define SLJIT_ASHR			(SLJIT_OP2_BASE + 10)
+#define SLJIT_ASHR32			(SLJIT_ASHR | SLJIT_I32_OP)
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w);
+
+/* Starting index of opcodes for sljit_emit_op2. */
+#define SLJIT_OP_SRC_BASE		128
+
+/* Note: src cannot be an immedate value
+   Flags: - (does not modify flags) */
+#define SLJIT_FAST_RETURN		(SLJIT_OP_SRC_BASE + 0)
+/* Skip stack frames before fast return.
+   Note: src cannot be an immedate value
+   Flags: may destroy flags. */
+#define SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN	(SLJIT_OP_SRC_BASE + 1)
+/* Prefetch value into the level 1 data cache
+   Note: if the target CPU does not support data prefetch,
+         no instructions are emitted.
+   Note: this instruction never fails, even if the memory address is invalid.
+   Flags: - (does not modify flags) */
+#define SLJIT_PREFETCH_L1		(SLJIT_OP_SRC_BASE + 2)
+/* Prefetch value into the level 2 data cache
+   Note: same as SLJIT_PREFETCH_L1 if the target CPU
+         does not support this instruction form.
+   Note: this instruction never fails, even if the memory address is invalid.
+   Flags: - (does not modify flags) */
+#define SLJIT_PREFETCH_L2		(SLJIT_OP_SRC_BASE + 3)
+/* Prefetch value into the level 3 data cache
+   Note: same as SLJIT_PREFETCH_L2 if the target CPU
+         does not support this instruction form.
+   Note: this instruction never fails, even if the memory address is invalid.
+   Flags: - (does not modify flags) */
+#define SLJIT_PREFETCH_L3		(SLJIT_OP_SRC_BASE + 4)
+/* Prefetch a value which is only used once (and can be discarded afterwards)
+   Note: same as SLJIT_PREFETCH_L1 if the target CPU
+         does not support this instruction form.
+   Note: this instruction never fails, even if the memory address is invalid.
+   Flags: - (does not modify flags) */
+#define SLJIT_PREFETCH_ONCE		(SLJIT_OP_SRC_BASE + 5)
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src, sljit_sw srcw);
+
+/* Starting index of opcodes for sljit_emit_fop1. */
+#define SLJIT_FOP1_BASE			160
+
+/* Flags: - (does not modify flags) */
+#define SLJIT_MOV_F64			(SLJIT_FOP1_BASE + 0)
+#define SLJIT_MOV_F32			(SLJIT_MOV_F64 | SLJIT_F32_OP)
+/* Convert opcodes: CONV[DST_TYPE].FROM[SRC_TYPE]
+   SRC/DST TYPE can be: D - double, S - single, W - signed word, I - signed int
+   Rounding mode when the destination is W or I: round towards zero. */
+/* Flags: - (does not modify flags) */
+#define SLJIT_CONV_F64_FROM_F32		(SLJIT_FOP1_BASE + 1)
+#define SLJIT_CONV_F32_FROM_F64		(SLJIT_CONV_F64_FROM_F32 | SLJIT_F32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_CONV_SW_FROM_F64		(SLJIT_FOP1_BASE + 2)
+#define SLJIT_CONV_SW_FROM_F32		(SLJIT_CONV_SW_FROM_F64 | SLJIT_F32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_CONV_S32_FROM_F64		(SLJIT_FOP1_BASE + 3)
+#define SLJIT_CONV_S32_FROM_F32		(SLJIT_CONV_S32_FROM_F64 | SLJIT_F32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_CONV_F64_FROM_SW		(SLJIT_FOP1_BASE + 4)
+#define SLJIT_CONV_F32_FROM_SW		(SLJIT_CONV_F64_FROM_SW | SLJIT_F32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_CONV_F64_FROM_S32		(SLJIT_FOP1_BASE + 5)
+#define SLJIT_CONV_F32_FROM_S32		(SLJIT_CONV_F64_FROM_S32 | SLJIT_F32_OP)
+/* Note: dst is the left and src is the right operand for SLJIT_CMPD.
+   Flags: EQUAL_F | LESS_F | GREATER_EQUAL_F | GREATER_F | LESS_EQUAL_F */
+#define SLJIT_CMP_F64			(SLJIT_FOP1_BASE + 6)
+#define SLJIT_CMP_F32			(SLJIT_CMP_F64 | SLJIT_F32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_NEG_F64			(SLJIT_FOP1_BASE + 7)
+#define SLJIT_NEG_F32			(SLJIT_NEG_F64 | SLJIT_F32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_ABS_F64			(SLJIT_FOP1_BASE + 8)
+#define SLJIT_ABS_F32			(SLJIT_ABS_F64 | SLJIT_F32_OP)
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw);
+
+/* Starting index of opcodes for sljit_emit_fop2. */
+#define SLJIT_FOP2_BASE			192
+
+/* Flags: - (does not modify flags) */
+#define SLJIT_ADD_F64			(SLJIT_FOP2_BASE + 0)
+#define SLJIT_ADD_F32			(SLJIT_ADD_F64 | SLJIT_F32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_SUB_F64			(SLJIT_FOP2_BASE + 1)
+#define SLJIT_SUB_F32			(SLJIT_SUB_F64 | SLJIT_F32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_MUL_F64			(SLJIT_FOP2_BASE + 2)
+#define SLJIT_MUL_F32			(SLJIT_MUL_F64 | SLJIT_F32_OP)
+/* Flags: - (does not modify flags) */
+#define SLJIT_DIV_F64			(SLJIT_FOP2_BASE + 3)
+#define SLJIT_DIV_F32			(SLJIT_DIV_F64 | SLJIT_F32_OP)
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w);
+
+/* Label and jump instructions. */
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler);
+
+/* Invert (negate) conditional type: xor (^) with 0x1 */
+
+/* Integer comparison types. */
+#define SLJIT_EQUAL			0
+#define SLJIT_EQUAL32			(SLJIT_EQUAL | SLJIT_I32_OP)
+#define SLJIT_ZERO			0
+#define SLJIT_ZERO32			(SLJIT_ZERO | SLJIT_I32_OP)
+#define SLJIT_NOT_EQUAL			1
+#define SLJIT_NOT_EQUAL32		(SLJIT_NOT_EQUAL | SLJIT_I32_OP)
+#define SLJIT_NOT_ZERO			1
+#define SLJIT_NOT_ZERO32		(SLJIT_NOT_ZERO | SLJIT_I32_OP)
+
+#define SLJIT_LESS			2
+#define SLJIT_LESS32			(SLJIT_LESS | SLJIT_I32_OP)
+#define SLJIT_SET_LESS			SLJIT_SET(SLJIT_LESS)
+#define SLJIT_GREATER_EQUAL		3
+#define SLJIT_GREATER_EQUAL32		(SLJIT_GREATER_EQUAL | SLJIT_I32_OP)
+#define SLJIT_SET_GREATER_EQUAL		SLJIT_SET(SLJIT_GREATER_EQUAL)
+#define SLJIT_GREATER			4
+#define SLJIT_GREATER32			(SLJIT_GREATER | SLJIT_I32_OP)
+#define SLJIT_SET_GREATER		SLJIT_SET(SLJIT_GREATER)
+#define SLJIT_LESS_EQUAL		5
+#define SLJIT_LESS_EQUAL32		(SLJIT_LESS_EQUAL | SLJIT_I32_OP)
+#define SLJIT_SET_LESS_EQUAL		SLJIT_SET(SLJIT_LESS_EQUAL)
+#define SLJIT_SIG_LESS			6
+#define SLJIT_SIG_LESS32		(SLJIT_SIG_LESS | SLJIT_I32_OP)
+#define SLJIT_SET_SIG_LESS		SLJIT_SET(SLJIT_SIG_LESS)
+#define SLJIT_SIG_GREATER_EQUAL		7
+#define SLJIT_SIG_GREATER_EQUAL32	(SLJIT_SIG_GREATER_EQUAL | SLJIT_I32_OP)
+#define SLJIT_SET_SIG_GREATER_EQUAL	SLJIT_SET(SLJIT_SIG_GREATER_EQUAL)
+#define SLJIT_SIG_GREATER		8
+#define SLJIT_SIG_GREATER32		(SLJIT_SIG_GREATER | SLJIT_I32_OP)
+#define SLJIT_SET_SIG_GREATER		SLJIT_SET(SLJIT_SIG_GREATER)
+#define SLJIT_SIG_LESS_EQUAL		9
+#define SLJIT_SIG_LESS_EQUAL32		(SLJIT_SIG_LESS_EQUAL | SLJIT_I32_OP)
+#define SLJIT_SET_SIG_LESS_EQUAL	SLJIT_SET(SLJIT_SIG_LESS_EQUAL)
+
+#define SLJIT_OVERFLOW			10
+#define SLJIT_OVERFLOW32		(SLJIT_OVERFLOW | SLJIT_I32_OP)
+#define SLJIT_SET_OVERFLOW		SLJIT_SET(SLJIT_OVERFLOW)
+#define SLJIT_NOT_OVERFLOW		11
+#define SLJIT_NOT_OVERFLOW32		(SLJIT_NOT_OVERFLOW | SLJIT_I32_OP)
+
+#define SLJIT_MUL_OVERFLOW		12
+#define SLJIT_MUL_OVERFLOW32		(SLJIT_MUL_OVERFLOW | SLJIT_I32_OP)
+#define SLJIT_SET_MUL_OVERFLOW		SLJIT_SET(SLJIT_MUL_OVERFLOW)
+#define SLJIT_MUL_NOT_OVERFLOW		13
+#define SLJIT_MUL_NOT_OVERFLOW32	(SLJIT_MUL_NOT_OVERFLOW | SLJIT_I32_OP)
+
+/* There is no SLJIT_CARRY or SLJIT_NOT_CARRY. */
+#define SLJIT_SET_CARRY			SLJIT_SET(14)
+
+/* Floating point comparison types. */
+#define SLJIT_EQUAL_F64			16
+#define SLJIT_EQUAL_F32			(SLJIT_EQUAL_F64 | SLJIT_F32_OP)
+#define SLJIT_SET_EQUAL_F		SLJIT_SET(SLJIT_EQUAL_F64)
+#define SLJIT_NOT_EQUAL_F64		17
+#define SLJIT_NOT_EQUAL_F32		(SLJIT_NOT_EQUAL_F64 | SLJIT_F32_OP)
+#define SLJIT_SET_NOT_EQUAL_F		SLJIT_SET(SLJIT_NOT_EQUAL_F64)
+#define SLJIT_LESS_F64			18
+#define SLJIT_LESS_F32			(SLJIT_LESS_F64 | SLJIT_F32_OP)
+#define SLJIT_SET_LESS_F		SLJIT_SET(SLJIT_LESS_F64)
+#define SLJIT_GREATER_EQUAL_F64		19
+#define SLJIT_GREATER_EQUAL_F32		(SLJIT_GREATER_EQUAL_F64 | SLJIT_F32_OP)
+#define SLJIT_SET_GREATER_EQUAL_F	SLJIT_SET(SLJIT_GREATER_EQUAL_F64)
+#define SLJIT_GREATER_F64		20
+#define SLJIT_GREATER_F32		(SLJIT_GREATER_F64 | SLJIT_F32_OP)
+#define SLJIT_SET_GREATER_F		SLJIT_SET(SLJIT_GREATER_F64)
+#define SLJIT_LESS_EQUAL_F64		21
+#define SLJIT_LESS_EQUAL_F32		(SLJIT_LESS_EQUAL_F64 | SLJIT_F32_OP)
+#define SLJIT_SET_LESS_EQUAL_F		SLJIT_SET(SLJIT_LESS_EQUAL_F64)
+#define SLJIT_UNORDERED_F64		22
+#define SLJIT_UNORDERED_F32		(SLJIT_UNORDERED_F64 | SLJIT_F32_OP)
+#define SLJIT_SET_UNORDERED_F		SLJIT_SET(SLJIT_UNORDERED_F64)
+#define SLJIT_ORDERED_F64		23
+#define SLJIT_ORDERED_F32		(SLJIT_ORDERED_F64 | SLJIT_F32_OP)
+#define SLJIT_SET_ORDERED_F		SLJIT_SET(SLJIT_ORDERED_F64)
+
+/* Unconditional jump types. */
+#define SLJIT_JUMP			24
+	/* Fast calling method. See sljit_emit_fast_enter / SLJIT_FAST_RETURN. */
+#define SLJIT_FAST_CALL			25
+	/* Called function must be declared with the SLJIT_FUNC attribute. */
+#define SLJIT_CALL			26
+	/* Called function must be declared with cdecl attribute.
+	   This is the default attribute for C functions. */
+#define SLJIT_CALL_CDECL		27
+
+/* The target can be changed during runtime (see: sljit_set_jump_addr). */
+#define SLJIT_REWRITABLE_JUMP		0x1000
+
+/* Emit a jump instruction. The destination is not set, only the type of the jump.
+    type must be between SLJIT_EQUAL and SLJIT_FAST_CALL
+    type can be combined (or'ed) with SLJIT_REWRITABLE_JUMP
+
+   Flags: does not modify flags. */
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type);
+
+/* Emit a C compiler (ABI) compatible function call.
+    type must be SLJIT_CALL or SLJIT_CALL_CDECL
+    type can be combined (or'ed) with SLJIT_REWRITABLE_JUMP
+    arg_types is the combination of SLJIT_RET / SLJIT_ARGx (SLJIT_DEF_RET / SLJIT_DEF_ARGx) macros
+
+   Flags: destroy all flags. */
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 arg_types);
+
+/* Basic arithmetic comparison. In most architectures it is implemented as
+   an SLJIT_SUB operation (with SLJIT_UNUSED destination and setting
+   appropriate flags) followed by a sljit_emit_jump. However some
+   architectures (i.e: ARM64 or MIPS) may employ special optimizations here.
+   It is suggested to use this comparison form when appropriate.
+    type must be between SLJIT_EQUAL and SLJIT_I_SIG_LESS_EQUAL
+    type can be combined (or'ed) with SLJIT_REWRITABLE_JUMP
+
+   Flags: may destroy flags. */
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w);
+
+/* Basic floating point comparison. In most architectures it is implemented as
+   an SLJIT_FCMP operation (setting appropriate flags) followed by a
+   sljit_emit_jump. However some architectures (i.e: MIPS) may employ
+   special optimizations here. It is suggested to use this comparison form
+   when appropriate.
+    type must be between SLJIT_EQUAL_F64 and SLJIT_ORDERED_F32
+    type can be combined (or'ed) with SLJIT_REWRITABLE_JUMP
+   Flags: destroy flags.
+   Note: if either operand is NaN, the behaviour is undefined for
+         types up to SLJIT_S_LESS_EQUAL. */
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w);
+
+/* Set the destination of the jump to this label. */
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_label(struct sljit_jump *jump, struct sljit_label* label);
+/* Set the destination address of the jump to this label. */
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_target(struct sljit_jump *jump, sljit_uw target);
+
+/* Emit an indirect jump or fast call.
+   Direct form: set src to SLJIT_IMM() and srcw to the address
+   Indirect form: any other valid addressing mode
+    type must be between SLJIT_JUMP and SLJIT_FAST_CALL
+
+   Flags: does not modify flags. */
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw);
+
+/* Emit a C compiler (ABI) compatible function call.
+   Direct form: set src to SLJIT_IMM() and srcw to the address
+   Indirect form: any other valid addressing mode
+    type must be SLJIT_CALL or SLJIT_CALL_CDECL
+    arg_types is the combination of SLJIT_RET / SLJIT_ARGx (SLJIT_DEF_RET / SLJIT_DEF_ARGx) macros
+
+   Flags: destroy all flags. */
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 arg_types, sljit_s32 src, sljit_sw srcw);
+
+/* Perform the operation using the conditional flags as the second argument.
+   Type must always be between SLJIT_EQUAL and SLJIT_ORDERED_F64. The value
+   represented by the type is 1, if the condition represented by the type
+   is fulfilled, and 0 otherwise.
+
+   If op == SLJIT_MOV, SLJIT_MOV32:
+     Set dst to the value represented by the type (0 or 1).
+     Flags: - (does not modify flags)
+   If op == SLJIT_OR, op == SLJIT_AND, op == SLJIT_XOR
+     Performs the binary operation using dst as the first, and the value
+     represented by type as the second argument. Result is written into dst.
+     Flags: Z (may destroy flags) */
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 type);
+
+/* Emit a conditional mov instruction which moves source to destination,
+   if the condition is satisfied. Unlike other arithmetic operations this
+   instruction does not support memory access.
+
+   type must be between SLJIT_EQUAL and SLJIT_ORDERED_F64
+   dst_reg must be a valid register and it can be combined
+      with SLJIT_I32_OP to perform a 32 bit arithmetic operation
+   src must be register or immediate (SLJIT_IMM)
+
+   Flags: - (does not modify flags) */
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 dst_reg,
+	sljit_s32 src, sljit_sw srcw);
+
+/* The following flags are used by sljit_emit_mem() and sljit_emit_fmem(). */
+
+/* When SLJIT_MEM_SUPP is passed, no instructions are emitted.
+   Instead the function returns with SLJIT_SUCCESS if the instruction
+   form is supported and SLJIT_ERR_UNSUPPORTED otherwise. This flag
+   allows runtime checking of available instruction forms. */
+#define SLJIT_MEM_SUPP		0x0200
+/* Memory load operation. This is the default. */
+#define SLJIT_MEM_LOAD		0x0000
+/* Memory store operation. */
+#define SLJIT_MEM_STORE		0x0400
+/* Base register is updated before the memory access. */
+#define SLJIT_MEM_PRE		0x0800
+/* Base register is updated after the memory access. */
+#define SLJIT_MEM_POST		0x1000
+
+/* Emit a single memory load or store with update instruction. When the
+   requested instruction form is not supported by the CPU, it returns
+   with SLJIT_ERR_UNSUPPORTED instead of emulating the instruction. This
+   allows specializing tight loops based on the supported instruction
+   forms (see SLJIT_MEM_SUPP flag).
+
+   type must be between SLJIT_MOV and SLJIT_MOV_P and can be
+     combined with SLJIT_MEM_* flags. Either SLJIT_MEM_PRE
+     or SLJIT_MEM_POST must be specified.
+   reg is the source or destination register, and must be
+     different from the base register of the mem operand
+   mem must be a SLJIT_MEM1() or SLJIT_MEM2() operand
+
+   Flags: - (does not modify flags) */
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 reg,
+	sljit_s32 mem, sljit_sw memw);
+
+/* Same as sljit_emit_mem except the followings:
+
+   type must be SLJIT_MOV_F64 or SLJIT_MOV_F32 and can be
+     combined with SLJIT_MEM_* flags. Either SLJIT_MEM_PRE
+     or SLJIT_MEM_POST must be specified.
+   freg is the source or destination floating point register */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 freg,
+	sljit_s32 mem, sljit_sw memw);
+
+/* Copies the base address of SLJIT_SP + offset to dst. The offset can be
+   anything to negate the effect of relative addressing. For example if an
+   array of sljit_sw values is stored on the stack from offset 0x40, and R0
+   contains the offset of an array item plus 0x120, this item can be
+   overwritten by two SLJIT instructions:
+
+   sljit_get_local_base(compiler, SLJIT_R1, 0, 0x40 - 0x120);
+   sljit_emit_op1(compiler, SLJIT_MOV, SLJIT_MEM2(SLJIT_R1, SLJIT_R0), 0, SLJIT_IMM, 0x5);
+
+   Flags: - (may destroy flags) */
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset);
+
+/* Store a value that can be changed runtime (see: sljit_get_const_addr / sljit_set_const)
+   Flags: - (does not modify flags) */
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value);
+
+/* Store the value of a label (see: sljit_set_put_label)
+   Flags: - (does not modify flags) */
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw);
+
+/* Set the value stored by put_label to this label. */
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_put_label(struct sljit_put_label *put_label, struct sljit_label *label);
+
+/* After the code generation the address for label, jump and const instructions
+   are computed. Since these structures are freed by sljit_free_compiler, the
+   addresses must be preserved by the user program elsewere. */
+static SLJIT_INLINE sljit_uw sljit_get_label_addr(struct sljit_label *label) { return label->addr; }
+static SLJIT_INLINE sljit_uw sljit_get_jump_addr(struct sljit_jump *jump) { return jump->addr; }
+static SLJIT_INLINE sljit_uw sljit_get_const_addr(struct sljit_const *const_) { return const_->addr; }
+
+/* Only the address and executable offset are required to perform dynamic
+   code modifications. See sljit_get_executable_offset function. */
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset);
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset);
+
+/* --------------------------------------------------------------------- */
+/*  Miscellaneous utility functions                                      */
+/* --------------------------------------------------------------------- */
+
+#define SLJIT_MAJOR_VERSION	0
+#define SLJIT_MINOR_VERSION	94
+
+/* Get the human readable name of the platform. Can be useful on platforms
+   like ARM, where ARM and Thumb2 functions can be mixed, and
+   it is useful to know the type of the code generator. */
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void);
+
+/* Portable helper function to get an offset of a member. */
+#define SLJIT_OFFSETOF(base, member) ((sljit_sw)(&((base*)0x10)->member) - 0x10)
+
+#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK)
+
+/* The sljit_stack structure and its manipulation functions provides
+   an implementation for a top-down stack. The stack top is stored
+   in the end field of the sljit_stack structure and the stack goes
+   down to the min_start field, so the memory region reserved for
+   this stack is between min_start (inclusive) and end (exclusive)
+   fields. However the application can only use the region between
+   start (inclusive) and end (exclusive) fields. The sljit_stack_resize
+   function can be used to extend this region up to min_start.
+
+   This feature uses the "address space reserve" feature of modern
+   operating systems. Instead of allocating a large memory block
+   applications can allocate a small memory region and extend it
+   later without moving the content of the memory area. Therefore
+   after a successful resize by sljit_stack_resize all pointers into
+   this region are still valid.
+
+   Note:
+     this structure may not be supported by all operating systems.
+     end and max_limit fields are aligned to PAGE_SIZE bytes (usually
+         4 Kbyte or more).
+     stack should grow in larger steps, e.g. 4Kbyte, 16Kbyte or more. */
+
+struct sljit_stack {
+	/* User data, anything can be stored here.
+	   Initialized to the same value as the end field. */
+	sljit_u8 *top;
+/* These members are read only. */
+	/* End address of the stack */
+	sljit_u8 *end;
+	/* Current start address of the stack. */
+	sljit_u8 *start;
+	/* Lowest start address of the stack. */
+	sljit_u8 *min_start;
+};
+
+/* Allocates a new stack. Returns NULL if unsuccessful.
+   Note: see sljit_create_compiler for the explanation of allocator_data. */
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_FUNC sljit_allocate_stack(sljit_uw start_size, sljit_uw max_size, void *allocator_data);
+SLJIT_API_FUNC_ATTRIBUTE void SLJIT_FUNC sljit_free_stack(struct sljit_stack *stack, void *allocator_data);
+
+/* Can be used to increase (extend) or decrease (shrink) the stack
+   memory area. Returns with new_start if successful and NULL otherwise.
+   It always fails if new_start is less than min_start or greater or equal
+   than end fields. The fields of the stack are not changed if the returned
+   value is NULL (the current memory content is never lost). */
+SLJIT_API_FUNC_ATTRIBUTE sljit_u8 *SLJIT_FUNC sljit_stack_resize(struct sljit_stack *stack, sljit_u8 *new_start);
+
+#endif /* (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) */
+
+#if !(defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
+
+/* Get the entry address of a given function. */
+#define SLJIT_FUNC_OFFSET(func_name)	((sljit_sw)func_name)
+
+#else /* !(defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) */
+
+/* All JIT related code should be placed in the same context (library, binary, etc.). */
+
+#define SLJIT_FUNC_OFFSET(func_name)	(*(sljit_sw*)(void*)func_name)
+
+/* For powerpc64, the function pointers point to a context descriptor. */
+struct sljit_function_context {
+	sljit_sw addr;
+	sljit_sw r2;
+	sljit_sw r11;
+};
+
+/* Fill the context arguments using the addr and the function.
+   If func_ptr is NULL, it will not be set to the address of context
+   If addr is NULL, the function address also comes from the func pointer. */
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_function_context(void** func_ptr, struct sljit_function_context* context, sljit_sw addr, void* func);
+
+#endif /* !(defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL) */
+
+#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
+/* Free unused executable memory. The allocator keeps some free memory
+   around to reduce the number of OS executable memory allocations.
+   This improves performance since these calls are costly. However
+   it is sometimes desired to free all unused memory regions, e.g.
+   before the application terminates. */
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void);
+#endif
+
+/* --------------------------------------------------------------------- */
+/*  CPU specific functions                                               */
+/* --------------------------------------------------------------------- */
+
+/* The following function is a helper function for sljit_emit_op_custom.
+   It returns with the real machine register index ( >=0 ) of any SLJIT_R,
+   SLJIT_S and SLJIT_SP registers.
+
+   Note: it returns with -1 for virtual registers (only on x86-32). */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg);
+
+/* The following function is a helper function for sljit_emit_op_custom.
+   It returns with the real machine register index of any SLJIT_FLOAT register.
+
+   Note: the index is always an even number on ARM (except ARM-64), MIPS, and SPARC. */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg);
+
+/* Any instruction can be inserted into the instruction stream by
+   sljit_emit_op_custom. It has a similar purpose as inline assembly.
+   The size parameter must match to the instruction size of the target
+   architecture:
+
+         x86: 0 < size <= 15. The instruction argument can be byte aligned.
+      Thumb2: if size == 2, the instruction argument must be 2 byte aligned.
+              if size == 4, the instruction argument must be 4 byte aligned.
+   Otherwise: size must be 4 and instruction argument must be 4 byte aligned. */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+	void *instruction, sljit_s32 size);
+
+/* Define the currently available CPU status flags. It is usually used after an
+   sljit_emit_op_custom call to define which flags are set. */
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler,
+	sljit_s32 current_flags);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* SLJIT_LIR_H_ */
diff --git a/src/c/pcre2/src/sljit/sljitNativeARM_32.c b/src/c/pcre2/src/sljit/sljitNativeARM_32.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitNativeARM_32.c
@@ -0,0 +1,2824 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef __SOFTFP__
+#define ARM_ABI_INFO " ABI:softfp"
+#else
+#define ARM_ABI_INFO " ABI:hardfp"
+#endif
+
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
+{
+#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+	return "ARMv7" SLJIT_CPUINFO ARM_ABI_INFO;
+#elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+	return "ARMv5" SLJIT_CPUINFO ARM_ABI_INFO;
+#else
+#error "Internal error: Unknown ARM architecture"
+#endif
+}
+
+/* Last register + 1. */
+#define TMP_REG1	(SLJIT_NUMBER_OF_REGISTERS + 2)
+#define TMP_REG2	(SLJIT_NUMBER_OF_REGISTERS + 3)
+#define TMP_PC		(SLJIT_NUMBER_OF_REGISTERS + 4)
+
+#define TMP_FREG1	(SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
+#define TMP_FREG2	(SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2)
+
+/* In ARM instruction words.
+   Cache lines are usually 32 byte aligned. */
+#define CONST_POOL_ALIGNMENT	8
+#define CONST_POOL_EMPTY	0xffffffff
+
+#define ALIGN_INSTRUCTION(ptr) \
+	(sljit_uw*)(((sljit_uw)(ptr) + (CONST_POOL_ALIGNMENT * sizeof(sljit_uw)) - 1) & ~((CONST_POOL_ALIGNMENT * sizeof(sljit_uw)) - 1))
+#define MAX_DIFFERENCE(max_diff) \
+	(((max_diff) / (sljit_s32)sizeof(sljit_uw)) - (CONST_POOL_ALIGNMENT - 1))
+
+/* See sljit_emit_enter and sljit_emit_op0 if you want to change them. */
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = {
+	0, 0, 1, 2, 3, 11, 10, 9, 8, 7, 6, 5, 4, 13, 12, 14, 15
+};
+
+static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
+	0, 0, 1, 2, 3, 4, 5, 6, 7
+};
+
+#define RM(rm) (reg_map[rm])
+#define RD(rd) (reg_map[rd] << 12)
+#define RN(rn) (reg_map[rn] << 16)
+
+/* --------------------------------------------------------------------- */
+/*  Instrucion forms                                                     */
+/* --------------------------------------------------------------------- */
+
+/* The instruction includes the AL condition.
+   INST_NAME - CONDITIONAL remove this flag. */
+#define COND_MASK	0xf0000000
+#define CONDITIONAL	0xe0000000
+#define PUSH_POOL	0xff000000
+
+#define ADC		0xe0a00000
+#define ADD		0xe0800000
+#define AND		0xe0000000
+#define B		0xea000000
+#define BIC		0xe1c00000
+#define BL		0xeb000000
+#define BLX		0xe12fff30
+#define BX		0xe12fff10
+#define CLZ		0xe16f0f10
+#define CMN		0xe1600000
+#define CMP		0xe1400000
+#define BKPT		0xe1200070
+#define EOR		0xe0200000
+#define MOV		0xe1a00000
+#define MUL		0xe0000090
+#define MVN		0xe1e00000
+#define NOP		0xe1a00000
+#define ORR		0xe1800000
+#define PUSH		0xe92d0000
+#define POP		0xe8bd0000
+#define RSB		0xe0600000
+#define RSC		0xe0e00000
+#define SBC		0xe0c00000
+#define SMULL		0xe0c00090
+#define SUB		0xe0400000
+#define UMULL		0xe0800090
+#define VABS_F32	0xeeb00ac0
+#define VADD_F32	0xee300a00
+#define VCMP_F32	0xeeb40a40
+#define VCVT_F32_S32	0xeeb80ac0
+#define VCVT_F64_F32	0xeeb70ac0
+#define VCVT_S32_F32	0xeebd0ac0
+#define VDIV_F32	0xee800a00
+#define VMOV_F32	0xeeb00a40
+#define VMOV		0xee000a10
+#define VMOV2		0xec400a10
+#define VMRS		0xeef1fa10
+#define VMUL_F32	0xee200a00
+#define VNEG_F32	0xeeb10a40
+#define VSTR_F32	0xed000a00
+#define VSUB_F32	0xee300a40
+
+#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+/* Arm v7 specific instructions. */
+#define MOVW		0xe3000000
+#define MOVT		0xe3400000
+#define SXTB		0xe6af0070
+#define SXTH		0xe6bf0070
+#define UXTB		0xe6ef0070
+#define UXTH		0xe6ff0070
+#endif
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+
+static sljit_s32 push_cpool(struct sljit_compiler *compiler)
+{
+	/* Pushing the constant pool into the instruction stream. */
+	sljit_uw* inst;
+	sljit_uw* cpool_ptr;
+	sljit_uw* cpool_end;
+	sljit_s32 i;
+
+	/* The label could point the address after the constant pool. */
+	if (compiler->last_label && compiler->last_label->size == compiler->size)
+		compiler->last_label->size += compiler->cpool_fill + (CONST_POOL_ALIGNMENT - 1) + 1;
+
+	SLJIT_ASSERT(compiler->cpool_fill > 0 && compiler->cpool_fill <= CPOOL_SIZE);
+	inst = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
+	FAIL_IF(!inst);
+	compiler->size++;
+	*inst = 0xff000000 | compiler->cpool_fill;
+
+	for (i = 0; i < CONST_POOL_ALIGNMENT - 1; i++) {
+		inst = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
+		FAIL_IF(!inst);
+		compiler->size++;
+		*inst = 0;
+	}
+
+	cpool_ptr = compiler->cpool;
+	cpool_end = cpool_ptr + compiler->cpool_fill;
+	while (cpool_ptr < cpool_end) {
+		inst = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
+		FAIL_IF(!inst);
+		compiler->size++;
+		*inst = *cpool_ptr++;
+	}
+	compiler->cpool_diff = CONST_POOL_EMPTY;
+	compiler->cpool_fill = 0;
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_uw inst)
+{
+	sljit_uw* ptr;
+
+	if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4092)))
+		FAIL_IF(push_cpool(compiler));
+
+	ptr = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
+	FAIL_IF(!ptr);
+	compiler->size++;
+	*ptr = inst;
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 push_inst_with_literal(struct sljit_compiler *compiler, sljit_uw inst, sljit_uw literal)
+{
+	sljit_uw* ptr;
+	sljit_uw cpool_index = CPOOL_SIZE;
+	sljit_uw* cpool_ptr;
+	sljit_uw* cpool_end;
+	sljit_u8* cpool_unique_ptr;
+
+	if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4092)))
+		FAIL_IF(push_cpool(compiler));
+	else if (compiler->cpool_fill > 0) {
+		cpool_ptr = compiler->cpool;
+		cpool_end = cpool_ptr + compiler->cpool_fill;
+		cpool_unique_ptr = compiler->cpool_unique;
+		do {
+			if ((*cpool_ptr == literal) && !(*cpool_unique_ptr)) {
+				cpool_index = cpool_ptr - compiler->cpool;
+				break;
+			}
+			cpool_ptr++;
+			cpool_unique_ptr++;
+		} while (cpool_ptr < cpool_end);
+	}
+
+	if (cpool_index == CPOOL_SIZE) {
+		/* Must allocate a new entry in the literal pool. */
+		if (compiler->cpool_fill < CPOOL_SIZE) {
+			cpool_index = compiler->cpool_fill;
+			compiler->cpool_fill++;
+		}
+		else {
+			FAIL_IF(push_cpool(compiler));
+			cpool_index = 0;
+			compiler->cpool_fill = 1;
+		}
+	}
+
+	SLJIT_ASSERT((inst & 0xfff) == 0);
+	ptr = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
+	FAIL_IF(!ptr);
+	compiler->size++;
+	*ptr = inst | cpool_index;
+
+	compiler->cpool[cpool_index] = literal;
+	compiler->cpool_unique[cpool_index] = 0;
+	if (compiler->cpool_diff == CONST_POOL_EMPTY)
+		compiler->cpool_diff = compiler->size;
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 push_inst_with_unique_literal(struct sljit_compiler *compiler, sljit_uw inst, sljit_uw literal)
+{
+	sljit_uw* ptr;
+	if (SLJIT_UNLIKELY((compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4092)) || compiler->cpool_fill >= CPOOL_SIZE))
+		FAIL_IF(push_cpool(compiler));
+
+	SLJIT_ASSERT(compiler->cpool_fill < CPOOL_SIZE && (inst & 0xfff) == 0);
+	ptr = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
+	FAIL_IF(!ptr);
+	compiler->size++;
+	*ptr = inst | compiler->cpool_fill;
+
+	compiler->cpool[compiler->cpool_fill] = literal;
+	compiler->cpool_unique[compiler->cpool_fill] = 1;
+	compiler->cpool_fill++;
+	if (compiler->cpool_diff == CONST_POOL_EMPTY)
+		compiler->cpool_diff = compiler->size;
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 prepare_blx(struct sljit_compiler *compiler)
+{
+	/* Place for at least two instruction (doesn't matter whether the first has a literal). */
+	if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4088)))
+		return push_cpool(compiler);
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 emit_blx(struct sljit_compiler *compiler)
+{
+	/* Must follow tightly the previous instruction (to be able to convert it to bl instruction). */
+	SLJIT_ASSERT(compiler->cpool_diff == CONST_POOL_EMPTY || compiler->size - compiler->cpool_diff < MAX_DIFFERENCE(4092));
+	SLJIT_ASSERT(reg_map[TMP_REG1] != 14);
+
+	return push_inst(compiler, BLX | RM(TMP_REG1));
+}
+
+static sljit_uw patch_pc_relative_loads(sljit_uw *last_pc_patch, sljit_uw *code_ptr, sljit_uw* const_pool, sljit_uw cpool_size)
+{
+	sljit_uw diff;
+	sljit_uw ind;
+	sljit_uw counter = 0;
+	sljit_uw* clear_const_pool = const_pool;
+	sljit_uw* clear_const_pool_end = const_pool + cpool_size;
+
+	SLJIT_ASSERT(const_pool - code_ptr <= CONST_POOL_ALIGNMENT);
+	/* Set unused flag for all literals in the constant pool.
+	   I.e.: unused literals can belong to branches, which can be encoded as B or BL.
+	   We can "compress" the constant pool by discarding these literals. */
+	while (clear_const_pool < clear_const_pool_end)
+		*clear_const_pool++ = (sljit_uw)(-1);
+
+	while (last_pc_patch < code_ptr) {
+		/* Data transfer instruction with Rn == r15. */
+		if ((*last_pc_patch & 0x0c0f0000) == 0x040f0000) {
+			diff = const_pool - last_pc_patch;
+			ind = (*last_pc_patch) & 0xfff;
+
+			/* Must be a load instruction with immediate offset. */
+			SLJIT_ASSERT(ind < cpool_size && !(*last_pc_patch & (1 << 25)) && (*last_pc_patch & (1 << 20)));
+			if ((sljit_s32)const_pool[ind] < 0) {
+				const_pool[ind] = counter;
+				ind = counter;
+				counter++;
+			}
+			else
+				ind = const_pool[ind];
+
+			SLJIT_ASSERT(diff >= 1);
+			if (diff >= 2 || ind > 0) {
+				diff = (diff + ind - 2) << 2;
+				SLJIT_ASSERT(diff <= 0xfff);
+				*last_pc_patch = (*last_pc_patch & ~0xfff) | diff;
+			}
+			else
+				*last_pc_patch = (*last_pc_patch & ~(0xfff | (1 << 23))) | 0x004;
+		}
+		last_pc_patch++;
+	}
+	return counter;
+}
+
+/* In some rare ocasions we may need future patches. The probability is close to 0 in practice. */
+struct future_patch {
+	struct future_patch* next;
+	sljit_s32 index;
+	sljit_s32 value;
+};
+
+static sljit_s32 resolve_const_pool_index(struct sljit_compiler *compiler, struct future_patch **first_patch, sljit_uw cpool_current_index, sljit_uw *cpool_start_address, sljit_uw *buf_ptr)
+{
+	sljit_s32 value;
+	struct future_patch *curr_patch, *prev_patch;
+
+	SLJIT_UNUSED_ARG(compiler);
+
+	/* Using the values generated by patch_pc_relative_loads. */
+	if (!*first_patch)
+		value = (sljit_s32)cpool_start_address[cpool_current_index];
+	else {
+		curr_patch = *first_patch;
+		prev_patch = NULL;
+		while (1) {
+			if (!curr_patch) {
+				value = (sljit_s32)cpool_start_address[cpool_current_index];
+				break;
+			}
+			if ((sljit_uw)curr_patch->index == cpool_current_index) {
+				value = curr_patch->value;
+				if (prev_patch)
+					prev_patch->next = curr_patch->next;
+				else
+					*first_patch = curr_patch->next;
+				SLJIT_FREE(curr_patch, compiler->allocator_data);
+				break;
+			}
+			prev_patch = curr_patch;
+			curr_patch = curr_patch->next;
+		}
+	}
+
+	if (value >= 0) {
+		if ((sljit_uw)value > cpool_current_index) {
+			curr_patch = (struct future_patch*)SLJIT_MALLOC(sizeof(struct future_patch), compiler->allocator_data);
+			if (!curr_patch) {
+				while (*first_patch) {
+					curr_patch = *first_patch;
+					*first_patch = (*first_patch)->next;
+					SLJIT_FREE(curr_patch, compiler->allocator_data);
+				}
+				return SLJIT_ERR_ALLOC_FAILED;
+			}
+			curr_patch->next = *first_patch;
+			curr_patch->index = value;
+			curr_patch->value = cpool_start_address[value];
+			*first_patch = curr_patch;
+		}
+		cpool_start_address[value] = *buf_ptr;
+	}
+	return SLJIT_SUCCESS;
+}
+
+#else
+
+static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_uw inst)
+{
+	sljit_uw* ptr;
+
+	ptr = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
+	FAIL_IF(!ptr);
+	compiler->size++;
+	*ptr = inst;
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 emit_imm(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
+{
+	FAIL_IF(push_inst(compiler, MOVW | RD(reg) | ((imm << 4) & 0xf0000) | (imm & 0xfff)));
+	return push_inst(compiler, MOVT | RD(reg) | ((imm >> 12) & 0xf0000) | ((imm >> 16) & 0xfff));
+}
+
+#endif
+
+static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw *code_ptr, sljit_uw *code, sljit_sw executable_offset)
+{
+	sljit_sw diff;
+
+	if (jump->flags & SLJIT_REWRITABLE_JUMP)
+		return 0;
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+	if (jump->flags & IS_BL)
+		code_ptr--;
+
+	if (jump->flags & JUMP_ADDR)
+		diff = ((sljit_sw)jump->u.target - (sljit_sw)(code_ptr + 2) - executable_offset);
+	else {
+		SLJIT_ASSERT(jump->flags & JUMP_LABEL);
+		diff = ((sljit_sw)(code + jump->u.label->size) - (sljit_sw)(code_ptr + 2));
+	}
+
+	/* Branch to Thumb code has not been optimized yet. */
+	if (diff & 0x3)
+		return 0;
+
+	if (jump->flags & IS_BL) {
+		if (diff <= 0x01ffffff && diff >= -0x02000000) {
+			*code_ptr = (BL - CONDITIONAL) | (*(code_ptr + 1) & COND_MASK);
+			jump->flags |= PATCH_B;
+			return 1;
+		}
+	}
+	else {
+		if (diff <= 0x01ffffff && diff >= -0x02000000) {
+			*code_ptr = (B - CONDITIONAL) | (*code_ptr & COND_MASK);
+			jump->flags |= PATCH_B;
+		}
+	}
+#else
+	if (jump->flags & JUMP_ADDR)
+		diff = ((sljit_sw)jump->u.target - (sljit_sw)code_ptr - executable_offset);
+	else {
+		SLJIT_ASSERT(jump->flags & JUMP_LABEL);
+		diff = ((sljit_sw)(code + jump->u.label->size) - (sljit_sw)code_ptr);
+	}
+
+	/* Branch to Thumb code has not been optimized yet. */
+	if (diff & 0x3)
+		return 0;
+
+	if (diff <= 0x01ffffff && diff >= -0x02000000) {
+		code_ptr -= 2;
+		*code_ptr = ((jump->flags & IS_BL) ? (BL - CONDITIONAL) : (B - CONDITIONAL)) | (code_ptr[2] & COND_MASK);
+		jump->flags |= PATCH_B;
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+static SLJIT_INLINE void inline_set_jump_addr(sljit_uw jump_ptr, sljit_sw executable_offset, sljit_uw new_addr, sljit_s32 flush_cache)
+{
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+	sljit_uw *ptr = (sljit_uw *)jump_ptr;
+	sljit_uw *inst = (sljit_uw *)ptr[0];
+	sljit_uw mov_pc = ptr[1];
+	sljit_s32 bl = (mov_pc & 0x0000f000) != RD(TMP_PC);
+	sljit_sw diff = (sljit_sw)(((sljit_sw)new_addr - (sljit_sw)(inst + 2) - executable_offset) >> 2);
+
+	SLJIT_UNUSED_ARG(executable_offset);
+
+	if (diff <= 0x7fffff && diff >= -0x800000) {
+		/* Turn to branch. */
+		if (!bl) {
+			if (flush_cache) {
+				SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0);
+			}
+			inst[0] = (mov_pc & COND_MASK) | (B - CONDITIONAL) | (diff & 0xffffff);
+			if (flush_cache) {
+				SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);
+				inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+				SLJIT_CACHE_FLUSH(inst, inst + 1);
+			}
+		} else {
+			if (flush_cache) {
+				SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);
+			}
+			inst[0] = (mov_pc & COND_MASK) | (BL - CONDITIONAL) | (diff & 0xffffff);
+			inst[1] = NOP;
+			if (flush_cache) {
+				SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
+				inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+				SLJIT_CACHE_FLUSH(inst, inst + 2);
+			}
+		}
+	} else {
+		/* Get the position of the constant. */
+		if (mov_pc & (1 << 23))
+			ptr = inst + ((mov_pc & 0xfff) >> 2) + 2;
+		else
+			ptr = inst + 1;
+
+		if (*inst != mov_pc) {
+			if (flush_cache) {
+				SLJIT_UPDATE_WX_FLAGS(inst, inst + (!bl ? 1 : 2), 0);
+			}
+			inst[0] = mov_pc;
+			if (!bl) {
+				if (flush_cache) {
+					SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);
+					inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+					SLJIT_CACHE_FLUSH(inst, inst + 1);
+				}
+			} else {
+				inst[1] = BLX | RM(TMP_REG1);
+				if (flush_cache) {
+					SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
+					inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+					SLJIT_CACHE_FLUSH(inst, inst + 2);
+				}
+			}
+		}
+
+		if (flush_cache) {
+			SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 0);
+		}
+
+		*ptr = new_addr;
+
+		if (flush_cache) {
+			SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 1);
+		}
+	}
+#else
+	sljit_uw *inst = (sljit_uw*)jump_ptr;
+
+	SLJIT_UNUSED_ARG(executable_offset);
+
+	SLJIT_ASSERT((inst[0] & 0xfff00000) == MOVW && (inst[1] & 0xfff00000) == MOVT);
+
+	if (flush_cache) {
+		SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);
+	}
+
+	inst[0] = MOVW | (inst[0] & 0xf000) | ((new_addr << 4) & 0xf0000) | (new_addr & 0xfff);
+	inst[1] = MOVT | (inst[1] & 0xf000) | ((new_addr >> 12) & 0xf0000) | ((new_addr >> 16) & 0xfff);
+
+	if (flush_cache) {
+		SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
+		inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+		SLJIT_CACHE_FLUSH(inst, inst + 2);
+	}
+#endif
+}
+
+static sljit_uw get_imm(sljit_uw imm);
+
+static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_sw executable_offset, sljit_sw new_constant, sljit_s32 flush_cache)
+{
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+	sljit_uw *ptr = (sljit_uw*)addr;
+	sljit_uw *inst = (sljit_uw*)ptr[0];
+	sljit_uw ldr_literal = ptr[1];
+	sljit_uw src2;
+
+	SLJIT_UNUSED_ARG(executable_offset);
+
+	src2 = get_imm(new_constant);
+	if (src2) {
+		if (flush_cache) {
+			SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0);
+		}
+
+		*inst = 0xe3a00000 | (ldr_literal & 0xf000) | src2;
+
+		if (flush_cache) {
+			SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);
+			inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+			SLJIT_CACHE_FLUSH(inst, inst + 1);
+		}
+		return;
+	}
+
+	src2 = get_imm(~new_constant);
+	if (src2) {
+		if (flush_cache) {
+			SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0);
+		}
+
+		*inst = 0xe3e00000 | (ldr_literal & 0xf000) | src2;
+
+		if (flush_cache) {
+			SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);
+			inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+			SLJIT_CACHE_FLUSH(inst, inst + 1);
+		}
+		return;
+	}
+
+	if (ldr_literal & (1 << 23))
+		ptr = inst + ((ldr_literal & 0xfff) >> 2) + 2;
+	else
+		ptr = inst + 1;
+
+	if (*inst != ldr_literal) {
+		if (flush_cache) {
+			SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 0);
+		}
+
+		*inst = ldr_literal;
+
+		if (flush_cache) {
+			SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);
+			inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+			SLJIT_CACHE_FLUSH(inst, inst + 1);
+		}
+	}
+
+	if (flush_cache) {
+		SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 0);
+	}
+
+	*ptr = new_constant;
+
+	if (flush_cache) {
+		SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 1);
+	}
+#else
+	sljit_uw *inst = (sljit_uw*)addr;
+
+	SLJIT_UNUSED_ARG(executable_offset);
+
+	SLJIT_ASSERT((inst[0] & 0xfff00000) == MOVW && (inst[1] & 0xfff00000) == MOVT);
+
+	if (flush_cache) {
+		SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);
+	}
+
+	inst[0] = MOVW | (inst[0] & 0xf000) | ((new_constant << 4) & 0xf0000) | (new_constant & 0xfff);
+	inst[1] = MOVT | (inst[1] & 0xf000) | ((new_constant >> 12) & 0xf0000) | ((new_constant >> 16) & 0xfff);
+
+	if (flush_cache) {
+		SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
+		inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+		SLJIT_CACHE_FLUSH(inst, inst + 2);
+	}
+#endif
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+{
+	struct sljit_memory_fragment *buf;
+	sljit_uw *code;
+	sljit_uw *code_ptr;
+	sljit_uw *buf_ptr;
+	sljit_uw *buf_end;
+	sljit_uw size;
+	sljit_uw word_count;
+	sljit_uw next_addr;
+	sljit_sw executable_offset;
+	sljit_sw addr;
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+	sljit_uw cpool_size;
+	sljit_uw cpool_skip_alignment;
+	sljit_uw cpool_current_index;
+	sljit_uw *cpool_start_address;
+	sljit_uw *last_pc_patch;
+	struct future_patch *first_patch;
+#endif
+
+	struct sljit_label *label;
+	struct sljit_jump *jump;
+	struct sljit_const *const_;
+	struct sljit_put_label *put_label;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_generate_code(compiler));
+	reverse_buf(compiler);
+
+	/* Second code generation pass. */
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+	size = compiler->size + (compiler->patches << 1);
+	if (compiler->cpool_fill > 0)
+		size += compiler->cpool_fill + CONST_POOL_ALIGNMENT - 1;
+#else
+	size = compiler->size;
+#endif
+	code = (sljit_uw*)SLJIT_MALLOC_EXEC(size * sizeof(sljit_uw), compiler->exec_allocator_data);
+	PTR_FAIL_WITH_EXEC_IF(code);
+	buf = compiler->buf;
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+	cpool_size = 0;
+	cpool_skip_alignment = 0;
+	cpool_current_index = 0;
+	cpool_start_address = NULL;
+	first_patch = NULL;
+	last_pc_patch = code;
+#endif
+
+	code_ptr = code;
+	word_count = 0;
+	next_addr = 1;
+	executable_offset = SLJIT_EXEC_OFFSET(code);
+
+	label = compiler->labels;
+	jump = compiler->jumps;
+	const_ = compiler->consts;
+	put_label = compiler->put_labels;
+
+	if (label && label->size == 0) {
+		label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
+		label = label->next;
+	}
+
+	do {
+		buf_ptr = (sljit_uw*)buf->memory;
+		buf_end = buf_ptr + (buf->used_size >> 2);
+		do {
+			word_count++;
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+			if (cpool_size > 0) {
+				if (cpool_skip_alignment > 0) {
+					buf_ptr++;
+					cpool_skip_alignment--;
+				}
+				else {
+					if (SLJIT_UNLIKELY(resolve_const_pool_index(compiler, &first_patch, cpool_current_index, cpool_start_address, buf_ptr))) {
+						SLJIT_FREE_EXEC(code, compiler->exec_allocator_data);
+						compiler->error = SLJIT_ERR_ALLOC_FAILED;
+						return NULL;
+					}
+					buf_ptr++;
+					if (++cpool_current_index >= cpool_size) {
+						SLJIT_ASSERT(!first_patch);
+						cpool_size = 0;
+						if (label && label->size == word_count) {
+							/* Points after the current instruction. */
+							label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+							label->size = code_ptr - code;
+							label = label->next;
+
+							next_addr = compute_next_addr(label, jump, const_, put_label);
+						}
+					}
+				}
+			}
+			else if ((*buf_ptr & 0xff000000) != PUSH_POOL) {
+#endif
+				*code_ptr = *buf_ptr++;
+				if (next_addr == word_count) {
+					SLJIT_ASSERT(!label || label->size >= word_count);
+					SLJIT_ASSERT(!jump || jump->addr >= word_count);
+					SLJIT_ASSERT(!const_ || const_->addr >= word_count);
+					SLJIT_ASSERT(!put_label || put_label->addr >= word_count);
+
+				/* These structures are ordered by their address. */
+					if (jump && jump->addr == word_count) {
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+						if (detect_jump_type(jump, code_ptr, code, executable_offset))
+							code_ptr--;
+						jump->addr = (sljit_uw)code_ptr;
+#else
+						jump->addr = (sljit_uw)(code_ptr - 2);
+						if (detect_jump_type(jump, code_ptr, code, executable_offset))
+							code_ptr -= 2;
+#endif
+						jump = jump->next;
+					}
+					if (label && label->size == word_count) {
+						/* code_ptr can be affected above. */
+						label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr + 1, executable_offset);
+						label->size = (code_ptr + 1) - code;
+						label = label->next;
+					}
+					if (const_ && const_->addr == word_count) {
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+						const_->addr = (sljit_uw)code_ptr;
+#else
+						const_->addr = (sljit_uw)(code_ptr - 1);
+#endif
+						const_ = const_->next;
+					}
+					if (put_label && put_label->addr == word_count) {
+						SLJIT_ASSERT(put_label->label);
+						put_label->addr = (sljit_uw)code_ptr;
+						put_label = put_label->next;
+					}
+					next_addr = compute_next_addr(label, jump, const_, put_label);
+				}
+				code_ptr++;
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+			}
+			else {
+				/* Fortunately, no need to shift. */
+				cpool_size = *buf_ptr++ & ~PUSH_POOL;
+				SLJIT_ASSERT(cpool_size > 0);
+				cpool_start_address = ALIGN_INSTRUCTION(code_ptr + 1);
+				cpool_current_index = patch_pc_relative_loads(last_pc_patch, code_ptr, cpool_start_address, cpool_size);
+				if (cpool_current_index > 0) {
+					/* Unconditional branch. */
+					*code_ptr = B | (((cpool_start_address - code_ptr) + cpool_current_index - 2) & ~PUSH_POOL);
+					code_ptr = cpool_start_address + cpool_current_index;
+				}
+				cpool_skip_alignment = CONST_POOL_ALIGNMENT - 1;
+				cpool_current_index = 0;
+				last_pc_patch = code_ptr;
+			}
+#endif
+		} while (buf_ptr < buf_end);
+		buf = buf->next;
+	} while (buf);
+
+	SLJIT_ASSERT(!label);
+	SLJIT_ASSERT(!jump);
+	SLJIT_ASSERT(!const_);
+	SLJIT_ASSERT(!put_label);
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+	SLJIT_ASSERT(cpool_size == 0);
+	if (compiler->cpool_fill > 0) {
+		cpool_start_address = ALIGN_INSTRUCTION(code_ptr);
+		cpool_current_index = patch_pc_relative_loads(last_pc_patch, code_ptr, cpool_start_address, compiler->cpool_fill);
+		if (cpool_current_index > 0)
+			code_ptr = cpool_start_address + cpool_current_index;
+
+		buf_ptr = compiler->cpool;
+		buf_end = buf_ptr + compiler->cpool_fill;
+		cpool_current_index = 0;
+		while (buf_ptr < buf_end) {
+			if (SLJIT_UNLIKELY(resolve_const_pool_index(compiler, &first_patch, cpool_current_index, cpool_start_address, buf_ptr))) {
+				SLJIT_FREE_EXEC(code, compiler->exec_allocator_data);
+				compiler->error = SLJIT_ERR_ALLOC_FAILED;
+				return NULL;
+			}
+			buf_ptr++;
+			cpool_current_index++;
+		}
+		SLJIT_ASSERT(!first_patch);
+	}
+#endif
+
+	jump = compiler->jumps;
+	while (jump) {
+		buf_ptr = (sljit_uw *)jump->addr;
+
+		if (jump->flags & PATCH_B) {
+			addr = (sljit_sw)SLJIT_ADD_EXEC_OFFSET(buf_ptr + 2, executable_offset);
+			if (!(jump->flags & JUMP_ADDR)) {
+				SLJIT_ASSERT(jump->flags & JUMP_LABEL);
+				SLJIT_ASSERT(((sljit_sw)jump->u.label->addr - addr) <= 0x01ffffff && ((sljit_sw)jump->u.label->addr - addr) >= -0x02000000);
+				*buf_ptr |= (((sljit_sw)jump->u.label->addr - addr) >> 2) & 0x00ffffff;
+			}
+			else {
+				SLJIT_ASSERT(((sljit_sw)jump->u.target - addr) <= 0x01ffffff && ((sljit_sw)jump->u.target - addr) >= -0x02000000);
+				*buf_ptr |= (((sljit_sw)jump->u.target - addr) >> 2) & 0x00ffffff;
+			}
+		}
+		else if (jump->flags & SLJIT_REWRITABLE_JUMP) {
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+			jump->addr = (sljit_uw)code_ptr;
+			code_ptr[0] = (sljit_uw)buf_ptr;
+			code_ptr[1] = *buf_ptr;
+			inline_set_jump_addr((sljit_uw)code_ptr, executable_offset, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
+			code_ptr += 2;
+#else
+			inline_set_jump_addr((sljit_uw)buf_ptr, executable_offset, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
+#endif
+		}
+		else {
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+			if (jump->flags & IS_BL)
+				buf_ptr--;
+			if (*buf_ptr & (1 << 23))
+				buf_ptr += ((*buf_ptr & 0xfff) >> 2) + 2;
+			else
+				buf_ptr += 1;
+			*buf_ptr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
+#else
+			inline_set_jump_addr((sljit_uw)buf_ptr, executable_offset, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
+#endif
+		}
+		jump = jump->next;
+	}
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+	const_ = compiler->consts;
+	while (const_) {
+		buf_ptr = (sljit_uw*)const_->addr;
+		const_->addr = (sljit_uw)code_ptr;
+
+		code_ptr[0] = (sljit_uw)buf_ptr;
+		code_ptr[1] = *buf_ptr;
+		if (*buf_ptr & (1 << 23))
+			buf_ptr += ((*buf_ptr & 0xfff) >> 2) + 2;
+		else
+			buf_ptr += 1;
+		/* Set the value again (can be a simple constant). */
+		inline_set_const((sljit_uw)code_ptr, executable_offset, *buf_ptr, 0);
+		code_ptr += 2;
+
+		const_ = const_->next;
+	}
+#endif
+
+	put_label = compiler->put_labels;
+	while (put_label) {
+		addr = put_label->label->addr;
+		buf_ptr = (sljit_uw*)put_label->addr;
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+		SLJIT_ASSERT((buf_ptr[0] & 0xffff0000) == 0xe59f0000);
+		buf_ptr[((buf_ptr[0] & 0xfff) >> 2) + 2] = addr;
+#else
+		SLJIT_ASSERT((buf_ptr[-1] & 0xfff00000) == MOVW && (buf_ptr[0] & 0xfff00000) == MOVT);
+		buf_ptr[-1] |= ((addr << 4) & 0xf0000) | (addr & 0xfff);
+		buf_ptr[0] |= ((addr >> 12) & 0xf0000) | ((addr >> 16) & 0xfff);
+#endif
+		put_label = put_label->next;
+	}
+
+	SLJIT_ASSERT(code_ptr - code <= (sljit_s32)size);
+
+	compiler->error = SLJIT_ERR_COMPILED;
+	compiler->executable_offset = executable_offset;
+	compiler->executable_size = (code_ptr - code) * sizeof(sljit_uw);
+
+	code = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
+	code_ptr = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+
+	SLJIT_CACHE_FLUSH(code, code_ptr);
+	SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);
+	return code;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
+{
+	switch (feature_type) {
+	case SLJIT_HAS_FPU:
+#ifdef SLJIT_IS_FPU_AVAILABLE
+		return SLJIT_IS_FPU_AVAILABLE;
+#else
+		/* Available by default. */
+		return 1;
+#endif
+
+	case SLJIT_HAS_CLZ:
+	case SLJIT_HAS_CMOV:
+#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+	case SLJIT_HAS_PREFETCH:
+#endif
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+/*  Entry, exit                                                          */
+/* --------------------------------------------------------------------- */
+
+/* Creates an index in data_transfer_insts array. */
+#define WORD_SIZE	0x00
+#define BYTE_SIZE	0x01
+#define HALF_SIZE	0x02
+#define PRELOAD		0x03
+#define SIGNED		0x04
+#define LOAD_DATA	0x08
+
+/* Flag bits for emit_op. */
+#define ALLOW_IMM	0x10
+#define ALLOW_INV_IMM	0x20
+#define ALLOW_ANY_IMM	(ALLOW_IMM | ALLOW_INV_IMM)
+
+/* s/l - store/load (1 bit)
+   u/s - signed/unsigned (1 bit)
+   w/b/h/N - word/byte/half/NOT allowed (2 bit)
+   Storing signed and unsigned values are the same operations. */
+
+static const sljit_uw data_transfer_insts[16] = {
+/* s u w */ 0xe5000000 /* str */,
+/* s u b */ 0xe5400000 /* strb */,
+/* s u h */ 0xe10000b0 /* strh */,
+/* s u N */ 0x00000000 /* not allowed */,
+/* s s w */ 0xe5000000 /* str */,
+/* s s b */ 0xe5400000 /* strb */,
+/* s s h */ 0xe10000b0 /* strh */,
+/* s s N */ 0x00000000 /* not allowed */,
+
+/* l u w */ 0xe5100000 /* ldr */,
+/* l u b */ 0xe5500000 /* ldrb */,
+/* l u h */ 0xe11000b0 /* ldrh */,
+/* l u p */ 0xf5500000 /* preload */,
+/* l s w */ 0xe5100000 /* ldr */,
+/* l s b */ 0xe11000d0 /* ldrsb */,
+/* l s h */ 0xe11000f0 /* ldrsh */,
+/* l s N */ 0x00000000 /* not allowed */,
+};
+
+#define EMIT_DATA_TRANSFER(type, add, target_reg, base_reg, arg) \
+	(data_transfer_insts[(type) & 0xf] | ((add) << 23) | RD(target_reg) | RN(base_reg) | (arg))
+
+/* Normal ldr/str instruction.
+   Type2: ldrsb, ldrh, ldrsh */
+#define IS_TYPE1_TRANSFER(type) \
+	(data_transfer_insts[(type) & 0xf] & 0x04000000)
+#define TYPE2_TRANSFER_IMM(imm) \
+	(((imm) & 0xf) | (((imm) & 0xf0) << 4) | (1 << 22))
+
+static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 inp_flags,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w);
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	sljit_s32 args, size, i, tmp;
+	sljit_uw push;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+	/* Push saved registers, temporary registers
+	   stmdb sp!, {..., lr} */
+	push = PUSH | (1 << 14);
+
+	tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
+	for (i = SLJIT_S0; i >= tmp; i--)
+		push |= 1 << reg_map[i];
+
+	for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--)
+		push |= 1 << reg_map[i];
+
+	FAIL_IF(push_inst(compiler, push));
+
+	/* Stack must be aligned to 8 bytes: */
+	size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
+	local_size = ((size + local_size + 7) & ~7) - size;
+	compiler->local_size = local_size;
+	if (local_size > 0)
+		FAIL_IF(emit_op(compiler, SLJIT_SUB, ALLOW_IMM, SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size));
+
+	args = get_arg_count(arg_types);
+
+	if (args >= 1)
+		FAIL_IF(push_inst(compiler, MOV | RD(SLJIT_S0) | RM(SLJIT_R0)));
+	if (args >= 2)
+		FAIL_IF(push_inst(compiler, MOV | RD(SLJIT_S1) | RM(SLJIT_R1)));
+	if (args >= 3)
+		FAIL_IF(push_inst(compiler, MOV | RD(SLJIT_S2) | RM(SLJIT_R2)));
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	sljit_s32 size;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+	size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
+	compiler->local_size = ((size + local_size + 7) & ~7) - size;
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 i, tmp;
+	sljit_uw pop;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_return(compiler, op, src, srcw));
+
+	FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
+
+	if (compiler->local_size > 0)
+		FAIL_IF(emit_op(compiler, SLJIT_ADD, ALLOW_IMM, SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, compiler->local_size));
+
+	/* Push saved registers, temporary registers
+	   ldmia sp!, {..., pc} */
+	pop = POP | (1 << 15);
+
+	tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG;
+	for (i = SLJIT_S0; i >= tmp; i--)
+		pop |= 1 << reg_map[i];
+
+	for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--)
+		pop |= 1 << reg_map[i];
+
+	return push_inst(compiler, pop);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Operators                                                            */
+/* --------------------------------------------------------------------- */
+
+/* flags: */
+  /* Arguments are swapped. */
+#define ARGS_SWAPPED	0x01
+  /* Inverted immediate. */
+#define INV_IMM		0x02
+  /* Source and destination is register. */
+#define MOVE_REG_CONV	0x04
+  /* Unused return value. */
+#define UNUSED_RETURN	0x08
+/* SET_FLAGS must be (1 << 20) as it is also the value of S bit (can be used for optimization). */
+#define SET_FLAGS	(1 << 20)
+/* dst: reg
+   src1: reg
+   src2: reg or imm (if allowed)
+   SRC2_IMM must be (1 << 25) as it is also the value of I bit (can be used for optimization). */
+#define SRC2_IMM	(1 << 25)
+
+#define EMIT_SHIFT_INS_AND_RETURN(opcode) \
+	SLJIT_ASSERT(!(flags & INV_IMM) && !(src2 & SRC2_IMM)); \
+	if (compiler->shift_imm != 0x20) { \
+		SLJIT_ASSERT(src1 == TMP_REG1); \
+		SLJIT_ASSERT(!(flags & ARGS_SWAPPED)); \
+		\
+		if (compiler->shift_imm != 0) \
+			return push_inst(compiler, MOV | (flags & SET_FLAGS) | \
+				RD(dst) | (compiler->shift_imm << 7) | (opcode << 5) | RM(src2)); \
+		return push_inst(compiler, MOV | (flags & SET_FLAGS) | RD(dst) | RM(src2)); \
+	} \
+	return push_inst(compiler, MOV | (flags & SET_FLAGS) | RD(dst) | \
+		(reg_map[(flags & ARGS_SWAPPED) ? src1 : src2] << 8) | (opcode << 5) | 0x10 | RM((flags & ARGS_SWAPPED) ? src2 : src1));
+
+static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
+	sljit_s32 dst, sljit_s32 src1, sljit_s32 src2)
+{
+	switch (GET_OPCODE(op)) {
+	case SLJIT_MOV:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
+		if (dst != src2) {
+			if (src2 & SRC2_IMM) {
+				return push_inst(compiler, ((flags & INV_IMM) ? MVN : MOV) | RD(dst) | src2);
+			}
+			return push_inst(compiler, MOV | RD(dst) | RM(src2));
+		}
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U8:
+	case SLJIT_MOV_S8:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
+		if (flags & MOVE_REG_CONV) {
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+			if (op == SLJIT_MOV_U8)
+				return push_inst(compiler, AND | RD(dst) | RN(src2) | SRC2_IMM | 0xff);
+			FAIL_IF(push_inst(compiler, MOV | RD(dst) | (24 << 7) | RM(src2)));
+			return push_inst(compiler, MOV | RD(dst) | (24 << 7) | (op == SLJIT_MOV_U8 ? 0x20 : 0x40) | RM(dst));
+#else
+			return push_inst(compiler, (op == SLJIT_MOV_U8 ? UXTB : SXTB) | RD(dst) | RM(src2));
+#endif
+		}
+		else if (dst != src2) {
+			SLJIT_ASSERT(src2 & SRC2_IMM);
+			return push_inst(compiler, ((flags & INV_IMM) ? MVN : MOV) | RD(dst) | src2);
+		}
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U16:
+	case SLJIT_MOV_S16:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
+		if (flags & MOVE_REG_CONV) {
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+			FAIL_IF(push_inst(compiler, MOV | RD(dst) | (16 << 7) | RM(src2)));
+			return push_inst(compiler, MOV | RD(dst) | (16 << 7) | (op == SLJIT_MOV_U16 ? 0x20 : 0x40) | RM(dst));
+#else
+			return push_inst(compiler, (op == SLJIT_MOV_U16 ? UXTH : SXTH) | RD(dst) | RM(src2));
+#endif
+		}
+		else if (dst != src2) {
+			SLJIT_ASSERT(src2 & SRC2_IMM);
+			return push_inst(compiler, ((flags & INV_IMM) ? MVN : MOV) | RD(dst) | src2);
+		}
+		return SLJIT_SUCCESS;
+
+	case SLJIT_NOT:
+		if (src2 & SRC2_IMM) {
+			return push_inst(compiler, ((flags & INV_IMM) ? MOV : MVN) | (flags & SET_FLAGS) | RD(dst) | src2);
+		}
+		return push_inst(compiler, MVN | (flags & SET_FLAGS) | RD(dst) | RM(src2));
+
+	case SLJIT_CLZ:
+		SLJIT_ASSERT(!(flags & INV_IMM));
+		SLJIT_ASSERT(!(src2 & SRC2_IMM));
+		FAIL_IF(push_inst(compiler, CLZ | RD(dst) | RM(src2)));
+		return SLJIT_SUCCESS;
+
+	case SLJIT_ADD:
+		SLJIT_ASSERT(!(flags & INV_IMM));
+		if ((flags & (UNUSED_RETURN | SET_FLAGS)) == (UNUSED_RETURN | SET_FLAGS) && !(flags & ARGS_SWAPPED))
+			return push_inst(compiler, CMN | SET_FLAGS | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));
+		return push_inst(compiler, ADD | (flags & SET_FLAGS) | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));
+
+	case SLJIT_ADDC:
+		SLJIT_ASSERT(!(flags & INV_IMM));
+		return push_inst(compiler, ADC | (flags & SET_FLAGS) | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));
+
+	case SLJIT_SUB:
+		SLJIT_ASSERT(!(flags & INV_IMM));
+		if ((flags & (UNUSED_RETURN | SET_FLAGS)) == (UNUSED_RETURN | SET_FLAGS) && !(flags & ARGS_SWAPPED))
+			return push_inst(compiler, CMP | SET_FLAGS | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));
+		return push_inst(compiler, (!(flags & ARGS_SWAPPED) ? SUB : RSB) | (flags & SET_FLAGS)
+			| RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));
+
+	case SLJIT_SUBC:
+		SLJIT_ASSERT(!(flags & INV_IMM));
+		return push_inst(compiler, (!(flags & ARGS_SWAPPED) ? SBC : RSC) | (flags & SET_FLAGS)
+			| RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));
+
+	case SLJIT_MUL:
+		SLJIT_ASSERT(!(flags & INV_IMM));
+		SLJIT_ASSERT(!(src2 & SRC2_IMM));
+
+		if (!HAS_FLAGS(op))
+			return push_inst(compiler, MUL | (reg_map[dst] << 16) | (reg_map[src2] << 8) | reg_map[src1]);
+
+		FAIL_IF(push_inst(compiler, SMULL | (reg_map[TMP_REG1] << 16) | (reg_map[dst] << 12) | (reg_map[src2] << 8) | reg_map[src1]));
+
+		/* cmp TMP_REG1, dst asr #31. */
+		return push_inst(compiler, CMP | SET_FLAGS | RN(TMP_REG1) | RM(dst) | 0xfc0);
+
+	case SLJIT_AND:
+		return push_inst(compiler, (!(flags & INV_IMM) ? AND : BIC) | (flags & SET_FLAGS)
+			| RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));
+
+	case SLJIT_OR:
+		SLJIT_ASSERT(!(flags & INV_IMM));
+		return push_inst(compiler, ORR | (flags & SET_FLAGS) | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));
+
+	case SLJIT_XOR:
+		SLJIT_ASSERT(!(flags & INV_IMM));
+		return push_inst(compiler, EOR | (flags & SET_FLAGS) | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));
+
+	case SLJIT_SHL:
+		EMIT_SHIFT_INS_AND_RETURN(0);
+
+	case SLJIT_LSHR:
+		EMIT_SHIFT_INS_AND_RETURN(1);
+
+	case SLJIT_ASHR:
+		EMIT_SHIFT_INS_AND_RETURN(2);
+	}
+
+	SLJIT_UNREACHABLE();
+	return SLJIT_SUCCESS;
+}
+
+#undef EMIT_SHIFT_INS_AND_RETURN
+
+/* Tests whether the immediate can be stored in the 12 bit imm field.
+   Returns with 0 if not possible. */
+static sljit_uw get_imm(sljit_uw imm)
+{
+	sljit_s32 rol;
+
+	if (imm <= 0xff)
+		return SRC2_IMM | imm;
+
+	if (!(imm & 0xff000000)) {
+		imm <<= 8;
+		rol = 8;
+	}
+	else {
+		imm = (imm << 24) | (imm >> 8);
+		rol = 0;
+	}
+
+	if (!(imm & 0xff000000)) {
+		imm <<= 8;
+		rol += 4;
+	}
+
+	if (!(imm & 0xf0000000)) {
+		imm <<= 4;
+		rol += 2;
+	}
+
+	if (!(imm & 0xc0000000)) {
+		imm <<= 2;
+		rol += 1;
+	}
+
+	if (!(imm & 0x00ffffff))
+		return SRC2_IMM | (imm >> 24) | (rol << 8);
+	else
+		return 0;
+}
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+static sljit_s32 generate_int(struct sljit_compiler *compiler, sljit_s32 reg, sljit_uw imm, sljit_s32 positive)
+{
+	sljit_uw mask;
+	sljit_uw imm1;
+	sljit_uw imm2;
+	sljit_s32 rol;
+
+	/* Step1: Search a zero byte (8 continous zero bit). */
+	mask = 0xff000000;
+	rol = 8;
+	while(1) {
+		if (!(imm & mask)) {
+			/* Rol imm by rol. */
+			imm = (imm << rol) | (imm >> (32 - rol));
+			/* Calculate arm rol. */
+			rol = 4 + (rol >> 1);
+			break;
+		}
+		rol += 2;
+		mask >>= 2;
+		if (mask & 0x3) {
+			/* rol by 8. */
+			imm = (imm << 8) | (imm >> 24);
+			mask = 0xff00;
+			rol = 24;
+			while (1) {
+				if (!(imm & mask)) {
+					/* Rol imm by rol. */
+					imm = (imm << rol) | (imm >> (32 - rol));
+					/* Calculate arm rol. */
+					rol = (rol >> 1) - 8;
+					break;
+				}
+				rol += 2;
+				mask >>= 2;
+				if (mask & 0x3)
+					return 0;
+			}
+			break;
+		}
+	}
+
+	/* The low 8 bit must be zero. */
+	SLJIT_ASSERT(!(imm & 0xff));
+
+	if (!(imm & 0xff000000)) {
+		imm1 = SRC2_IMM | ((imm >> 16) & 0xff) | (((rol + 4) & 0xf) << 8);
+		imm2 = SRC2_IMM | ((imm >> 8) & 0xff) | (((rol + 8) & 0xf) << 8);
+	}
+	else if (imm & 0xc0000000) {
+		imm1 = SRC2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8);
+		imm <<= 8;
+		rol += 4;
+
+		if (!(imm & 0xff000000)) {
+			imm <<= 8;
+			rol += 4;
+		}
+
+		if (!(imm & 0xf0000000)) {
+			imm <<= 4;
+			rol += 2;
+		}
+
+		if (!(imm & 0xc0000000)) {
+			imm <<= 2;
+			rol += 1;
+		}
+
+		if (!(imm & 0x00ffffff))
+			imm2 = SRC2_IMM | (imm >> 24) | ((rol & 0xf) << 8);
+		else
+			return 0;
+	}
+	else {
+		if (!(imm & 0xf0000000)) {
+			imm <<= 4;
+			rol += 2;
+		}
+
+		if (!(imm & 0xc0000000)) {
+			imm <<= 2;
+			rol += 1;
+		}
+
+		imm1 = SRC2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8);
+		imm <<= 8;
+		rol += 4;
+
+		if (!(imm & 0xf0000000)) {
+			imm <<= 4;
+			rol += 2;
+		}
+
+		if (!(imm & 0xc0000000)) {
+			imm <<= 2;
+			rol += 1;
+		}
+
+		if (!(imm & 0x00ffffff))
+			imm2 = SRC2_IMM | (imm >> 24) | ((rol & 0xf) << 8);
+		else
+			return 0;
+	}
+
+	FAIL_IF(push_inst(compiler, (positive ? MOV : MVN) | RD(reg) | imm1));
+	FAIL_IF(push_inst(compiler, (positive ? ORR : BIC) | RD(reg) | RN(reg) | imm2));
+	return 1;
+}
+#endif
+
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_uw imm)
+{
+	sljit_uw tmp;
+
+#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+	if (!(imm & ~0xffff))
+		return push_inst(compiler, MOVW | RD(reg) | ((imm << 4) & 0xf0000) | (imm & 0xfff));
+#endif
+
+	/* Create imm by 1 inst. */
+	tmp = get_imm(imm);
+	if (tmp)
+		return push_inst(compiler, MOV | RD(reg) | tmp);
+
+	tmp = get_imm(~imm);
+	if (tmp)
+		return push_inst(compiler, MVN | RD(reg) | tmp);
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+	/* Create imm by 2 inst. */
+	FAIL_IF(generate_int(compiler, reg, imm, 1));
+	FAIL_IF(generate_int(compiler, reg, ~imm, 0));
+
+	/* Load integer. */
+	return push_inst_with_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, reg, TMP_PC, 0), imm);
+#else
+	FAIL_IF(push_inst(compiler, MOVW | RD(reg) | ((imm << 4) & 0xf0000) | (imm & 0xfff)));
+	if (imm <= 0xffff)
+		return SLJIT_SUCCESS;
+	return push_inst(compiler, MOVT | RD(reg) | ((imm >> 12) & 0xf0000) | ((imm >> 16) & 0xfff));
+#endif
+}
+
+static SLJIT_INLINE sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg,
+	sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg)
+{
+	sljit_uw imm, offset_reg;
+	sljit_uw is_type1_transfer = IS_TYPE1_TRANSFER(flags);
+
+	SLJIT_ASSERT (arg & SLJIT_MEM);
+	SLJIT_ASSERT((arg & REG_MASK) != tmp_reg);
+
+	if ((arg & REG_MASK) == SLJIT_UNUSED) {
+		if (is_type1_transfer) {
+			FAIL_IF(load_immediate(compiler, tmp_reg, argw & ~0xfff));
+			argw &= 0xfff;
+		}
+		else {
+			FAIL_IF(load_immediate(compiler, tmp_reg, argw & ~0xff));
+			argw &= 0xff;
+		}
+
+		return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, reg, tmp_reg,
+			is_type1_transfer ? argw : TYPE2_TRANSFER_IMM(argw)));
+	}
+
+	if (arg & OFFS_REG_MASK) {
+		offset_reg = OFFS_REG(arg);
+		arg &= REG_MASK;
+		argw &= 0x3;
+
+		if (argw != 0 && !is_type1_transfer) {
+			FAIL_IF(push_inst(compiler, ADD | RD(tmp_reg) | RN(arg) | RM(offset_reg) | (argw << 7)));
+			return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, reg, tmp_reg, TYPE2_TRANSFER_IMM(0)));
+		}
+
+		/* Bit 25: RM is offset. */
+		return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, reg, arg,
+			RM(offset_reg) | (is_type1_transfer ? (1 << 25) : 0) | (argw << 7)));
+	}
+
+	arg &= REG_MASK;
+
+	if (is_type1_transfer) {
+		if (argw > 0xfff) {
+			imm = get_imm(argw & ~0xfff);
+			if (imm) {
+				FAIL_IF(push_inst(compiler, ADD | RD(tmp_reg) | RN(arg) | imm));
+				argw = argw & 0xfff;
+				arg = tmp_reg;
+			}
+		}
+		else if (argw < -0xfff) {
+			imm = get_imm(-argw & ~0xfff);
+			if (imm) {
+				FAIL_IF(push_inst(compiler, SUB | RD(tmp_reg) | RN(arg) | imm));
+				argw = -(-argw & 0xfff);
+				arg = tmp_reg;
+			}
+		}
+
+		if (argw >= 0 && argw <= 0xfff)
+			return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, reg, arg, argw));
+
+		if (argw < 0 && argw >= -0xfff)
+			return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 0, reg, arg, -argw));
+	}
+	else {
+		if (argw > 0xff) {
+			imm = get_imm(argw & ~0xff);
+			if (imm) {
+				FAIL_IF(push_inst(compiler, ADD | RD(tmp_reg) | RN(arg) | imm));
+				argw = argw & 0xff;
+				arg = tmp_reg;
+			}
+		}
+		else if (argw < -0xff) {
+			imm = get_imm(-argw & ~0xff);
+			if (imm) {
+				FAIL_IF(push_inst(compiler, SUB | RD(tmp_reg) | RN(arg) | imm));
+				argw = -(-argw & 0xff);
+				arg = tmp_reg;
+			}
+		}
+
+		if (argw >= 0 && argw <= 0xff)
+			return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, reg, arg, TYPE2_TRANSFER_IMM(argw)));
+
+		if (argw < 0 && argw >= -0xff) {
+			argw = -argw;
+			return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 0, reg, arg, TYPE2_TRANSFER_IMM(argw)));
+		}
+	}
+
+	FAIL_IF(load_immediate(compiler, tmp_reg, argw));
+	return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, reg, arg,
+		RM(tmp_reg) | (is_type1_transfer ? (1 << 25) : 0)));
+}
+
+static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 inp_flags,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	/* src1 is reg or TMP_REG1
+	   src2 is reg, TMP_REG2, or imm
+	   result goes to TMP_REG2, so put result can use TMP_REG1. */
+
+	/* We prefers register and simple consts. */
+	sljit_s32 dst_reg;
+	sljit_s32 src1_reg;
+	sljit_s32 src2_reg;
+	sljit_s32 flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
+
+	/* Destination check. */
+	if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED))
+		flags |= UNUSED_RETURN;
+
+	SLJIT_ASSERT(!(inp_flags & ALLOW_INV_IMM) || (inp_flags & ALLOW_IMM));
+
+	src2_reg = 0;
+
+	do {
+		if (!(inp_flags & ALLOW_IMM))
+			break;
+
+		if (src2 & SLJIT_IMM) {
+			src2_reg = get_imm(src2w);
+			if (src2_reg)
+				break;
+			if (inp_flags & ALLOW_INV_IMM) {
+				src2_reg = get_imm(~src2w);
+				if (src2_reg) {
+					flags |= INV_IMM;
+					break;
+				}
+			}
+			if (GET_OPCODE(op) == SLJIT_ADD) {
+				src2_reg = get_imm(-src2w);
+				if (src2_reg) {
+					op = SLJIT_SUB | GET_ALL_FLAGS(op);
+					break;
+				}
+			}
+			if (GET_OPCODE(op) == SLJIT_SUB) {
+				src2_reg = get_imm(-src2w);
+				if (src2_reg) {
+					op = SLJIT_ADD | GET_ALL_FLAGS(op);
+					break;
+				}
+			}
+		}
+
+		if (src1 & SLJIT_IMM) {
+			src2_reg = get_imm(src1w);
+			if (src2_reg) {
+				flags |= ARGS_SWAPPED;
+				src1 = src2;
+				src1w = src2w;
+				break;
+			}
+			if (inp_flags & ALLOW_INV_IMM) {
+				src2_reg = get_imm(~src1w);
+				if (src2_reg) {
+					flags |= ARGS_SWAPPED | INV_IMM;
+					src1 = src2;
+					src1w = src2w;
+					break;
+				}
+			}
+			if (GET_OPCODE(op) == SLJIT_ADD) {
+				src2_reg = get_imm(-src1w);
+				if (src2_reg) {
+					/* Note: add is commutative operation. */
+					src1 = src2;
+					src1w = src2w;
+					op = SLJIT_SUB | GET_ALL_FLAGS(op);
+					break;
+				}
+			}
+		}
+	} while(0);
+
+	/* Source 1. */
+	if (FAST_IS_REG(src1))
+		src1_reg = src1;
+	else if (src1 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1));
+		src1_reg = TMP_REG1;
+	}
+	else {
+		FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
+		src1_reg = TMP_REG1;
+	}
+
+	/* Destination. */
+	dst_reg = SLOW_IS_REG(dst) ? dst : TMP_REG2;
+
+	if (op <= SLJIT_MOV_P) {
+		if (dst & SLJIT_MEM) {
+			if (inp_flags & BYTE_SIZE)
+				inp_flags &= ~SIGNED;
+
+			if (FAST_IS_REG(src2))
+				return emit_op_mem(compiler, inp_flags, src2, dst, dstw, TMP_REG2);
+		}
+
+		if (FAST_IS_REG(src2) && dst_reg != TMP_REG2)
+			flags |= MOVE_REG_CONV;
+	}
+
+	/* Source 2. */
+	if (src2_reg == 0) {
+		src2_reg = (op <= SLJIT_MOV_P) ? dst_reg : TMP_REG2;
+
+		if (FAST_IS_REG(src2))
+			src2_reg = src2;
+		else if (src2 & SLJIT_MEM)
+			FAIL_IF(emit_op_mem(compiler, inp_flags | LOAD_DATA, src2_reg, src2, src2w, TMP_REG2));
+		else
+			FAIL_IF(load_immediate(compiler, src2_reg, src2w));
+	}
+
+	FAIL_IF(emit_single_op(compiler, op, flags, dst_reg, src1_reg, src2_reg));
+
+	if (!(dst & SLJIT_MEM))
+		return SLJIT_SUCCESS;
+
+	return emit_op_mem(compiler, inp_flags, dst_reg, dst, dstw, TMP_REG1);
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__GNUC__)
+extern unsigned int __aeabi_uidivmod(unsigned int numerator, unsigned int denominator);
+extern int __aeabi_idivmod(int numerator, int denominator);
+#else
+#error "Software divmod functions are needed"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
+{
+	sljit_sw saved_reg_list[3];
+	sljit_sw saved_reg_count;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op0(compiler, op));
+
+	op = GET_OPCODE(op);
+	switch (op) {
+	case SLJIT_BREAKPOINT:
+		FAIL_IF(push_inst(compiler, BKPT));
+		break;
+	case SLJIT_NOP:
+		FAIL_IF(push_inst(compiler, NOP));
+		break;
+	case SLJIT_LMUL_UW:
+	case SLJIT_LMUL_SW:
+		return push_inst(compiler, (op == SLJIT_LMUL_UW ? UMULL : SMULL)
+			| (reg_map[SLJIT_R1] << 16)
+			| (reg_map[SLJIT_R0] << 12)
+			| (reg_map[SLJIT_R0] << 8)
+			| reg_map[SLJIT_R1]);
+	case SLJIT_DIVMOD_UW:
+	case SLJIT_DIVMOD_SW:
+	case SLJIT_DIV_UW:
+	case SLJIT_DIV_SW:
+		SLJIT_COMPILE_ASSERT((SLJIT_DIVMOD_UW & 0x2) == 0 && SLJIT_DIV_UW - 0x2 == SLJIT_DIVMOD_UW, bad_div_opcode_assignments);
+		SLJIT_ASSERT(reg_map[2] == 1 && reg_map[3] == 2 && reg_map[4] == 3);
+
+		saved_reg_count = 0;
+		if (compiler->scratches >= 4)
+			saved_reg_list[saved_reg_count++] = 3;
+		if (compiler->scratches >= 3)
+			saved_reg_list[saved_reg_count++] = 2;
+		if (op >= SLJIT_DIV_UW)
+			saved_reg_list[saved_reg_count++] = 1;
+
+		if (saved_reg_count > 0) {
+			FAIL_IF(push_inst(compiler, 0xe52d0000 | (saved_reg_count >= 3 ? 16 : 8)
+						| (saved_reg_list[0] << 12) /* str rX, [sp, #-8/-16]! */));
+			if (saved_reg_count >= 2) {
+				SLJIT_ASSERT(saved_reg_list[1] < 8);
+				FAIL_IF(push_inst(compiler, 0xe58d0004 | (saved_reg_list[1] << 12) /* str rX, [sp, #4] */));
+			}
+			if (saved_reg_count >= 3) {
+				SLJIT_ASSERT(saved_reg_list[2] < 8);
+				FAIL_IF(push_inst(compiler, 0xe58d0008 | (saved_reg_list[2] << 12) /* str rX, [sp, #8] */));
+			}
+		}
+
+#if defined(__GNUC__)
+		FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM,
+			((op | 0x2) == SLJIT_DIV_UW ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod))));
+#else
+#error "Software divmod functions are needed"
+#endif
+
+		if (saved_reg_count > 0) {
+			if (saved_reg_count >= 3) {
+				SLJIT_ASSERT(saved_reg_list[2] < 8);
+				FAIL_IF(push_inst(compiler, 0xe59d0008 | (saved_reg_list[2] << 12) /* ldr rX, [sp, #8] */));
+			}
+			if (saved_reg_count >= 2) {
+				SLJIT_ASSERT(saved_reg_list[1] < 8);
+				FAIL_IF(push_inst(compiler, 0xe59d0004 | (saved_reg_list[1] << 12) /* ldr rX, [sp, #4] */));
+			}
+			return push_inst(compiler, 0xe49d0000 | (saved_reg_count >= 3 ? 16 : 8)
+						| (saved_reg_list[0] << 12) /* ldr rX, [sp], #8/16 */);
+		}
+		return SLJIT_SUCCESS;
+	case SLJIT_ENDBR:
+	case SLJIT_SKIP_FRAMES_BEFORE_RETURN:
+		return SLJIT_SUCCESS;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_U32:
+	case SLJIT_MOV_S32:
+	case SLJIT_MOV_P:
+		return emit_op(compiler, SLJIT_MOV, ALLOW_ANY_IMM, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_MOV_U8:
+		return emit_op(compiler, SLJIT_MOV_U8, ALLOW_ANY_IMM | BYTE_SIZE, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8)srcw : srcw);
+
+	case SLJIT_MOV_S8:
+		return emit_op(compiler, SLJIT_MOV_S8, ALLOW_ANY_IMM | SIGNED | BYTE_SIZE, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8)srcw : srcw);
+
+	case SLJIT_MOV_U16:
+		return emit_op(compiler, SLJIT_MOV_U16, ALLOW_ANY_IMM | HALF_SIZE, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16)srcw : srcw);
+
+	case SLJIT_MOV_S16:
+		return emit_op(compiler, SLJIT_MOV_S16, ALLOW_ANY_IMM | SIGNED | HALF_SIZE, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16)srcw : srcw);
+
+	case SLJIT_NOT:
+		return emit_op(compiler, op, ALLOW_ANY_IMM, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_NEG:
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+			|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+		compiler->skip_checks = 1;
+#endif
+		return sljit_emit_op2(compiler, SLJIT_SUB | GET_ALL_FLAGS(op), dst, dstw, SLJIT_IMM, 0, src, srcw);
+
+	case SLJIT_CLZ:
+		return emit_op(compiler, op, 0, dst, dstw, TMP_REG1, 0, src, srcw);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
+		return SLJIT_SUCCESS;
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_ADD:
+	case SLJIT_ADDC:
+	case SLJIT_SUB:
+	case SLJIT_SUBC:
+	case SLJIT_OR:
+	case SLJIT_XOR:
+		return emit_op(compiler, op, ALLOW_IMM, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_MUL:
+		return emit_op(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_AND:
+		return emit_op(compiler, op, ALLOW_ANY_IMM, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_SHL:
+	case SLJIT_LSHR:
+	case SLJIT_ASHR:
+		if (src2 & SLJIT_IMM) {
+			compiler->shift_imm = src2w & 0x1f;
+			return emit_op(compiler, op, 0, dst, dstw, TMP_REG1, 0, src1, src1w);
+		}
+		else {
+			compiler->shift_imm = 0x20;
+			return emit_op(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w);
+		}
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_src(compiler, op, src, srcw));
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	switch (op) {
+	case SLJIT_FAST_RETURN:
+		SLJIT_ASSERT(reg_map[TMP_REG2] == 14);
+
+		if (FAST_IS_REG(src))
+			FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG2) | RM(src)));
+		else
+			FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG2, src, srcw, TMP_REG1));
+
+		return push_inst(compiler, BX | RM(TMP_REG2));
+	case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN:
+		return SLJIT_SUCCESS;
+	case SLJIT_PREFETCH_L1:
+	case SLJIT_PREFETCH_L2:
+	case SLJIT_PREFETCH_L3:
+	case SLJIT_PREFETCH_ONCE:
+#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+		SLJIT_ASSERT(src & SLJIT_MEM);
+		return emit_op_mem(compiler, PRELOAD | LOAD_DATA, TMP_PC, src, srcw, TMP_REG1);
+#else /* !SLJIT_CONFIG_ARM_V7 */
+		return SLJIT_SUCCESS;
+#endif /* SLJIT_CONFIG_ARM_V7 */
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+{
+	CHECK_REG_INDEX(check_sljit_get_register_index(reg));
+	return reg_map[reg];
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
+{
+	CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
+	return (freg_map[reg] << 1);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+	void *instruction, sljit_s32 size)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
+
+	return push_inst(compiler, *(sljit_uw*)instruction);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Floating point operators                                             */
+/* --------------------------------------------------------------------- */
+
+
+#define FPU_LOAD (1 << 20)
+#define EMIT_FPU_DATA_TRANSFER(inst, add, base, freg, offs) \
+	((inst) | ((add) << 23) | (reg_map[base] << 16) | (freg_map[freg] << 12) | (offs))
+#define EMIT_FPU_OPERATION(opcode, mode, dst, src1, src2) \
+	((opcode) | (mode) | (freg_map[dst] << 12) | freg_map[src1] | (freg_map[src2] << 16))
+
+static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
+{
+	sljit_uw imm;
+	sljit_sw inst = VSTR_F32 | (flags & (SLJIT_F32_OP | FPU_LOAD));
+
+	SLJIT_ASSERT(arg & SLJIT_MEM);
+	arg &= ~SLJIT_MEM;
+
+	if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
+		FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG2) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | ((argw & 0x3) << 7)));
+		arg = TMP_REG2;
+		argw = 0;
+	}
+
+	/* Fast loads and stores. */
+	if (arg) {
+		if (!(argw & ~0x3fc))
+			return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, arg & REG_MASK, reg, argw >> 2));
+		if (!(-argw & ~0x3fc))
+			return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 0, arg & REG_MASK, reg, (-argw) >> 2));
+
+		imm = get_imm(argw & ~0x3fc);
+		if (imm) {
+			FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG2) | RN(arg & REG_MASK) | imm));
+			return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG2, reg, (argw & 0x3fc) >> 2));
+		}
+		imm = get_imm(-argw & ~0x3fc);
+		if (imm) {
+			argw = -argw;
+			FAIL_IF(push_inst(compiler, SUB | RD(TMP_REG2) | RN(arg & REG_MASK) | imm));
+			return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 0, TMP_REG2, reg, (argw & 0x3fc) >> 2));
+		}
+	}
+
+	if (arg) {
+		FAIL_IF(load_immediate(compiler, TMP_REG2, argw));
+		FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG2) | RN(arg & REG_MASK) | RM(TMP_REG2)));
+	}
+	else
+		FAIL_IF(load_immediate(compiler, TMP_REG2, argw));
+
+	return push_inst(compiler, EMIT_FPU_DATA_TRANSFER(inst, 1, TMP_REG2, reg, 0));
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	op ^= SLJIT_F32_OP;
+
+	if (src & SLJIT_MEM) {
+		FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG1, src, srcw));
+		src = TMP_FREG1;
+	}
+
+	FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCVT_S32_F32, op & SLJIT_F32_OP, TMP_FREG1, src, 0)));
+
+	if (FAST_IS_REG(dst))
+		return push_inst(compiler, VMOV | (1 << 20) | RD(dst) | (freg_map[TMP_FREG1] << 16));
+
+	/* Store the integer value from a VFP register. */
+	return emit_fop_mem(compiler, 0, TMP_FREG1, dst, dstw);
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	op ^= SLJIT_F32_OP;
+
+	if (FAST_IS_REG(src))
+		FAIL_IF(push_inst(compiler, VMOV | RD(src) | (freg_map[TMP_FREG1] << 16)));
+	else if (src & SLJIT_MEM) {
+		/* Load the integer value into a VFP register. */
+		FAIL_IF(emit_fop_mem(compiler, FPU_LOAD, TMP_FREG1, src, srcw));
+	}
+	else {
+		FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+		FAIL_IF(push_inst(compiler, VMOV | RD(TMP_REG1) | (freg_map[TMP_FREG1] << 16)));
+	}
+
+	FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCVT_F32_S32, op & SLJIT_F32_OP, dst_r, TMP_FREG1, 0)));
+
+	if (dst & SLJIT_MEM)
+		return emit_fop_mem(compiler, (op & SLJIT_F32_OP), TMP_FREG1, dst, dstw);
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	op ^= SLJIT_F32_OP;
+
+	if (src1 & SLJIT_MEM) {
+		FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG1, src1, src1w));
+		src1 = TMP_FREG1;
+	}
+
+	if (src2 & SLJIT_MEM) {
+		FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG2, src2, src2w));
+		src2 = TMP_FREG2;
+	}
+
+	FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCMP_F32, op & SLJIT_F32_OP, src1, src2, 0)));
+	return push_inst(compiler, VMRS);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r;
+
+	CHECK_ERROR();
+
+	SLJIT_COMPILE_ASSERT((SLJIT_F32_OP == 0x100), float_transfer_bit_error);
+	SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	if (GET_OPCODE(op) != SLJIT_CONV_F64_FROM_F32)
+		op ^= SLJIT_F32_OP;
+
+	if (src & SLJIT_MEM) {
+		FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, dst_r, src, srcw));
+		src = dst_r;
+	}
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_MOV_F64:
+		if (src != dst_r) {
+			if (dst_r != TMP_FREG1)
+				FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMOV_F32, op & SLJIT_F32_OP, dst_r, src, 0)));
+			else
+				dst_r = src;
+		}
+		break;
+	case SLJIT_NEG_F64:
+		FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VNEG_F32, op & SLJIT_F32_OP, dst_r, src, 0)));
+		break;
+	case SLJIT_ABS_F64:
+		FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VABS_F32, op & SLJIT_F32_OP, dst_r, src, 0)));
+		break;
+	case SLJIT_CONV_F64_FROM_F32:
+		FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCVT_F64_F32, op & SLJIT_F32_OP, dst_r, src, 0)));
+		op ^= SLJIT_F32_OP;
+		break;
+	}
+
+	if (dst & SLJIT_MEM)
+		return emit_fop_mem(compiler, (op & SLJIT_F32_OP), dst_r, dst, dstw);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_s32 dst_r;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	op ^= SLJIT_F32_OP;
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	if (src2 & SLJIT_MEM) {
+		FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG2, src2, src2w));
+		src2 = TMP_FREG2;
+	}
+
+	if (src1 & SLJIT_MEM) {
+		FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG1, src1, src1w));
+		src1 = TMP_FREG1;
+	}
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_ADD_F64:
+		FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VADD_F32, op & SLJIT_F32_OP, dst_r, src2, src1)));
+		break;
+
+	case SLJIT_SUB_F64:
+		FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VSUB_F32, op & SLJIT_F32_OP, dst_r, src2, src1)));
+		break;
+
+	case SLJIT_MUL_F64:
+		FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMUL_F32, op & SLJIT_F32_OP, dst_r, src2, src1)));
+		break;
+
+	case SLJIT_DIV_F64:
+		FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VDIV_F32, op & SLJIT_F32_OP, dst_r, src2, src1)));
+		break;
+	}
+
+	if (dst_r == TMP_FREG1)
+		FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_F32_OP), TMP_FREG1, dst, dstw));
+
+	return SLJIT_SUCCESS;
+}
+
+#undef FPU_LOAD
+#undef EMIT_FPU_DATA_TRANSFER
+
+/* --------------------------------------------------------------------- */
+/*  Other instructions                                                   */
+/* --------------------------------------------------------------------- */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	SLJIT_ASSERT(reg_map[TMP_REG2] == 14);
+
+	if (FAST_IS_REG(dst))
+		return push_inst(compiler, MOV | RD(dst) | RM(TMP_REG2));
+
+	/* Memory. */
+	return emit_op_mem(compiler, WORD_SIZE, TMP_REG2, dst, dstw, TMP_REG1);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Conditional instructions                                             */
+/* --------------------------------------------------------------------- */
+
+static sljit_uw get_cc(sljit_s32 type)
+{
+	switch (type) {
+	case SLJIT_EQUAL:
+	case SLJIT_MUL_NOT_OVERFLOW:
+	case SLJIT_EQUAL_F64:
+		return 0x00000000;
+
+	case SLJIT_NOT_EQUAL:
+	case SLJIT_MUL_OVERFLOW:
+	case SLJIT_NOT_EQUAL_F64:
+		return 0x10000000;
+
+	case SLJIT_LESS:
+	case SLJIT_LESS_F64:
+		return 0x30000000;
+
+	case SLJIT_GREATER_EQUAL:
+	case SLJIT_GREATER_EQUAL_F64:
+		return 0x20000000;
+
+	case SLJIT_GREATER:
+	case SLJIT_GREATER_F64:
+		return 0x80000000;
+
+	case SLJIT_LESS_EQUAL:
+	case SLJIT_LESS_EQUAL_F64:
+		return 0x90000000;
+
+	case SLJIT_SIG_LESS:
+		return 0xb0000000;
+
+	case SLJIT_SIG_GREATER_EQUAL:
+		return 0xa0000000;
+
+	case SLJIT_SIG_GREATER:
+		return 0xc0000000;
+
+	case SLJIT_SIG_LESS_EQUAL:
+		return 0xd0000000;
+
+	case SLJIT_OVERFLOW:
+	case SLJIT_UNORDERED_F64:
+		return 0x60000000;
+
+	case SLJIT_NOT_OVERFLOW:
+	case SLJIT_ORDERED_F64:
+		return 0x70000000;
+
+	default:
+		SLJIT_ASSERT(type >= SLJIT_JUMP && type <= SLJIT_CALL_CDECL);
+		return 0xe0000000;
+	}
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
+{
+	struct sljit_label *label;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_label(compiler));
+
+	if (compiler->last_label && compiler->last_label->size == compiler->size)
+		return compiler->last_label;
+
+	label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));
+	PTR_FAIL_IF(!label);
+	set_label(label, compiler);
+	return label;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
+{
+	struct sljit_jump *jump;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_jump(compiler, type));
+
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	PTR_FAIL_IF(!jump);
+	set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
+	type &= 0xff;
+
+	SLJIT_ASSERT(reg_map[TMP_REG1] != 14);
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+	if (type >= SLJIT_FAST_CALL)
+		PTR_FAIL_IF(prepare_blx(compiler));
+	PTR_FAIL_IF(push_inst_with_unique_literal(compiler, ((EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1,
+		type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, TMP_PC, 0)) & ~COND_MASK) | get_cc(type), 0));
+
+	if (jump->flags & SLJIT_REWRITABLE_JUMP) {
+		jump->addr = compiler->size;
+		compiler->patches++;
+	}
+
+	if (type >= SLJIT_FAST_CALL) {
+		jump->flags |= IS_BL;
+		PTR_FAIL_IF(emit_blx(compiler));
+	}
+
+	if (!(jump->flags & SLJIT_REWRITABLE_JUMP))
+		jump->addr = compiler->size;
+#else
+	if (type >= SLJIT_FAST_CALL)
+		jump->flags |= IS_BL;
+	PTR_FAIL_IF(emit_imm(compiler, TMP_REG1, 0));
+	PTR_FAIL_IF(push_inst(compiler, (((type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1)) & ~COND_MASK) | get_cc(type)));
+	jump->addr = compiler->size;
+#endif
+	return jump;
+}
+
+#ifdef __SOFTFP__
+
+static sljit_s32 softfloat_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *src)
+{
+	sljit_s32 stack_offset = 0;
+	sljit_s32 arg_count = 0;
+	sljit_s32 word_arg_offset = 0;
+	sljit_s32 float_arg_count = 0;
+	sljit_s32 types = 0;
+	sljit_s32 src_offset = 4 * sizeof(sljit_sw);
+	sljit_u8 offsets[4];
+
+	if (src && FAST_IS_REG(*src))
+		src_offset = reg_map[*src] * sizeof(sljit_sw);
+
+	arg_types >>= SLJIT_DEF_SHIFT;
+
+	while (arg_types) {
+		types = (types << SLJIT_DEF_SHIFT) | (arg_types & SLJIT_DEF_MASK);
+
+		switch (arg_types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			offsets[arg_count] = (sljit_u8)stack_offset;
+			stack_offset += sizeof(sljit_f32);
+			arg_count++;
+			float_arg_count++;
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			if (stack_offset & 0x7)
+				stack_offset += sizeof(sljit_sw);
+			offsets[arg_count] = (sljit_u8)stack_offset;
+			stack_offset += sizeof(sljit_f64);
+			arg_count++;
+			float_arg_count++;
+			break;
+		default:
+			offsets[arg_count] = (sljit_u8)stack_offset;
+			stack_offset += sizeof(sljit_sw);
+			arg_count++;
+			word_arg_offset += sizeof(sljit_sw);
+			break;
+		}
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	if (stack_offset > 16)
+		FAIL_IF(push_inst(compiler, SUB | RD(SLJIT_SP) | RN(SLJIT_SP) | SRC2_IMM | (((stack_offset - 16) + 0x7) & ~0x7)));
+
+	/* Process arguments in reversed direction. */
+	while (types) {
+		switch (types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			arg_count--;
+			float_arg_count--;
+			stack_offset = offsets[arg_count];
+
+			if (stack_offset < 16) {
+				if (src_offset == stack_offset) {
+					FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | (src_offset >> 2)));
+					*src = TMP_REG1;
+				}
+				FAIL_IF(push_inst(compiler, VMOV | 0x100000 | (float_arg_count << 16) | (stack_offset << 10)));
+			} else
+				FAIL_IF(push_inst(compiler, VSTR_F32 | 0x800000 | RN(SLJIT_SP) | (float_arg_count << 12) | ((stack_offset - 16) >> 2)));
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			arg_count--;
+			float_arg_count--;
+			stack_offset = offsets[arg_count];
+
+			SLJIT_ASSERT((stack_offset & 0x7) == 0);
+
+			if (stack_offset < 16) {
+				if (src_offset == stack_offset || src_offset == stack_offset + sizeof(sljit_sw)) {
+					FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | (src_offset >> 2)));
+					*src = TMP_REG1;
+				}
+				FAIL_IF(push_inst(compiler, VMOV2 | 0x100000 | (stack_offset << 10) | ((stack_offset + sizeof(sljit_sw)) << 14) | float_arg_count));
+			} else
+				FAIL_IF(push_inst(compiler, VSTR_F32 | 0x800100 | RN(SLJIT_SP) | (float_arg_count << 12) | ((stack_offset - 16) >> 2)));
+			break;
+		default:
+			arg_count--;
+			word_arg_offset -= sizeof(sljit_sw);
+			stack_offset = offsets[arg_count];
+
+			SLJIT_ASSERT(stack_offset >= word_arg_offset);
+
+			if (stack_offset != word_arg_offset) {
+				if (stack_offset < 16) {
+					if (src_offset == stack_offset) {
+						FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | (src_offset >> 2)));
+						*src = TMP_REG1;
+					}
+					else if (src_offset == word_arg_offset) {
+						*src = 1 + (stack_offset >> 2);
+						src_offset = stack_offset;
+					}
+					FAIL_IF(push_inst(compiler, MOV | (stack_offset << 10) | (word_arg_offset >> 2)));
+				} else
+					FAIL_IF(push_inst(compiler, data_transfer_insts[WORD_SIZE] | 0x800000 | RN(SLJIT_SP) | (word_arg_offset << 10) | (stack_offset - 16)));
+			}
+			break;
+		}
+
+		types >>= SLJIT_DEF_SHIFT;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 softfloat_post_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types)
+{
+	sljit_s32 stack_size = 0;
+
+	if ((arg_types & SLJIT_DEF_MASK) == SLJIT_ARG_TYPE_F32)
+		FAIL_IF(push_inst(compiler, VMOV | (0 << 16) | (0 << 12)));
+	if ((arg_types & SLJIT_DEF_MASK) == SLJIT_ARG_TYPE_F64)
+		FAIL_IF(push_inst(compiler, VMOV2 | (1 << 16) | (0 << 12) | 0));
+
+	arg_types >>= SLJIT_DEF_SHIFT;
+
+	while (arg_types) {
+		switch (arg_types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			stack_size += sizeof(sljit_f32);
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			if (stack_size & 0x7)
+				stack_size += sizeof(sljit_sw);
+			stack_size += sizeof(sljit_f64);
+			break;
+		default:
+			stack_size += sizeof(sljit_sw);
+			break;
+		}
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	if (stack_size <= 16)
+		return SLJIT_SUCCESS;
+
+	return push_inst(compiler, ADD | RD(SLJIT_SP) | RN(SLJIT_SP) | SRC2_IMM | (((stack_size - 16) + 0x7) & ~0x7));
+}
+
+#else /* !__SOFTFP__ */
+
+static sljit_s32 hardfloat_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types)
+{
+	sljit_u32 remap = 0;
+	sljit_u32 offset = 0;
+	sljit_u32 new_offset, mask;
+
+	/* Remove return value. */
+	arg_types >>= SLJIT_DEF_SHIFT;
+
+	while (arg_types) {
+		if ((arg_types & SLJIT_DEF_MASK) == SLJIT_ARG_TYPE_F32) {
+			new_offset = 0;
+			mask = 1;
+
+			while (remap & mask) {
+				new_offset++;
+				mask <<= 1;
+			}
+			remap |= mask;
+
+			if (offset != new_offset)
+				FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMOV_F32,
+					0, (new_offset >> 1) + 1, (offset >> 1) + 1, 0) | ((new_offset & 0x1) ? 0x400000 : 0)));
+
+			offset += 2;
+		}
+		else if ((arg_types & SLJIT_DEF_MASK) == SLJIT_ARG_TYPE_F64) {
+			new_offset = 0;
+			mask = 3;
+
+			while (remap & mask) {
+				new_offset += 2;
+				mask <<= 2;
+			}
+			remap |= mask;
+
+			if (offset != new_offset)
+				FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMOV_F32, SLJIT_F32_OP, (new_offset >> 1) + 1, (offset >> 1) + 1, 0)));
+
+			offset += 2;
+		}
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+#endif /* __SOFTFP__ */
+
+#undef EMIT_FPU_OPERATION
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types)
+{
+#ifdef __SOFTFP__
+	struct sljit_jump *jump;
+#endif
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
+
+#ifdef __SOFTFP__
+	PTR_FAIL_IF(softfloat_call_with_args(compiler, arg_types, NULL));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+
+	jump = sljit_emit_jump(compiler, type);
+	PTR_FAIL_IF(jump == NULL);
+
+	PTR_FAIL_IF(softfloat_post_call_with_args(compiler, arg_types));
+	return jump;
+#else /* !__SOFTFP__ */
+	PTR_FAIL_IF(hardfloat_call_with_args(compiler, arg_types));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+
+	return sljit_emit_jump(compiler, type);
+#endif /* __SOFTFP__ */
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
+{
+	struct sljit_jump *jump;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	SLJIT_ASSERT(reg_map[TMP_REG1] != 14);
+
+	if (!(src & SLJIT_IMM)) {
+		if (FAST_IS_REG(src)) {
+			SLJIT_ASSERT(reg_map[src] != 14);
+			return push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(src));
+		}
+
+		SLJIT_ASSERT(src & SLJIT_MEM);
+		FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
+		return push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1));
+	}
+
+	/* These jumps are converted to jump/call instructions when possible. */
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	FAIL_IF(!jump);
+	set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_BL : 0));
+	jump->u.target = srcw;
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+	if (type >= SLJIT_FAST_CALL)
+		FAIL_IF(prepare_blx(compiler));
+	FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, TMP_PC, 0), 0));
+	if (type >= SLJIT_FAST_CALL)
+		FAIL_IF(emit_blx(compiler));
+#else
+	FAIL_IF(emit_imm(compiler, TMP_REG1, 0));
+	FAIL_IF(push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1)));
+#endif
+	jump->addr = compiler->size;
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
+
+#ifdef __SOFTFP__
+	if (src & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
+		src = TMP_REG1;
+	}
+
+	FAIL_IF(softfloat_call_with_args(compiler, arg_types, &src));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+
+	FAIL_IF(sljit_emit_ijump(compiler, type, src, srcw));
+
+	return softfloat_post_call_with_args(compiler, arg_types);
+#else /* !__SOFTFP__ */
+	FAIL_IF(hardfloat_call_with_args(compiler, arg_types));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+
+	return sljit_emit_ijump(compiler, type, src, srcw);
+#endif /* __SOFTFP__ */
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 type)
+{
+	sljit_s32 dst_reg, flags = GET_ALL_FLAGS(op);
+	sljit_uw cc, ins;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	op = GET_OPCODE(op);
+	cc = get_cc(type & 0xff);
+	dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG1;
+
+	if (op < SLJIT_ADD) {
+		FAIL_IF(push_inst(compiler, MOV | RD(dst_reg) | SRC2_IMM | 0));
+		FAIL_IF(push_inst(compiler, ((MOV | RD(dst_reg) | SRC2_IMM | 1) & ~COND_MASK) | cc));
+		if (dst & SLJIT_MEM)
+			return emit_op_mem(compiler, WORD_SIZE, TMP_REG1, dst, dstw, TMP_REG2);
+		return SLJIT_SUCCESS;
+	}
+
+	ins = (op == SLJIT_AND ? AND : (op == SLJIT_OR ? ORR : EOR));
+
+	if (dst & SLJIT_MEM)
+		FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, dst, dstw, TMP_REG2));
+
+	FAIL_IF(push_inst(compiler, ((ins | RD(dst_reg) | RN(dst_reg) | SRC2_IMM | 1) & ~COND_MASK) | cc));
+
+	if (op == SLJIT_AND)
+		FAIL_IF(push_inst(compiler, ((ins | RD(dst_reg) | RN(dst_reg) | SRC2_IMM | 0) & ~COND_MASK) | (cc ^ 0x10000000)));
+
+	if (dst & SLJIT_MEM)
+		FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, dst, dstw, TMP_REG2));
+
+	if (flags & SLJIT_SET_Z)
+		return push_inst(compiler, MOV | SET_FLAGS | RD(TMP_REG2) | RM(dst_reg));
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 dst_reg,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_uw cc, tmp;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+
+	dst_reg &= ~SLJIT_I32_OP;
+
+	cc = get_cc(type & 0xff);
+
+	if (SLJIT_UNLIKELY(src & SLJIT_IMM)) {
+		tmp = get_imm(srcw);
+		if (tmp)
+			return push_inst(compiler, ((MOV | RD(dst_reg) | tmp) & ~COND_MASK) | cc);
+
+		tmp = get_imm(~srcw);
+		if (tmp)
+			return push_inst(compiler, ((MVN | RD(dst_reg) | tmp) & ~COND_MASK) | cc);
+
+#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+		tmp = (sljit_uw) srcw;
+		FAIL_IF(push_inst(compiler, (MOVW & ~COND_MASK) | cc | RD(dst_reg) | ((tmp << 4) & 0xf0000) | (tmp & 0xfff)));
+		if (tmp <= 0xffff)
+			return SLJIT_SUCCESS;
+		return push_inst(compiler, (MOVT & ~COND_MASK) | cc | RD(dst_reg) | ((tmp >> 12) & 0xf0000) | ((tmp >> 16) & 0xfff));
+#else
+		FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+		src = TMP_REG1;
+#endif
+	}
+
+	return push_inst(compiler, ((MOV | RD(dst_reg) | RM(src)) & ~COND_MASK) | cc);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 reg,
+	sljit_s32 mem, sljit_sw memw)
+{
+	sljit_s32 flags;
+	sljit_uw is_type1_transfer, inst;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw));
+
+	is_type1_transfer = 1;
+
+	switch (type & 0xff) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_U32:
+	case SLJIT_MOV_S32:
+	case SLJIT_MOV_P:
+		flags = WORD_SIZE;
+		break;
+	case SLJIT_MOV_U8:
+		flags = BYTE_SIZE;
+		break;
+	case SLJIT_MOV_S8:
+		if (!(type & SLJIT_MEM_STORE))
+			is_type1_transfer = 0;
+		flags = BYTE_SIZE | SIGNED;
+		break;
+	case SLJIT_MOV_U16:
+		is_type1_transfer = 0;
+		flags = HALF_SIZE;
+		break;
+	case SLJIT_MOV_S16:
+		is_type1_transfer = 0;
+		flags = HALF_SIZE | SIGNED;
+		break;
+	default:
+		SLJIT_UNREACHABLE();
+		flags = WORD_SIZE;
+		break;
+	}
+
+	if (!(type & SLJIT_MEM_STORE))
+		flags |= LOAD_DATA;
+
+	SLJIT_ASSERT(is_type1_transfer == !!IS_TYPE1_TRANSFER(flags));
+
+	if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {
+		if (!is_type1_transfer && memw != 0)
+			return SLJIT_ERR_UNSUPPORTED;
+	}
+	else {
+		if (is_type1_transfer) {
+			if (memw > 4095 || memw < -4095)
+				return SLJIT_ERR_UNSUPPORTED;
+		}
+		else {
+			if (memw > 255 || memw < -255)
+				return SLJIT_ERR_UNSUPPORTED;
+		}
+	}
+
+	if (type & SLJIT_MEM_SUPP)
+		return SLJIT_SUCCESS;
+
+	if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {
+		memw &= 0x3;
+
+		inst = EMIT_DATA_TRANSFER(flags, 1, reg, mem & REG_MASK, RM(OFFS_REG(mem)) | (memw << 7));
+
+		if (is_type1_transfer)
+			inst |= (1 << 25);
+
+		if (type & SLJIT_MEM_PRE)
+			inst |= (1 << 21);
+		else
+			inst ^= (1 << 24);
+
+		return push_inst(compiler, inst);
+	}
+
+	inst = EMIT_DATA_TRANSFER(flags, 0, reg, mem & REG_MASK, 0);
+
+	if (type & SLJIT_MEM_PRE)
+		inst |= (1 << 21);
+	else
+		inst ^= (1 << 24);
+
+	if (is_type1_transfer) {
+		if (memw >= 0)
+			inst |= (1 << 23);
+		else
+			memw = -memw;
+
+		return push_inst(compiler, inst | memw);
+	}
+
+	if (memw >= 0)
+		inst |= (1 << 23);
+	else
+		memw = -memw;
+
+	return push_inst(compiler, inst | TYPE2_TRANSFER_IMM(memw));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
+{
+	struct sljit_const *const_;
+	sljit_s32 dst_r;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	dst_r = SLOW_IS_REG(dst) ? dst : TMP_REG2;
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+	PTR_FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, dst_r, TMP_PC, 0), init_value));
+	compiler->patches++;
+#else
+	PTR_FAIL_IF(emit_imm(compiler, dst_r, init_value));
+#endif
+
+	const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
+	PTR_FAIL_IF(!const_);
+	set_const(const_, compiler);
+
+	if (dst & SLJIT_MEM)
+		PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, dst, dstw, TMP_REG1));
+	return const_;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	struct sljit_put_label *put_label;
+	sljit_s32 dst_r;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	dst_r = SLOW_IS_REG(dst) ? dst : TMP_REG2;
+
+#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+	PTR_FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, dst_r, TMP_PC, 0), 0));
+	compiler->patches++;
+#else
+	PTR_FAIL_IF(emit_imm(compiler, dst_r, 0));
+#endif
+
+	put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label));
+	PTR_FAIL_IF(!put_label);
+	set_put_label(put_label, compiler, 0);
+
+	if (dst & SLJIT_MEM)
+		PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, dst, dstw, TMP_REG1));
+	return put_label;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
+{
+	inline_set_jump_addr(addr, executable_offset, new_target, 1);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
+{
+	inline_set_const(addr, executable_offset, new_constant, 1);
+}
diff --git a/src/c/pcre2/src/sljit/sljitNativeARM_64.c b/src/c/pcre2/src/sljit/sljitNativeARM_64.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitNativeARM_64.c
@@ -0,0 +1,2048 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
+{
+	return "ARM-64" SLJIT_CPUINFO;
+}
+
+/* Length of an instruction word */
+typedef sljit_u32 sljit_ins;
+
+#define TMP_ZERO	(0)
+
+#define TMP_REG1	(SLJIT_NUMBER_OF_REGISTERS + 2)
+#define TMP_REG2	(SLJIT_NUMBER_OF_REGISTERS + 3)
+#define TMP_LR		(SLJIT_NUMBER_OF_REGISTERS + 4)
+#define TMP_FP		(SLJIT_NUMBER_OF_REGISTERS + 5)
+
+#define TMP_FREG1	(SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
+#define TMP_FREG2	(SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2)
+
+/* r18 - platform register, currently not used */
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 8] = {
+	31, 0, 1, 2, 3, 4, 5, 6, 7, 11, 12, 13, 14, 15, 16, 17, 8, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 31, 9, 10, 30, 29
+};
+
+static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
+	0, 0, 1, 2, 3, 4, 5, 6, 7
+};
+
+#define W_OP (1u << 31)
+#define RD(rd) (reg_map[rd])
+#define RT(rt) (reg_map[rt])
+#define RN(rn) (reg_map[rn] << 5)
+#define RT2(rt2) (reg_map[rt2] << 10)
+#define RM(rm) (reg_map[rm] << 16)
+#define VD(vd) (freg_map[vd])
+#define VT(vt) (freg_map[vt])
+#define VN(vn) (freg_map[vn] << 5)
+#define VM(vm) (freg_map[vm] << 16)
+
+/* --------------------------------------------------------------------- */
+/*  Instrucion forms                                                     */
+/* --------------------------------------------------------------------- */
+
+#define ADC 0x9a000000
+#define ADD 0x8b000000
+#define ADDE 0x8b200000
+#define ADDI 0x91000000
+#define AND 0x8a000000
+#define ANDI 0x92000000
+#define ASRV 0x9ac02800
+#define B 0x14000000
+#define B_CC 0x54000000
+#define BL 0x94000000
+#define BLR 0xd63f0000
+#define BR 0xd61f0000
+#define BRK 0xd4200000
+#define CBZ 0xb4000000
+#define CLZ 0xdac01000
+#define CSEL 0x9a800000
+#define CSINC 0x9a800400
+#define EOR 0xca000000
+#define EORI 0xd2000000
+#define FABS 0x1e60c000
+#define FADD 0x1e602800
+#define FCMP 0x1e602000
+#define FCVT 0x1e224000
+#define FCVTZS 0x9e780000
+#define FDIV 0x1e601800
+#define FMOV 0x1e604000
+#define FMUL 0x1e600800
+#define FNEG 0x1e614000
+#define FSUB 0x1e603800
+#define LDRI 0xf9400000
+#define LDP 0xa9400000
+#define LDP_PRE 0xa9c00000
+#define LDR_PRE 0xf8400c00
+#define LSLV 0x9ac02000
+#define LSRV 0x9ac02400
+#define MADD 0x9b000000
+#define MOVK 0xf2800000
+#define MOVN 0x92800000
+#define MOVZ 0xd2800000
+#define NOP 0xd503201f
+#define ORN 0xaa200000
+#define ORR 0xaa000000
+#define ORRI 0xb2000000
+#define RET 0xd65f0000
+#define SBC 0xda000000
+#define SBFM 0x93000000
+#define SCVTF 0x9e620000
+#define SDIV 0x9ac00c00
+#define SMADDL 0x9b200000
+#define SMULH 0x9b403c00
+#define STP 0xa9000000
+#define STP_PRE 0xa9800000
+#define STRB 0x38206800
+#define STRBI 0x39000000
+#define STRI 0xf9000000
+#define STR_FI 0x3d000000
+#define STR_FR 0x3c206800
+#define STUR_FI 0x3c000000
+#define STURBI 0x38000000
+#define SUB 0xcb000000
+#define SUBI 0xd1000000
+#define SUBS 0xeb000000
+#define UBFM 0xd3000000
+#define UDIV 0x9ac00800
+#define UMULH 0x9bc03c00
+
+/* dest_reg is the absolute name of the register
+   Useful for reordering instructions in the delay slot. */
+static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins)
+{
+	sljit_ins *ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
+	FAIL_IF(!ptr);
+	*ptr = ins;
+	compiler->size++;
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 emit_imm64_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_uw imm)
+{
+	FAIL_IF(push_inst(compiler, MOVZ | RD(dst) | ((imm & 0xffff) << 5)));
+	FAIL_IF(push_inst(compiler, MOVK | RD(dst) | (((imm >> 16) & 0xffff) << 5) | (1 << 21)));
+	FAIL_IF(push_inst(compiler, MOVK | RD(dst) | (((imm >> 32) & 0xffff) << 5) | (2 << 21)));
+	return push_inst(compiler, MOVK | RD(dst) | ((imm >> 48) << 5) | (3 << 21));
+}
+
+static SLJIT_INLINE sljit_sw detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
+{
+	sljit_sw diff;
+	sljit_uw target_addr;
+
+	if (jump->flags & SLJIT_REWRITABLE_JUMP) {
+		jump->flags |= PATCH_ABS64;
+		return 0;
+	}
+
+	if (jump->flags & JUMP_ADDR)
+		target_addr = jump->u.target;
+	else {
+		SLJIT_ASSERT(jump->flags & JUMP_LABEL);
+		target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset;
+	}
+
+	diff = (sljit_sw)target_addr - (sljit_sw)(code_ptr + 4) - executable_offset;
+
+	if (jump->flags & IS_COND) {
+		diff += sizeof(sljit_ins);
+		if (diff <= 0xfffff && diff >= -0x100000) {
+			code_ptr[-5] ^= (jump->flags & IS_CBZ) ? (0x1 << 24) : 0x1;
+			jump->addr -= sizeof(sljit_ins);
+			jump->flags |= PATCH_COND;
+			return 5;
+		}
+		diff -= sizeof(sljit_ins);
+	}
+
+	if (diff <= 0x7ffffff && diff >= -0x8000000) {
+		jump->flags |= PATCH_B;
+		return 4;
+	}
+
+	if (target_addr < 0x100000000l) {
+		if (jump->flags & IS_COND)
+			code_ptr[-5] -= (2 << 5);
+		code_ptr[-2] = code_ptr[0];
+		return 2;
+	}
+
+	if (target_addr < 0x1000000000000l) {
+		if (jump->flags & IS_COND)
+			code_ptr[-5] -= (1 << 5);
+		jump->flags |= PATCH_ABS48;
+		code_ptr[-1] = code_ptr[0];
+		return 1;
+	}
+
+	jump->flags |= PATCH_ABS64;
+	return 0;
+}
+
+static SLJIT_INLINE sljit_sw put_label_get_length(struct sljit_put_label *put_label, sljit_uw max_label)
+{
+	if (max_label < 0x100000000l) {
+		put_label->flags = 0;
+		return 2;
+	}
+
+	if (max_label < 0x1000000000000l) {
+		put_label->flags = 1;
+		return 1;
+	}
+
+	put_label->flags = 2;
+	return 0;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+{
+	struct sljit_memory_fragment *buf;
+	sljit_ins *code;
+	sljit_ins *code_ptr;
+	sljit_ins *buf_ptr;
+	sljit_ins *buf_end;
+	sljit_uw word_count;
+	sljit_uw next_addr;
+	sljit_sw executable_offset;
+	sljit_uw addr;
+	sljit_s32 dst;
+
+	struct sljit_label *label;
+	struct sljit_jump *jump;
+	struct sljit_const *const_;
+	struct sljit_put_label *put_label;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_generate_code(compiler));
+	reverse_buf(compiler);
+
+	code = (sljit_ins*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins), compiler->exec_allocator_data);
+	PTR_FAIL_WITH_EXEC_IF(code);
+	buf = compiler->buf;
+
+	code_ptr = code;
+	word_count = 0;
+	next_addr = 0;
+	executable_offset = SLJIT_EXEC_OFFSET(code);
+
+	label = compiler->labels;
+	jump = compiler->jumps;
+	const_ = compiler->consts;
+	put_label = compiler->put_labels;
+
+	do {
+		buf_ptr = (sljit_ins*)buf->memory;
+		buf_end = buf_ptr + (buf->used_size >> 2);
+		do {
+			*code_ptr = *buf_ptr++;
+			if (next_addr == word_count) {
+				SLJIT_ASSERT(!label || label->size >= word_count);
+				SLJIT_ASSERT(!jump || jump->addr >= word_count);
+				SLJIT_ASSERT(!const_ || const_->addr >= word_count);
+				SLJIT_ASSERT(!put_label || put_label->addr >= word_count);
+
+				/* These structures are ordered by their address. */
+				if (label && label->size == word_count) {
+					label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+					label->size = code_ptr - code;
+					label = label->next;
+				}
+				if (jump && jump->addr == word_count) {
+						jump->addr = (sljit_uw)(code_ptr - 4);
+						code_ptr -= detect_jump_type(jump, code_ptr, code, executable_offset);
+						jump = jump->next;
+				}
+				if (const_ && const_->addr == word_count) {
+					const_->addr = (sljit_uw)code_ptr;
+					const_ = const_->next;
+				}
+				if (put_label && put_label->addr == word_count) {
+					SLJIT_ASSERT(put_label->label);
+					put_label->addr = (sljit_uw)(code_ptr - 3);
+					code_ptr -= put_label_get_length(put_label, (sljit_uw)(SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + put_label->label->size));
+					put_label = put_label->next;
+				}
+				next_addr = compute_next_addr(label, jump, const_, put_label);
+			}
+			code_ptr ++;
+			word_count ++;
+		} while (buf_ptr < buf_end);
+
+		buf = buf->next;
+	} while (buf);
+
+	if (label && label->size == word_count) {
+		label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+		label->size = code_ptr - code;
+		label = label->next;
+	}
+
+	SLJIT_ASSERT(!label);
+	SLJIT_ASSERT(!jump);
+	SLJIT_ASSERT(!const_);
+	SLJIT_ASSERT(!put_label);
+	SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size);
+
+	jump = compiler->jumps;
+	while (jump) {
+		do {
+			addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
+			buf_ptr = (sljit_ins *)jump->addr;
+
+			if (jump->flags & PATCH_B) {
+				addr = (sljit_sw)(addr - (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2;
+				SLJIT_ASSERT((sljit_sw)addr <= 0x1ffffff && (sljit_sw)addr >= -0x2000000);
+				buf_ptr[0] = ((jump->flags & IS_BL) ? BL : B) | (addr & 0x3ffffff);
+				if (jump->flags & IS_COND)
+					buf_ptr[-1] -= (4 << 5);
+				break;
+			}
+			if (jump->flags & PATCH_COND) {
+				addr = (sljit_sw)(addr - (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2;
+				SLJIT_ASSERT((sljit_sw)addr <= 0x3ffff && (sljit_sw)addr >= -0x40000);
+				buf_ptr[0] = (buf_ptr[0] & ~0xffffe0) | ((addr & 0x7ffff) << 5);
+				break;
+			}
+
+			SLJIT_ASSERT((jump->flags & (PATCH_ABS48 | PATCH_ABS64)) || addr <= 0xffffffffl);
+			SLJIT_ASSERT((jump->flags & PATCH_ABS64) || addr <= 0xffffffffffffl);
+
+			dst = buf_ptr[0] & 0x1f;
+			buf_ptr[0] = MOVZ | dst | ((addr & 0xffff) << 5);
+			buf_ptr[1] = MOVK | dst | (((addr >> 16) & 0xffff) << 5) | (1 << 21);
+			if (jump->flags & (PATCH_ABS48 | PATCH_ABS64))
+				buf_ptr[2] = MOVK | dst | (((addr >> 32) & 0xffff) << 5) | (2 << 21);
+			if (jump->flags & PATCH_ABS64)
+				buf_ptr[3] = MOVK | dst | (((addr >> 48) & 0xffff) << 5) | (3 << 21);
+		} while (0);
+		jump = jump->next;
+	}
+
+	put_label = compiler->put_labels;
+	while (put_label) {
+		addr = put_label->label->addr;
+		buf_ptr = (sljit_ins *)put_label->addr;
+
+		buf_ptr[0] |= (addr & 0xffff) << 5;
+		buf_ptr[1] |= ((addr >> 16) & 0xffff) << 5;
+
+		if (put_label->flags >= 1)
+			buf_ptr[2] |= ((addr >> 32) & 0xffff) << 5;
+
+		if (put_label->flags >= 2)
+			buf_ptr[3] |= ((addr >> 48) & 0xffff) << 5;
+
+		put_label = put_label->next;
+	}
+
+	compiler->error = SLJIT_ERR_COMPILED;
+	compiler->executable_offset = executable_offset;
+	compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins);
+
+	code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
+	code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+
+	SLJIT_CACHE_FLUSH(code, code_ptr);
+	SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);
+	return code;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
+{
+	switch (feature_type) {
+	case SLJIT_HAS_FPU:
+#ifdef SLJIT_IS_FPU_AVAILABLE
+		return SLJIT_IS_FPU_AVAILABLE;
+#else
+		/* Available by default. */
+		return 1;
+#endif
+
+	case SLJIT_HAS_CLZ:
+	case SLJIT_HAS_CMOV:
+	case SLJIT_HAS_PREFETCH:
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+/*  Core code generator functions.                                       */
+/* --------------------------------------------------------------------- */
+
+#define COUNT_TRAILING_ZERO(value, result) \
+	result = 0; \
+	if (!(value & 0xffffffff)) { \
+		result += 32; \
+		value >>= 32; \
+	} \
+	if (!(value & 0xffff)) { \
+		result += 16; \
+		value >>= 16; \
+	} \
+	if (!(value & 0xff)) { \
+		result += 8; \
+		value >>= 8; \
+	} \
+	if (!(value & 0xf)) { \
+		result += 4; \
+		value >>= 4; \
+	} \
+	if (!(value & 0x3)) { \
+		result += 2; \
+		value >>= 2; \
+	} \
+	if (!(value & 0x1)) { \
+		result += 1; \
+		value >>= 1; \
+	}
+
+#define LOGICAL_IMM_CHECK 0x100
+
+static sljit_ins logical_imm(sljit_sw imm, sljit_s32 len)
+{
+	sljit_s32 negated, ones, right;
+	sljit_uw mask, uimm;
+	sljit_ins ins;
+
+	if (len & LOGICAL_IMM_CHECK) {
+		len &= ~LOGICAL_IMM_CHECK;
+		if (len == 32 && (imm == 0 || imm == -1))
+			return 0;
+		if (len == 16 && ((sljit_s32)imm == 0 || (sljit_s32)imm == -1))
+			return 0;
+	}
+
+	SLJIT_ASSERT((len == 32 && imm != 0 && imm != -1)
+		|| (len == 16 && (sljit_s32)imm != 0 && (sljit_s32)imm != -1));
+
+	uimm = (sljit_uw)imm;
+	while (1) {
+		if (len <= 0) {
+			SLJIT_UNREACHABLE();
+			return 0;
+		}
+
+		mask = ((sljit_uw)1 << len) - 1;
+		if ((uimm & mask) != ((uimm >> len) & mask))
+			break;
+		len >>= 1;
+	}
+
+	len <<= 1;
+
+	negated = 0;
+	if (uimm & 0x1) {
+		negated = 1;
+		uimm = ~uimm;
+	}
+
+	if (len < 64)
+		uimm &= ((sljit_uw)1 << len) - 1;
+
+	/* Unsigned right shift. */
+	COUNT_TRAILING_ZERO(uimm, right);
+
+	/* Signed shift. We also know that the highest bit is set. */
+	imm = (sljit_sw)~uimm;
+	SLJIT_ASSERT(imm < 0);
+
+	COUNT_TRAILING_ZERO(imm, ones);
+
+	if (~imm)
+		return 0;
+
+	if (len == 64)
+		ins = 1 << 22;
+	else
+		ins = (0x3f - ((len << 1) - 1)) << 10;
+
+	if (negated)
+		return ins | ((len - ones - 1) << 10) | ((len - ones - right) << 16);
+
+	return ins | ((ones - 1) << 10) | ((len - right) << 16);
+}
+
+#undef COUNT_TRAILING_ZERO
+
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw simm)
+{
+	sljit_uw imm = (sljit_uw)simm;
+	sljit_s32 i, zeros, ones, first;
+	sljit_ins bitmask;
+
+	/* Handling simple immediates first. */
+	if (imm <= 0xffff)
+		return push_inst(compiler, MOVZ | RD(dst) | (imm << 5));
+
+	if (simm < 0 && simm >= -0x10000)
+		return push_inst(compiler, MOVN | RD(dst) | ((~imm & 0xffff) << 5));
+
+	if (imm <= 0xffffffffl) {
+		if ((imm & 0xffff) == 0)
+			return push_inst(compiler, MOVZ | RD(dst) | ((imm >> 16) << 5) | (1 << 21));
+		if ((imm & 0xffff0000l) == 0xffff0000)
+			return push_inst(compiler, (MOVN ^ W_OP) | RD(dst) | ((~imm & 0xffff) << 5));
+		if ((imm & 0xffff) == 0xffff)
+			return push_inst(compiler, (MOVN ^ W_OP) | RD(dst) | ((~imm & 0xffff0000l) >> (16 - 5)) | (1 << 21));
+
+		bitmask = logical_imm(simm, 16);
+		if (bitmask != 0)
+			return push_inst(compiler, (ORRI ^ W_OP) | RD(dst) | RN(TMP_ZERO) | bitmask);
+
+		FAIL_IF(push_inst(compiler, MOVZ | RD(dst) | ((imm & 0xffff) << 5)));
+		return push_inst(compiler, MOVK | RD(dst) | ((imm & 0xffff0000l) >> (16 - 5)) | (1 << 21));
+	}
+
+	bitmask = logical_imm(simm, 32);
+	if (bitmask != 0)
+		return push_inst(compiler, ORRI | RD(dst) | RN(TMP_ZERO) | bitmask);
+
+	if (simm < 0 && simm >= -0x100000000l) {
+		if ((imm & 0xffff) == 0xffff)
+			return push_inst(compiler, MOVN | RD(dst) | ((~imm & 0xffff0000l) >> (16 - 5)) | (1 << 21));
+
+		FAIL_IF(push_inst(compiler, MOVN | RD(dst) | ((~imm & 0xffff) << 5)));
+		return push_inst(compiler, MOVK | RD(dst) | ((imm & 0xffff0000l) >> (16 - 5)) | (1 << 21));
+	}
+
+	/* A large amount of number can be constructed from ORR and MOVx, but computing them is costly. */
+
+	zeros = 0;
+	ones = 0;
+	for (i = 4; i > 0; i--) {
+		if ((simm & 0xffff) == 0)
+			zeros++;
+		if ((simm & 0xffff) == 0xffff)
+			ones++;
+		simm >>= 16;
+	}
+
+	simm = (sljit_sw)imm;
+	first = 1;
+	if (ones > zeros) {
+		simm = ~simm;
+		for (i = 0; i < 4; i++) {
+			if (!(simm & 0xffff)) {
+				simm >>= 16;
+				continue;
+			}
+			if (first) {
+				first = 0;
+				FAIL_IF(push_inst(compiler, MOVN | RD(dst) | ((simm & 0xffff) << 5) | (i << 21)));
+			}
+			else
+				FAIL_IF(push_inst(compiler, MOVK | RD(dst) | ((~simm & 0xffff) << 5) | (i << 21)));
+			simm >>= 16;
+		}
+		return SLJIT_SUCCESS;
+	}
+
+	for (i = 0; i < 4; i++) {
+		if (!(simm & 0xffff)) {
+			simm >>= 16;
+			continue;
+		}
+		if (first) {
+			first = 0;
+			FAIL_IF(push_inst(compiler, MOVZ | RD(dst) | ((simm & 0xffff) << 5) | (i << 21)));
+		}
+		else
+			FAIL_IF(push_inst(compiler, MOVK | RD(dst) | ((simm & 0xffff) << 5) | (i << 21)));
+		simm >>= 16;
+	}
+	return SLJIT_SUCCESS;
+}
+
+#define ARG1_IMM	0x0010000
+#define ARG2_IMM	0x0020000
+#define INT_OP		0x0040000
+#define SET_FLAGS	0x0080000
+#define UNUSED_RETURN	0x0100000
+
+#define CHECK_FLAGS(flag_bits) \
+	if (flags & SET_FLAGS) { \
+		inv_bits |= flag_bits; \
+		if (flags & UNUSED_RETURN) \
+			dst = TMP_ZERO; \
+	}
+
+static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 dst, sljit_sw arg1, sljit_sw arg2)
+{
+	/* dst must be register, TMP_REG1
+	   arg1 must be register, TMP_REG1, imm
+	   arg2 must be register, TMP_REG2, imm */
+	sljit_ins inv_bits = (flags & INT_OP) ? W_OP : 0;
+	sljit_ins inst_bits;
+	sljit_s32 op = (flags & 0xffff);
+	sljit_s32 reg;
+	sljit_sw imm, nimm;
+
+	if (SLJIT_UNLIKELY((flags & (ARG1_IMM | ARG2_IMM)) == (ARG1_IMM | ARG2_IMM))) {
+		/* Both are immediates. */
+		flags &= ~ARG1_IMM;
+		if (arg1 == 0 && op != SLJIT_ADD && op != SLJIT_SUB)
+			arg1 = TMP_ZERO;
+		else {
+			FAIL_IF(load_immediate(compiler, TMP_REG1, arg1));
+			arg1 = TMP_REG1;
+		}
+	}
+
+	if (flags & (ARG1_IMM | ARG2_IMM)) {
+		reg = (flags & ARG2_IMM) ? arg1 : arg2;
+		imm = (flags & ARG2_IMM) ? arg2 : arg1;
+
+		switch (op) {
+		case SLJIT_MUL:
+		case SLJIT_NEG:
+		case SLJIT_CLZ:
+		case SLJIT_ADDC:
+		case SLJIT_SUBC:
+			/* No form with immediate operand (except imm 0, which
+			is represented by a ZERO register). */
+			break;
+		case SLJIT_MOV:
+			SLJIT_ASSERT(!(flags & SET_FLAGS) && (flags & ARG2_IMM) && arg1 == TMP_REG1);
+			return load_immediate(compiler, dst, imm);
+		case SLJIT_NOT:
+			SLJIT_ASSERT(flags & ARG2_IMM);
+			FAIL_IF(load_immediate(compiler, dst, (flags & INT_OP) ? (~imm & 0xffffffff) : ~imm));
+			goto set_flags;
+		case SLJIT_SUB:
+			if (flags & ARG1_IMM)
+				break;
+			imm = -imm;
+			/* Fall through. */
+		case SLJIT_ADD:
+			if (imm == 0) {
+				CHECK_FLAGS(1 << 29);
+				return push_inst(compiler, ((op == SLJIT_ADD ? ADDI : SUBI) ^ inv_bits) | RD(dst) | RN(reg));
+			}
+			if (imm > 0 && imm <= 0xfff) {
+				CHECK_FLAGS(1 << 29);
+				return push_inst(compiler, (ADDI ^ inv_bits) | RD(dst) | RN(reg) | (imm << 10));
+			}
+			nimm = -imm;
+			if (nimm > 0 && nimm <= 0xfff) {
+				CHECK_FLAGS(1 << 29);
+				return push_inst(compiler, (SUBI ^ inv_bits) | RD(dst) | RN(reg) | (nimm << 10));
+			}
+			if (imm > 0 && imm <= 0xffffff && !(imm & 0xfff)) {
+				CHECK_FLAGS(1 << 29);
+				return push_inst(compiler, (ADDI ^ inv_bits) | RD(dst) | RN(reg) | ((imm >> 12) << 10) | (1 << 22));
+			}
+			if (nimm > 0 && nimm <= 0xffffff && !(nimm & 0xfff)) {
+				CHECK_FLAGS(1 << 29);
+				return push_inst(compiler, (SUBI ^ inv_bits) | RD(dst) | RN(reg) | ((nimm >> 12) << 10) | (1 << 22));
+			}
+			if (imm > 0 && imm <= 0xffffff && !(flags & SET_FLAGS)) {
+				FAIL_IF(push_inst(compiler, (ADDI ^ inv_bits) | RD(dst) | RN(reg) | ((imm >> 12) << 10) | (1 << 22)));
+				return push_inst(compiler, (ADDI ^ inv_bits) | RD(dst) | RN(dst) | ((imm & 0xfff) << 10));
+			}
+			if (nimm > 0 && nimm <= 0xffffff && !(flags & SET_FLAGS)) {
+				FAIL_IF(push_inst(compiler, (SUBI ^ inv_bits) | RD(dst) | RN(reg) | ((nimm >> 12) << 10) | (1 << 22)));
+				return push_inst(compiler, (SUBI ^ inv_bits) | RD(dst) | RN(dst) | ((nimm & 0xfff) << 10));
+			}
+			break;
+		case SLJIT_AND:
+			inst_bits = logical_imm(imm, LOGICAL_IMM_CHECK | ((flags & INT_OP) ? 16 : 32));
+			if (!inst_bits)
+				break;
+			CHECK_FLAGS(3 << 29);
+			return push_inst(compiler, (ANDI ^ inv_bits) | RD(dst) | RN(reg) | inst_bits);
+		case SLJIT_OR:
+		case SLJIT_XOR:
+			inst_bits = logical_imm(imm, LOGICAL_IMM_CHECK | ((flags & INT_OP) ? 16 : 32));
+			if (!inst_bits)
+				break;
+			if (op == SLJIT_OR)
+				inst_bits |= ORRI;
+			else
+				inst_bits |= EORI;
+			FAIL_IF(push_inst(compiler, (inst_bits ^ inv_bits) | RD(dst) | RN(reg)));
+			goto set_flags;
+		case SLJIT_SHL:
+			if (flags & ARG1_IMM)
+				break;
+			if (flags & INT_OP) {
+				imm &= 0x1f;
+				FAIL_IF(push_inst(compiler, (UBFM ^ inv_bits) | RD(dst) | RN(arg1) | ((-imm & 0x1f) << 16) | ((31 - imm) << 10)));
+			}
+			else {
+				imm &= 0x3f;
+				FAIL_IF(push_inst(compiler, (UBFM ^ inv_bits) | RD(dst) | RN(arg1) | (1 << 22) | ((-imm & 0x3f) << 16) | ((63 - imm) << 10)));
+			}
+			goto set_flags;
+		case SLJIT_LSHR:
+		case SLJIT_ASHR:
+			if (flags & ARG1_IMM)
+				break;
+			if (op == SLJIT_ASHR)
+				inv_bits |= 1 << 30;
+			if (flags & INT_OP) {
+				imm &= 0x1f;
+				FAIL_IF(push_inst(compiler, (UBFM ^ inv_bits) | RD(dst) | RN(arg1) | (imm << 16) | (31 << 10)));
+			}
+			else {
+				imm &= 0x3f;
+				FAIL_IF(push_inst(compiler, (UBFM ^ inv_bits) | RD(dst) | RN(arg1) | (1 << 22) | (imm << 16) | (63 << 10)));
+			}
+			goto set_flags;
+		default:
+			SLJIT_UNREACHABLE();
+			break;
+		}
+
+		if (flags & ARG2_IMM) {
+			if (arg2 == 0)
+				arg2 = TMP_ZERO;
+			else {
+				FAIL_IF(load_immediate(compiler, TMP_REG2, arg2));
+				arg2 = TMP_REG2;
+			}
+		}
+		else {
+			if (arg1 == 0)
+				arg1 = TMP_ZERO;
+			else {
+				FAIL_IF(load_immediate(compiler, TMP_REG1, arg1));
+				arg1 = TMP_REG1;
+			}
+		}
+	}
+
+	/* Both arguments are registers. */
+	switch (op) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_P:
+		SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
+		if (dst == arg2)
+			return SLJIT_SUCCESS;
+		return push_inst(compiler, ORR | RD(dst) | RN(TMP_ZERO) | RM(arg2));
+	case SLJIT_MOV_U8:
+		SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
+		return push_inst(compiler, (UBFM ^ W_OP) | RD(dst) | RN(arg2) | (7 << 10));
+	case SLJIT_MOV_S8:
+		SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
+		if (!(flags & INT_OP))
+			inv_bits |= 1 << 22;
+		return push_inst(compiler, (SBFM ^ inv_bits) | RD(dst) | RN(arg2) | (7 << 10));
+	case SLJIT_MOV_U16:
+		SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
+		return push_inst(compiler, (UBFM ^ W_OP) | RD(dst) | RN(arg2) | (15 << 10));
+	case SLJIT_MOV_S16:
+		SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
+		if (!(flags & INT_OP))
+			inv_bits |= 1 << 22;
+		return push_inst(compiler, (SBFM ^ inv_bits) | RD(dst) | RN(arg2) | (15 << 10));
+	case SLJIT_MOV_U32:
+		SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
+		if ((flags & INT_OP) && dst == arg2)
+			return SLJIT_SUCCESS;
+		return push_inst(compiler, (ORR ^ W_OP) | RD(dst) | RN(TMP_ZERO) | RM(arg2));
+	case SLJIT_MOV_S32:
+		SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
+		if ((flags & INT_OP) && dst == arg2)
+			return SLJIT_SUCCESS;
+		return push_inst(compiler, SBFM | (1 << 22) | RD(dst) | RN(arg2) | (31 << 10));
+	case SLJIT_NOT:
+		SLJIT_ASSERT(arg1 == TMP_REG1);
+		FAIL_IF(push_inst(compiler, (ORN ^ inv_bits) | RD(dst) | RN(TMP_ZERO) | RM(arg2)));
+		break; /* Set flags. */
+	case SLJIT_NEG:
+		SLJIT_ASSERT(arg1 == TMP_REG1);
+		if (flags & SET_FLAGS)
+			inv_bits |= 1 << 29;
+		return push_inst(compiler, (SUB ^ inv_bits) | RD(dst) | RN(TMP_ZERO) | RM(arg2));
+	case SLJIT_CLZ:
+		SLJIT_ASSERT(arg1 == TMP_REG1);
+		return push_inst(compiler, (CLZ ^ inv_bits) | RD(dst) | RN(arg2));
+	case SLJIT_ADD:
+		CHECK_FLAGS(1 << 29);
+		return push_inst(compiler, (ADD ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2));
+	case SLJIT_ADDC:
+		CHECK_FLAGS(1 << 29);
+		return push_inst(compiler, (ADC ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2));
+	case SLJIT_SUB:
+		CHECK_FLAGS(1 << 29);
+		return push_inst(compiler, (SUB ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2));
+	case SLJIT_SUBC:
+		CHECK_FLAGS(1 << 29);
+		return push_inst(compiler, (SBC ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2));
+	case SLJIT_MUL:
+		if (!(flags & SET_FLAGS))
+			return push_inst(compiler, (MADD ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2) | RT2(TMP_ZERO));
+		if (flags & INT_OP) {
+			FAIL_IF(push_inst(compiler, SMADDL | RD(dst) | RN(arg1) | RM(arg2) | (31 << 10)));
+			FAIL_IF(push_inst(compiler, ADD | RD(TMP_LR) | RN(TMP_ZERO) | RM(dst) | (2 << 22) | (31 << 10)));
+			return push_inst(compiler, SUBS | RD(TMP_ZERO) | RN(TMP_LR) | RM(dst) | (2 << 22) | (63 << 10));
+		}
+		FAIL_IF(push_inst(compiler, SMULH | RD(TMP_LR) | RN(arg1) | RM(arg2)));
+		FAIL_IF(push_inst(compiler, MADD | RD(dst) | RN(arg1) | RM(arg2) | RT2(TMP_ZERO)));
+		return push_inst(compiler, SUBS | RD(TMP_ZERO) | RN(TMP_LR) | RM(dst) | (2 << 22) | (63 << 10));
+	case SLJIT_AND:
+		CHECK_FLAGS(3 << 29);
+		return push_inst(compiler, (AND ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2));
+	case SLJIT_OR:
+		FAIL_IF(push_inst(compiler, (ORR ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)));
+		break; /* Set flags. */
+	case SLJIT_XOR:
+		FAIL_IF(push_inst(compiler, (EOR ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)));
+		break; /* Set flags. */
+	case SLJIT_SHL:
+		FAIL_IF(push_inst(compiler, (LSLV ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)));
+		break; /* Set flags. */
+	case SLJIT_LSHR:
+		FAIL_IF(push_inst(compiler, (LSRV ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)));
+		break; /* Set flags. */
+	case SLJIT_ASHR:
+		FAIL_IF(push_inst(compiler, (ASRV ^ inv_bits) | RD(dst) | RN(arg1) | RM(arg2)));
+		break; /* Set flags. */
+	default:
+		SLJIT_UNREACHABLE();
+		return SLJIT_SUCCESS;
+	}
+
+set_flags:
+	if (flags & SET_FLAGS)
+		return push_inst(compiler, (SUBS ^ inv_bits) | RD(TMP_ZERO) | RN(dst) | RM(TMP_ZERO));
+	return SLJIT_SUCCESS;
+}
+
+#define STORE		0x10
+#define SIGNED		0x20
+
+#define BYTE_SIZE	0x0
+#define HALF_SIZE	0x1
+#define INT_SIZE	0x2
+#define WORD_SIZE	0x3
+
+#define MEM_SIZE_SHIFT(flags) ((flags) & 0x3)
+
+static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg,
+	sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg)
+{
+	sljit_u32 shift = MEM_SIZE_SHIFT(flags);
+	sljit_u32 type = (shift << 30);
+
+	if (!(flags & STORE))
+		type |= (flags & SIGNED) ? 0x00800000 : 0x00400000;
+
+	SLJIT_ASSERT(arg & SLJIT_MEM);
+
+	if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
+		argw &= 0x3;
+
+		if (argw == 0 || argw == shift)
+			return push_inst(compiler, STRB | type | RT(reg)
+				| RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | (argw ? (1 << 12) : 0));
+
+		FAIL_IF(push_inst(compiler, ADD | RD(tmp_reg) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | (argw << 10)));
+		return push_inst(compiler, STRBI | type | RT(reg) | RN(tmp_reg));
+	}
+
+	arg &= REG_MASK;
+
+	if (arg == SLJIT_UNUSED) {
+		FAIL_IF(load_immediate(compiler, tmp_reg, argw & ~(0xfff << shift)));
+
+		argw = (argw >> shift) & 0xfff;
+
+		return push_inst(compiler, STRBI | type | RT(reg) | RN(tmp_reg) | (argw << 10));
+	}
+
+	if (argw >= 0 && (argw & ((1 << shift) - 1)) == 0) {
+		if ((argw >> shift) <= 0xfff) {
+			return push_inst(compiler, STRBI | type | RT(reg) | RN(arg) | (argw << (10 - shift)));
+		}
+
+		if (argw <= 0xffffff) {
+			FAIL_IF(push_inst(compiler, ADDI | (1 << 22) | RD(tmp_reg) | RN(arg) | ((argw >> 12) << 10)));
+
+			argw = ((argw & 0xfff) >> shift);
+			return push_inst(compiler, STRBI | type | RT(reg) | RN(tmp_reg) | (argw << 10));
+		}
+	}
+
+	if (argw <= 255 && argw >= -256)
+		return push_inst(compiler, STURBI | type | RT(reg) | RN(arg) | ((argw & 0x1ff) << 12));
+
+	FAIL_IF(load_immediate(compiler, tmp_reg, argw));
+
+	return push_inst(compiler, STRB | type | RT(reg) | RN(arg) | RM(tmp_reg));
+}
+
+/* --------------------------------------------------------------------- */
+/*  Entry, exit                                                          */
+/* --------------------------------------------------------------------- */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	sljit_s32 args, i, tmp, offs, prev, saved_regs_size;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+	saved_regs_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 2);
+	if (saved_regs_size & 0x8)
+		saved_regs_size += sizeof(sljit_sw);
+
+	local_size = (local_size + 15) & ~0xf;
+	compiler->local_size = local_size + saved_regs_size;
+
+	FAIL_IF(push_inst(compiler, STP_PRE | RT(TMP_FP) | RT2(TMP_LR)
+		| RN(SLJIT_SP) | ((-(saved_regs_size >> 3) & 0x7f) << 15)));
+
+#ifdef _WIN32
+	if (local_size >= 4096)
+		FAIL_IF(push_inst(compiler, SUBI | RD(TMP_REG1) | RN(SLJIT_SP) | (1 << 10) | (1 << 22)));
+	else if (local_size > 256)
+		FAIL_IF(push_inst(compiler, SUBI | RD(TMP_REG1) | RN(SLJIT_SP) | (local_size << 10)));
+#endif
+
+	tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
+	prev = -1;
+	offs = 2 << 15;
+	for (i = SLJIT_S0; i >= tmp; i--) {
+		if (prev == -1) {
+			prev = i;
+			continue;
+		}
+		FAIL_IF(push_inst(compiler, STP | RT(prev) | RT2(i) | RN(SLJIT_SP) | offs));
+		offs += 2 << 15;
+		prev = -1;
+	}
+
+	for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
+		if (prev == -1) {
+			prev = i;
+			continue;
+		}
+		FAIL_IF(push_inst(compiler, STP | RT(prev) | RT2(i) | RN(SLJIT_SP) | offs));
+		offs += 2 << 15;
+		prev = -1;
+	}
+
+	if (prev != -1)
+		FAIL_IF(push_inst(compiler, STRI | RT(prev) | RN(SLJIT_SP) | (offs >> 5)));
+
+
+	FAIL_IF(push_inst(compiler, ADDI | RD(TMP_FP) | RN(SLJIT_SP) | (0 << 10)));
+
+	args = get_arg_count(arg_types);
+
+	if (args >= 1)
+		FAIL_IF(push_inst(compiler, ORR | RD(SLJIT_S0) | RN(TMP_ZERO) | RM(SLJIT_R0)));
+	if (args >= 2)
+		FAIL_IF(push_inst(compiler, ORR | RD(SLJIT_S1) | RN(TMP_ZERO) | RM(SLJIT_R1)));
+	if (args >= 3)
+		FAIL_IF(push_inst(compiler, ORR | RD(SLJIT_S2) | RN(TMP_ZERO) | RM(SLJIT_R2)));
+
+#ifdef _WIN32
+	if (local_size >= 4096) {
+		if (local_size < 4 * 4096) {
+			/* No need for a loop. */
+			if (local_size >= 2 * 4096) {
+				FAIL_IF(push_inst(compiler, LDRI | RT(TMP_ZERO) | RN(TMP_REG1)));
+				FAIL_IF(push_inst(compiler, SUBI | RD(TMP_REG1) | RN(TMP_REG1) | (1 << 10) | (1 << 22)));
+				local_size -= 4096;
+			}
+
+			if (local_size >= 2 * 4096) {
+				FAIL_IF(push_inst(compiler, LDRI | RT(TMP_ZERO) | RN(TMP_REG1)));
+				FAIL_IF(push_inst(compiler, SUBI | RD(TMP_REG1) | RN(TMP_REG1) | (1 << 10) | (1 << 22)));
+				local_size -= 4096;
+			}
+
+			FAIL_IF(push_inst(compiler, LDRI | RT(TMP_ZERO) | RN(TMP_REG1)));
+			local_size -= 4096;
+		}
+		else {
+			FAIL_IF(push_inst(compiler, MOVZ | RD(TMP_REG2) | (((local_size >> 12) - 1) << 5)));
+			FAIL_IF(push_inst(compiler, LDRI | RT(TMP_ZERO) | RN(TMP_REG1)));
+			FAIL_IF(push_inst(compiler, SUBI | RD(TMP_REG1) | RN(TMP_REG1) | (1 << 10) | (1 << 22)));
+			FAIL_IF(push_inst(compiler, SUBI | (1 << 29) | RD(TMP_REG2) | RN(TMP_REG2) | (1 << 10)));
+			FAIL_IF(push_inst(compiler, B_CC | ((((sljit_ins) -3) & 0x7ffff) << 5) | 0x1 /* not-equal */));
+			FAIL_IF(push_inst(compiler, LDRI | RT(TMP_ZERO) | RN(TMP_REG1)));
+
+			local_size &= 0xfff;
+		}
+
+		if (local_size > 256) {
+			FAIL_IF(push_inst(compiler, SUBI | RD(TMP_REG1) | RN(TMP_REG1) | (local_size << 10)));
+			FAIL_IF(push_inst(compiler, LDRI | RT(TMP_ZERO) | RN(TMP_REG1)));
+		}
+		else if (local_size > 0)
+			FAIL_IF(push_inst(compiler, LDR_PRE | RT(TMP_ZERO) | RN(TMP_REG1) | ((-local_size & 0x1ff) << 12)));
+
+		FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RN(TMP_REG1) | (0 << 10)));
+	}
+	else if (local_size > 256) {
+		FAIL_IF(push_inst(compiler, LDRI | RT(TMP_ZERO) | RN(TMP_REG1)));
+		FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RN(TMP_REG1) | (0 << 10)));
+	}
+	else if (local_size > 0)
+		FAIL_IF(push_inst(compiler, LDR_PRE | RT(TMP_ZERO) | RN(SLJIT_SP) | ((-local_size & 0x1ff) << 12)));
+
+#else /* !_WIN32 */
+
+	/* The local_size does not include saved registers size. */
+	if (local_size > 0xfff) {
+		FAIL_IF(push_inst(compiler, SUBI | RD(SLJIT_SP) | RN(SLJIT_SP) | ((local_size >> 12) << 10) | (1 << 22)));
+		local_size &= 0xfff;
+	}
+	if (local_size != 0)
+		FAIL_IF(push_inst(compiler, SUBI | RD(SLJIT_SP) | RN(SLJIT_SP) | (local_size << 10)));
+
+#endif /* _WIN32 */
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	sljit_s32 saved_regs_size;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+	saved_regs_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 2);
+	if (saved_regs_size & 0x8)
+		saved_regs_size += sizeof(sljit_sw);
+
+	compiler->local_size = saved_regs_size + ((local_size + 15) & ~0xf);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 local_size;
+	sljit_s32 i, tmp, offs, prev, saved_regs_size;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_return(compiler, op, src, srcw));
+
+	FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
+
+	saved_regs_size = GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds, 2);
+	if (saved_regs_size & 0x8)
+		saved_regs_size += sizeof(sljit_sw);
+
+	local_size = compiler->local_size - saved_regs_size;
+
+	/* Load LR as early as possible. */
+	if (local_size == 0)
+		FAIL_IF(push_inst(compiler, LDP | RT(TMP_FP) | RT2(TMP_LR) | RN(SLJIT_SP)));
+	else if (local_size < 63 * sizeof(sljit_sw)) {
+		FAIL_IF(push_inst(compiler, LDP_PRE | RT(TMP_FP) | RT2(TMP_LR)
+			| RN(SLJIT_SP) | (local_size << (15 - 3))));
+	}
+	else {
+		if (local_size > 0xfff) {
+			FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RN(SLJIT_SP) | ((local_size >> 12) << 10) | (1 << 22)));
+			local_size &= 0xfff;
+		}
+		if (local_size)
+			FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RN(SLJIT_SP) | (local_size << 10)));
+
+		FAIL_IF(push_inst(compiler, LDP | RT(TMP_FP) | RT2(TMP_LR) | RN(SLJIT_SP)));
+	}
+
+	tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG;
+	prev = -1;
+	offs = 2 << 15;
+	for (i = SLJIT_S0; i >= tmp; i--) {
+		if (prev == -1) {
+			prev = i;
+			continue;
+		}
+		FAIL_IF(push_inst(compiler, LDP | RT(prev) | RT2(i) | RN(SLJIT_SP) | offs));
+		offs += 2 << 15;
+		prev = -1;
+	}
+
+	for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
+		if (prev == -1) {
+			prev = i;
+			continue;
+		}
+		FAIL_IF(push_inst(compiler, LDP | RT(prev) | RT2(i) | RN(SLJIT_SP) | offs));
+		offs += 2 << 15;
+		prev = -1;
+	}
+
+	if (prev != -1)
+		FAIL_IF(push_inst(compiler, LDRI | RT(prev) | RN(SLJIT_SP) | (offs >> 5)));
+
+	/* These two can be executed in parallel. */
+	FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RN(SLJIT_SP) | (saved_regs_size << 10)));
+	return push_inst(compiler, RET | RN(TMP_LR));
+}
+
+/* --------------------------------------------------------------------- */
+/*  Operators                                                            */
+/* --------------------------------------------------------------------- */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
+{
+	sljit_ins inv_bits = (op & SLJIT_I32_OP) ? W_OP : 0;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op0(compiler, op));
+
+	op = GET_OPCODE(op);
+	switch (op) {
+	case SLJIT_BREAKPOINT:
+		return push_inst(compiler, BRK);
+	case SLJIT_NOP:
+		return push_inst(compiler, NOP);
+	case SLJIT_LMUL_UW:
+	case SLJIT_LMUL_SW:
+		FAIL_IF(push_inst(compiler, ORR | RD(TMP_REG1) | RN(TMP_ZERO) | RM(SLJIT_R0)));
+		FAIL_IF(push_inst(compiler, MADD | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1) | RT2(TMP_ZERO)));
+		return push_inst(compiler, (op == SLJIT_LMUL_UW ? UMULH : SMULH) | RD(SLJIT_R1) | RN(TMP_REG1) | RM(SLJIT_R1));
+	case SLJIT_DIVMOD_UW:
+	case SLJIT_DIVMOD_SW:
+		FAIL_IF(push_inst(compiler, (ORR ^ inv_bits) | RD(TMP_REG1) | RN(TMP_ZERO) | RM(SLJIT_R0)));
+		FAIL_IF(push_inst(compiler, ((op == SLJIT_DIVMOD_UW ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1)));
+		FAIL_IF(push_inst(compiler, (MADD ^ inv_bits) | RD(SLJIT_R1) | RN(SLJIT_R0) | RM(SLJIT_R1) | RT2(TMP_ZERO)));
+		return push_inst(compiler, (SUB ^ inv_bits) | RD(SLJIT_R1) | RN(TMP_REG1) | RM(SLJIT_R1));
+	case SLJIT_DIV_UW:
+	case SLJIT_DIV_SW:
+		return push_inst(compiler, ((op == SLJIT_DIV_UW ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1));
+	case SLJIT_ENDBR:
+	case SLJIT_SKIP_FRAMES_BEFORE_RETURN:
+		return SLJIT_SUCCESS;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r, flags, mem_flags;
+	sljit_s32 op_flags = GET_ALL_FLAGS(op);
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	dst_r = SLOW_IS_REG(dst) ? dst : TMP_REG1;
+
+	op = GET_OPCODE(op);
+	if (op >= SLJIT_MOV && op <= SLJIT_MOV_P) {
+		/* Both operands are registers. */
+		if (dst_r != TMP_REG1 && FAST_IS_REG(src))
+			return emit_op_imm(compiler, op | ((op_flags & SLJIT_I32_OP) ? INT_OP : 0), dst_r, TMP_REG1, src);
+
+		switch (op) {
+		case SLJIT_MOV:
+		case SLJIT_MOV_P:
+			mem_flags = WORD_SIZE;
+			break;
+		case SLJIT_MOV_U8:
+			mem_flags = BYTE_SIZE;
+			if (src & SLJIT_IMM)
+				srcw = (sljit_u8)srcw;
+			break;
+		case SLJIT_MOV_S8:
+			mem_flags = BYTE_SIZE | SIGNED;
+			if (src & SLJIT_IMM)
+				srcw = (sljit_s8)srcw;
+			break;
+		case SLJIT_MOV_U16:
+			mem_flags = HALF_SIZE;
+			if (src & SLJIT_IMM)
+				srcw = (sljit_u16)srcw;
+			break;
+		case SLJIT_MOV_S16:
+			mem_flags = HALF_SIZE | SIGNED;
+			if (src & SLJIT_IMM)
+				srcw = (sljit_s16)srcw;
+			break;
+		case SLJIT_MOV_U32:
+			mem_flags = INT_SIZE;
+			if (src & SLJIT_IMM)
+				srcw = (sljit_u32)srcw;
+			break;
+		case SLJIT_MOV_S32:
+			mem_flags = INT_SIZE | SIGNED;
+			if (src & SLJIT_IMM)
+				srcw = (sljit_s32)srcw;
+			break;
+		default:
+			SLJIT_UNREACHABLE();
+			mem_flags = 0;
+			break;
+		}
+
+		if (src & SLJIT_IMM)
+			FAIL_IF(emit_op_imm(compiler, SLJIT_MOV | ARG2_IMM, dst_r, TMP_REG1, srcw));
+		else if (!(src & SLJIT_MEM))
+			dst_r = src;
+		else
+			FAIL_IF(emit_op_mem(compiler, mem_flags, dst_r, src, srcw, TMP_REG1));
+
+		if (dst & SLJIT_MEM)
+			return emit_op_mem(compiler, mem_flags | STORE, dst_r, dst, dstw, TMP_REG2);
+		return SLJIT_SUCCESS;
+	}
+
+	flags = HAS_FLAGS(op_flags) ? SET_FLAGS : 0;
+	mem_flags = WORD_SIZE;
+
+	if (op_flags & SLJIT_I32_OP) {
+		flags |= INT_OP;
+		mem_flags = INT_SIZE;
+	}
+
+	if (dst == SLJIT_UNUSED)
+		flags |= UNUSED_RETURN;
+
+	if (src & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, mem_flags, TMP_REG2, src, srcw, TMP_REG2));
+		src = TMP_REG2;
+	}
+
+	emit_op_imm(compiler, flags | op, dst_r, TMP_REG1, src);
+
+	if (SLJIT_UNLIKELY(dst & SLJIT_MEM))
+		return emit_op_mem(compiler, mem_flags | STORE, dst_r, dst, dstw, TMP_REG2);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_s32 dst_r, flags, mem_flags;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
+		return SLJIT_SUCCESS;
+
+	dst_r = SLOW_IS_REG(dst) ? dst : TMP_REG1;
+	flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
+	mem_flags = WORD_SIZE;
+
+	if (op & SLJIT_I32_OP) {
+		flags |= INT_OP;
+		mem_flags = INT_SIZE;
+	}
+
+	if (dst == SLJIT_UNUSED)
+		flags |= UNUSED_RETURN;
+
+	if (src1 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, mem_flags, TMP_REG1, src1, src1w, TMP_REG1));
+		src1 = TMP_REG1;
+	}
+
+	if (src2 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, mem_flags, TMP_REG2, src2, src2w, TMP_REG2));
+		src2 = TMP_REG2;
+	}
+
+	if (src1 & SLJIT_IMM)
+		flags |= ARG1_IMM;
+	else
+		src1w = src1;
+
+	if (src2 & SLJIT_IMM)
+		flags |= ARG2_IMM;
+	else
+		src2w = src2;
+
+	emit_op_imm(compiler, flags | GET_OPCODE(op), dst_r, src1w, src2w);
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem(compiler, mem_flags | STORE, dst_r, dst, dstw, TMP_REG2);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_src(compiler, op, src, srcw));
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	switch (op) {
+	case SLJIT_FAST_RETURN:
+		if (FAST_IS_REG(src))
+			FAIL_IF(push_inst(compiler, ORR | RD(TMP_LR) | RN(TMP_ZERO) | RM(src)));
+		else
+			FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_LR, src, srcw, TMP_REG1));
+
+		return push_inst(compiler, RET | RN(TMP_LR));
+	case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN:
+		return SLJIT_SUCCESS;
+	case SLJIT_PREFETCH_L1:
+	case SLJIT_PREFETCH_L2:
+	case SLJIT_PREFETCH_L3:
+	case SLJIT_PREFETCH_ONCE:
+		SLJIT_ASSERT(reg_map[1] == 0 && reg_map[3] == 2 && reg_map[5] == 4);
+
+		/* The reg_map[op] should provide the appropriate constant. */
+		if (op == SLJIT_PREFETCH_L1)
+			op = 1;
+		else if (op == SLJIT_PREFETCH_L2)
+			op = 3;
+		else if (op == SLJIT_PREFETCH_L3)
+			op = 5;
+		else
+			op = 2;
+
+		/* Signed word sized load is the prefetch instruction. */
+		return emit_op_mem(compiler, WORD_SIZE | SIGNED, op, src, srcw, TMP_REG1);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+{
+	CHECK_REG_INDEX(check_sljit_get_register_index(reg));
+	return reg_map[reg];
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
+{
+	CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
+	return freg_map[reg];
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+	void *instruction, sljit_s32 size)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
+
+	return push_inst(compiler, *(sljit_ins*)instruction);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Floating point operators                                             */
+/* --------------------------------------------------------------------- */
+
+static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
+{
+	sljit_u32 shift = MEM_SIZE_SHIFT(flags);
+	sljit_ins type = (shift << 30);
+
+	SLJIT_ASSERT(arg & SLJIT_MEM);
+
+	if (!(flags & STORE))
+		type |= 0x00400000;
+
+	if (arg & OFFS_REG_MASK) {
+		argw &= 3;
+		if (argw == 0 || argw == shift)
+			return push_inst(compiler, STR_FR | type | VT(reg)
+				| RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | (argw ? (1 << 12) : 0));
+
+		FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | (argw << 10)));
+		return push_inst(compiler, STR_FI | type | VT(reg) | RN(TMP_REG1));
+	}
+
+	arg &= REG_MASK;
+
+	if (arg == SLJIT_UNUSED) {
+		FAIL_IF(load_immediate(compiler, TMP_REG1, argw & ~(0xfff << shift)));
+
+		argw = (argw >> shift) & 0xfff;
+
+		return push_inst(compiler, STR_FI | type | VT(reg) | RN(TMP_REG1) | (argw << 10));
+	}
+
+	if (argw >= 0 && (argw & ((1 << shift) - 1)) == 0) {
+		if ((argw >> shift) <= 0xfff)
+			return push_inst(compiler, STR_FI | type | VT(reg) | RN(arg) | (argw << (10 - shift)));
+
+		if (argw <= 0xffffff) {
+			FAIL_IF(push_inst(compiler, ADDI | (1 << 22) | RD(TMP_REG1) | RN(arg) | ((argw >> 12) << 10)));
+
+			argw = ((argw & 0xfff) >> shift);
+			return push_inst(compiler, STR_FI | type | VT(reg) | RN(TMP_REG1) | (argw << 10));
+		}
+	}
+
+	if (argw <= 255 && argw >= -256)
+		return push_inst(compiler, STUR_FI | type | VT(reg) | RN(arg) | ((argw & 0x1ff) << 12));
+
+	FAIL_IF(load_immediate(compiler, TMP_REG1, argw));
+	return push_inst(compiler, STR_FR | type | VT(reg) | RN(arg) | RM(TMP_REG1));
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+	sljit_ins inv_bits = (op & SLJIT_F32_OP) ? (1 << 22) : 0;
+
+	if (GET_OPCODE(op) == SLJIT_CONV_S32_FROM_F64)
+		inv_bits |= W_OP;
+
+	if (src & SLJIT_MEM) {
+		emit_fop_mem(compiler, (op & SLJIT_F32_OP) ? INT_SIZE : WORD_SIZE, TMP_FREG1, src, srcw);
+		src = TMP_FREG1;
+	}
+
+	FAIL_IF(push_inst(compiler, (FCVTZS ^ inv_bits) | RD(dst_r) | VN(src)));
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem(compiler, ((GET_OPCODE(op) == SLJIT_CONV_S32_FROM_F64) ? INT_SIZE : WORD_SIZE) | STORE, TMP_REG1, dst, dstw, TMP_REG2);
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+	sljit_ins inv_bits = (op & SLJIT_F32_OP) ? (1 << 22) : 0;
+
+	if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
+		inv_bits |= W_OP;
+
+	if (src & SLJIT_MEM) {
+		emit_op_mem(compiler, ((GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) ? INT_SIZE : WORD_SIZE), TMP_REG1, src, srcw, TMP_REG1);
+		src = TMP_REG1;
+	} else if (src & SLJIT_IMM) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+		if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
+			srcw = (sljit_s32)srcw;
+#endif
+		FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+		src = TMP_REG1;
+	}
+
+	FAIL_IF(push_inst(compiler, (SCVTF ^ inv_bits) | VD(dst_r) | RN(src)));
+
+	if (dst & SLJIT_MEM)
+		return emit_fop_mem(compiler, ((op & SLJIT_F32_OP) ? INT_SIZE : WORD_SIZE) | STORE, TMP_FREG1, dst, dstw);
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_s32 mem_flags = (op & SLJIT_F32_OP) ? INT_SIZE : WORD_SIZE;
+	sljit_ins inv_bits = (op & SLJIT_F32_OP) ? (1 << 22) : 0;
+
+	if (src1 & SLJIT_MEM) {
+		emit_fop_mem(compiler, mem_flags, TMP_FREG1, src1, src1w);
+		src1 = TMP_FREG1;
+	}
+
+	if (src2 & SLJIT_MEM) {
+		emit_fop_mem(compiler, mem_flags, TMP_FREG2, src2, src2w);
+		src2 = TMP_FREG2;
+	}
+
+	return push_inst(compiler, (FCMP ^ inv_bits) | VN(src1) | VM(src2));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r, mem_flags = (op & SLJIT_F32_OP) ? INT_SIZE : WORD_SIZE;
+	sljit_ins inv_bits;
+
+	CHECK_ERROR();
+
+	SLJIT_COMPILE_ASSERT((INT_SIZE ^ 0x1) == WORD_SIZE, must_be_one_bit_difference);
+	SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
+
+	inv_bits = (op & SLJIT_F32_OP) ? (1 << 22) : 0;
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	if (src & SLJIT_MEM) {
+		emit_fop_mem(compiler, (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32) ? (mem_flags ^ 0x1) : mem_flags, dst_r, src, srcw);
+		src = dst_r;
+	}
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_MOV_F64:
+		if (src != dst_r) {
+			if (dst_r != TMP_FREG1)
+				FAIL_IF(push_inst(compiler, (FMOV ^ inv_bits) | VD(dst_r) | VN(src)));
+			else
+				dst_r = src;
+		}
+		break;
+	case SLJIT_NEG_F64:
+		FAIL_IF(push_inst(compiler, (FNEG ^ inv_bits) | VD(dst_r) | VN(src)));
+		break;
+	case SLJIT_ABS_F64:
+		FAIL_IF(push_inst(compiler, (FABS ^ inv_bits) | VD(dst_r) | VN(src)));
+		break;
+	case SLJIT_CONV_F64_FROM_F32:
+		FAIL_IF(push_inst(compiler, FCVT | ((op & SLJIT_F32_OP) ? (1 << 22) : (1 << 15)) | VD(dst_r) | VN(src)));
+		break;
+	}
+
+	if (dst & SLJIT_MEM)
+		return emit_fop_mem(compiler, mem_flags | STORE, dst_r, dst, dstw);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_s32 dst_r, mem_flags = (op & SLJIT_F32_OP) ? INT_SIZE : WORD_SIZE;
+	sljit_ins inv_bits = (op & SLJIT_F32_OP) ? (1 << 22) : 0;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+	if (src1 & SLJIT_MEM) {
+		emit_fop_mem(compiler, mem_flags, TMP_FREG1, src1, src1w);
+		src1 = TMP_FREG1;
+	}
+	if (src2 & SLJIT_MEM) {
+		emit_fop_mem(compiler, mem_flags, TMP_FREG2, src2, src2w);
+		src2 = TMP_FREG2;
+	}
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_ADD_F64:
+		FAIL_IF(push_inst(compiler, (FADD ^ inv_bits) | VD(dst_r) | VN(src1) | VM(src2)));
+		break;
+	case SLJIT_SUB_F64:
+		FAIL_IF(push_inst(compiler, (FSUB ^ inv_bits) | VD(dst_r) | VN(src1) | VM(src2)));
+		break;
+	case SLJIT_MUL_F64:
+		FAIL_IF(push_inst(compiler, (FMUL ^ inv_bits) | VD(dst_r) | VN(src1) | VM(src2)));
+		break;
+	case SLJIT_DIV_F64:
+		FAIL_IF(push_inst(compiler, (FDIV ^ inv_bits) | VD(dst_r) | VN(src1) | VM(src2)));
+		break;
+	}
+
+	if (!(dst & SLJIT_MEM))
+		return SLJIT_SUCCESS;
+	return emit_fop_mem(compiler, mem_flags | STORE, TMP_FREG1, dst, dstw);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Other instructions                                                   */
+/* --------------------------------------------------------------------- */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	if (FAST_IS_REG(dst))
+		return push_inst(compiler, ORR | RD(dst) | RN(TMP_ZERO) | RM(TMP_LR));
+
+	/* Memory. */
+	return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_LR, dst, dstw, TMP_REG1);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Conditional instructions                                             */
+/* --------------------------------------------------------------------- */
+
+static sljit_uw get_cc(sljit_s32 type)
+{
+	switch (type) {
+	case SLJIT_EQUAL:
+	case SLJIT_MUL_NOT_OVERFLOW:
+	case SLJIT_EQUAL_F64:
+		return 0x1;
+
+	case SLJIT_NOT_EQUAL:
+	case SLJIT_MUL_OVERFLOW:
+	case SLJIT_NOT_EQUAL_F64:
+		return 0x0;
+
+	case SLJIT_LESS:
+	case SLJIT_LESS_F64:
+		return 0x2;
+
+	case SLJIT_GREATER_EQUAL:
+	case SLJIT_GREATER_EQUAL_F64:
+		return 0x3;
+
+	case SLJIT_GREATER:
+	case SLJIT_GREATER_F64:
+		return 0x9;
+
+	case SLJIT_LESS_EQUAL:
+	case SLJIT_LESS_EQUAL_F64:
+		return 0x8;
+
+	case SLJIT_SIG_LESS:
+		return 0xa;
+
+	case SLJIT_SIG_GREATER_EQUAL:
+		return 0xb;
+
+	case SLJIT_SIG_GREATER:
+		return 0xd;
+
+	case SLJIT_SIG_LESS_EQUAL:
+		return 0xc;
+
+	case SLJIT_OVERFLOW:
+	case SLJIT_UNORDERED_F64:
+		return 0x7;
+
+	case SLJIT_NOT_OVERFLOW:
+	case SLJIT_ORDERED_F64:
+		return 0x6;
+
+	default:
+		SLJIT_UNREACHABLE();
+		return 0xe;
+	}
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
+{
+	struct sljit_label *label;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_label(compiler));
+
+	if (compiler->last_label && compiler->last_label->size == compiler->size)
+		return compiler->last_label;
+
+	label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));
+	PTR_FAIL_IF(!label);
+	set_label(label, compiler);
+	return label;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
+{
+	struct sljit_jump *jump;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_jump(compiler, type));
+
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	PTR_FAIL_IF(!jump);
+	set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
+	type &= 0xff;
+
+	if (type < SLJIT_JUMP) {
+		jump->flags |= IS_COND;
+		PTR_FAIL_IF(push_inst(compiler, B_CC | (6 << 5) | get_cc(type)));
+	}
+	else if (type >= SLJIT_FAST_CALL)
+		jump->flags |= IS_BL;
+
+	PTR_FAIL_IF(emit_imm64_const(compiler, TMP_REG1, 0));
+	jump->addr = compiler->size;
+	PTR_FAIL_IF(push_inst(compiler, ((type >= SLJIT_FAST_CALL) ? BLR : BR) | RN(TMP_REG1)));
+
+	return jump;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types)
+{
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+
+	return sljit_emit_jump(compiler, type);
+}
+
+static SLJIT_INLINE struct sljit_jump* emit_cmp_to0(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 src, sljit_sw srcw)
+{
+	struct sljit_jump *jump;
+	sljit_ins inv_bits = (type & SLJIT_I32_OP) ? W_OP : 0;
+
+	SLJIT_ASSERT((type & 0xff) == SLJIT_EQUAL || (type & 0xff) == SLJIT_NOT_EQUAL);
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	PTR_FAIL_IF(!jump);
+	set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
+	jump->flags |= IS_CBZ | IS_COND;
+
+	if (src & SLJIT_MEM) {
+		PTR_FAIL_IF(emit_op_mem(compiler, inv_bits ? INT_SIZE : WORD_SIZE, TMP_REG1, src, srcw, TMP_REG1));
+		src = TMP_REG1;
+	}
+	else if (src & SLJIT_IMM) {
+		PTR_FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+		src = TMP_REG1;
+	}
+
+	SLJIT_ASSERT(FAST_IS_REG(src));
+
+	if ((type & 0xff) == SLJIT_EQUAL)
+		inv_bits |= 1 << 24;
+
+	PTR_FAIL_IF(push_inst(compiler, (CBZ ^ inv_bits) | (6 << 5) | RT(src)));
+	PTR_FAIL_IF(emit_imm64_const(compiler, TMP_REG1, 0));
+	jump->addr = compiler->size;
+	PTR_FAIL_IF(push_inst(compiler, BR | RN(TMP_REG1)));
+	return jump;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
+{
+	struct sljit_jump *jump;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	if (!(src & SLJIT_IMM)) {
+		if (src & SLJIT_MEM) {
+			FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src, srcw, TMP_REG1));
+			src = TMP_REG1;
+		}
+		return push_inst(compiler, ((type >= SLJIT_FAST_CALL) ? BLR : BR) | RN(src));
+	}
+
+	/* These jumps are converted to jump/call instructions when possible. */
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	FAIL_IF(!jump);
+	set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_BL : 0));
+	jump->u.target = srcw;
+
+	FAIL_IF(emit_imm64_const(compiler, TMP_REG1, 0));
+	jump->addr = compiler->size;
+	return push_inst(compiler, ((type >= SLJIT_FAST_CALL) ? BLR : BR) | RN(TMP_REG1));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+
+	return sljit_emit_ijump(compiler, type, src, srcw);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 type)
+{
+	sljit_s32 dst_r, src_r, flags, mem_flags;
+	sljit_ins cc;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	cc = get_cc(type & 0xff);
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+
+	if (GET_OPCODE(op) < SLJIT_ADD) {
+		FAIL_IF(push_inst(compiler, CSINC | (cc << 12) | RD(dst_r) | RN(TMP_ZERO) | RM(TMP_ZERO)));
+
+		if (dst_r == TMP_REG1) {
+			mem_flags = (GET_OPCODE(op) == SLJIT_MOV ? WORD_SIZE : INT_SIZE) | STORE;
+			return emit_op_mem(compiler, mem_flags, TMP_REG1, dst, dstw, TMP_REG2);
+		}
+
+		return SLJIT_SUCCESS;
+	}
+
+	flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
+	mem_flags = WORD_SIZE;
+
+	if (op & SLJIT_I32_OP) {
+		flags |= INT_OP;
+		mem_flags = INT_SIZE;
+	}
+
+	src_r = dst;
+
+	if (dst & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, mem_flags, TMP_REG1, dst, dstw, TMP_REG1));
+		src_r = TMP_REG1;
+	}
+
+	FAIL_IF(push_inst(compiler, CSINC | (cc << 12) | RD(TMP_REG2) | RN(TMP_ZERO) | RM(TMP_ZERO)));
+	emit_op_imm(compiler, flags | GET_OPCODE(op), dst_r, src_r, TMP_REG2);
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem(compiler, mem_flags | STORE, TMP_REG1, dst, dstw, TMP_REG2);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 dst_reg,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_ins inv_bits = (dst_reg & SLJIT_I32_OP) ? W_OP : 0;
+	sljit_ins cc;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+
+	if (SLJIT_UNLIKELY(src & SLJIT_IMM)) {
+		if (dst_reg & SLJIT_I32_OP)
+			srcw = (sljit_s32)srcw;
+		FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+		src = TMP_REG1;
+		srcw = 0;
+	}
+
+	cc = get_cc(type & 0xff);
+	dst_reg &= ~SLJIT_I32_OP;
+
+	return push_inst(compiler, (CSEL ^ inv_bits) | (cc << 12) | RD(dst_reg) | RN(dst_reg) | RM(src));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 reg,
+	sljit_s32 mem, sljit_sw memw)
+{
+	sljit_u32 sign = 0, inst;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw));
+
+	if ((mem & OFFS_REG_MASK) || (memw > 255 || memw < -256))
+		return SLJIT_ERR_UNSUPPORTED;
+
+	if (type & SLJIT_MEM_SUPP)
+		return SLJIT_SUCCESS;
+
+	switch (type & 0xff) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_P:
+		inst = STURBI | (MEM_SIZE_SHIFT(WORD_SIZE) << 30) | 0x400;
+		break;
+	case SLJIT_MOV_S8:
+		sign = 1;
+	case SLJIT_MOV_U8:
+		inst = STURBI | (MEM_SIZE_SHIFT(BYTE_SIZE) << 30) | 0x400;
+		break;
+	case SLJIT_MOV_S16:
+		sign = 1;
+	case SLJIT_MOV_U16:
+		inst = STURBI | (MEM_SIZE_SHIFT(HALF_SIZE) << 30) | 0x400;
+		break;
+	case SLJIT_MOV_S32:
+		sign = 1;
+	case SLJIT_MOV_U32:
+		inst = STURBI | (MEM_SIZE_SHIFT(INT_SIZE) << 30) | 0x400;
+		break;
+	default:
+		SLJIT_UNREACHABLE();
+		inst = STURBI | (MEM_SIZE_SHIFT(WORD_SIZE) << 30) | 0x400;
+		break;
+	}
+
+	if (!(type & SLJIT_MEM_STORE))
+		inst |= sign ? 0x00800000 : 0x00400000;
+
+	if (type & SLJIT_MEM_PRE)
+		inst |= 0x800;
+
+	return push_inst(compiler, inst | RT(reg) | RN(mem & REG_MASK) | ((memw & 0x1ff) << 12));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 freg,
+	sljit_s32 mem, sljit_sw memw)
+{
+	sljit_u32 inst;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fmem(compiler, type, freg, mem, memw));
+
+	if ((mem & OFFS_REG_MASK) || (memw > 255 || memw < -256))
+		return SLJIT_ERR_UNSUPPORTED;
+
+	if (type & SLJIT_MEM_SUPP)
+		return SLJIT_SUCCESS;
+
+	inst = STUR_FI | 0x80000400;
+
+	if (!(type & SLJIT_F32_OP))
+		inst |= 0x40000000;
+
+	if (!(type & SLJIT_MEM_STORE))
+		inst |= 0x00400000;
+
+	if (type & SLJIT_MEM_PRE)
+		inst |= 0x800;
+
+	return push_inst(compiler, inst | VT(freg) | RN(mem & REG_MASK) | ((memw & 0x1ff) << 12));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset)
+{
+	sljit_s32 dst_reg;
+	sljit_ins ins;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_get_local_base(compiler, dst, dstw, offset));
+
+	SLJIT_ASSERT (SLJIT_LOCALS_OFFSET_BASE == 0);
+
+	dst_reg = FAST_IS_REG(dst) ? dst : TMP_REG1;
+
+	if (offset <= 0xffffff && offset >= -0xffffff) {
+		ins = ADDI;
+		if (offset < 0) {
+			offset = -offset;
+			ins = SUBI;
+		}
+
+		if (offset <= 0xfff)
+			FAIL_IF(push_inst(compiler, ins | RD(dst_reg) | RN(SLJIT_SP) | (offset << 10)));
+		else {
+			FAIL_IF(push_inst(compiler, ins | RD(dst_reg) | RN(SLJIT_SP) | ((offset & 0xfff000) >> (12 - 10)) | (1 << 22)));
+
+			offset &= 0xfff;
+			if (offset != 0)
+				FAIL_IF(push_inst(compiler, ins | RD(dst_reg) | RN(dst_reg) | (offset << 10)));
+		}
+	}
+	else {
+		FAIL_IF(load_immediate (compiler, dst_reg, offset));
+		/* Add extended register form. */
+		FAIL_IF(push_inst(compiler, ADDE | (0x3 << 13) | RD(dst_reg) | RN(SLJIT_SP) | RM(dst_reg)));
+	}
+
+	if (SLJIT_UNLIKELY(dst & SLJIT_MEM))
+		return emit_op_mem(compiler, WORD_SIZE | STORE, dst_reg, dst, dstw, TMP_REG1);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
+{
+	struct sljit_const *const_;
+	sljit_s32 dst_r;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
+	PTR_FAIL_IF(!const_);
+	set_const(const_, compiler);
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+	PTR_FAIL_IF(emit_imm64_const(compiler, dst_r, init_value));
+
+	if (dst & SLJIT_MEM)
+		PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2));
+	return const_;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	struct sljit_put_label *put_label;
+	sljit_s32 dst_r;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+	PTR_FAIL_IF(emit_imm64_const(compiler, dst_r, 0));
+
+	put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label));
+	PTR_FAIL_IF(!put_label);
+	set_put_label(put_label, compiler, 1);
+
+	if (dst & SLJIT_MEM)
+		PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2));
+
+	return put_label;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
+{
+	sljit_ins* inst = (sljit_ins*)addr;
+	sljit_s32 dst;
+	SLJIT_UNUSED_ARG(executable_offset);
+
+	SLJIT_UPDATE_WX_FLAGS(inst, inst + 4, 0);
+
+	dst = inst[0] & 0x1f;
+	SLJIT_ASSERT((inst[0] & 0xffe00000) == MOVZ && (inst[1] & 0xffe00000) == (MOVK | (1 << 21)));
+	inst[0] = MOVZ | dst | ((new_target & 0xffff) << 5);
+	inst[1] = MOVK | dst | (((new_target >> 16) & 0xffff) << 5) | (1 << 21);
+	inst[2] = MOVK | dst | (((new_target >> 32) & 0xffff) << 5) | (2 << 21);
+	inst[3] = MOVK | dst | ((new_target >> 48) << 5) | (3 << 21);
+
+	SLJIT_UPDATE_WX_FLAGS(inst, inst + 4, 1);
+	inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+	SLJIT_CACHE_FLUSH(inst, inst + 4);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
+{
+	sljit_set_jump_addr(addr, new_constant, executable_offset);
+}
diff --git a/src/c/pcre2/src/sljit/sljitNativeARM_T2_32.c b/src/c/pcre2/src/sljit/sljitNativeARM_T2_32.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitNativeARM_T2_32.c
@@ -0,0 +1,2383 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
+{
+#ifdef __SOFTFP__
+	return "ARM-Thumb2" SLJIT_CPUINFO " ABI:softfp";
+#else
+	return "ARM-Thumb2" SLJIT_CPUINFO " ABI:hardfp";
+#endif
+}
+
+/* Length of an instruction word. */
+typedef sljit_u32 sljit_ins;
+
+/* Last register + 1. */
+#define TMP_REG1	(SLJIT_NUMBER_OF_REGISTERS + 2)
+#define TMP_REG2	(SLJIT_NUMBER_OF_REGISTERS + 3)
+#define TMP_PC		(SLJIT_NUMBER_OF_REGISTERS + 4)
+
+#define TMP_FREG1	(SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
+#define TMP_FREG2	(SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2)
+
+/* See sljit_emit_enter and sljit_emit_op0 if you want to change them. */
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = {
+	0, 0, 1, 2, 3, 11, 10, 9, 8, 7, 6, 5, 4, 13, 12, 14, 15
+};
+
+static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
+	0, 0, 1, 2, 3, 4, 5, 6, 7
+};
+
+#define COPY_BITS(src, from, to, bits) \
+	((from >= to ? (src >> (from - to)) : (src << (to - from))) & (((1 << bits) - 1) << to))
+
+/* Thumb16 encodings. */
+#define RD3(rd) (reg_map[rd])
+#define RN3(rn) (reg_map[rn] << 3)
+#define RM3(rm) (reg_map[rm] << 6)
+#define RDN3(rdn) (reg_map[rdn] << 8)
+#define IMM3(imm) (imm << 6)
+#define IMM8(imm) (imm)
+
+/* Thumb16 helpers. */
+#define SET_REGS44(rd, rn) \
+	((reg_map[rn] << 3) | (reg_map[rd] & 0x7) | ((reg_map[rd] & 0x8) << 4))
+#define IS_2_LO_REGS(reg1, reg2) \
+	(reg_map[reg1] <= 7 && reg_map[reg2] <= 7)
+#define IS_3_LO_REGS(reg1, reg2, reg3) \
+	(reg_map[reg1] <= 7 && reg_map[reg2] <= 7 && reg_map[reg3] <= 7)
+
+/* Thumb32 encodings. */
+#define RD4(rd) (reg_map[rd] << 8)
+#define RN4(rn) (reg_map[rn] << 16)
+#define RM4(rm) (reg_map[rm])
+#define RT4(rt) (reg_map[rt] << 12)
+#define DD4(dd) (freg_map[dd] << 12)
+#define DN4(dn) (freg_map[dn] << 16)
+#define DM4(dm) (freg_map[dm])
+#define IMM5(imm) \
+	(COPY_BITS(imm, 2, 12, 3) | ((imm & 0x3) << 6))
+#define IMM12(imm) \
+	(COPY_BITS(imm, 11, 26, 1) | COPY_BITS(imm, 8, 12, 3) | (imm & 0xff))
+
+/* --------------------------------------------------------------------- */
+/*  Instrucion forms                                                     */
+/* --------------------------------------------------------------------- */
+
+/* dot '.' changed to _
+   I immediate form (possibly followed by number of immediate bits). */
+#define ADCI		0xf1400000
+#define ADCS		0x4140
+#define ADC_W		0xeb400000
+#define ADD		0x4400
+#define ADDS		0x1800
+#define ADDSI3		0x1c00
+#define ADDSI8		0x3000
+#define ADD_W		0xeb000000
+#define ADDWI		0xf2000000
+#define ADD_SP		0xb000
+#define ADD_W		0xeb000000
+#define ADD_WI		0xf1000000
+#define ANDI		0xf0000000
+#define ANDS		0x4000
+#define AND_W		0xea000000
+#define ASRS		0x4100
+#define ASRSI		0x1000
+#define ASR_W		0xfa40f000
+#define ASR_WI		0xea4f0020
+#define BCC		0xd000
+#define BICI		0xf0200000
+#define BKPT		0xbe00
+#define BLX		0x4780
+#define BX		0x4700
+#define CLZ		0xfab0f080
+#define CMNI_W		0xf1100f00
+#define CMP		0x4280
+#define CMPI		0x2800
+#define CMPI_W		0xf1b00f00
+#define CMP_X		0x4500
+#define CMP_W		0xebb00f00
+#define EORI		0xf0800000
+#define EORS		0x4040
+#define EOR_W		0xea800000
+#define IT		0xbf00
+#define LDRI		0xf8500800
+#define LSLS		0x4080
+#define LSLSI		0x0000
+#define LSL_W		0xfa00f000
+#define LSL_WI		0xea4f0000
+#define LSRS		0x40c0
+#define LSRSI		0x0800
+#define LSR_W		0xfa20f000
+#define LSR_WI		0xea4f0010
+#define MOV		0x4600
+#define MOVS		0x0000
+#define MOVSI		0x2000
+#define MOVT		0xf2c00000
+#define MOVW		0xf2400000
+#define MOV_W		0xea4f0000
+#define MOV_WI		0xf04f0000
+#define MUL		0xfb00f000
+#define MVNS		0x43c0
+#define MVN_W		0xea6f0000
+#define MVN_WI		0xf06f0000
+#define NOP		0xbf00
+#define ORNI		0xf0600000
+#define ORRI		0xf0400000
+#define ORRS		0x4300
+#define ORR_W		0xea400000
+#define POP		0xbc00
+#define POP_W		0xe8bd0000
+#define PUSH		0xb400
+#define PUSH_W		0xe92d0000
+#define RSB_WI		0xf1c00000
+#define RSBSI		0x4240
+#define SBCI		0xf1600000
+#define SBCS		0x4180
+#define SBC_W		0xeb600000
+#define SDIV		0xfb90f0f0
+#define SMULL		0xfb800000
+#define STR_SP		0x9000
+#define SUBS		0x1a00
+#define SUBSI3		0x1e00
+#define SUBSI8		0x3800
+#define SUB_W		0xeba00000
+#define SUBWI		0xf2a00000
+#define SUB_SP		0xb080
+#define SUB_WI		0xf1a00000
+#define SXTB		0xb240
+#define SXTB_W		0xfa4ff080
+#define SXTH		0xb200
+#define SXTH_W		0xfa0ff080
+#define TST		0x4200
+#define UDIV		0xfbb0f0f0
+#define UMULL		0xfba00000
+#define UXTB		0xb2c0
+#define UXTB_W		0xfa5ff080
+#define UXTH		0xb280
+#define UXTH_W		0xfa1ff080
+#define VABS_F32	0xeeb00ac0
+#define VADD_F32	0xee300a00
+#define VCMP_F32	0xeeb40a40
+#define VCVT_F32_S32	0xeeb80ac0
+#define VCVT_F64_F32	0xeeb70ac0
+#define VCVT_S32_F32	0xeebd0ac0
+#define VDIV_F32	0xee800a00
+#define VMOV_F32	0xeeb00a40
+#define VMOV		0xee000a10
+#define VMOV2		0xec400a10
+#define VMRS		0xeef1fa10
+#define VMUL_F32	0xee200a00
+#define VNEG_F32	0xeeb10a40
+#define VSTR_F32	0xed000a00
+#define VSUB_F32	0xee300a40
+
+static sljit_s32 push_inst16(struct sljit_compiler *compiler, sljit_ins inst)
+{
+	sljit_u16 *ptr;
+	SLJIT_ASSERT(!(inst & 0xffff0000));
+
+	ptr = (sljit_u16*)ensure_buf(compiler, sizeof(sljit_u16));
+	FAIL_IF(!ptr);
+	*ptr = inst;
+	compiler->size++;
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 push_inst32(struct sljit_compiler *compiler, sljit_ins inst)
+{
+	sljit_u16 *ptr = (sljit_u16*)ensure_buf(compiler, sizeof(sljit_ins));
+	FAIL_IF(!ptr);
+	*ptr++ = inst >> 16;
+	*ptr = inst;
+	compiler->size += 2;
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 emit_imm32_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_uw imm)
+{
+	FAIL_IF(push_inst32(compiler, MOVW | RD4(dst)
+		| COPY_BITS(imm, 12, 16, 4) | COPY_BITS(imm, 11, 26, 1) | COPY_BITS(imm, 8, 12, 3) | (imm & 0xff)));
+	return push_inst32(compiler, MOVT | RD4(dst)
+		| COPY_BITS(imm, 12 + 16, 16, 4) | COPY_BITS(imm, 11 + 16, 26, 1) | COPY_BITS(imm, 8 + 16, 12, 3) | ((imm & 0xff0000) >> 16));
+}
+
+static SLJIT_INLINE void modify_imm32_const(sljit_u16 *inst, sljit_uw new_imm)
+{
+	sljit_s32 dst = inst[1] & 0x0f00;
+	SLJIT_ASSERT(((inst[0] & 0xfbf0) == (MOVW >> 16)) && ((inst[2] & 0xfbf0) == (MOVT >> 16)) && dst == (inst[3] & 0x0f00));
+	inst[0] = (MOVW >> 16) | COPY_BITS(new_imm, 12, 0, 4) | COPY_BITS(new_imm, 11, 10, 1);
+	inst[1] = dst | COPY_BITS(new_imm, 8, 12, 3) | (new_imm & 0xff);
+	inst[2] = (MOVT >> 16) | COPY_BITS(new_imm, 12 + 16, 0, 4) | COPY_BITS(new_imm, 11 + 16, 10, 1);
+	inst[3] = dst | COPY_BITS(new_imm, 8 + 16, 12, 3) | ((new_imm & 0xff0000) >> 16);
+}
+
+static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_u16 *code_ptr, sljit_u16 *code, sljit_sw executable_offset)
+{
+	sljit_sw diff;
+
+	if (jump->flags & SLJIT_REWRITABLE_JUMP)
+		return 0;
+
+	if (jump->flags & JUMP_ADDR) {
+		/* Branch to ARM code is not optimized yet. */
+		if (!(jump->u.target & 0x1))
+			return 0;
+		diff = ((sljit_sw)jump->u.target - (sljit_sw)(code_ptr + 2) - executable_offset) >> 1;
+	}
+	else {
+		SLJIT_ASSERT(jump->flags & JUMP_LABEL);
+		diff = ((sljit_sw)(code + jump->u.label->size) - (sljit_sw)(code_ptr + 2)) >> 1;
+	}
+
+	if (jump->flags & IS_COND) {
+		SLJIT_ASSERT(!(jump->flags & IS_BL));
+		if (diff <= 127 && diff >= -128) {
+			jump->flags |= PATCH_TYPE1;
+			return 5;
+		}
+		if (diff <= 524287 && diff >= -524288) {
+			jump->flags |= PATCH_TYPE2;
+			return 4;
+		}
+		/* +1 comes from the prefix IT instruction. */
+		diff--;
+		if (diff <= 8388607 && diff >= -8388608) {
+			jump->flags |= PATCH_TYPE3;
+			return 3;
+		}
+	}
+	else if (jump->flags & IS_BL) {
+		if (diff <= 8388607 && diff >= -8388608) {
+			jump->flags |= PATCH_BL;
+			return 3;
+		}
+	}
+	else {
+		if (diff <= 1023 && diff >= -1024) {
+			jump->flags |= PATCH_TYPE4;
+			return 4;
+		}
+		if (diff <= 8388607 && diff >= -8388608) {
+			jump->flags |= PATCH_TYPE5;
+			return 3;
+		}
+	}
+
+	return 0;
+}
+
+static SLJIT_INLINE void set_jump_instruction(struct sljit_jump *jump, sljit_sw executable_offset)
+{
+	sljit_s32 type = (jump->flags >> 4) & 0xf;
+	sljit_sw diff;
+	sljit_u16 *jump_inst;
+	sljit_s32 s, j1, j2;
+
+	if (SLJIT_UNLIKELY(type == 0)) {
+		modify_imm32_const((sljit_u16*)jump->addr, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target);
+		return;
+	}
+
+	if (jump->flags & JUMP_ADDR) {
+		SLJIT_ASSERT(jump->u.target & 0x1);
+		diff = ((sljit_sw)jump->u.target - (sljit_sw)(jump->addr + sizeof(sljit_u32)) - executable_offset) >> 1;
+	}
+	else {
+		SLJIT_ASSERT(jump->u.label->addr & 0x1);
+		diff = ((sljit_sw)(jump->u.label->addr) - (sljit_sw)(jump->addr + sizeof(sljit_u32)) - executable_offset) >> 1;
+	}
+	jump_inst = (sljit_u16*)jump->addr;
+
+	switch (type) {
+	case 1:
+		/* Encoding T1 of 'B' instruction */
+		SLJIT_ASSERT(diff <= 127 && diff >= -128 && (jump->flags & IS_COND));
+		jump_inst[0] = 0xd000 | (jump->flags & 0xf00) | (diff & 0xff);
+		return;
+	case 2:
+		/* Encoding T3 of 'B' instruction */
+		SLJIT_ASSERT(diff <= 524287 && diff >= -524288 && (jump->flags & IS_COND));
+		jump_inst[0] = 0xf000 | COPY_BITS(jump->flags, 8, 6, 4) | COPY_BITS(diff, 11, 0, 6) | COPY_BITS(diff, 19, 10, 1);
+		jump_inst[1] = 0x8000 | COPY_BITS(diff, 17, 13, 1) | COPY_BITS(diff, 18, 11, 1) | (diff & 0x7ff);
+		return;
+	case 3:
+		SLJIT_ASSERT(jump->flags & IS_COND);
+		*jump_inst++ = IT | ((jump->flags >> 4) & 0xf0) | 0x8;
+		diff--;
+		type = 5;
+		break;
+	case 4:
+		/* Encoding T2 of 'B' instruction */
+		SLJIT_ASSERT(diff <= 1023 && diff >= -1024 && !(jump->flags & IS_COND));
+		jump_inst[0] = 0xe000 | (diff & 0x7ff);
+		return;
+	}
+
+	SLJIT_ASSERT(diff <= 8388607 && diff >= -8388608);
+
+	/* Really complex instruction form for branches. */
+	s = (diff >> 23) & 0x1;
+	j1 = (~(diff >> 22) ^ s) & 0x1;
+	j2 = (~(diff >> 21) ^ s) & 0x1;
+	jump_inst[0] = 0xf000 | (s << 10) | COPY_BITS(diff, 11, 0, 10);
+	jump_inst[1] = (j1 << 13) | (j2 << 11) | (diff & 0x7ff);
+
+	/* The others have a common form. */
+	if (type == 5) /* Encoding T4 of 'B' instruction */
+		jump_inst[1] |= 0x9000;
+	else if (type == 6) /* Encoding T1 of 'BL' instruction */
+		jump_inst[1] |= 0xd000;
+	else
+		SLJIT_UNREACHABLE();
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+{
+	struct sljit_memory_fragment *buf;
+	sljit_u16 *code;
+	sljit_u16 *code_ptr;
+	sljit_u16 *buf_ptr;
+	sljit_u16 *buf_end;
+	sljit_uw half_count;
+	sljit_uw next_addr;
+	sljit_sw executable_offset;
+
+	struct sljit_label *label;
+	struct sljit_jump *jump;
+	struct sljit_const *const_;
+	struct sljit_put_label *put_label;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_generate_code(compiler));
+	reverse_buf(compiler);
+
+	code = (sljit_u16*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_u16), compiler->exec_allocator_data);
+	PTR_FAIL_WITH_EXEC_IF(code);
+	buf = compiler->buf;
+
+	code_ptr = code;
+	half_count = 0;
+	next_addr = 0;
+	executable_offset = SLJIT_EXEC_OFFSET(code);
+
+	label = compiler->labels;
+	jump = compiler->jumps;
+	const_ = compiler->consts;
+	put_label = compiler->put_labels;
+
+	do {
+		buf_ptr = (sljit_u16*)buf->memory;
+		buf_end = buf_ptr + (buf->used_size >> 1);
+		do {
+			*code_ptr = *buf_ptr++;
+			if (next_addr == half_count) {
+				SLJIT_ASSERT(!label || label->size >= half_count);
+				SLJIT_ASSERT(!jump || jump->addr >= half_count);
+				SLJIT_ASSERT(!const_ || const_->addr >= half_count);
+				SLJIT_ASSERT(!put_label || put_label->addr >= half_count);
+
+				/* These structures are ordered by their address. */
+				if (label && label->size == half_count) {
+					label->addr = ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset)) | 0x1;
+					label->size = code_ptr - code;
+					label = label->next;
+				}
+				if (jump && jump->addr == half_count) {
+						jump->addr = (sljit_uw)code_ptr - ((jump->flags & IS_COND) ? 10 : 8);
+						code_ptr -= detect_jump_type(jump, code_ptr, code, executable_offset);
+						jump = jump->next;
+				}
+				if (const_ && const_->addr == half_count) {
+					const_->addr = (sljit_uw)code_ptr;
+					const_ = const_->next;
+				}
+				if (put_label && put_label->addr == half_count) {
+					SLJIT_ASSERT(put_label->label);
+					put_label->addr = (sljit_uw)code_ptr;
+					put_label = put_label->next;
+				}
+				next_addr = compute_next_addr(label, jump, const_, put_label);
+			}
+			code_ptr ++;
+			half_count ++;
+		} while (buf_ptr < buf_end);
+
+		buf = buf->next;
+	} while (buf);
+
+	if (label && label->size == half_count) {
+		label->addr = ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset)) | 0x1;
+		label->size = code_ptr - code;
+		label = label->next;
+	}
+
+	SLJIT_ASSERT(!label);
+	SLJIT_ASSERT(!jump);
+	SLJIT_ASSERT(!const_);
+	SLJIT_ASSERT(!put_label);
+	SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size);
+
+	jump = compiler->jumps;
+	while (jump) {
+		set_jump_instruction(jump, executable_offset);
+		jump = jump->next;
+	}
+
+	put_label = compiler->put_labels;
+	while (put_label) {
+		modify_imm32_const((sljit_u16 *)put_label->addr, put_label->label->addr);
+		put_label = put_label->next;
+	}
+
+	compiler->error = SLJIT_ERR_COMPILED;
+	compiler->executable_offset = executable_offset;
+	compiler->executable_size = (code_ptr - code) * sizeof(sljit_u16);
+
+	code = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
+	code_ptr = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+
+	SLJIT_CACHE_FLUSH(code, code_ptr);
+	SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);
+
+	/* Set thumb mode flag. */
+	return (void*)((sljit_uw)code | 0x1);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
+{
+	switch (feature_type) {
+	case SLJIT_HAS_FPU:
+#ifdef SLJIT_IS_FPU_AVAILABLE
+		return SLJIT_IS_FPU_AVAILABLE;
+#else
+		/* Available by default. */
+		return 1;
+#endif
+
+	case SLJIT_HAS_CLZ:
+	case SLJIT_HAS_CMOV:
+	case SLJIT_HAS_PREFETCH:
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+/*  Core code generator functions.                                       */
+/* --------------------------------------------------------------------- */
+
+#define INVALID_IMM	0x80000000
+static sljit_uw get_imm(sljit_uw imm)
+{
+	/* Thumb immediate form. */
+	sljit_s32 counter;
+
+	if (imm <= 0xff)
+		return imm;
+
+	if ((imm & 0xffff) == (imm >> 16)) {
+		/* Some special cases. */
+		if (!(imm & 0xff00))
+			return (1 << 12) | (imm & 0xff);
+		if (!(imm & 0xff))
+			return (2 << 12) | ((imm >> 8) & 0xff);
+		if ((imm & 0xff00) == ((imm & 0xff) << 8))
+			return (3 << 12) | (imm & 0xff);
+	}
+
+	/* Assembly optimization: count leading zeroes? */
+	counter = 8;
+	if (!(imm & 0xffff0000)) {
+		counter += 16;
+		imm <<= 16;
+	}
+	if (!(imm & 0xff000000)) {
+		counter += 8;
+		imm <<= 8;
+	}
+	if (!(imm & 0xf0000000)) {
+		counter += 4;
+		imm <<= 4;
+	}
+	if (!(imm & 0xc0000000)) {
+		counter += 2;
+		imm <<= 2;
+	}
+	if (!(imm & 0x80000000)) {
+		counter += 1;
+		imm <<= 1;
+	}
+	/* Since imm >= 128, this must be true. */
+	SLJIT_ASSERT(counter <= 31);
+
+	if (imm & 0x00ffffff)
+		return INVALID_IMM; /* Cannot be encoded. */
+
+	return ((imm >> 24) & 0x7f) | COPY_BITS(counter, 4, 26, 1) | COPY_BITS(counter, 1, 12, 3) | COPY_BITS(counter, 0, 7, 1);
+}
+
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst, sljit_uw imm)
+{
+	sljit_uw tmp;
+
+	/* MOVS cannot be used since it destroy flags. */
+
+	if (imm >= 0x10000) {
+		tmp = get_imm(imm);
+		if (tmp != INVALID_IMM)
+			return push_inst32(compiler, MOV_WI | RD4(dst) | tmp);
+		tmp = get_imm(~imm);
+		if (tmp != INVALID_IMM)
+			return push_inst32(compiler, MVN_WI | RD4(dst) | tmp);
+	}
+
+	/* set low 16 bits, set hi 16 bits to 0. */
+	FAIL_IF(push_inst32(compiler, MOVW | RD4(dst)
+		| COPY_BITS(imm, 12, 16, 4) | COPY_BITS(imm, 11, 26, 1) | COPY_BITS(imm, 8, 12, 3) | (imm & 0xff)));
+
+	/* set hi 16 bit if needed. */
+	if (imm >= 0x10000)
+		return push_inst32(compiler, MOVT | RD4(dst)
+			| COPY_BITS(imm, 12 + 16, 16, 4) | COPY_BITS(imm, 11 + 16, 26, 1) | COPY_BITS(imm, 8 + 16, 12, 3) | ((imm & 0xff0000) >> 16));
+	return SLJIT_SUCCESS;
+}
+
+#define ARG1_IMM	0x0010000
+#define ARG2_IMM	0x0020000
+/* SET_FLAGS must be 0x100000 as it is also the value of S bit (can be used for optimization). */
+#define SET_FLAGS	0x0100000
+#define UNUSED_RETURN	0x0200000
+
+static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 dst, sljit_uw arg1, sljit_uw arg2)
+{
+	/* dst must be register, TMP_REG1
+	   arg1 must be register, imm
+	   arg2 must be register, imm */
+	sljit_s32 reg;
+	sljit_uw imm, nimm;
+
+	if (SLJIT_UNLIKELY((flags & (ARG1_IMM | ARG2_IMM)) == (ARG1_IMM | ARG2_IMM))) {
+		/* Both are immediates, no temporaries are used. */
+		flags &= ~ARG1_IMM;
+		FAIL_IF(load_immediate(compiler, TMP_REG1, arg1));
+		arg1 = TMP_REG1;
+	}
+
+	if (flags & (ARG1_IMM | ARG2_IMM)) {
+		reg = (flags & ARG2_IMM) ? arg1 : arg2;
+		imm = (flags & ARG2_IMM) ? arg2 : arg1;
+
+		switch (flags & 0xffff) {
+		case SLJIT_CLZ:
+		case SLJIT_MUL:
+			/* No form with immediate operand. */
+			break;
+		case SLJIT_MOV:
+			SLJIT_ASSERT(!(flags & SET_FLAGS) && (flags & ARG2_IMM) && arg1 == TMP_REG2);
+			return load_immediate(compiler, dst, imm);
+		case SLJIT_NOT:
+			if (!(flags & SET_FLAGS))
+				return load_immediate(compiler, dst, ~imm);
+			/* Since the flags should be set, we just fallback to the register mode.
+			   Although some clever things could be done here, "NOT IMM" does not worth the efforts. */
+			break;
+		case SLJIT_ADD:
+			nimm = -(sljit_sw)imm;
+			if (IS_2_LO_REGS(reg, dst)) {
+				if (imm <= 0x7)
+					return push_inst16(compiler, ADDSI3 | IMM3(imm) | RD3(dst) | RN3(reg));
+				if (nimm <= 0x7)
+					return push_inst16(compiler, SUBSI3 | IMM3(nimm) | RD3(dst) | RN3(reg));
+				if (reg == dst) {
+					if (imm <= 0xff)
+						return push_inst16(compiler, ADDSI8 | IMM8(imm) | RDN3(dst));
+					if (nimm <= 0xff)
+						return push_inst16(compiler, SUBSI8 | IMM8(nimm) | RDN3(dst));
+				}
+			}
+			if (!(flags & SET_FLAGS)) {
+				if (imm <= 0xfff)
+					return push_inst32(compiler, ADDWI | RD4(dst) | RN4(reg) | IMM12(imm));
+				if (nimm <= 0xfff)
+					return push_inst32(compiler, SUBWI | RD4(dst) | RN4(reg) | IMM12(nimm));
+			}
+			nimm = get_imm(imm);
+			if (nimm != INVALID_IMM)
+				return push_inst32(compiler, ADD_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | nimm);
+			nimm = get_imm(-(sljit_sw)imm);
+			if (nimm != INVALID_IMM)
+				return push_inst32(compiler, SUB_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | nimm);
+			break;
+		case SLJIT_ADDC:
+			imm = get_imm(imm);
+			if (imm != INVALID_IMM)
+				return push_inst32(compiler, ADCI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm);
+			break;
+		case SLJIT_SUB:
+			/* SUB operation can be replaced by ADD because of the negative carry flag. */
+			if (flags & ARG1_IMM) {
+				if (imm == 0 && IS_2_LO_REGS(reg, dst))
+					return push_inst16(compiler, RSBSI | RD3(dst) | RN3(reg));
+				imm = get_imm(imm);
+				if (imm != INVALID_IMM)
+					return push_inst32(compiler, RSB_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm);
+				break;
+			}
+			if (flags & UNUSED_RETURN) {
+				if (imm <= 0xff && reg_map[reg] <= 7)
+					return push_inst16(compiler, CMPI | IMM8(imm) | RDN3(reg));
+				nimm = get_imm(imm);
+				if (nimm != INVALID_IMM)
+					return push_inst32(compiler, CMPI_W | RN4(reg) | nimm);
+				nimm = get_imm(-(sljit_sw)imm);
+				if (nimm != INVALID_IMM)
+					return push_inst32(compiler, CMNI_W | RN4(reg) | nimm);
+			}
+			nimm = -(sljit_sw)imm;
+			if (IS_2_LO_REGS(reg, dst)) {
+				if (imm <= 0x7)
+					return push_inst16(compiler, SUBSI3 | IMM3(imm) | RD3(dst) | RN3(reg));
+				if (nimm <= 0x7)
+					return push_inst16(compiler, ADDSI3 | IMM3(nimm) | RD3(dst) | RN3(reg));
+				if (reg == dst) {
+					if (imm <= 0xff)
+						return push_inst16(compiler, SUBSI8 | IMM8(imm) | RDN3(dst));
+					if (nimm <= 0xff)
+						return push_inst16(compiler, ADDSI8 | IMM8(nimm) | RDN3(dst));
+				}
+			}
+			if (!(flags & SET_FLAGS)) {
+				if (imm <= 0xfff)
+					return push_inst32(compiler, SUBWI | RD4(dst) | RN4(reg) | IMM12(imm));
+				if (nimm <= 0xfff)
+					return push_inst32(compiler, ADDWI | RD4(dst) | RN4(reg) | IMM12(nimm));
+			}
+			nimm = get_imm(imm);
+			if (nimm != INVALID_IMM)
+				return push_inst32(compiler, SUB_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | nimm);
+			nimm = get_imm(-(sljit_sw)imm);
+			if (nimm != INVALID_IMM)
+				return push_inst32(compiler, ADD_WI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | nimm);
+			break;
+		case SLJIT_SUBC:
+			if (flags & ARG1_IMM)
+				break;
+			imm = get_imm(imm);
+			if (imm != INVALID_IMM)
+				return push_inst32(compiler, SBCI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm);
+			break;
+		case SLJIT_AND:
+			nimm = get_imm(imm);
+			if (nimm != INVALID_IMM)
+				return push_inst32(compiler, ANDI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | nimm);
+			imm = get_imm(imm);
+			if (imm != INVALID_IMM)
+				return push_inst32(compiler, BICI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm);
+			break;
+		case SLJIT_OR:
+			nimm = get_imm(imm);
+			if (nimm != INVALID_IMM)
+				return push_inst32(compiler, ORRI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | nimm);
+			imm = get_imm(imm);
+			if (imm != INVALID_IMM)
+				return push_inst32(compiler, ORNI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm);
+			break;
+		case SLJIT_XOR:
+			imm = get_imm(imm);
+			if (imm != INVALID_IMM)
+				return push_inst32(compiler, EORI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm);
+			break;
+		case SLJIT_SHL:
+		case SLJIT_LSHR:
+		case SLJIT_ASHR:
+			if (flags & ARG1_IMM)
+				break;
+			imm &= 0x1f;
+			if (imm == 0) {
+				if (!(flags & SET_FLAGS))
+					return push_inst16(compiler, MOV | SET_REGS44(dst, reg));
+				if (IS_2_LO_REGS(dst, reg))
+					return push_inst16(compiler, MOVS | RD3(dst) | RN3(reg));
+				return push_inst32(compiler, MOV_W | SET_FLAGS | RD4(dst) | RM4(reg));
+			}
+			switch (flags & 0xffff) {
+			case SLJIT_SHL:
+				if (IS_2_LO_REGS(dst, reg))
+					return push_inst16(compiler, LSLSI | RD3(dst) | RN3(reg) | (imm << 6));
+				return push_inst32(compiler, LSL_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm));
+			case SLJIT_LSHR:
+				if (IS_2_LO_REGS(dst, reg))
+					return push_inst16(compiler, LSRSI | RD3(dst) | RN3(reg) | (imm << 6));
+				return push_inst32(compiler, LSR_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm));
+			default: /* SLJIT_ASHR */
+				if (IS_2_LO_REGS(dst, reg))
+					return push_inst16(compiler, ASRSI | RD3(dst) | RN3(reg) | (imm << 6));
+				return push_inst32(compiler, ASR_WI | (flags & SET_FLAGS) | RD4(dst) | RM4(reg) | IMM5(imm));
+			}
+		default:
+			SLJIT_UNREACHABLE();
+			break;
+		}
+
+		if (flags & ARG2_IMM) {
+			imm = arg2;
+			arg2 = (arg1 == TMP_REG1) ? TMP_REG2 : TMP_REG1;
+			FAIL_IF(load_immediate(compiler, arg2, imm));
+		}
+		else {
+			imm = arg1;
+			arg1 = (arg2 == TMP_REG1) ? TMP_REG2 : TMP_REG1;
+			FAIL_IF(load_immediate(compiler, arg1, imm));
+		}
+
+		SLJIT_ASSERT(arg1 != arg2);
+	}
+
+	/* Both arguments are registers. */
+	switch (flags & 0xffff) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_U32:
+	case SLJIT_MOV_S32:
+	case SLJIT_MOV_P:
+		SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2);
+		if (dst == arg2)
+			return SLJIT_SUCCESS;
+		return push_inst16(compiler, MOV | SET_REGS44(dst, arg2));
+	case SLJIT_MOV_U8:
+		SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2);
+		if (IS_2_LO_REGS(dst, arg2))
+			return push_inst16(compiler, UXTB | RD3(dst) | RN3(arg2));
+		return push_inst32(compiler, UXTB_W | RD4(dst) | RM4(arg2));
+	case SLJIT_MOV_S8:
+		SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2);
+		if (IS_2_LO_REGS(dst, arg2))
+			return push_inst16(compiler, SXTB | RD3(dst) | RN3(arg2));
+		return push_inst32(compiler, SXTB_W | RD4(dst) | RM4(arg2));
+	case SLJIT_MOV_U16:
+		SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2);
+		if (IS_2_LO_REGS(dst, arg2))
+			return push_inst16(compiler, UXTH | RD3(dst) | RN3(arg2));
+		return push_inst32(compiler, UXTH_W | RD4(dst) | RM4(arg2));
+	case SLJIT_MOV_S16:
+		SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG2);
+		if (IS_2_LO_REGS(dst, arg2))
+			return push_inst16(compiler, SXTH | RD3(dst) | RN3(arg2));
+		return push_inst32(compiler, SXTH_W | RD4(dst) | RM4(arg2));
+	case SLJIT_NOT:
+		SLJIT_ASSERT(arg1 == TMP_REG2);
+		if (IS_2_LO_REGS(dst, arg2))
+			return push_inst16(compiler, MVNS | RD3(dst) | RN3(arg2));
+		return push_inst32(compiler, MVN_W | (flags & SET_FLAGS) | RD4(dst) | RM4(arg2));
+	case SLJIT_CLZ:
+		SLJIT_ASSERT(arg1 == TMP_REG2);
+		FAIL_IF(push_inst32(compiler, CLZ | RN4(arg2) | RD4(dst) | RM4(arg2)));
+		return SLJIT_SUCCESS;
+	case SLJIT_ADD:
+		if (IS_3_LO_REGS(dst, arg1, arg2))
+			return push_inst16(compiler, ADDS | RD3(dst) | RN3(arg1) | RM3(arg2));
+		if (dst == arg1 && !(flags & SET_FLAGS))
+			return push_inst16(compiler, ADD | SET_REGS44(dst, arg2));
+		return push_inst32(compiler, ADD_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
+	case SLJIT_ADDC:
+		if (dst == arg1 && IS_2_LO_REGS(dst, arg2))
+			return push_inst16(compiler, ADCS | RD3(dst) | RN3(arg2));
+		return push_inst32(compiler, ADC_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
+	case SLJIT_SUB:
+		if (flags & UNUSED_RETURN) {
+			if (IS_2_LO_REGS(arg1, arg2))
+				return push_inst16(compiler, CMP | RD3(arg1) | RN3(arg2));
+			return push_inst16(compiler, CMP_X | SET_REGS44(arg1, arg2));
+		}
+		if (IS_3_LO_REGS(dst, arg1, arg2))
+			return push_inst16(compiler, SUBS | RD3(dst) | RN3(arg1) | RM3(arg2));
+		return push_inst32(compiler, SUB_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
+	case SLJIT_SUBC:
+		if (dst == arg1 && IS_2_LO_REGS(dst, arg2))
+			return push_inst16(compiler, SBCS | RD3(dst) | RN3(arg2));
+		return push_inst32(compiler, SBC_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
+	case SLJIT_MUL:
+		if (!(flags & SET_FLAGS))
+			return push_inst32(compiler, MUL | RD4(dst) | RN4(arg1) | RM4(arg2));
+		SLJIT_ASSERT(dst != TMP_REG2);
+		FAIL_IF(push_inst32(compiler, SMULL | RT4(dst) | RD4(TMP_REG2) | RN4(arg1) | RM4(arg2)));
+		/* cmp TMP_REG2, dst asr #31. */
+		return push_inst32(compiler, CMP_W | RN4(TMP_REG2) | 0x70e0 | RM4(dst));
+	case SLJIT_AND:
+		if (dst == arg1 && IS_2_LO_REGS(dst, arg2))
+			return push_inst16(compiler, ANDS | RD3(dst) | RN3(arg2));
+		if ((flags & UNUSED_RETURN) && IS_2_LO_REGS(arg1, arg2))
+			return push_inst16(compiler, TST | RD3(arg1) | RN3(arg2));
+		return push_inst32(compiler, AND_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
+	case SLJIT_OR:
+		if (dst == arg1 && IS_2_LO_REGS(dst, arg2))
+			return push_inst16(compiler, ORRS | RD3(dst) | RN3(arg2));
+		return push_inst32(compiler, ORR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
+	case SLJIT_XOR:
+		if (dst == arg1 && IS_2_LO_REGS(dst, arg2))
+			return push_inst16(compiler, EORS | RD3(dst) | RN3(arg2));
+		return push_inst32(compiler, EOR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
+	case SLJIT_SHL:
+		if (dst == arg1 && IS_2_LO_REGS(dst, arg2))
+			return push_inst16(compiler, LSLS | RD3(dst) | RN3(arg2));
+		return push_inst32(compiler, LSL_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
+	case SLJIT_LSHR:
+		if (dst == arg1 && IS_2_LO_REGS(dst, arg2))
+			return push_inst16(compiler, LSRS | RD3(dst) | RN3(arg2));
+		return push_inst32(compiler, LSR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
+	case SLJIT_ASHR:
+		if (dst == arg1 && IS_2_LO_REGS(dst, arg2))
+			return push_inst16(compiler, ASRS | RD3(dst) | RN3(arg2));
+		return push_inst32(compiler, ASR_W | (flags & SET_FLAGS) | RD4(dst) | RN4(arg1) | RM4(arg2));
+	}
+
+	SLJIT_UNREACHABLE();
+	return SLJIT_SUCCESS;
+}
+
+#define STORE		0x01
+#define SIGNED		0x02
+
+#define WORD_SIZE	0x00
+#define BYTE_SIZE	0x04
+#define HALF_SIZE	0x08
+#define PRELOAD		0x0c
+
+#define IS_WORD_SIZE(flags)		(!(flags & (BYTE_SIZE | HALF_SIZE)))
+#define OFFSET_CHECK(imm, shift)	(!(argw & ~(imm << shift)))
+
+/*
+  1st letter:
+  w = word
+  b = byte
+  h = half
+
+  2nd letter:
+  s = signed
+  u = unsigned
+
+  3rd letter:
+  l = load
+  s = store
+*/
+
+static const sljit_ins sljit_mem16[12] = {
+/* w u l */ 0x5800 /* ldr */,
+/* w u s */ 0x5000 /* str */,
+/* w s l */ 0x5800 /* ldr */,
+/* w s s */ 0x5000 /* str */,
+
+/* b u l */ 0x5c00 /* ldrb */,
+/* b u s */ 0x5400 /* strb */,
+/* b s l */ 0x5600 /* ldrsb */,
+/* b s s */ 0x5400 /* strb */,
+
+/* h u l */ 0x5a00 /* ldrh */,
+/* h u s */ 0x5200 /* strh */,
+/* h s l */ 0x5e00 /* ldrsh */,
+/* h s s */ 0x5200 /* strh */,
+};
+
+static const sljit_ins sljit_mem16_imm5[12] = {
+/* w u l */ 0x6800 /* ldr imm5 */,
+/* w u s */ 0x6000 /* str imm5 */,
+/* w s l */ 0x6800 /* ldr imm5 */,
+/* w s s */ 0x6000 /* str imm5 */,
+
+/* b u l */ 0x7800 /* ldrb imm5 */,
+/* b u s */ 0x7000 /* strb imm5 */,
+/* b s l */ 0x0000 /* not allowed */,
+/* b s s */ 0x7000 /* strb imm5 */,
+
+/* h u l */ 0x8800 /* ldrh imm5 */,
+/* h u s */ 0x8000 /* strh imm5 */,
+/* h s l */ 0x0000 /* not allowed */,
+/* h s s */ 0x8000 /* strh imm5 */,
+};
+
+#define MEM_IMM8	0xc00
+#define MEM_IMM12	0x800000
+static const sljit_ins sljit_mem32[13] = {
+/* w u l */ 0xf8500000 /* ldr.w */,
+/* w u s */ 0xf8400000 /* str.w */,
+/* w s l */ 0xf8500000 /* ldr.w */,
+/* w s s */ 0xf8400000 /* str.w */,
+
+/* b u l */ 0xf8100000 /* ldrb.w */,
+/* b u s */ 0xf8000000 /* strb.w */,
+/* b s l */ 0xf9100000 /* ldrsb.w */,
+/* b s s */ 0xf8000000 /* strb.w */,
+
+/* h u l */ 0xf8300000 /* ldrh.w */,
+/* h u s */ 0xf8200000 /* strsh.w */,
+/* h s l */ 0xf9300000 /* ldrsh.w */,
+/* h s s */ 0xf8200000 /* strsh.w */,
+
+/* p u l */ 0xf8100000 /* pld */,
+};
+
+/* Helper function. Dst should be reg + value, using at most 1 instruction, flags does not set. */
+static sljit_s32 emit_set_delta(struct sljit_compiler *compiler, sljit_s32 dst, sljit_s32 reg, sljit_sw value)
+{
+	if (value >= 0) {
+		if (value <= 0xfff)
+			return push_inst32(compiler, ADDWI | RD4(dst) | RN4(reg) | IMM12(value));
+		value = get_imm(value);
+		if (value != INVALID_IMM)
+			return push_inst32(compiler, ADD_WI | RD4(dst) | RN4(reg) | value);
+	}
+	else {
+		value = -value;
+		if (value <= 0xfff)
+			return push_inst32(compiler, SUBWI | RD4(dst) | RN4(reg) | IMM12(value));
+		value = get_imm(value);
+		if (value != INVALID_IMM)
+			return push_inst32(compiler, SUB_WI | RD4(dst) | RN4(reg) | value);
+	}
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+static SLJIT_INLINE sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg,
+	sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg)
+{
+	sljit_s32 other_r;
+	sljit_uw tmp;
+
+	SLJIT_ASSERT(arg & SLJIT_MEM);
+	SLJIT_ASSERT((arg & REG_MASK) != tmp_reg);
+	arg &= ~SLJIT_MEM;
+
+	if (SLJIT_UNLIKELY(!(arg & REG_MASK))) {
+		tmp = get_imm(argw & ~0xfff);
+		if (tmp != INVALID_IMM) {
+			FAIL_IF(push_inst32(compiler, MOV_WI | RD4(tmp_reg) | tmp));
+			return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(tmp_reg) | (argw & 0xfff));
+		}
+
+		FAIL_IF(load_immediate(compiler, tmp_reg, argw));
+		if (IS_2_LO_REGS(reg, tmp_reg) && sljit_mem16_imm5[flags])
+			return push_inst16(compiler, sljit_mem16_imm5[flags] | RD3(reg) | RN3(tmp_reg));
+		return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(tmp_reg));
+	}
+
+	if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
+		argw &= 0x3;
+		other_r = OFFS_REG(arg);
+		arg &= 0xf;
+
+		if (!argw && IS_3_LO_REGS(reg, arg, other_r))
+			return push_inst16(compiler, sljit_mem16[flags] | RD3(reg) | RN3(arg) | RM3(other_r));
+		return push_inst32(compiler, sljit_mem32[flags] | RT4(reg) | RN4(arg) | RM4(other_r) | (argw << 4));
+	}
+
+	if (argw > 0xfff) {
+		tmp = get_imm(argw & ~0xfff);
+		if (tmp != INVALID_IMM) {
+			push_inst32(compiler, ADD_WI | RD4(tmp_reg) | RN4(arg) | tmp);
+			arg = tmp_reg;
+			argw = argw & 0xfff;
+		}
+	}
+	else if (argw < -0xff) {
+		tmp = get_imm(-argw & ~0xff);
+		if (tmp != INVALID_IMM) {
+			push_inst32(compiler, SUB_WI | RD4(tmp_reg) | RN4(arg) | tmp);
+			arg = tmp_reg;
+			argw = -(-argw & 0xff);
+		}
+	}
+
+	if (IS_2_LO_REGS(reg, arg) && sljit_mem16_imm5[flags]) {
+		tmp = 3;
+		if (IS_WORD_SIZE(flags)) {
+			if (OFFSET_CHECK(0x1f, 2))
+				tmp = 2;
+		}
+		else if (flags & BYTE_SIZE)
+		{
+			if (OFFSET_CHECK(0x1f, 0))
+				tmp = 0;
+		}
+		else {
+			SLJIT_ASSERT(flags & HALF_SIZE);
+			if (OFFSET_CHECK(0x1f, 1))
+				tmp = 1;
+		}
+
+		if (tmp < 3)
+			return push_inst16(compiler, sljit_mem16_imm5[flags] | RD3(reg) | RN3(arg) | (argw << (6 - tmp)));
+	}
+	else if (SLJIT_UNLIKELY(arg == SLJIT_SP) && IS_WORD_SIZE(flags) && OFFSET_CHECK(0xff, 2) && reg_map[reg] <= 7) {
+		/* SP based immediate. */
+		return push_inst16(compiler, STR_SP | ((flags & STORE) ? 0 : 0x800) | RDN3(reg) | (argw >> 2));
+	}
+
+	if (argw >= 0 && argw <= 0xfff)
+		return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM12 | RT4(reg) | RN4(arg) | argw);
+	else if (argw < 0 && argw >= -0xff)
+		return push_inst32(compiler, sljit_mem32[flags] | MEM_IMM8 | RT4(reg) | RN4(arg) | -argw);
+
+	SLJIT_ASSERT(arg != tmp_reg);
+
+	FAIL_IF(load_immediate(compiler, tmp_reg, argw));
+	if (IS_3_LO_REGS(reg, arg, tmp_reg))
+		return push_inst16(compiler, sljit_mem16[flags] | RD3(reg) | RN3(arg) | RM3(tmp_reg));
+	return push_inst32(compiler, sljit_mem32[flags] | RT4(reg) | RN4(arg) | RM4(tmp_reg));
+}
+
+/* --------------------------------------------------------------------- */
+/*  Entry, exit                                                          */
+/* --------------------------------------------------------------------- */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	sljit_s32 args, size, i, tmp;
+	sljit_ins push = 0;
+#ifdef _WIN32
+	sljit_uw imm;
+#endif
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+	tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
+	for (i = SLJIT_S0; i >= tmp; i--)
+		push |= 1 << reg_map[i];
+
+	for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--)
+		push |= 1 << reg_map[i];
+
+	FAIL_IF((push & 0xff00)
+		? push_inst32(compiler, PUSH_W | (1 << 14) | push)
+		: push_inst16(compiler, PUSH | (1 << 8) | push));
+
+	/* Stack must be aligned to 8 bytes: (LR, R4) */
+	size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
+	local_size = ((size + local_size + 7) & ~7) - size;
+	compiler->local_size = local_size;
+
+#ifdef _WIN32
+	if (local_size >= 256) {
+		if (local_size > 4096)
+			imm = get_imm(4096);
+		else
+			imm = get_imm(local_size & ~0xff);
+
+		SLJIT_ASSERT(imm != INVALID_IMM);
+		FAIL_IF(push_inst32(compiler, SUB_WI | RD4(TMP_REG1) | RN4(SLJIT_SP) | imm));
+	}
+#else
+	if (local_size > 0) {
+		if (local_size <= (127 << 2))
+			FAIL_IF(push_inst16(compiler, SUB_SP | (local_size >> 2)));
+		else
+			FAIL_IF(emit_op_imm(compiler, SLJIT_SUB | ARG2_IMM, SLJIT_SP, SLJIT_SP, local_size));
+	}
+#endif
+
+	args = get_arg_count(arg_types);
+
+	if (args >= 1)
+		FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_S0, SLJIT_R0)));
+	if (args >= 2)
+		FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_S1, SLJIT_R1)));
+	if (args >= 3)
+		FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_S2, SLJIT_R2)));
+
+#ifdef _WIN32
+	if (local_size >= 256) {
+		if (local_size > 4096) {
+			imm = get_imm(4096);
+			SLJIT_ASSERT(imm != INVALID_IMM);
+
+			if (local_size < 4 * 4096) {
+				if (local_size > 2 * 4096) {
+					FAIL_IF(push_inst32(compiler, LDRI | 0x400 | RT4(TMP_REG2) | RN4(TMP_REG1)));
+					FAIL_IF(push_inst32(compiler, SUB_WI | RD4(TMP_REG1) | RN4(TMP_REG1) | imm));
+					local_size -= 4096;
+				}
+
+				if (local_size > 2 * 4096) {
+					FAIL_IF(push_inst32(compiler, LDRI | 0x400 | RT4(TMP_REG2) | RN4(TMP_REG1)));
+					FAIL_IF(push_inst32(compiler, SUB_WI | RD4(TMP_REG1) | RN4(TMP_REG1) | imm));
+					local_size -= 4096;
+				}
+
+				FAIL_IF(push_inst32(compiler, LDRI | 0x400 | RT4(TMP_REG2) | RN4(TMP_REG1)));
+				local_size -= 4096;
+
+				SLJIT_ASSERT(local_size > 0);
+			}
+			else {
+				FAIL_IF(load_immediate(compiler, SLJIT_R3, (local_size >> 12) - 1));
+				FAIL_IF(push_inst32(compiler, LDRI | 0x400 | RT4(TMP_REG2) | RN4(TMP_REG1)));
+				FAIL_IF(push_inst32(compiler, SUB_WI | RD4(TMP_REG1) | RN4(TMP_REG1) | imm));
+				SLJIT_ASSERT(reg_map[SLJIT_R3] < 7);
+				FAIL_IF(push_inst16(compiler, SUBSI8 | RDN3(SLJIT_R3) | 1));
+				FAIL_IF(push_inst16(compiler, BCC | (0x1 << 8) /* not-equal */ | (-7 & 0xff)));
+
+				local_size &= 0xfff;
+
+				if (local_size != 0)
+					FAIL_IF(push_inst32(compiler, LDRI | 0x400 | RT4(TMP_REG2) | RN4(TMP_REG1)));
+			}
+
+			if (local_size >= 256) {
+				imm = get_imm(local_size & ~0xff);
+				SLJIT_ASSERT(imm != INVALID_IMM);
+
+				FAIL_IF(push_inst32(compiler, SUB_WI | RD4(TMP_REG1) | RN4(TMP_REG1) | imm));
+			}
+		}
+
+		local_size &= 0xff;
+		FAIL_IF(push_inst32(compiler, LDRI | 0x400 | (local_size > 0 ? 0x100 : 0) | RT4(TMP_REG2) | RN4(TMP_REG1) | local_size));
+
+		FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_SP, TMP_REG1)));
+	}
+	else if (local_size > 0)
+		FAIL_IF(push_inst32(compiler, LDRI | 0x500 | RT4(TMP_REG1) | RN4(SLJIT_SP) | local_size));
+#endif
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	sljit_s32 size;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+	size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
+	compiler->local_size = ((size + local_size + 7) & ~7) - size;
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 i, tmp;
+	sljit_ins pop = 0;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_return(compiler, op, src, srcw));
+
+	FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
+
+	if (compiler->local_size > 0) {
+		if (compiler->local_size <= (127 << 2))
+			FAIL_IF(push_inst16(compiler, ADD_SP | (compiler->local_size >> 2)));
+		else
+			FAIL_IF(emit_op_imm(compiler, SLJIT_ADD | ARG2_IMM, SLJIT_SP, SLJIT_SP, compiler->local_size));
+	}
+
+	tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG;
+	for (i = SLJIT_S0; i >= tmp; i--)
+		pop |= 1 << reg_map[i];
+
+	for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--)
+		pop |= 1 << reg_map[i];
+
+	return (pop & 0xff00)
+		? push_inst32(compiler, POP_W | (1 << 15) | pop)
+		: push_inst16(compiler, POP | (1 << 8) | pop);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Operators                                                            */
+/* --------------------------------------------------------------------- */
+
+#if !(defined __ARM_FEATURE_IDIV) && !(defined __ARM_ARCH_EXT_IDIV__)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _WIN32
+extern unsigned long long __rt_udiv(unsigned int denominator, unsigned int numerator);
+extern long long __rt_sdiv(int denominator, int numerator);
+#elif defined(__GNUC__)
+extern unsigned int __aeabi_uidivmod(unsigned int numerator, int unsigned denominator);
+extern int __aeabi_idivmod(int numerator, int denominator);
+#else
+#error "Software divmod functions are needed"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !__ARM_FEATURE_IDIV && !__ARM_ARCH_EXT_IDIV__ */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
+{
+#if !(defined __ARM_FEATURE_IDIV) && !(defined __ARM_ARCH_EXT_IDIV__)
+	sljit_sw saved_reg_list[3];
+	sljit_sw saved_reg_count;
+#endif
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op0(compiler, op));
+
+	op = GET_OPCODE(op);
+	switch (op) {
+	case SLJIT_BREAKPOINT:
+		return push_inst16(compiler, BKPT);
+	case SLJIT_NOP:
+		return push_inst16(compiler, NOP);
+	case SLJIT_LMUL_UW:
+	case SLJIT_LMUL_SW:
+		return push_inst32(compiler, (op == SLJIT_LMUL_UW ? UMULL : SMULL)
+			| (reg_map[SLJIT_R1] << 8)
+			| (reg_map[SLJIT_R0] << 12)
+			| (reg_map[SLJIT_R0] << 16)
+			| reg_map[SLJIT_R1]);
+#if (defined __ARM_FEATURE_IDIV) || (defined __ARM_ARCH_EXT_IDIV__)
+	case SLJIT_DIVMOD_UW:
+	case SLJIT_DIVMOD_SW:
+		FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(TMP_REG1, SLJIT_R0)));
+		FAIL_IF(push_inst32(compiler, (op == SLJIT_DIVMOD_UW ? UDIV : SDIV) | RD4(SLJIT_R0) | RN4(SLJIT_R0) | RM4(SLJIT_R1)));
+		FAIL_IF(push_inst32(compiler, MUL | RD4(SLJIT_R1) | RN4(SLJIT_R0) | RM4(SLJIT_R1)));
+		return push_inst32(compiler, SUB_W | RD4(SLJIT_R1) | RN4(TMP_REG1) | RM4(SLJIT_R1));
+	case SLJIT_DIV_UW:
+	case SLJIT_DIV_SW:
+		return push_inst32(compiler, (op == SLJIT_DIV_UW ? UDIV : SDIV) | RD4(SLJIT_R0) | RN4(SLJIT_R0) | RM4(SLJIT_R1));
+#else /* !__ARM_FEATURE_IDIV && !__ARM_ARCH_EXT_IDIV__ */
+	case SLJIT_DIVMOD_UW:
+	case SLJIT_DIVMOD_SW:
+	case SLJIT_DIV_UW:
+	case SLJIT_DIV_SW:
+		SLJIT_COMPILE_ASSERT((SLJIT_DIVMOD_UW & 0x2) == 0 && SLJIT_DIV_UW - 0x2 == SLJIT_DIVMOD_UW, bad_div_opcode_assignments);
+		SLJIT_ASSERT(reg_map[2] == 1 && reg_map[3] == 2 && reg_map[4] == 3);
+
+		saved_reg_count = 0;
+		if (compiler->scratches >= 4)
+			saved_reg_list[saved_reg_count++] = 3;
+		if (compiler->scratches >= 3)
+			saved_reg_list[saved_reg_count++] = 2;
+		if (op >= SLJIT_DIV_UW)
+			saved_reg_list[saved_reg_count++] = 1;
+
+		if (saved_reg_count > 0) {
+			FAIL_IF(push_inst32(compiler, 0xf84d0d00 | (saved_reg_count >= 3 ? 16 : 8)
+						| (saved_reg_list[0] << 12) /* str rX, [sp, #-8/-16]! */));
+			if (saved_reg_count >= 2) {
+				SLJIT_ASSERT(saved_reg_list[1] < 8);
+				FAIL_IF(push_inst16(compiler, 0x9001 | (saved_reg_list[1] << 8) /* str rX, [sp, #4] */));
+			}
+			if (saved_reg_count >= 3) {
+				SLJIT_ASSERT(saved_reg_list[2] < 8);
+				FAIL_IF(push_inst16(compiler, 0x9002 | (saved_reg_list[2] << 8) /* str rX, [sp, #8] */));
+			}
+		}
+
+#ifdef _WIN32
+		FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(TMP_REG1, SLJIT_R0)));
+		FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_R0, SLJIT_R1)));
+		FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(SLJIT_R1, TMP_REG1)));
+		FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM,
+			((op | 0x2) == SLJIT_DIV_UW ? SLJIT_FUNC_OFFSET(__rt_udiv) : SLJIT_FUNC_OFFSET(__rt_sdiv))));
+#elif defined(__GNUC__)
+		FAIL_IF(sljit_emit_ijump(compiler, SLJIT_FAST_CALL, SLJIT_IMM,
+			((op | 0x2) == SLJIT_DIV_UW ? SLJIT_FUNC_OFFSET(__aeabi_uidivmod) : SLJIT_FUNC_OFFSET(__aeabi_idivmod))));
+#else
+#error "Software divmod functions are needed"
+#endif
+
+		if (saved_reg_count > 0) {
+			if (saved_reg_count >= 3) {
+				SLJIT_ASSERT(saved_reg_list[2] < 8);
+				FAIL_IF(push_inst16(compiler, 0x9802 | (saved_reg_list[2] << 8) /* ldr rX, [sp, #8] */));
+			}
+			if (saved_reg_count >= 2) {
+				SLJIT_ASSERT(saved_reg_list[1] < 8);
+				FAIL_IF(push_inst16(compiler, 0x9801 | (saved_reg_list[1] << 8) /* ldr rX, [sp, #4] */));
+			}
+			return push_inst32(compiler, 0xf85d0b00 | (saved_reg_count >= 3 ? 16 : 8)
+						| (saved_reg_list[0] << 12) /* ldr rX, [sp], #8/16 */);
+		}
+		return SLJIT_SUCCESS;
+#endif /* __ARM_FEATURE_IDIV || __ARM_ARCH_EXT_IDIV__ */
+	case SLJIT_ENDBR:
+	case SLJIT_SKIP_FRAMES_BEFORE_RETURN:
+		return SLJIT_SUCCESS;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r, flags;
+	sljit_s32 op_flags = GET_ALL_FLAGS(op);
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	dst_r = SLOW_IS_REG(dst) ? dst : TMP_REG1;
+
+	op = GET_OPCODE(op);
+	if (op >= SLJIT_MOV && op <= SLJIT_MOV_P) {
+		switch (op) {
+		case SLJIT_MOV:
+		case SLJIT_MOV_U32:
+		case SLJIT_MOV_S32:
+		case SLJIT_MOV_P:
+			flags = WORD_SIZE;
+			break;
+		case SLJIT_MOV_U8:
+			flags = BYTE_SIZE;
+			if (src & SLJIT_IMM)
+				srcw = (sljit_u8)srcw;
+			break;
+		case SLJIT_MOV_S8:
+			flags = BYTE_SIZE | SIGNED;
+			if (src & SLJIT_IMM)
+				srcw = (sljit_s8)srcw;
+			break;
+		case SLJIT_MOV_U16:
+			flags = HALF_SIZE;
+			if (src & SLJIT_IMM)
+				srcw = (sljit_u16)srcw;
+			break;
+		case SLJIT_MOV_S16:
+			flags = HALF_SIZE | SIGNED;
+			if (src & SLJIT_IMM)
+				srcw = (sljit_s16)srcw;
+			break;
+		default:
+			SLJIT_UNREACHABLE();
+			flags = 0;
+			break;
+		}
+
+		if (src & SLJIT_IMM)
+			FAIL_IF(emit_op_imm(compiler, SLJIT_MOV | ARG2_IMM, dst_r, TMP_REG2, srcw));
+		else if (src & SLJIT_MEM) {
+			FAIL_IF(emit_op_mem(compiler, flags, dst_r, src, srcw, TMP_REG1));
+		} else {
+			if (dst_r != TMP_REG1)
+				return emit_op_imm(compiler, op, dst_r, TMP_REG2, src);
+			dst_r = src;
+		}
+
+		if (!(dst & SLJIT_MEM))
+			return SLJIT_SUCCESS;
+
+		return emit_op_mem(compiler, flags | STORE, dst_r, dst, dstw, TMP_REG2);
+	}
+
+	if (op == SLJIT_NEG) {
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+			|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+		compiler->skip_checks = 1;
+#endif
+		return sljit_emit_op2(compiler, SLJIT_SUB | op_flags, dst, dstw, SLJIT_IMM, 0, src, srcw);
+	}
+
+	flags = HAS_FLAGS(op_flags) ? SET_FLAGS : 0;
+
+	if (src & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src, srcw, TMP_REG1));
+		src = TMP_REG1;
+	}
+
+	emit_op_imm(compiler, flags | op, dst_r, TMP_REG2, src);
+
+	if (SLJIT_UNLIKELY(dst & SLJIT_MEM))
+		return emit_op_mem(compiler, flags | STORE, dst_r, dst, dstw, TMP_REG2);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_s32 dst_reg, flags, src2_reg;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
+		return SLJIT_SUCCESS;
+
+	dst_reg = SLOW_IS_REG(dst) ? dst : TMP_REG1;
+	flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
+
+	if (src1 & SLJIT_IMM)
+		flags |= ARG1_IMM;
+	else if (src1 & SLJIT_MEM) {
+		emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src1, src1w, TMP_REG1);
+		src1w = TMP_REG1;
+	}
+	else
+		src1w = src1;
+
+	if (src2 & SLJIT_IMM)
+		flags |= ARG2_IMM;
+	else if (src2 & SLJIT_MEM) {
+		src2_reg = (!(flags & ARG1_IMM) && (src1w == TMP_REG1)) ? TMP_REG2 : TMP_REG1;
+		emit_op_mem(compiler, WORD_SIZE, src2_reg, src2, src2w, src2_reg);
+		src2w = src2_reg;
+	}
+	else
+		src2w = src2;
+
+	if (dst == SLJIT_UNUSED)
+		flags |= UNUSED_RETURN;
+
+	emit_op_imm(compiler, flags | GET_OPCODE(op), dst_reg, src1w, src2w);
+
+	if (!(dst & SLJIT_MEM))
+		return SLJIT_SUCCESS;
+	return emit_op_mem(compiler, WORD_SIZE | STORE, dst_reg, dst, dstw, TMP_REG2);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_src(compiler, op, src, srcw));
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	switch (op) {
+	case SLJIT_FAST_RETURN:
+		SLJIT_ASSERT(reg_map[TMP_REG2] == 14);
+
+		if (FAST_IS_REG(src))
+			FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(TMP_REG2, src)));
+		else
+			FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, src, srcw, TMP_REG2));
+
+		return push_inst16(compiler, BX | RN3(TMP_REG2));
+	case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN:
+		return SLJIT_SUCCESS;
+	case SLJIT_PREFETCH_L1:
+	case SLJIT_PREFETCH_L2:
+	case SLJIT_PREFETCH_L3:
+	case SLJIT_PREFETCH_ONCE:
+		return emit_op_mem(compiler, PRELOAD, TMP_PC, src, srcw, TMP_REG1);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+{
+	CHECK_REG_INDEX(check_sljit_get_register_index(reg));
+	return reg_map[reg];
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
+{
+	CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
+	return (freg_map[reg] << 1);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+	void *instruction, sljit_s32 size)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
+
+	if (size == 2)
+		return push_inst16(compiler, *(sljit_u16*)instruction);
+	return push_inst32(compiler, *(sljit_ins*)instruction);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Floating point operators                                             */
+/* --------------------------------------------------------------------- */
+
+#define FPU_LOAD (1 << 20)
+
+static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
+{
+	sljit_uw imm;
+	sljit_sw inst = VSTR_F32 | (flags & (SLJIT_F32_OP | FPU_LOAD));
+
+	SLJIT_ASSERT(arg & SLJIT_MEM);
+
+	/* Fast loads and stores. */
+	if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
+		FAIL_IF(push_inst32(compiler, ADD_W | RD4(TMP_REG1) | RN4(arg & REG_MASK) | RM4(OFFS_REG(arg)) | ((argw & 0x3) << 6)));
+		arg = SLJIT_MEM | TMP_REG1;
+		argw = 0;
+	}
+
+	if ((arg & REG_MASK) && (argw & 0x3) == 0) {
+		if (!(argw & ~0x3fc))
+			return push_inst32(compiler, inst | 0x800000 | RN4(arg & REG_MASK) | DD4(reg) | (argw >> 2));
+		if (!(-argw & ~0x3fc))
+			return push_inst32(compiler, inst | RN4(arg & REG_MASK) | DD4(reg) | (-argw >> 2));
+	}
+
+	if (arg & REG_MASK) {
+		if (emit_set_delta(compiler, TMP_REG1, arg & REG_MASK, argw) != SLJIT_ERR_UNSUPPORTED) {
+			FAIL_IF(compiler->error);
+			return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | DD4(reg));
+		}
+		imm = get_imm(argw & ~0x3fc);
+		if (imm != INVALID_IMM) {
+			FAIL_IF(push_inst32(compiler, ADD_WI | RD4(TMP_REG1) | RN4(arg & REG_MASK) | imm));
+			return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | DD4(reg) | ((argw & 0x3fc) >> 2));
+		}
+		imm = get_imm(-argw & ~0x3fc);
+		if (imm != INVALID_IMM) {
+			argw = -argw;
+			FAIL_IF(push_inst32(compiler, SUB_WI | RD4(TMP_REG1) | RN4(arg & REG_MASK) | imm));
+			return push_inst32(compiler, inst | RN4(TMP_REG1) | DD4(reg) | ((argw & 0x3fc) >> 2));
+		}
+	}
+
+	FAIL_IF(load_immediate(compiler, TMP_REG1, argw));
+	if (arg & REG_MASK)
+		FAIL_IF(push_inst16(compiler, ADD | SET_REGS44(TMP_REG1, (arg & REG_MASK))));
+	return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | DD4(reg));
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	op ^= SLJIT_F32_OP;
+
+	if (src & SLJIT_MEM) {
+		FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG1, src, srcw));
+		src = TMP_FREG1;
+	}
+
+	FAIL_IF(push_inst32(compiler, VCVT_S32_F32 | (op & SLJIT_F32_OP) | DD4(TMP_FREG1) | DM4(src)));
+
+	if (FAST_IS_REG(dst))
+		return push_inst32(compiler, VMOV | (1 << 20) | RT4(dst) | DN4(TMP_FREG1));
+
+	/* Store the integer value from a VFP register. */
+	return emit_fop_mem(compiler, 0, TMP_FREG1, dst, dstw);
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	op ^= SLJIT_F32_OP;
+
+	if (FAST_IS_REG(src))
+		FAIL_IF(push_inst32(compiler, VMOV | RT4(src) | DN4(TMP_FREG1)));
+	else if (src & SLJIT_MEM) {
+		/* Load the integer value into a VFP register. */
+		FAIL_IF(emit_fop_mem(compiler, FPU_LOAD, TMP_FREG1, src, srcw));
+	}
+	else {
+		FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+		FAIL_IF(push_inst32(compiler, VMOV | RT4(TMP_REG1) | DN4(TMP_FREG1)));
+	}
+
+	FAIL_IF(push_inst32(compiler, VCVT_F32_S32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DM4(TMP_FREG1)));
+
+	if (dst & SLJIT_MEM)
+		return emit_fop_mem(compiler, (op & SLJIT_F32_OP), TMP_FREG1, dst, dstw);
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	op ^= SLJIT_F32_OP;
+
+	if (src1 & SLJIT_MEM) {
+		emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG1, src1, src1w);
+		src1 = TMP_FREG1;
+	}
+
+	if (src2 & SLJIT_MEM) {
+		emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG2, src2, src2w);
+		src2 = TMP_FREG2;
+	}
+
+	FAIL_IF(push_inst32(compiler, VCMP_F32 | (op & SLJIT_F32_OP) | DD4(src1) | DM4(src2)));
+	return push_inst32(compiler, VMRS);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r;
+
+	CHECK_ERROR();
+
+	SLJIT_COMPILE_ASSERT((SLJIT_F32_OP == 0x100), float_transfer_bit_error);
+	SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	if (GET_OPCODE(op) != SLJIT_CONV_F64_FROM_F32)
+		op ^= SLJIT_F32_OP;
+
+	if (src & SLJIT_MEM) {
+		emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, dst_r, src, srcw);
+		src = dst_r;
+	}
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_MOV_F64:
+		if (src != dst_r) {
+			if (dst_r != TMP_FREG1)
+				FAIL_IF(push_inst32(compiler, VMOV_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DM4(src)));
+			else
+				dst_r = src;
+		}
+		break;
+	case SLJIT_NEG_F64:
+		FAIL_IF(push_inst32(compiler, VNEG_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DM4(src)));
+		break;
+	case SLJIT_ABS_F64:
+		FAIL_IF(push_inst32(compiler, VABS_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DM4(src)));
+		break;
+	case SLJIT_CONV_F64_FROM_F32:
+		FAIL_IF(push_inst32(compiler, VCVT_F64_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DM4(src)));
+		op ^= SLJIT_F32_OP;
+		break;
+	}
+
+	if (dst & SLJIT_MEM)
+		return emit_fop_mem(compiler, (op & SLJIT_F32_OP), dst_r, dst, dstw);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_s32 dst_r;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	op ^= SLJIT_F32_OP;
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+	if (src1 & SLJIT_MEM) {
+		emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG1, src1, src1w);
+		src1 = TMP_FREG1;
+	}
+	if (src2 & SLJIT_MEM) {
+		emit_fop_mem(compiler, (op & SLJIT_F32_OP) | FPU_LOAD, TMP_FREG2, src2, src2w);
+		src2 = TMP_FREG2;
+	}
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_ADD_F64:
+		FAIL_IF(push_inst32(compiler, VADD_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DN4(src1) | DM4(src2)));
+		break;
+	case SLJIT_SUB_F64:
+		FAIL_IF(push_inst32(compiler, VSUB_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DN4(src1) | DM4(src2)));
+		break;
+	case SLJIT_MUL_F64:
+		FAIL_IF(push_inst32(compiler, VMUL_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DN4(src1) | DM4(src2)));
+		break;
+	case SLJIT_DIV_F64:
+		FAIL_IF(push_inst32(compiler, VDIV_F32 | (op & SLJIT_F32_OP) | DD4(dst_r) | DN4(src1) | DM4(src2)));
+		break;
+	}
+
+	if (!(dst & SLJIT_MEM))
+		return SLJIT_SUCCESS;
+	return emit_fop_mem(compiler, (op & SLJIT_F32_OP), TMP_FREG1, dst, dstw);
+}
+
+#undef FPU_LOAD
+
+/* --------------------------------------------------------------------- */
+/*  Other instructions                                                   */
+/* --------------------------------------------------------------------- */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	SLJIT_ASSERT(reg_map[TMP_REG2] == 14);
+
+	if (FAST_IS_REG(dst))
+		return push_inst16(compiler, MOV | SET_REGS44(dst, TMP_REG2));
+
+	/* Memory. */
+	return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG2, dst, dstw, TMP_REG1);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Conditional instructions                                             */
+/* --------------------------------------------------------------------- */
+
+static sljit_uw get_cc(sljit_s32 type)
+{
+	switch (type) {
+	case SLJIT_EQUAL:
+	case SLJIT_MUL_NOT_OVERFLOW:
+	case SLJIT_EQUAL_F64:
+		return 0x0;
+
+	case SLJIT_NOT_EQUAL:
+	case SLJIT_MUL_OVERFLOW:
+	case SLJIT_NOT_EQUAL_F64:
+		return 0x1;
+
+	case SLJIT_LESS:
+	case SLJIT_LESS_F64:
+		return 0x3;
+
+	case SLJIT_GREATER_EQUAL:
+	case SLJIT_GREATER_EQUAL_F64:
+		return 0x2;
+
+	case SLJIT_GREATER:
+	case SLJIT_GREATER_F64:
+		return 0x8;
+
+	case SLJIT_LESS_EQUAL:
+	case SLJIT_LESS_EQUAL_F64:
+		return 0x9;
+
+	case SLJIT_SIG_LESS:
+		return 0xb;
+
+	case SLJIT_SIG_GREATER_EQUAL:
+		return 0xa;
+
+	case SLJIT_SIG_GREATER:
+		return 0xc;
+
+	case SLJIT_SIG_LESS_EQUAL:
+		return 0xd;
+
+	case SLJIT_OVERFLOW:
+	case SLJIT_UNORDERED_F64:
+		return 0x6;
+
+	case SLJIT_NOT_OVERFLOW:
+	case SLJIT_ORDERED_F64:
+		return 0x7;
+
+	default: /* SLJIT_JUMP */
+		SLJIT_UNREACHABLE();
+		return 0xe;
+	}
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
+{
+	struct sljit_label *label;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_label(compiler));
+
+	if (compiler->last_label && compiler->last_label->size == compiler->size)
+		return compiler->last_label;
+
+	label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));
+	PTR_FAIL_IF(!label);
+	set_label(label, compiler);
+	return label;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
+{
+	struct sljit_jump *jump;
+	sljit_ins cc;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_jump(compiler, type));
+
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	PTR_FAIL_IF(!jump);
+	set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
+	type &= 0xff;
+
+	PTR_FAIL_IF(emit_imm32_const(compiler, TMP_REG1, 0));
+	if (type < SLJIT_JUMP) {
+		jump->flags |= IS_COND;
+		cc = get_cc(type);
+		jump->flags |= cc << 8;
+		PTR_FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
+	}
+
+	jump->addr = compiler->size;
+	if (type <= SLJIT_JUMP)
+		PTR_FAIL_IF(push_inst16(compiler, BX | RN3(TMP_REG1)));
+	else {
+		jump->flags |= IS_BL;
+		PTR_FAIL_IF(push_inst16(compiler, BLX | RN3(TMP_REG1)));
+	}
+
+	return jump;
+}
+
+#ifdef __SOFTFP__
+
+static sljit_s32 softfloat_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *src)
+{
+	sljit_s32 stack_offset = 0;
+	sljit_s32 arg_count = 0;
+	sljit_s32 word_arg_offset = 0;
+	sljit_s32 float_arg_count = 0;
+	sljit_s32 types = 0;
+	sljit_s32 src_offset = 4 * sizeof(sljit_sw);
+	sljit_u8 offsets[4];
+
+	if (src && FAST_IS_REG(*src))
+		src_offset = reg_map[*src] * sizeof(sljit_sw);
+
+	arg_types >>= SLJIT_DEF_SHIFT;
+
+	while (arg_types) {
+		types = (types << SLJIT_DEF_SHIFT) | (arg_types & SLJIT_DEF_MASK);
+
+		switch (arg_types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			offsets[arg_count] = (sljit_u8)stack_offset;
+			stack_offset += sizeof(sljit_f32);
+			arg_count++;
+			float_arg_count++;
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			if (stack_offset & 0x7)
+				stack_offset += sizeof(sljit_sw);
+			offsets[arg_count] = (sljit_u8)stack_offset;
+			stack_offset += sizeof(sljit_f64);
+			arg_count++;
+			float_arg_count++;
+			break;
+		default:
+			offsets[arg_count] = (sljit_u8)stack_offset;
+			stack_offset += sizeof(sljit_sw);
+			arg_count++;
+			word_arg_offset += sizeof(sljit_sw);
+			break;
+		}
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	if (stack_offset > 16)
+		FAIL_IF(push_inst16(compiler, SUB_SP | (((stack_offset - 16) + 0x7) & ~0x7) >> 2));
+
+	SLJIT_ASSERT(reg_map[TMP_REG1] == 12);
+
+	/* Process arguments in reversed direction. */
+	while (types) {
+		switch (types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			arg_count--;
+			float_arg_count--;
+			stack_offset = offsets[arg_count];
+
+			if (stack_offset < 16) {
+				if (src_offset == stack_offset) {
+					FAIL_IF(push_inst16(compiler, MOV | (src_offset << 1) | 4 | (1 << 7)));
+					*src = TMP_REG1;
+				}
+				FAIL_IF(push_inst32(compiler, VMOV | 0x100000 | (float_arg_count << 16) | (stack_offset << 10)));
+			} else
+				FAIL_IF(push_inst32(compiler, VSTR_F32 | 0x800000 | RN4(SLJIT_SP) | (float_arg_count << 12) | ((stack_offset - 16) >> 2)));
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			arg_count--;
+			float_arg_count--;
+			stack_offset = offsets[arg_count];
+
+			SLJIT_ASSERT((stack_offset & 0x7) == 0);
+
+			if (stack_offset < 16) {
+				if (src_offset == stack_offset || src_offset == stack_offset + sizeof(sljit_sw)) {
+					FAIL_IF(push_inst16(compiler, MOV | (src_offset << 1) | 4 | (1 << 7)));
+					*src = TMP_REG1;
+				}
+				FAIL_IF(push_inst32(compiler, VMOV2 | 0x100000 | (stack_offset << 10) | ((stack_offset + sizeof(sljit_sw)) << 14) | float_arg_count));
+			} else
+				FAIL_IF(push_inst32(compiler, VSTR_F32 | 0x800100 | RN4(SLJIT_SP) | (float_arg_count << 12) | ((stack_offset - 16) >> 2)));
+			break;
+		default:
+			arg_count--;
+			word_arg_offset -= sizeof(sljit_sw);
+			stack_offset = offsets[arg_count];
+
+			SLJIT_ASSERT(stack_offset >= word_arg_offset);
+
+			if (stack_offset != word_arg_offset) {
+				if (stack_offset < 16) {
+					if (src_offset == stack_offset) {
+						FAIL_IF(push_inst16(compiler, MOV | (src_offset << 1) | 4 | (1 << 7)));
+						*src = TMP_REG1;
+					}
+					else if (src_offset == word_arg_offset) {
+						*src = 1 + (stack_offset >> 2);
+						src_offset = stack_offset;
+					}
+					FAIL_IF(push_inst16(compiler, MOV | (stack_offset >> 2) | (word_arg_offset << 1)));
+				} else
+					FAIL_IF(push_inst16(compiler, STR_SP | (word_arg_offset << 6) | ((stack_offset - 16) >> 2)));
+			}
+			break;
+		}
+
+		types >>= SLJIT_DEF_SHIFT;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 softfloat_post_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types)
+{
+	sljit_s32 stack_size = 0;
+
+	if ((arg_types & SLJIT_DEF_MASK) == SLJIT_ARG_TYPE_F32)
+		FAIL_IF(push_inst32(compiler, VMOV | (0 << 16) | (0 << 12)));
+	if ((arg_types & SLJIT_DEF_MASK) == SLJIT_ARG_TYPE_F64)
+		FAIL_IF(push_inst32(compiler, VMOV2 | (1 << 16) | (0 << 12) | 0));
+
+	arg_types >>= SLJIT_DEF_SHIFT;
+
+	while (arg_types) {
+		switch (arg_types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			stack_size += sizeof(sljit_f32);
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			if (stack_size & 0x7)
+				stack_size += sizeof(sljit_sw);
+			stack_size += sizeof(sljit_f64);
+			break;
+		default:
+			stack_size += sizeof(sljit_sw);
+			break;
+		}
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	if (stack_size <= 16)
+		return SLJIT_SUCCESS;
+
+	return push_inst16(compiler, ADD_SP | ((((stack_size - 16) + 0x7) & ~0x7) >> 2));
+}
+
+#else
+
+static sljit_s32 hardfloat_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types)
+{
+	sljit_u32 remap = 0;
+	sljit_u32 offset = 0;
+	sljit_u32 new_offset, mask;
+
+	/* Remove return value. */
+	arg_types >>= SLJIT_DEF_SHIFT;
+
+	while (arg_types) {
+		if ((arg_types & SLJIT_DEF_MASK) == SLJIT_ARG_TYPE_F32) {
+			new_offset = 0;
+			mask = 1;
+
+			while (remap & mask) {
+				new_offset++;
+				mask <<= 1;
+			}
+			remap |= mask;
+
+			if (offset != new_offset)
+				FAIL_IF(push_inst32(compiler, VMOV_F32 | DD4((new_offset >> 1) + 1)
+					| ((new_offset & 0x1) ? 0x400000 : 0) | DM4((offset >> 1) + 1)));
+
+			offset += 2;
+		}
+		else if ((arg_types & SLJIT_DEF_MASK) == SLJIT_ARG_TYPE_F64) {
+			new_offset = 0;
+			mask = 3;
+
+			while (remap & mask) {
+				new_offset += 2;
+				mask <<= 2;
+			}
+			remap |= mask;
+
+			if (offset != new_offset)
+				FAIL_IF(push_inst32(compiler, VMOV_F32 | SLJIT_F32_OP | DD4((new_offset >> 1) + 1) | DM4((offset >> 1) + 1)));
+
+			offset += 2;
+		}
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+#endif
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types)
+{
+#ifdef __SOFTFP__
+	struct sljit_jump *jump;
+#endif
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
+
+#ifdef __SOFTFP__
+	PTR_FAIL_IF(softfloat_call_with_args(compiler, arg_types, NULL));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+
+	jump = sljit_emit_jump(compiler, type);
+	PTR_FAIL_IF(jump == NULL);
+
+	PTR_FAIL_IF(softfloat_post_call_with_args(compiler, arg_types));
+	return jump;
+#else
+	PTR_FAIL_IF(hardfloat_call_with_args(compiler, arg_types));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+
+	return sljit_emit_jump(compiler, type);
+#endif
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
+{
+	struct sljit_jump *jump;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	SLJIT_ASSERT(reg_map[TMP_REG1] != 14);
+
+	if (!(src & SLJIT_IMM)) {
+		if (FAST_IS_REG(src)) {
+			SLJIT_ASSERT(reg_map[src] != 14);
+			return push_inst16(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RN3(src));
+		}
+
+		FAIL_IF(emit_op_mem(compiler, WORD_SIZE, type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, src, srcw, TMP_REG1));
+		if (type >= SLJIT_FAST_CALL)
+			return push_inst16(compiler, BLX | RN3(TMP_REG1));
+	}
+
+	/* These jumps are converted to jump/call instructions when possible. */
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	FAIL_IF(!jump);
+	set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_BL : 0));
+	jump->u.target = srcw;
+
+	FAIL_IF(emit_imm32_const(compiler, TMP_REG1, 0));
+	jump->addr = compiler->size;
+	return push_inst16(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RN3(TMP_REG1));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
+
+#ifdef __SOFTFP__
+	if (src & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src, srcw, TMP_REG1));
+		src = TMP_REG1;
+	}
+
+	FAIL_IF(softfloat_call_with_args(compiler, arg_types, &src));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+
+	FAIL_IF(sljit_emit_ijump(compiler, type, src, srcw));
+
+	return softfloat_post_call_with_args(compiler, arg_types);
+#else /* !__SOFTFP__ */
+	FAIL_IF(hardfloat_call_with_args(compiler, arg_types));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+
+	return sljit_emit_ijump(compiler, type, src, srcw);
+#endif /* __SOFTFP__ */
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 type)
+{
+	sljit_s32 dst_r, flags = GET_ALL_FLAGS(op);
+	sljit_ins cc;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	op = GET_OPCODE(op);
+	cc = get_cc(type & 0xff);
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+
+	if (op < SLJIT_ADD) {
+		FAIL_IF(push_inst16(compiler, IT | (cc << 4) | (((cc & 0x1) ^ 0x1) << 3) | 0x4));
+		if (reg_map[dst_r] > 7) {
+			FAIL_IF(push_inst32(compiler, MOV_WI | RD4(dst_r) | 1));
+			FAIL_IF(push_inst32(compiler, MOV_WI | RD4(dst_r) | 0));
+		} else {
+			/* The movsi (immediate) instruction does not set flags in IT block. */
+			FAIL_IF(push_inst16(compiler, MOVSI | RDN3(dst_r) | 1));
+			FAIL_IF(push_inst16(compiler, MOVSI | RDN3(dst_r) | 0));
+		}
+		if (!(dst & SLJIT_MEM))
+			return SLJIT_SUCCESS;
+		return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG1, dst, dstw, TMP_REG2);
+	}
+
+	if (dst & SLJIT_MEM)
+		FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, dst, dstw, TMP_REG2));
+
+	if (op == SLJIT_AND) {
+		FAIL_IF(push_inst16(compiler, IT | (cc << 4) | (((cc & 0x1) ^ 0x1) << 3) | 0x4));
+		FAIL_IF(push_inst32(compiler, ANDI | RN4(dst_r) | RD4(dst_r) | 1));
+		FAIL_IF(push_inst32(compiler, ANDI | RN4(dst_r) | RD4(dst_r) | 0));
+	}
+	else {
+		FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
+		FAIL_IF(push_inst32(compiler, ((op == SLJIT_OR) ? ORRI : EORI) | RN4(dst_r) | RD4(dst_r) | 1));
+	}
+
+	if (dst & SLJIT_MEM)
+		FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG1, dst, dstw, TMP_REG2));
+
+	if (!(flags & SLJIT_SET_Z))
+		return SLJIT_SUCCESS;
+
+	/* The condition must always be set, even if the ORR/EORI is not executed above. */
+	return push_inst32(compiler, MOV_W | SET_FLAGS | RD4(TMP_REG1) | RM4(dst_r));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 dst_reg,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_uw cc, tmp;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+
+	dst_reg &= ~SLJIT_I32_OP;
+
+	cc = get_cc(type & 0xff);
+
+	if (!(src & SLJIT_IMM)) {
+		FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
+		return push_inst16(compiler, MOV | SET_REGS44(dst_reg, src));
+	}
+
+	tmp = (sljit_uw) srcw;
+
+	if (tmp < 0x10000) {
+		/* set low 16 bits, set hi 16 bits to 0. */
+		FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
+		return push_inst32(compiler, MOVW | RD4(dst_reg)
+			| COPY_BITS(tmp, 12, 16, 4) | COPY_BITS(tmp, 11, 26, 1) | COPY_BITS(tmp, 8, 12, 3) | (tmp & 0xff));
+	}
+
+	tmp = get_imm(srcw);
+	if (tmp != INVALID_IMM) {
+		FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
+		return push_inst32(compiler, MOV_WI | RD4(dst_reg) | tmp);
+	}
+
+	tmp = get_imm(~srcw);
+	if (tmp != INVALID_IMM) {
+		FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
+		return push_inst32(compiler, MVN_WI | RD4(dst_reg) | tmp);
+	}
+
+	FAIL_IF(push_inst16(compiler, IT | (cc << 4) | ((cc & 0x1) << 3) | 0x4));
+
+	tmp = (sljit_uw) srcw;
+	FAIL_IF(push_inst32(compiler, MOVW | RD4(dst_reg)
+		| COPY_BITS(tmp, 12, 16, 4) | COPY_BITS(tmp, 11, 26, 1) | COPY_BITS(tmp, 8, 12, 3) | (tmp & 0xff)));
+	return push_inst32(compiler, MOVT | RD4(dst_reg)
+		| COPY_BITS(tmp, 12 + 16, 16, 4) | COPY_BITS(tmp, 11 + 16, 26, 1) | COPY_BITS(tmp, 8 + 16, 12, 3) | ((tmp & 0xff0000) >> 16));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 reg,
+	sljit_s32 mem, sljit_sw memw)
+{
+	sljit_s32 flags;
+	sljit_ins inst;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw));
+
+	if ((mem & OFFS_REG_MASK) || (memw > 255 || memw < -255))
+		return SLJIT_ERR_UNSUPPORTED;
+
+	if (type & SLJIT_MEM_SUPP)
+		return SLJIT_SUCCESS;
+
+	switch (type & 0xff) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_U32:
+	case SLJIT_MOV_S32:
+	case SLJIT_MOV_P:
+		flags = WORD_SIZE;
+		break;
+	case SLJIT_MOV_U8:
+		flags = BYTE_SIZE;
+		break;
+	case SLJIT_MOV_S8:
+		flags = BYTE_SIZE | SIGNED;
+		break;
+	case SLJIT_MOV_U16:
+		flags = HALF_SIZE;
+		break;
+	case SLJIT_MOV_S16:
+		flags = HALF_SIZE | SIGNED;
+		break;
+	default:
+		SLJIT_UNREACHABLE();
+		flags = WORD_SIZE;
+		break;
+	}
+
+	if (type & SLJIT_MEM_STORE)
+		flags |= STORE;
+
+	inst = sljit_mem32[flags] | 0x900;
+
+	if (type & SLJIT_MEM_PRE)
+		inst |= 0x400;
+
+	if (memw >= 0)
+		inst |= 0x200;
+	else
+		memw = -memw;
+
+	return push_inst32(compiler, inst | RT4(reg) | RN4(mem & REG_MASK) | memw);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
+{
+	struct sljit_const *const_;
+	sljit_s32 dst_r;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
+	PTR_FAIL_IF(!const_);
+	set_const(const_, compiler);
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+	PTR_FAIL_IF(emit_imm32_const(compiler, dst_r, init_value));
+
+	if (dst & SLJIT_MEM)
+		PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2));
+	return const_;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	struct sljit_put_label *put_label;
+	sljit_s32 dst_r;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label));
+	PTR_FAIL_IF(!put_label);
+	set_put_label(put_label, compiler, 0);
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+	PTR_FAIL_IF(emit_imm32_const(compiler, dst_r, 0));
+
+	if (dst & SLJIT_MEM)
+		PTR_FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2));
+	return put_label;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
+{
+	sljit_u16 *inst = (sljit_u16*)addr;
+	SLJIT_UNUSED_ARG(executable_offset);
+
+	SLJIT_UPDATE_WX_FLAGS(inst, inst + 4, 0);
+	modify_imm32_const(inst, new_target);
+	SLJIT_UPDATE_WX_FLAGS(inst, inst + 4, 1);
+	inst = (sljit_u16 *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+	SLJIT_CACHE_FLUSH(inst, inst + 4);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
+{
+	sljit_set_jump_addr(addr, new_constant, executable_offset);
+}
diff --git a/src/c/pcre2/src/sljit/sljitNativeMIPS_32.c b/src/c/pcre2/src/sljit/sljitNativeMIPS_32.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitNativeMIPS_32.c
@@ -0,0 +1,671 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* mips 32-bit arch dependent functions. */
+
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
+{
+	if (!(imm & ~0xffff))
+		return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
+
+	if (imm < 0 && imm >= SIMM_MIN)
+		return push_inst(compiler, ADDIU | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
+
+	FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(imm >> 16), dst_ar));
+	return (imm & 0xffff) ? push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar) : SLJIT_SUCCESS;
+}
+
+#define EMIT_LOGICAL(op_imm, op_norm) \
+	if (flags & SRC2_IMM) { \
+		if (op & SLJIT_SET_Z) \
+			FAIL_IF(push_inst(compiler, op_imm | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); \
+		if (!(flags & UNUSED_DEST)) \
+			FAIL_IF(push_inst(compiler, op_imm | S(src1) | T(dst) | IMM(src2), DR(dst))); \
+	} \
+	else { \
+		if (op & SLJIT_SET_Z) \
+			FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
+		if (!(flags & UNUSED_DEST)) \
+			FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | D(dst), DR(dst))); \
+	}
+
+#define EMIT_SHIFT(op_imm, op_v) \
+	if (flags & SRC2_IMM) { \
+		if (op & SLJIT_SET_Z) \
+			FAIL_IF(push_inst(compiler, op_imm | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); \
+		if (!(flags & UNUSED_DEST)) \
+			FAIL_IF(push_inst(compiler, op_imm | T(src1) | D(dst) | SH_IMM(src2), DR(dst))); \
+	} \
+	else { \
+		if (op & SLJIT_SET_Z) \
+			FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
+		if (!(flags & UNUSED_DEST)) \
+			FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | D(dst), DR(dst))); \
+	}
+
+static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
+	sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
+{
+	sljit_s32 is_overflow, is_carry, is_handled;
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_U32:
+	case SLJIT_MOV_S32:
+	case SLJIT_MOV_P:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if (dst != src2)
+			return push_inst(compiler, ADDU | S(src2) | TA(0) | D(dst), DR(dst));
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U8:
+	case SLJIT_MOV_S8:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
+			if (op == SLJIT_MOV_S8) {
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
+				return push_inst(compiler, SEB | T(src2) | D(dst), DR(dst));
+#else /* SLJIT_MIPS_REV < 1 */
+				FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(24), DR(dst)));
+				return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(24), DR(dst));
+#endif /* SLJIT_MIPS_REV >= 1 */
+			}
+			return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst));
+		}
+		else {
+			SLJIT_ASSERT(dst == src2);
+		}
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U16:
+	case SLJIT_MOV_S16:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
+			if (op == SLJIT_MOV_S16) {
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
+				return push_inst(compiler, SEH | T(src2) | D(dst), DR(dst));
+#else /* SLJIT_MIPS_REV < 1 */
+				FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(16), DR(dst)));
+				return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(16), DR(dst));
+#endif /* SLJIT_MIPS_REV >= 1 */
+			}
+			return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst));
+		}
+		else {
+			SLJIT_ASSERT(dst == src2);
+		}
+		return SLJIT_SUCCESS;
+
+	case SLJIT_NOT:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if (op & SLJIT_SET_Z)
+			FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+		if (!(flags & UNUSED_DEST))
+			FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst)));
+		return SLJIT_SUCCESS;
+
+	case SLJIT_CLZ:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
+		if (op & SLJIT_SET_Z)
+			FAIL_IF(push_inst(compiler, CLZ | S(src2) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
+		if (!(flags & UNUSED_DEST))
+			FAIL_IF(push_inst(compiler, CLZ | S(src2) | T(dst) | D(dst), DR(dst)));
+#else /* SLJIT_MIPS_REV < 1 */
+		if (SLJIT_UNLIKELY(flags & UNUSED_DEST)) {
+			FAIL_IF(push_inst(compiler, SRL | T(src2) | DA(EQUAL_FLAG) | SH_IMM(31), EQUAL_FLAG));
+			return push_inst(compiler, XORI | SA(EQUAL_FLAG) | TA(EQUAL_FLAG) | IMM(1), EQUAL_FLAG);
+		}
+		/* Nearly all instructions are unmovable in the following sequence. */
+		FAIL_IF(push_inst(compiler, ADDU | S(src2) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
+		/* Check zero. */
+		FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG1) | TA(0) | IMM(5), UNMOVABLE_INS));
+		FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM(32), UNMOVABLE_INS));
+		FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(dst) | IMM(-1), DR(dst)));
+		/* Loop for searching the highest bit. */
+		FAIL_IF(push_inst(compiler, ADDIU | S(dst) | T(dst) | IMM(1), DR(dst)));
+		FAIL_IF(push_inst(compiler, BGEZ | S(TMP_REG1) | IMM(-2), UNMOVABLE_INS));
+		FAIL_IF(push_inst(compiler, SLL | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), UNMOVABLE_INS));
+#endif /* SLJIT_MIPS_REV >= 1 */
+		return SLJIT_SUCCESS;
+
+	case SLJIT_ADD:
+		is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
+		is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+
+		if (flags & SRC2_IMM) {
+			if (is_overflow) {
+				if (src2 >= 0)
+					FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
+				else
+					FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
+			}
+			else if (op & SLJIT_SET_Z)
+				FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
+
+			if (is_overflow || is_carry) {
+				if (src2 >= 0)
+					FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
+				else {
+					FAIL_IF(push_inst(compiler, ADDIU | SA(0) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
+					FAIL_IF(push_inst(compiler, OR | S(src1) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
+				}
+			}
+			/* dst may be the same as src1 or src2. */
+			if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
+				FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(src2), DR(dst)));
+		}
+		else {
+			if (is_overflow)
+				FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+			else if (op & SLJIT_SET_Z)
+				FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+
+			if (is_overflow || is_carry)
+				FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
+			/* dst may be the same as src1 or src2. */
+			if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
+				FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | D(dst), DR(dst)));
+		}
+
+		/* a + b >= a | b (otherwise, the carry should be set to 1). */
+		if (is_overflow || is_carry)
+			FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
+		if (!is_overflow)
+			return SLJIT_SUCCESS;
+		FAIL_IF(push_inst(compiler, SLL | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
+		FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
+		FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
+		if (op & SLJIT_SET_Z)
+			FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
+		return push_inst(compiler, SRL | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
+
+	case SLJIT_ADDC:
+		is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+
+		if (flags & SRC2_IMM) {
+			if (is_carry) {
+				if (src2 >= 0)
+					FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
+				else {
+					FAIL_IF(push_inst(compiler, ADDIU | SA(0) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
+					FAIL_IF(push_inst(compiler, OR | S(src1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
+				}
+			}
+			FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(src2), DR(dst)));
+		} else {
+			if (is_carry)
+				FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+			/* dst may be the same as src1 or src2. */
+			FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | D(dst), DR(dst)));
+		}
+		if (is_carry)
+			FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
+
+		FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
+		if (!is_carry)
+			return SLJIT_SUCCESS;
+
+		/* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */
+		FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
+		/* Set carry flag. */
+		return push_inst(compiler, OR | SA(OTHER_FLAG) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
+
+	case SLJIT_SUB:
+		if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
+			FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
+			src2 = TMP_REG2;
+			flags &= ~SRC2_IMM;
+		}
+
+		is_handled = 0;
+
+		if (flags & SRC2_IMM) {
+			if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
+				FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
+				is_handled = 1;
+			}
+			else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
+				FAIL_IF(push_inst(compiler, SLTI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
+				is_handled = 1;
+			}
+		}
+
+		if (!is_handled && GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
+			is_handled = 1;
+
+			if (flags & SRC2_IMM) {
+				FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
+				src2 = TMP_REG2;
+				flags &= ~SRC2_IMM;
+			}
+
+			if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
+				FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
+			}
+			else if (GET_FLAG_TYPE(op) == SLJIT_GREATER || GET_FLAG_TYPE(op) == SLJIT_LESS_EQUAL)
+			{
+				FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
+			}
+			else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
+				FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
+			}
+			else if (GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER || GET_FLAG_TYPE(op) == SLJIT_SIG_LESS_EQUAL)
+			{
+				FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
+			}
+		}
+
+		if (is_handled) {
+			if (flags & SRC2_IMM) {
+				if (op & SLJIT_SET_Z)
+					FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
+				if (!(flags & UNUSED_DEST))
+					return push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst));
+			}
+			else {
+				if (op & SLJIT_SET_Z)
+					FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+				if (!(flags & UNUSED_DEST))
+					return push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst));
+			}
+			return SLJIT_SUCCESS;
+		}
+
+		is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
+		is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+
+		if (flags & SRC2_IMM) {
+			if (is_overflow) {
+				if (src2 >= 0)
+					FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
+				else
+					FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
+			}
+			else if (op & SLJIT_SET_Z)
+				FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
+
+			if (is_overflow || is_carry)
+				FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
+			/* dst may be the same as src1 or src2. */
+			if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
+				FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst)));
+		}
+		else {
+			if (is_overflow)
+				FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+			else if (op & SLJIT_SET_Z)
+				FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+
+			if (is_overflow || is_carry)
+				FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
+			/* dst may be the same as src1 or src2. */
+			if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
+				FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst)));
+		}
+
+		if (!is_overflow)
+			return SLJIT_SUCCESS;
+		FAIL_IF(push_inst(compiler, SLL | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
+		FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
+		FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
+		if (op & SLJIT_SET_Z)
+			FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
+		return push_inst(compiler, SRL | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
+
+	case SLJIT_SUBC:
+		if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
+			FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
+			src2 = TMP_REG2;
+			flags &= ~SRC2_IMM;
+		}
+
+		is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+
+		if (flags & SRC2_IMM) {
+			if (is_carry)
+				FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
+			/* dst may be the same as src1 or src2. */
+			FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst)));
+		}
+		else {
+			if (is_carry)
+				FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+			/* dst may be the same as src1 or src2. */
+			FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst)));
+		}
+
+		if (is_carry)
+			FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | D(TMP_REG1), DR(TMP_REG1)));
+
+		FAIL_IF(push_inst(compiler, SUBU | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
+		return (is_carry) ? push_inst(compiler, OR | SA(EQUAL_FLAG) | T(TMP_REG1) | DA(OTHER_FLAG), OTHER_FLAG) : SLJIT_SUCCESS;
+
+	case SLJIT_MUL:
+		SLJIT_ASSERT(!(flags & SRC2_IMM));
+
+		if (GET_FLAG_TYPE(op) != SLJIT_MUL_OVERFLOW) {
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
+			return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
+#else /* SLJIT_MIPS_REV < 1 */
+			FAIL_IF(push_inst(compiler, MULT | S(src1) | T(src2), MOVABLE_INS));
+			return push_inst(compiler, MFLO | D(dst), DR(dst));
+#endif /* SLJIT_MIPS_REV >= 1 */
+		}
+
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
+		FAIL_IF(push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst)));
+		FAIL_IF(push_inst(compiler, MUH | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+#else /* SLJIT_MIPS_REV < 6 */
+		FAIL_IF(push_inst(compiler, MULT | S(src1) | T(src2), MOVABLE_INS));
+		FAIL_IF(push_inst(compiler, MFHI | DA(EQUAL_FLAG), EQUAL_FLAG));
+		FAIL_IF(push_inst(compiler, MFLO | D(dst), DR(dst)));
+#endif /* SLJIT_MIPS_REV >= 6 */
+		FAIL_IF(push_inst(compiler, SRA | T(dst) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG));
+		return push_inst(compiler, SUBU | SA(EQUAL_FLAG) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
+
+	case SLJIT_AND:
+		EMIT_LOGICAL(ANDI, AND);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_OR:
+		EMIT_LOGICAL(ORI, OR);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_XOR:
+		EMIT_LOGICAL(XORI, XOR);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_SHL:
+		EMIT_SHIFT(SLL, SLLV);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_LSHR:
+		EMIT_SHIFT(SRL, SRLV);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_ASHR:
+		EMIT_SHIFT(SRA, SRAV);
+		return SLJIT_SUCCESS;
+	}
+
+	SLJIT_UNREACHABLE();
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
+{
+	FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 16), DR(dst)));
+	return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
+{
+	sljit_ins *inst = (sljit_ins *)addr;
+	SLJIT_UNUSED_ARG(executable_offset);
+
+	SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);
+	SLJIT_ASSERT((inst[0] & 0xffe00000) == LUI && (inst[1] & 0xfc000000) == ORI);
+	inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff);
+	inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff);
+	SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
+	inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+	SLJIT_CACHE_FLUSH(inst, inst + 2);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
+{
+	sljit_set_jump_addr(addr, new_constant, executable_offset);
+}
+
+static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_ins *ins_ptr)
+{
+	sljit_s32 stack_offset = 0;
+	sljit_s32 arg_count = 0;
+	sljit_s32 float_arg_count = 0;
+	sljit_s32 word_arg_count = 0;
+	sljit_s32 types = 0;
+	sljit_s32 arg_count_save, types_save;
+	sljit_ins prev_ins = NOP;
+	sljit_ins ins = NOP;
+	sljit_u8 offsets[4];
+
+	SLJIT_ASSERT(reg_map[TMP_REG1] == 4 && freg_map[TMP_FREG1] == 12);
+
+	arg_types >>= SLJIT_DEF_SHIFT;
+
+	while (arg_types) {
+		types = (types << SLJIT_DEF_SHIFT) | (arg_types & SLJIT_DEF_MASK);
+
+		switch (arg_types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			offsets[arg_count] = (sljit_u8)stack_offset;
+
+			if (word_arg_count == 0 && arg_count <= 1)
+				offsets[arg_count] = 254 + arg_count;
+
+			stack_offset += sizeof(sljit_f32);
+			arg_count++;
+			float_arg_count++;
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			if (stack_offset & 0x7)
+				stack_offset += sizeof(sljit_sw);
+			offsets[arg_count] = (sljit_u8)stack_offset;
+
+			if (word_arg_count == 0 && arg_count <= 1)
+				offsets[arg_count] = 254 + arg_count;
+
+			stack_offset += sizeof(sljit_f64);
+			arg_count++;
+			float_arg_count++;
+			break;
+		default:
+			offsets[arg_count] = (sljit_u8)stack_offset;
+			stack_offset += sizeof(sljit_sw);
+			arg_count++;
+			word_arg_count++;
+			break;
+		}
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	/* Stack is aligned to 16 bytes, max two doubles can be placed on the stack. */
+	if (stack_offset > 16)
+		FAIL_IF(push_inst(compiler, ADDIU | S(SLJIT_SP) | T(SLJIT_SP) | IMM(-16), DR(SLJIT_SP)));
+
+	types_save = types;
+	arg_count_save = arg_count;
+
+	while (types) {
+		switch (types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			arg_count--;
+			if (offsets[arg_count] < 254)
+				ins = SWC1 | S(SLJIT_SP) | FT(float_arg_count) | IMM(offsets[arg_count]);
+			float_arg_count--;
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			arg_count--;
+			if (offsets[arg_count] < 254)
+				ins = SDC1 | S(SLJIT_SP) | FT(float_arg_count) | IMM(offsets[arg_count]);
+			float_arg_count--;
+			break;
+		default:
+			if (offsets[arg_count - 1] >= 16)
+				ins = SW | S(SLJIT_SP) | T(word_arg_count) | IMM(offsets[arg_count - 1]);
+			else if (arg_count != word_arg_count)
+				ins = ADDU | S(word_arg_count) | TA(0) | DA(4 + (offsets[arg_count - 1] >> 2));
+			else if (arg_count == 1)
+				ins = ADDU | S(SLJIT_R0) | TA(0) | DA(4);
+
+			arg_count--;
+			word_arg_count--;
+			break;
+		}
+
+		if (ins != NOP) {
+			if (prev_ins != NOP)
+				FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS));
+			prev_ins = ins;
+			ins = NOP;
+		}
+
+		types >>= SLJIT_DEF_SHIFT;
+	}
+
+	types = types_save;
+	arg_count = arg_count_save;
+
+	while (types) {
+		switch (types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			arg_count--;
+			if (offsets[arg_count] == 254)
+				ins = MOV_S | FMT_S | FS(SLJIT_FR0) | FD(TMP_FREG1);
+			else if (offsets[arg_count] < 16)
+				ins = LW | S(SLJIT_SP) | TA(4 + (offsets[arg_count] >> 2)) | IMM(offsets[arg_count]);
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			arg_count--;
+			if (offsets[arg_count] == 254)
+				ins = MOV_S | FMT_D | FS(SLJIT_FR0) | FD(TMP_FREG1);
+			else if (offsets[arg_count] < 16) {
+				if (prev_ins != NOP)
+					FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS));
+				prev_ins = LW | S(SLJIT_SP) | TA(4 + (offsets[arg_count] >> 2)) | IMM(offsets[arg_count]);
+				ins = LW | S(SLJIT_SP) | TA(5 + (offsets[arg_count] >> 2)) | IMM(offsets[arg_count] + sizeof(sljit_sw));
+			}
+			break;
+		default:
+			arg_count--;
+			break;
+		}
+
+		if (ins != NOP) {
+			if (prev_ins != NOP)
+				FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS));
+			prev_ins = ins;
+			ins = NOP;
+		}
+
+		types >>= SLJIT_DEF_SHIFT;
+	}
+
+	*ins_ptr = prev_ins;
+
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 post_call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types)
+{
+	sljit_s32 stack_offset = 0;
+
+	arg_types >>= SLJIT_DEF_SHIFT;
+
+	while (arg_types) {
+		switch (arg_types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			stack_offset += sizeof(sljit_f32);
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			if (stack_offset & 0x7)
+				stack_offset += sizeof(sljit_sw);
+			stack_offset += sizeof(sljit_f64);
+			break;
+		default:
+			stack_offset += sizeof(sljit_sw);
+			break;
+		}
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	/* Stack is aligned to 16 bytes, max two doubles can be placed on the stack. */
+	if (stack_offset > 16)
+		return push_inst(compiler, ADDIU | S(SLJIT_SP) | T(SLJIT_SP) | IMM(16), DR(SLJIT_SP));
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types)
+{
+	struct sljit_jump *jump;
+	sljit_ins ins;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
+
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	PTR_FAIL_IF(!jump);
+	set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
+	type &= 0xff;
+
+	PTR_FAIL_IF(call_with_args(compiler, arg_types, &ins));
+
+	SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
+
+	PTR_FAIL_IF(emit_const(compiler, PIC_ADDR_REG, 0));
+
+	jump->flags |= IS_JAL | IS_CALL;
+	PTR_FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS));
+	jump->addr = compiler->size;
+	PTR_FAIL_IF(push_inst(compiler, ins, UNMOVABLE_INS));
+
+	PTR_FAIL_IF(post_call_with_args(compiler, arg_types));
+
+	return jump;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_ins ins;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
+
+	SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
+
+	if (src & SLJIT_IMM)
+		FAIL_IF(load_immediate(compiler, DR(PIC_ADDR_REG), srcw));
+	else if (FAST_IS_REG(src))
+		FAIL_IF(push_inst(compiler, ADDU | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG)));
+	else if (src & SLJIT_MEM) {
+		ADJUST_LOCAL_OFFSET(src, srcw);
+		FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, DR(PIC_ADDR_REG), src, srcw));
+	}
+
+	FAIL_IF(call_with_args(compiler, arg_types, &ins));
+
+	/* Register input. */
+	FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS));
+	FAIL_IF(push_inst(compiler, ins, UNMOVABLE_INS));
+	return post_call_with_args(compiler, arg_types);
+}
diff --git a/src/c/pcre2/src/sljit/sljitNativeMIPS_64.c b/src/c/pcre2/src/sljit/sljitNativeMIPS_64.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitNativeMIPS_64.c
@@ -0,0 +1,672 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* mips 64-bit arch dependent functions. */
+
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
+{
+	sljit_s32 shift = 32;
+	sljit_s32 shift2;
+	sljit_s32 inv = 0;
+	sljit_ins ins;
+	sljit_uw uimm;
+
+	if (!(imm & ~0xffff))
+		return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
+
+	if (imm < 0 && imm >= SIMM_MIN)
+		return push_inst(compiler, ADDIU | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
+
+	if (imm <= 0x7fffffffl && imm >= -0x80000000l) {
+		FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(imm >> 16), dst_ar));
+		return (imm & 0xffff) ? push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar) : SLJIT_SUCCESS;
+	}
+
+	/* Zero extended number. */
+	uimm = imm;
+	if (imm < 0) {
+		uimm = ~imm;
+		inv = 1;
+	}
+
+	while (!(uimm & 0xff00000000000000l)) {
+		shift -= 8;
+		uimm <<= 8;
+	}
+
+	if (!(uimm & 0xf000000000000000l)) {
+		shift -= 4;
+		uimm <<= 4;
+	}
+
+	if (!(uimm & 0xc000000000000000l)) {
+		shift -= 2;
+		uimm <<= 2;
+	}
+
+	if ((sljit_sw)uimm < 0) {
+		uimm >>= 1;
+		shift += 1;
+	}
+	SLJIT_ASSERT(((uimm & 0xc000000000000000l) == 0x4000000000000000l) && (shift > 0) && (shift <= 32));
+
+	if (inv)
+		uimm = ~uimm;
+
+	FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(uimm >> 48), dst_ar));
+	if (uimm & 0x0000ffff00000000l)
+		FAIL_IF(push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(uimm >> 32), dst_ar));
+
+	imm &= (1l << shift) - 1;
+	if (!(imm & ~0xffff)) {
+		ins = (shift == 32) ? DSLL32 : DSLL;
+		if (shift < 32)
+			ins |= SH_IMM(shift);
+		FAIL_IF(push_inst(compiler, ins | TA(dst_ar) | DA(dst_ar), dst_ar));
+		return !(imm & 0xffff) ? SLJIT_SUCCESS : push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar);
+	}
+
+	/* Double shifts needs to be performed. */
+	uimm <<= 32;
+	shift2 = shift - 16;
+
+	while (!(uimm & 0xf000000000000000l)) {
+		shift2 -= 4;
+		uimm <<= 4;
+	}
+
+	if (!(uimm & 0xc000000000000000l)) {
+		shift2 -= 2;
+		uimm <<= 2;
+	}
+
+	if (!(uimm & 0x8000000000000000l)) {
+		shift2--;
+		uimm <<= 1;
+	}
+
+	SLJIT_ASSERT((uimm & 0x8000000000000000l) && (shift2 > 0) && (shift2 <= 16));
+
+	FAIL_IF(push_inst(compiler, DSLL | TA(dst_ar) | DA(dst_ar) | SH_IMM(shift - shift2), dst_ar));
+	FAIL_IF(push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(uimm >> 48), dst_ar));
+	FAIL_IF(push_inst(compiler, DSLL | TA(dst_ar) | DA(dst_ar) | SH_IMM(shift2), dst_ar));
+
+	imm &= (1l << shift2) - 1;
+	return !(imm & 0xffff) ? SLJIT_SUCCESS : push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar);
+}
+
+#define SELECT_OP(a, b) \
+	(!(op & SLJIT_I32_OP) ? a : b)
+
+#define EMIT_LOGICAL(op_imm, op_norm) \
+	if (flags & SRC2_IMM) { \
+		if (op & SLJIT_SET_Z) \
+			FAIL_IF(push_inst(compiler, op_imm | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); \
+		if (!(flags & UNUSED_DEST)) \
+			FAIL_IF(push_inst(compiler, op_imm | S(src1) | T(dst) | IMM(src2), DR(dst))); \
+	} \
+	else { \
+		if (op & SLJIT_SET_Z) \
+			FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
+		if (!(flags & UNUSED_DEST)) \
+			FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | D(dst), DR(dst))); \
+	}
+
+#define EMIT_SHIFT(op_dimm, op_dimm32, op_imm, op_dv, op_v) \
+	if (flags & SRC2_IMM) { \
+		if (src2 >= 32) { \
+			SLJIT_ASSERT(!(op & SLJIT_I32_OP)); \
+			ins = op_dimm32; \
+			src2 -= 32; \
+		} \
+		else \
+			ins = (op & SLJIT_I32_OP) ? op_imm : op_dimm; \
+		if (op & SLJIT_SET_Z) \
+			FAIL_IF(push_inst(compiler, ins | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); \
+		if (!(flags & UNUSED_DEST)) \
+			FAIL_IF(push_inst(compiler, ins | T(src1) | D(dst) | SH_IMM(src2), DR(dst))); \
+	} \
+	else { \
+		ins = (op & SLJIT_I32_OP) ? op_v : op_dv; \
+		if (op & SLJIT_SET_Z) \
+			FAIL_IF(push_inst(compiler, ins | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
+		if (!(flags & UNUSED_DEST)) \
+			FAIL_IF(push_inst(compiler, ins | S(src2) | T(src1) | D(dst), DR(dst))); \
+	}
+
+static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
+	sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
+{
+	sljit_ins ins;
+	sljit_s32 is_overflow, is_carry, is_handled;
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_P:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if (dst != src2)
+			return push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src2) | TA(0) | D(dst), DR(dst));
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U8:
+	case SLJIT_MOV_S8:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
+			if (op == SLJIT_MOV_S8) {
+				FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(24), DR(dst)));
+				return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(24), DR(dst));
+			}
+			return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst));
+		}
+		else {
+			SLJIT_ASSERT(dst == src2);
+		}
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U16:
+	case SLJIT_MOV_S16:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
+			if (op == SLJIT_MOV_S16) {
+				FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(16), DR(dst)));
+				return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(16), DR(dst));
+			}
+			return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst));
+		}
+		else {
+			SLJIT_ASSERT(dst == src2);
+		}
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U32:
+		SLJIT_ASSERT(!(op & SLJIT_I32_OP));
+		FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(0), DR(dst)));
+		return push_inst(compiler, DSRL32 | T(dst) | D(dst) | SH_IMM(0), DR(dst));
+
+	case SLJIT_MOV_S32:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		return push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(0), DR(dst));
+
+	case SLJIT_NOT:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if (op & SLJIT_SET_Z)
+			FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+		if (!(flags & UNUSED_DEST))
+			FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst)));
+		return SLJIT_SUCCESS;
+
+	case SLJIT_CLZ:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
+		if (op & SLJIT_SET_Z)
+			FAIL_IF(push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(src2) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
+		if (!(flags & UNUSED_DEST))
+			FAIL_IF(push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(src2) | T(dst) | D(dst), DR(dst)));
+#else /* SLJIT_MIPS_REV < 1 */
+		if (SLJIT_UNLIKELY(flags & UNUSED_DEST)) {
+			FAIL_IF(push_inst(compiler, SELECT_OP(DSRL32, SRL) | T(src2) | DA(EQUAL_FLAG) | SH_IMM(31), EQUAL_FLAG));
+			return push_inst(compiler, XORI | SA(EQUAL_FLAG) | TA(EQUAL_FLAG) | IMM(1), EQUAL_FLAG);
+		}
+		/* Nearly all instructions are unmovable in the following sequence. */
+		FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src2) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
+		/* Check zero. */
+		FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG1) | TA(0) | IMM(5), UNMOVABLE_INS));
+		FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM((op & SLJIT_I32_OP) ? 32 : 64), UNMOVABLE_INS));
+		FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | T(dst) | IMM(-1), DR(dst)));
+		/* Loop for searching the highest bit. */
+		FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(dst) | T(dst) | IMM(1), DR(dst)));
+		FAIL_IF(push_inst(compiler, BGEZ | S(TMP_REG1) | IMM(-2), UNMOVABLE_INS));
+		FAIL_IF(push_inst(compiler, SELECT_OP(DSLL, SLL) | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), UNMOVABLE_INS));
+#endif /* SLJIT_MIPS_REV >= 1 */
+		return SLJIT_SUCCESS;
+
+	case SLJIT_ADD:
+		is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
+		is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+
+		if (flags & SRC2_IMM) {
+			if (is_overflow) {
+				if (src2 >= 0)
+					FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
+				else
+					FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
+			}
+			else if (op & SLJIT_SET_Z)
+				FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
+
+			if (is_overflow || is_carry) {
+				if (src2 >= 0)
+					FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
+				else {
+					FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
+					FAIL_IF(push_inst(compiler, OR | S(src1) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
+				}
+			}
+			/* dst may be the same as src1 or src2. */
+			if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
+				FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(src2), DR(dst)));
+		}
+		else {
+			if (is_overflow)
+				FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+			else if (op & SLJIT_SET_Z)
+				FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+
+			if (is_overflow || is_carry)
+				FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
+			/* dst may be the same as src1 or src2. */
+			if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
+				FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | D(dst), DR(dst)));
+		}
+
+		/* a + b >= a | b (otherwise, the carry should be set to 1). */
+		if (is_overflow || is_carry)
+			FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
+		if (!is_overflow)
+			return SLJIT_SUCCESS;
+		FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
+		FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
+		FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
+		if (op & SLJIT_SET_Z)
+			FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
+		return push_inst(compiler, SELECT_OP(DSRL32, SRL) | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
+
+	case SLJIT_ADDC:
+		is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+
+		if (flags & SRC2_IMM) {
+			if (is_carry) {
+				if (src2 >= 0)
+					FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
+				else {
+					FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
+					FAIL_IF(push_inst(compiler, OR | S(src1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
+				}
+			}
+			FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(src2), DR(dst)));
+		} else {
+			if (is_carry)
+				FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+			/* dst may be the same as src1 or src2. */
+			FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | D(dst), DR(dst)));
+		}
+		if (is_carry)
+			FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
+
+		FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
+		if (!is_carry)
+			return SLJIT_SUCCESS;
+
+		/* Set ULESS_FLAG (dst == 0) && (OTHER_FLAG == 1). */
+		FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
+		/* Set carry flag. */
+		return push_inst(compiler, OR | SA(OTHER_FLAG) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
+
+	case SLJIT_SUB:
+		if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
+			FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
+			src2 = TMP_REG2;
+			flags &= ~SRC2_IMM;
+		}
+
+		is_handled = 0;
+
+		if (flags & SRC2_IMM) {
+			if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
+				FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
+				is_handled = 1;
+			}
+			else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
+				FAIL_IF(push_inst(compiler, SLTI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
+				is_handled = 1;
+			}
+		}
+
+		if (!is_handled && GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL) {
+			is_handled = 1;
+
+			if (flags & SRC2_IMM) {
+				FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
+				src2 = TMP_REG2;
+				flags &= ~SRC2_IMM;
+			}
+
+			if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
+				FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
+			}
+			else if (GET_FLAG_TYPE(op) == SLJIT_GREATER || GET_FLAG_TYPE(op) == SLJIT_LESS_EQUAL)
+			{
+				FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
+			}
+			else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
+				FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
+			}
+			else if (GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER || GET_FLAG_TYPE(op) == SLJIT_SIG_LESS_EQUAL)
+			{
+				FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
+			}
+		}
+
+		if (is_handled) {
+			if (flags & SRC2_IMM) {
+				if (op & SLJIT_SET_Z)
+					FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
+				if (!(flags & UNUSED_DEST))
+					return push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst));
+			}
+			else {
+				if (op & SLJIT_SET_Z)
+					FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+				if (!(flags & UNUSED_DEST))
+					return push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst));
+			}
+			return SLJIT_SUCCESS;
+		}
+
+		is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
+		is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+
+		if (flags & SRC2_IMM) {
+			if (is_overflow) {
+				if (src2 >= 0)
+					FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
+				else
+					FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
+			}
+			else if (op & SLJIT_SET_Z)
+				FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
+
+			if (is_overflow || is_carry)
+				FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
+			/* dst may be the same as src1 or src2. */
+			if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
+				FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst)));
+		}
+		else {
+			if (is_overflow)
+				FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+			else if (op & SLJIT_SET_Z)
+				FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+
+			if (is_overflow || is_carry)
+				FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
+			/* dst may be the same as src1 or src2. */
+			if (!(flags & UNUSED_DEST) || (op & VARIABLE_FLAG_MASK))
+				FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst)));
+		}
+
+		if (!is_overflow)
+			return SLJIT_SUCCESS;
+		FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | TA(OTHER_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
+		FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
+		FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
+		if (op & SLJIT_SET_Z)
+			FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
+		return push_inst(compiler, SELECT_OP(DSRL32, SRL) | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG);
+
+	case SLJIT_SUBC:
+		if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
+			FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
+			src2 = TMP_REG2;
+			flags &= ~SRC2_IMM;
+		}
+
+		is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+
+		if (flags & SRC2_IMM) {
+			if (is_carry)
+				FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
+			/* dst may be the same as src1 or src2. */
+			FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst)));
+		}
+		else {
+			if (is_carry)
+				FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+			/* dst may be the same as src1 or src2. */
+			FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst)));
+		}
+
+		if (is_carry)
+			FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OTHER_FLAG) | D(TMP_REG1), DR(TMP_REG1)));
+
+		FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
+		return (is_carry) ? push_inst(compiler, OR | SA(EQUAL_FLAG) | T(TMP_REG1) | DA(OTHER_FLAG), OTHER_FLAG) : SLJIT_SUCCESS;
+
+	case SLJIT_MUL:
+		SLJIT_ASSERT(!(flags & SRC2_IMM));
+
+		if (GET_FLAG_TYPE(op) != SLJIT_MUL_OVERFLOW) {
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
+			return push_inst(compiler, SELECT_OP(DMUL, MUL) | S(src1) | T(src2) | D(dst), DR(dst));
+#elif (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
+			if (op & SLJIT_I32_OP)
+				return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
+			FAIL_IF(push_inst(compiler, DMULT | S(src1) | T(src2), MOVABLE_INS));
+			return push_inst(compiler, MFLO | D(dst), DR(dst));
+#else /* SLJIT_MIPS_REV < 1 */
+			FAIL_IF(push_inst(compiler, SELECT_OP(DMULT, MULT) | S(src1) | T(src2), MOVABLE_INS));
+			return push_inst(compiler, MFLO | D(dst), DR(dst));
+#endif /* SLJIT_MIPS_REV >= 6 */
+		}
+
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
+		FAIL_IF(push_inst(compiler, SELECT_OP(DMUL, MUL) | S(src1) | T(src2) | D(dst), DR(dst)));
+		FAIL_IF(push_inst(compiler, SELECT_OP(DMUH, MUH) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
+#else /* SLJIT_MIPS_REV < 6 */
+		FAIL_IF(push_inst(compiler, SELECT_OP(DMULT, MULT) | S(src1) | T(src2), MOVABLE_INS));
+		FAIL_IF(push_inst(compiler, MFHI | DA(EQUAL_FLAG), EQUAL_FLAG));
+		FAIL_IF(push_inst(compiler, MFLO | D(dst), DR(dst)));
+#endif /* SLJIT_MIPS_REV >= 6 */
+		FAIL_IF(push_inst(compiler, SELECT_OP(DSRA32, SRA) | T(dst) | DA(OTHER_FLAG) | SH_IMM(31), OTHER_FLAG));
+		return push_inst(compiler, SELECT_OP(DSUBU, SUBU) | SA(EQUAL_FLAG) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
+
+	case SLJIT_AND:
+		EMIT_LOGICAL(ANDI, AND);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_OR:
+		EMIT_LOGICAL(ORI, OR);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_XOR:
+		EMIT_LOGICAL(XORI, XOR);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_SHL:
+		EMIT_SHIFT(DSLL, DSLL32, SLL, DSLLV, SLLV);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_LSHR:
+		EMIT_SHIFT(DSRL, DSRL32, SRL, DSRLV, SRLV);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_ASHR:
+		EMIT_SHIFT(DSRA, DSRA32, SRA, DSRAV, SRAV);
+		return SLJIT_SUCCESS;
+	}
+
+	SLJIT_UNREACHABLE();
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
+{
+	FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 48), DR(dst)));
+	FAIL_IF(push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value >> 32), DR(dst)));
+	FAIL_IF(push_inst(compiler, DSLL | T(dst) | D(dst) | SH_IMM(16), DR(dst)));
+	FAIL_IF(push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value >> 16), DR(dst)));
+	FAIL_IF(push_inst(compiler, DSLL | T(dst) | D(dst) | SH_IMM(16), DR(dst)));
+	return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
+{
+	sljit_ins *inst = (sljit_ins *)addr;
+	SLJIT_UNUSED_ARG(executable_offset);
+
+	SLJIT_UPDATE_WX_FLAGS(inst, inst + 6, 0);
+	inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 48) & 0xffff);
+	inst[1] = (inst[1] & 0xffff0000) | ((new_target >> 32) & 0xffff);
+	inst[3] = (inst[3] & 0xffff0000) | ((new_target >> 16) & 0xffff);
+	inst[5] = (inst[5] & 0xffff0000) | (new_target & 0xffff);
+	SLJIT_UPDATE_WX_FLAGS(inst, inst + 6, 1);
+	inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+	SLJIT_CACHE_FLUSH(inst, inst + 6);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
+{
+	sljit_set_jump_addr(addr, new_constant, executable_offset);
+}
+
+static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_ins *ins_ptr)
+{
+	sljit_s32 arg_count = 0;
+	sljit_s32 word_arg_count = 0;
+	sljit_s32 float_arg_count = 0;
+	sljit_s32 types = 0;
+	sljit_ins prev_ins = NOP;
+	sljit_ins ins = NOP;
+
+	SLJIT_ASSERT(reg_map[TMP_REG1] == 4 && freg_map[TMP_FREG1] == 12);
+
+	arg_types >>= SLJIT_DEF_SHIFT;
+
+	while (arg_types) {
+		types = (types << SLJIT_DEF_SHIFT) | (arg_types & SLJIT_DEF_MASK);
+
+		switch (arg_types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+		case SLJIT_ARG_TYPE_F64:
+			arg_count++;
+			float_arg_count++;
+			break;
+		default:
+			arg_count++;
+			word_arg_count++;
+			break;
+		}
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	while (types) {
+		switch (types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			if (arg_count != float_arg_count)
+				ins = MOV_S | FMT_S | FS(float_arg_count) | FD(arg_count);
+			else if (arg_count == 1)
+				ins = MOV_S | FMT_S | FS(SLJIT_FR0) | FD(TMP_FREG1);
+			arg_count--;
+			float_arg_count--;
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			if (arg_count != float_arg_count)
+				ins = MOV_S | FMT_D | FS(float_arg_count) | FD(arg_count);
+			else if (arg_count == 1)
+				ins = MOV_S | FMT_D | FS(SLJIT_FR0) | FD(TMP_FREG1);
+			arg_count--;
+			float_arg_count--;
+			break;
+		default:
+			if (arg_count != word_arg_count)
+				ins = DADDU | S(word_arg_count) | TA(0) | D(arg_count);
+			else if (arg_count == 1)
+				ins = DADDU | S(SLJIT_R0) | TA(0) | DA(4);
+			arg_count--;
+			word_arg_count--;
+			break;
+		}
+
+		if (ins != NOP) {
+			if (prev_ins != NOP)
+				FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS));
+			prev_ins = ins;
+			ins = NOP;
+		}
+
+		types >>= SLJIT_DEF_SHIFT;
+	}
+
+	*ins_ptr = prev_ins;
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types)
+{
+	struct sljit_jump *jump;
+	sljit_ins ins;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
+
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	PTR_FAIL_IF(!jump);
+	set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
+	type &= 0xff;
+
+	PTR_FAIL_IF(call_with_args(compiler, arg_types, &ins));
+
+	SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
+
+	PTR_FAIL_IF(emit_const(compiler, PIC_ADDR_REG, 0));
+
+	jump->flags |= IS_JAL | IS_CALL;
+	PTR_FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS));
+	jump->addr = compiler->size;
+	PTR_FAIL_IF(push_inst(compiler, ins, UNMOVABLE_INS));
+
+	return jump;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_ins ins;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
+
+	SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
+
+	if (src & SLJIT_IMM)
+		FAIL_IF(load_immediate(compiler, DR(PIC_ADDR_REG), srcw));
+	else if (FAST_IS_REG(src))
+		FAIL_IF(push_inst(compiler, DADDU | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG)));
+	else if (src & SLJIT_MEM) {
+		ADJUST_LOCAL_OFFSET(src, srcw);
+		FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, DR(PIC_ADDR_REG), src, srcw));
+	}
+
+	FAIL_IF(call_with_args(compiler, arg_types, &ins));
+
+	/* Register input. */
+	FAIL_IF(push_inst(compiler, JALR | S(PIC_ADDR_REG) | DA(RETURN_ADDR_REG), UNMOVABLE_INS));
+	return push_inst(compiler, ins, UNMOVABLE_INS);
+}
diff --git a/src/c/pcre2/src/sljit/sljitNativeMIPS_common.c b/src/c/pcre2/src/sljit/sljitNativeMIPS_common.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitNativeMIPS_common.c
@@ -0,0 +1,2305 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Latest MIPS architecture. */
+
+#ifndef __mips_hard_float
+/* Disable automatic detection, covers both -msoft-float and -mno-float */
+#undef SLJIT_IS_FPU_AVAILABLE
+#define SLJIT_IS_FPU_AVAILABLE 0
+#endif
+
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
+{
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
+
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+	return "MIPS32-R6" SLJIT_CPUINFO;
+#else /* !SLJIT_CONFIG_MIPS_32 */
+	return "MIPS64-R6" SLJIT_CPUINFO;
+#endif /* SLJIT_CONFIG_MIPS_32 */
+
+#elif (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
+
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+	return "MIPS32-R1" SLJIT_CPUINFO;
+#else /* !SLJIT_CONFIG_MIPS_32 */
+	return "MIPS64-R1" SLJIT_CPUINFO;
+#endif /* SLJIT_CONFIG_MIPS_32 */
+
+#else /* SLJIT_MIPS_REV < 1 */
+	return "MIPS III" SLJIT_CPUINFO;
+#endif /* SLJIT_MIPS_REV >= 6 */
+}
+
+/* Length of an instruction word
+   Both for mips-32 and mips-64 */
+typedef sljit_u32 sljit_ins;
+
+#define TMP_REG1	(SLJIT_NUMBER_OF_REGISTERS + 2)
+#define TMP_REG2	(SLJIT_NUMBER_OF_REGISTERS + 3)
+#define TMP_REG3	(SLJIT_NUMBER_OF_REGISTERS + 4)
+
+/* For position independent code, t9 must contain the function address. */
+#define PIC_ADDR_REG	TMP_REG2
+
+/* Floating point status register. */
+#define FCSR_REG	31
+/* Return address register. */
+#define RETURN_ADDR_REG	31
+
+/* Flags are kept in volatile registers. */
+#define EQUAL_FLAG	3
+#define OTHER_FLAG	1
+
+#define TMP_FREG1	(SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
+#define TMP_FREG2	(SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2)
+#define TMP_FREG3	(SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3)
+
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = {
+	0, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 24, 23, 22, 21, 20, 19, 18, 17, 16, 29, 4, 25, 31
+};
+
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+
+static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 4] = {
+	0, 0, 14, 2, 4, 6, 8, 12, 10, 16
+};
+
+#else
+
+static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 4] = {
+	0, 0, 13, 14, 15, 16, 17, 12, 18, 10
+};
+
+#endif
+
+/* --------------------------------------------------------------------- */
+/*  Instrucion forms                                                     */
+/* --------------------------------------------------------------------- */
+
+#define S(s)		(reg_map[s] << 21)
+#define T(t)		(reg_map[t] << 16)
+#define D(d)		(reg_map[d] << 11)
+#define FT(t)		(freg_map[t] << 16)
+#define FS(s)		(freg_map[s] << 11)
+#define FD(d)		(freg_map[d] << 6)
+/* Absolute registers. */
+#define SA(s)		((s) << 21)
+#define TA(t)		((t) << 16)
+#define DA(d)		((d) << 11)
+#define IMM(imm)	((imm) & 0xffff)
+#define SH_IMM(imm)	((imm) << 6)
+
+#define DR(dr)		(reg_map[dr])
+#define FR(dr)		(freg_map[dr])
+#define HI(opcode)	((opcode) << 26)
+#define LO(opcode)	(opcode)
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
+/* CMP.cond.fmt */
+/* S = (20 << 21) D = (21 << 21) */
+#define CMP_FMT_S	(20 << 21)
+#endif /* SLJIT_MIPS_REV >= 6 */
+/* S = (16 << 21) D = (17 << 21) */
+#define FMT_S		(16 << 21)
+#define FMT_D		(17 << 21)
+
+#define ABS_S		(HI(17) | FMT_S | LO(5))
+#define ADD_S		(HI(17) | FMT_S | LO(0))
+#define ADDIU		(HI(9))
+#define ADDU		(HI(0) | LO(33))
+#define AND		(HI(0) | LO(36))
+#define ANDI		(HI(12))
+#define B		(HI(4))
+#define BAL		(HI(1) | (17 << 16))
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
+#define BC1EQZ		(HI(17) | (9 << 21) | FT(TMP_FREG3))
+#define BC1NEZ		(HI(17) | (13 << 21) | FT(TMP_FREG3))
+#else /* SLJIT_MIPS_REV < 6 */
+#define BC1F		(HI(17) | (8 << 21))
+#define BC1T		(HI(17) | (8 << 21) | (1 << 16))
+#endif /* SLJIT_MIPS_REV >= 6 */
+#define BEQ		(HI(4))
+#define BGEZ		(HI(1) | (1 << 16))
+#define BGTZ		(HI(7))
+#define BLEZ		(HI(6))
+#define BLTZ		(HI(1) | (0 << 16))
+#define BNE		(HI(5))
+#define BREAK		(HI(0) | LO(13))
+#define CFC1		(HI(17) | (2 << 21))
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
+#define C_UEQ_S		(HI(17) | CMP_FMT_S | LO(3))
+#define C_ULE_S		(HI(17) | CMP_FMT_S | LO(7))
+#define C_ULT_S		(HI(17) | CMP_FMT_S | LO(5))
+#define C_UN_S		(HI(17) | CMP_FMT_S | LO(1))
+#define C_FD		(FD(TMP_FREG3))
+#else /* SLJIT_MIPS_REV < 6 */
+#define C_UEQ_S		(HI(17) | FMT_S | LO(51))
+#define C_ULE_S		(HI(17) | FMT_S | LO(55))
+#define C_ULT_S		(HI(17) | FMT_S | LO(53))
+#define C_UN_S		(HI(17) | FMT_S | LO(49))
+#define C_FD		(0)
+#endif /* SLJIT_MIPS_REV >= 6 */
+#define CVT_S_S		(HI(17) | FMT_S | LO(32))
+#define DADDIU		(HI(25))
+#define DADDU		(HI(0) | LO(45))
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
+#define DDIV		(HI(0) | (2 << 6) | LO(30))
+#define DDIVU		(HI(0) | (2 << 6) | LO(31))
+#define DMOD		(HI(0) | (3 << 6) | LO(30))
+#define DMODU		(HI(0) | (3 << 6) | LO(31))
+#define DIV		(HI(0) | (2 << 6) | LO(26))
+#define DIVU		(HI(0) | (2 << 6) | LO(27))
+#define DMUH		(HI(0) | (3 << 6) | LO(28))
+#define DMUHU		(HI(0) | (3 << 6) | LO(29))
+#define DMUL		(HI(0) | (2 << 6) | LO(28))
+#define DMULU		(HI(0) | (2 << 6) | LO(29))
+#else /* SLJIT_MIPS_REV < 6 */
+#define DDIV		(HI(0) | LO(30))
+#define DDIVU		(HI(0) | LO(31))
+#define DIV		(HI(0) | LO(26))
+#define DIVU		(HI(0) | LO(27))
+#define DMULT		(HI(0) | LO(28))
+#define DMULTU		(HI(0) | LO(29))
+#endif /* SLJIT_MIPS_REV >= 6 */
+#define DIV_S		(HI(17) | FMT_S | LO(3))
+#define DSLL		(HI(0) | LO(56))
+#define DSLL32		(HI(0) | LO(60))
+#define DSLLV		(HI(0) | LO(20))
+#define DSRA		(HI(0) | LO(59))
+#define DSRA32		(HI(0) | LO(63))
+#define DSRAV		(HI(0) | LO(23))
+#define DSRL		(HI(0) | LO(58))
+#define DSRL32		(HI(0) | LO(62))
+#define DSRLV		(HI(0) | LO(22))
+#define DSUBU		(HI(0) | LO(47))
+#define J		(HI(2))
+#define JAL		(HI(3))
+#define JALR		(HI(0) | LO(9))
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
+#define JR		(HI(0) | LO(9))
+#else /* SLJIT_MIPS_REV < 6 */
+#define JR		(HI(0) | LO(8))
+#endif /* SLJIT_MIPS_REV >= 6 */
+#define LD		(HI(55))
+#define LUI		(HI(15))
+#define LW		(HI(35))
+#define MFC1		(HI(17))
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
+#define MOD		(HI(0) | (3 << 6) | LO(26))
+#define MODU		(HI(0) | (3 << 6) | LO(27))
+#else /* SLJIT_MIPS_REV < 6 */
+#define MFHI		(HI(0) | LO(16))
+#define MFLO		(HI(0) | LO(18))
+#endif /* SLJIT_MIPS_REV >= 6 */
+#define MOV_S		(HI(17) | FMT_S | LO(6))
+#define MTC1		(HI(17) | (4 << 21))
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
+#define MUH		(HI(0) | (3 << 6) | LO(24))
+#define MUHU		(HI(0) | (3 << 6) | LO(25))
+#define MUL		(HI(0) | (2 << 6) | LO(24))
+#define MULU		(HI(0) | (2 << 6) | LO(25))
+#else /* SLJIT_MIPS_REV < 6 */
+#define MULT		(HI(0) | LO(24))
+#define MULTU		(HI(0) | LO(25))
+#endif /* SLJIT_MIPS_REV >= 6 */
+#define MUL_S		(HI(17) | FMT_S | LO(2))
+#define NEG_S		(HI(17) | FMT_S | LO(7))
+#define NOP		(HI(0) | LO(0))
+#define NOR		(HI(0) | LO(39))
+#define OR		(HI(0) | LO(37))
+#define ORI		(HI(13))
+#define SD		(HI(63))
+#define SDC1		(HI(61))
+#define SLT		(HI(0) | LO(42))
+#define SLTI		(HI(10))
+#define SLTIU		(HI(11))
+#define SLTU		(HI(0) | LO(43))
+#define SLL		(HI(0) | LO(0))
+#define SLLV		(HI(0) | LO(4))
+#define SRL		(HI(0) | LO(2))
+#define SRLV		(HI(0) | LO(6))
+#define SRA		(HI(0) | LO(3))
+#define SRAV		(HI(0) | LO(7))
+#define SUB_S		(HI(17) | FMT_S | LO(1))
+#define SUBU		(HI(0) | LO(35))
+#define SW		(HI(43))
+#define SWC1		(HI(57))
+#define TRUNC_W_S	(HI(17) | FMT_S | LO(13))
+#define XOR		(HI(0) | LO(38))
+#define XORI		(HI(14))
+
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
+#define CLZ		(HI(28) | LO(32))
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
+#define DCLZ		(LO(18))
+#else /* SLJIT_MIPS_REV < 6 */
+#define DCLZ		(HI(28) | LO(36))
+#define MOVF		(HI(0) | (0 << 16) | LO(1))
+#define MOVN		(HI(0) | LO(11))
+#define MOVT		(HI(0) | (1 << 16) | LO(1))
+#define MOVZ		(HI(0) | LO(10))
+#define MUL		(HI(28) | LO(2))
+#endif /* SLJIT_MIPS_REV >= 6 */
+#define PREF		(HI(51))
+#define PREFX		(HI(19) | LO(15))
+#define SEB		(HI(31) | (16 << 6) | LO(32))
+#define SEH		(HI(31) | (24 << 6) | LO(32))
+#endif /* SLJIT_MIPS_REV >= 1 */
+
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+#define ADDU_W		ADDU
+#define ADDIU_W		ADDIU
+#define SLL_W		SLL
+#define SUBU_W		SUBU
+#else
+#define ADDU_W		DADDU
+#define ADDIU_W		DADDIU
+#define SLL_W		DSLL
+#define SUBU_W		DSUBU
+#endif
+
+#define SIMM_MAX	(0x7fff)
+#define SIMM_MIN	(-0x8000)
+#define UIMM_MAX	(0xffff)
+
+/* dest_reg is the absolute name of the register
+   Useful for reordering instructions in the delay slot. */
+static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins, sljit_s32 delay_slot)
+{
+	sljit_ins *ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
+	SLJIT_ASSERT(delay_slot == MOVABLE_INS || delay_slot >= UNMOVABLE_INS
+		|| delay_slot == ((ins >> 11) & 0x1f) || delay_slot == ((ins >> 16) & 0x1f));
+	FAIL_IF(!ptr);
+	*ptr = ins;
+	compiler->size++;
+	compiler->delay_slot = delay_slot;
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_ins invert_branch(sljit_s32 flags)
+{
+	if (flags & IS_BIT26_COND)
+		return (1 << 26);
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
+	if (flags & IS_BIT23_COND)
+		return (1 << 23);
+#endif /* SLJIT_MIPS_REV >= 6 */
+	return (1 << 16);
+}
+
+static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
+{
+	sljit_sw diff;
+	sljit_uw target_addr;
+	sljit_ins *inst;
+	sljit_ins saved_inst;
+
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+	if (jump->flags & (SLJIT_REWRITABLE_JUMP | IS_CALL))
+		return code_ptr;
+#else
+	if (jump->flags & SLJIT_REWRITABLE_JUMP)
+		return code_ptr;
+#endif
+
+	if (jump->flags & JUMP_ADDR)
+		target_addr = jump->u.target;
+	else {
+		SLJIT_ASSERT(jump->flags & JUMP_LABEL);
+		target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset;
+	}
+
+	inst = (sljit_ins *)jump->addr;
+	if (jump->flags & IS_COND)
+		inst--;
+
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+	if (jump->flags & IS_CALL)
+		goto keep_address;
+#endif
+
+	/* B instructions. */
+	if (jump->flags & IS_MOVABLE) {
+		diff = ((sljit_sw)target_addr - (sljit_sw)inst - executable_offset) >> 2;
+		if (diff <= SIMM_MAX && diff >= SIMM_MIN) {
+			jump->flags |= PATCH_B;
+
+			if (!(jump->flags & IS_COND)) {
+				inst[0] = inst[-1];
+				inst[-1] = (jump->flags & IS_JAL) ? BAL : B;
+				jump->addr -= sizeof(sljit_ins);
+				return inst;
+			}
+			saved_inst = inst[0];
+			inst[0] = inst[-1];
+			inst[-1] = saved_inst ^ invert_branch(jump->flags);
+			jump->addr -= 2 * sizeof(sljit_ins);
+			return inst;
+		}
+	}
+	else {
+		diff = ((sljit_sw)target_addr - (sljit_sw)(inst + 1) - executable_offset) >> 2;
+		if (diff <= SIMM_MAX && diff >= SIMM_MIN) {
+			jump->flags |= PATCH_B;
+
+			if (!(jump->flags & IS_COND)) {
+				inst[0] = (jump->flags & IS_JAL) ? BAL : B;
+				inst[1] = NOP;
+				return inst + 1;
+			}
+			inst[0] = inst[0] ^ invert_branch(jump->flags);
+			inst[1] = NOP;
+			jump->addr -= sizeof(sljit_ins);
+			return inst + 1;
+		}
+	}
+
+	if (jump->flags & IS_COND) {
+		if ((jump->flags & IS_MOVABLE) && (target_addr & ~0xfffffff) == ((jump->addr + 2 * sizeof(sljit_ins)) & ~0xfffffff)) {
+			jump->flags |= PATCH_J;
+			saved_inst = inst[0];
+			inst[0] = inst[-1];
+			inst[-1] = (saved_inst & 0xffff0000) | 3;
+			inst[1] = J;
+			inst[2] = NOP;
+			return inst + 2;
+		}
+		else if ((target_addr & ~0xfffffff) == ((jump->addr + 3 * sizeof(sljit_ins)) & ~0xfffffff)) {
+			jump->flags |= PATCH_J;
+			inst[0] = (inst[0] & 0xffff0000) | 3;
+			inst[1] = NOP;
+			inst[2] = J;
+			inst[3] = NOP;
+			jump->addr += sizeof(sljit_ins);
+			return inst + 3;
+		}
+	}
+	else {
+		/* J instuctions. */
+		if ((jump->flags & IS_MOVABLE) && (target_addr & ~0xfffffff) == (jump->addr & ~0xfffffff)) {
+			jump->flags |= PATCH_J;
+			inst[0] = inst[-1];
+			inst[-1] = (jump->flags & IS_JAL) ? JAL : J;
+			jump->addr -= sizeof(sljit_ins);
+			return inst;
+		}
+
+		if ((target_addr & ~0xfffffff) == ((jump->addr + sizeof(sljit_ins)) & ~0xfffffff)) {
+			jump->flags |= PATCH_J;
+			inst[0] = (jump->flags & IS_JAL) ? JAL : J;
+			inst[1] = NOP;
+			return inst + 1;
+		}
+	}
+
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+keep_address:
+	if (target_addr <= 0x7fffffff) {
+		jump->flags |= PATCH_ABS32;
+		if (jump->flags & IS_COND) {
+			inst[0] -= 4;
+			inst++;
+		}
+		inst[2] = inst[6];
+		inst[3] = inst[7];
+		return inst + 3;
+	}
+	if (target_addr <= 0x7fffffffffffl) {
+		jump->flags |= PATCH_ABS48;
+		if (jump->flags & IS_COND) {
+			inst[0] -= 2;
+			inst++;
+		}
+		inst[4] = inst[6];
+		inst[5] = inst[7];
+		return inst + 5;
+	}
+#endif
+
+	return code_ptr;
+}
+
+#ifdef __GNUC__
+static __attribute__ ((noinline)) void sljit_cache_flush(void* code, void* code_ptr)
+{
+	SLJIT_CACHE_FLUSH(code, code_ptr);
+}
+#endif
+
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+
+static SLJIT_INLINE sljit_sw put_label_get_length(struct sljit_put_label *put_label, sljit_uw max_label)
+{
+	if (max_label < 0x80000000l) {
+		put_label->flags = 0;
+		return 1;
+	}
+
+	if (max_label < 0x800000000000l) {
+		put_label->flags = 1;
+		return 3;
+	}
+
+	put_label->flags = 2;
+	return 5;
+}
+
+static SLJIT_INLINE void put_label_set(struct sljit_put_label *put_label)
+{
+	sljit_uw addr = put_label->label->addr;
+	sljit_ins *inst = (sljit_ins *)put_label->addr;
+	sljit_s32 reg = *inst;
+
+	if (put_label->flags == 0) {
+		SLJIT_ASSERT(addr < 0x80000000l);
+		inst[0] = LUI | T(reg) | IMM(addr >> 16);
+	}
+	else if (put_label->flags == 1) {
+		SLJIT_ASSERT(addr < 0x800000000000l);
+		inst[0] = LUI | T(reg) | IMM(addr >> 32);
+		inst[1] = ORI | S(reg) | T(reg) | IMM((addr >> 16) & 0xffff);
+		inst[2] = DSLL | T(reg) | D(reg) | SH_IMM(16);
+		inst += 2;
+	}
+	else {
+		inst[0] = LUI | T(reg) | IMM(addr >> 48);
+		inst[1] = ORI | S(reg) | T(reg) | IMM((addr >> 32) & 0xffff);
+		inst[2] = DSLL | T(reg) | D(reg) | SH_IMM(16);
+		inst[3] = ORI | S(reg) | T(reg) | IMM((addr >> 16) & 0xffff);
+		inst[4] = DSLL | T(reg) | D(reg) | SH_IMM(16);
+		inst += 4;
+	}
+
+	inst[1] = ORI | S(reg) | T(reg) | IMM(addr & 0xffff);
+}
+
+#endif
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+{
+	struct sljit_memory_fragment *buf;
+	sljit_ins *code;
+	sljit_ins *code_ptr;
+	sljit_ins *buf_ptr;
+	sljit_ins *buf_end;
+	sljit_uw word_count;
+	sljit_uw next_addr;
+	sljit_sw executable_offset;
+	sljit_uw addr;
+
+	struct sljit_label *label;
+	struct sljit_jump *jump;
+	struct sljit_const *const_;
+	struct sljit_put_label *put_label;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_generate_code(compiler));
+	reverse_buf(compiler);
+
+	code = (sljit_ins*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins), compiler->exec_allocator_data);
+	PTR_FAIL_WITH_EXEC_IF(code);
+	buf = compiler->buf;
+
+	code_ptr = code;
+	word_count = 0;
+	next_addr = 0;
+	executable_offset = SLJIT_EXEC_OFFSET(code);
+
+	label = compiler->labels;
+	jump = compiler->jumps;
+	const_ = compiler->consts;
+	put_label = compiler->put_labels;
+
+	do {
+		buf_ptr = (sljit_ins*)buf->memory;
+		buf_end = buf_ptr + (buf->used_size >> 2);
+		do {
+			*code_ptr = *buf_ptr++;
+			if (next_addr == word_count) {
+				SLJIT_ASSERT(!label || label->size >= word_count);
+				SLJIT_ASSERT(!jump || jump->addr >= word_count);
+				SLJIT_ASSERT(!const_ || const_->addr >= word_count);
+				SLJIT_ASSERT(!put_label || put_label->addr >= word_count);
+
+				/* These structures are ordered by their address. */
+				if (label && label->size == word_count) {
+					label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+					label->size = code_ptr - code;
+					label = label->next;
+				}
+				if (jump && jump->addr == word_count) {
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+					jump->addr = (sljit_uw)(code_ptr - 3);
+#else
+					jump->addr = (sljit_uw)(code_ptr - 7);
+#endif
+					code_ptr = detect_jump_type(jump, code_ptr, code, executable_offset);
+					jump = jump->next;
+				}
+				if (const_ && const_->addr == word_count) {
+					const_->addr = (sljit_uw)code_ptr;
+					const_ = const_->next;
+				}
+				if (put_label && put_label->addr == word_count) {
+					SLJIT_ASSERT(put_label->label);
+					put_label->addr = (sljit_uw)code_ptr;
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+					code_ptr += put_label_get_length(put_label, (sljit_uw)(SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + put_label->label->size));
+					word_count += 5;
+#endif
+					put_label = put_label->next;
+				}
+				next_addr = compute_next_addr(label, jump, const_, put_label);
+			}
+			code_ptr ++;
+			word_count ++;
+		} while (buf_ptr < buf_end);
+
+		buf = buf->next;
+	} while (buf);
+
+	if (label && label->size == word_count) {
+		label->addr = (sljit_uw)code_ptr;
+		label->size = code_ptr - code;
+		label = label->next;
+	}
+
+	SLJIT_ASSERT(!label);
+	SLJIT_ASSERT(!jump);
+	SLJIT_ASSERT(!const_);
+	SLJIT_ASSERT(!put_label);
+	SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size);
+
+	jump = compiler->jumps;
+	while (jump) {
+		do {
+			addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
+			buf_ptr = (sljit_ins *)jump->addr;
+
+			if (jump->flags & PATCH_B) {
+				addr = (sljit_sw)(addr - ((sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset) + sizeof(sljit_ins))) >> 2;
+				SLJIT_ASSERT((sljit_sw)addr <= SIMM_MAX && (sljit_sw)addr >= SIMM_MIN);
+				buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | (addr & 0xffff);
+				break;
+			}
+			if (jump->flags & PATCH_J) {
+				SLJIT_ASSERT((addr & ~0xfffffff) == (((sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset) + sizeof(sljit_ins)) & ~0xfffffff));
+				buf_ptr[0] |= (addr >> 2) & 0x03ffffff;
+				break;
+			}
+
+			/* Set the fields of immediate loads. */
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+			buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | ((addr >> 16) & 0xffff);
+			buf_ptr[1] = (buf_ptr[1] & 0xffff0000) | (addr & 0xffff);
+#else
+			if (jump->flags & PATCH_ABS32) {
+				SLJIT_ASSERT(addr <= 0x7fffffff);
+				buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | ((addr >> 16) & 0xffff);
+				buf_ptr[1] = (buf_ptr[1] & 0xffff0000) | (addr & 0xffff);
+			}
+			else if (jump->flags & PATCH_ABS48) {
+				SLJIT_ASSERT(addr <= 0x7fffffffffffl);
+				buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | ((addr >> 32) & 0xffff);
+				buf_ptr[1] = (buf_ptr[1] & 0xffff0000) | ((addr >> 16) & 0xffff);
+				buf_ptr[3] = (buf_ptr[3] & 0xffff0000) | (addr & 0xffff);
+			}
+			else {
+				buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | ((addr >> 48) & 0xffff);
+				buf_ptr[1] = (buf_ptr[1] & 0xffff0000) | ((addr >> 32) & 0xffff);
+				buf_ptr[3] = (buf_ptr[3] & 0xffff0000) | ((addr >> 16) & 0xffff);
+				buf_ptr[5] = (buf_ptr[5] & 0xffff0000) | (addr & 0xffff);
+			}
+#endif
+		} while (0);
+		jump = jump->next;
+	}
+
+	put_label = compiler->put_labels;
+	while (put_label) {
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+		addr = put_label->label->addr;
+		buf_ptr = (sljit_ins *)put_label->addr;
+
+		SLJIT_ASSERT((buf_ptr[0] & 0xffe00000) == LUI && (buf_ptr[1] & 0xfc000000) == ORI);
+		buf_ptr[0] |= (addr >> 16) & 0xffff;
+		buf_ptr[1] |= addr & 0xffff;
+#else
+		put_label_set(put_label);
+#endif
+		put_label = put_label->next;
+	}
+
+	compiler->error = SLJIT_ERR_COMPILED;
+	compiler->executable_offset = executable_offset;
+	compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins);
+
+	code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
+	code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+
+#ifndef __GNUC__
+	SLJIT_CACHE_FLUSH(code, code_ptr);
+#else
+	/* GCC workaround for invalid code generation with -O2. */
+	sljit_cache_flush(code, code_ptr);
+#endif
+	SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);
+	return code;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
+{
+	sljit_sw fir = 0;
+
+	switch (feature_type) {
+	case SLJIT_HAS_FPU:
+#ifdef SLJIT_IS_FPU_AVAILABLE
+		return SLJIT_IS_FPU_AVAILABLE;
+#elif defined(__GNUC__)
+		__asm__ ("cfc1 %0, $0" : "=r"(fir));
+		return (fir >> 22) & 0x1;
+#else
+#error "FIR check is not implemented for this architecture"
+#endif
+	case SLJIT_HAS_ZERO_REGISTER:
+		return 1;
+
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
+	case SLJIT_HAS_CLZ:
+	case SLJIT_HAS_CMOV:
+	case SLJIT_HAS_PREFETCH:
+		return 1;
+#endif /* SLJIT_MIPS_REV >= 1 */
+
+	default:
+		return fir;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+/*  Entry, exit                                                          */
+/* --------------------------------------------------------------------- */
+
+/* Creates an index in data_transfer_insts array. */
+#define LOAD_DATA	0x01
+#define WORD_DATA	0x00
+#define BYTE_DATA	0x02
+#define HALF_DATA	0x04
+#define INT_DATA	0x06
+#define SIGNED_DATA	0x08
+/* Separates integer and floating point registers */
+#define GPR_REG		0x0f
+#define DOUBLE_DATA	0x10
+#define SINGLE_DATA	0x12
+
+#define MEM_MASK	0x1f
+
+#define ARG_TEST	0x00020
+#define ALT_KEEP_CACHE	0x00040
+#define CUMULATIVE_OP	0x00080
+#define LOGICAL_OP	0x00100
+#define IMM_OP		0x00200
+#define SRC2_IMM	0x00400
+
+#define UNUSED_DEST	0x00800
+#define REG_DEST	0x01000
+#define REG1_SOURCE	0x02000
+#define REG2_SOURCE	0x04000
+#define SLOW_SRC1	0x08000
+#define SLOW_SRC2	0x10000
+#define SLOW_DEST	0x20000
+
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+#define STACK_STORE	SW
+#define STACK_LOAD	LW
+#else
+#define STACK_STORE	SD
+#define STACK_LOAD	LD
+#endif
+
+static SLJIT_INLINE sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg, sljit_sw argw);
+
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+#include "sljitNativeMIPS_32.c"
+#else
+#include "sljitNativeMIPS_64.c"
+#endif
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	sljit_ins base;
+	sljit_s32 args, i, tmp, offs;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+	local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1) + SLJIT_LOCALS_OFFSET;
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+	local_size = (local_size + 15) & ~0xf;
+#else
+	local_size = (local_size + 31) & ~0x1f;
+#endif
+	compiler->local_size = local_size;
+
+	if (local_size <= SIMM_MAX) {
+		/* Frequent case. */
+		FAIL_IF(push_inst(compiler, ADDIU_W | S(SLJIT_SP) | T(SLJIT_SP) | IMM(-local_size), DR(SLJIT_SP)));
+		base = S(SLJIT_SP);
+		offs = local_size - (sljit_sw)sizeof(sljit_sw);
+	}
+	else {
+		FAIL_IF(load_immediate(compiler, DR(OTHER_FLAG), local_size));
+		FAIL_IF(push_inst(compiler, ADDU_W | S(SLJIT_SP) | TA(0) | D(TMP_REG2), DR(TMP_REG2)));
+		FAIL_IF(push_inst(compiler, SUBU_W | S(SLJIT_SP) | T(OTHER_FLAG) | D(SLJIT_SP), DR(SLJIT_SP)));
+		base = S(TMP_REG2);
+		local_size = 0;
+		offs = -(sljit_sw)sizeof(sljit_sw);
+	}
+
+	FAIL_IF(push_inst(compiler, STACK_STORE | base | TA(RETURN_ADDR_REG) | IMM(offs), MOVABLE_INS));
+
+	tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
+	for (i = SLJIT_S0; i >= tmp; i--) {
+		offs -= (sljit_s32)(sizeof(sljit_sw));
+		FAIL_IF(push_inst(compiler, STACK_STORE | base | T(i) | IMM(offs), MOVABLE_INS));
+	}
+
+	for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
+		offs -= (sljit_s32)(sizeof(sljit_sw));
+		FAIL_IF(push_inst(compiler, STACK_STORE | base | T(i) | IMM(offs), MOVABLE_INS));
+	}
+
+	args = get_arg_count(arg_types);
+
+	if (args >= 1)
+		FAIL_IF(push_inst(compiler, ADDU_W | SA(4) | TA(0) | D(SLJIT_S0), DR(SLJIT_S0)));
+	if (args >= 2)
+		FAIL_IF(push_inst(compiler, ADDU_W | SA(5) | TA(0) | D(SLJIT_S1), DR(SLJIT_S1)));
+	if (args >= 3)
+		FAIL_IF(push_inst(compiler, ADDU_W | SA(6) | TA(0) | D(SLJIT_S2), DR(SLJIT_S2)));
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+	local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1) + SLJIT_LOCALS_OFFSET;
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+	compiler->local_size = (local_size + 15) & ~0xf;
+#else
+	compiler->local_size = (local_size + 31) & ~0x1f;
+#endif
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 local_size, i, tmp, offs;
+	sljit_ins base;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_return(compiler, op, src, srcw));
+
+	FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
+
+	local_size = compiler->local_size;
+	if (local_size <= SIMM_MAX)
+		base = S(SLJIT_SP);
+	else {
+		FAIL_IF(load_immediate(compiler, DR(TMP_REG1), local_size));
+		FAIL_IF(push_inst(compiler, ADDU_W | S(SLJIT_SP) | T(TMP_REG1) | D(TMP_REG1), DR(TMP_REG1)));
+		base = S(TMP_REG1);
+		local_size = 0;
+	}
+
+	FAIL_IF(push_inst(compiler, STACK_LOAD | base | TA(RETURN_ADDR_REG) | IMM(local_size - (sljit_s32)sizeof(sljit_sw)), RETURN_ADDR_REG));
+	offs = local_size - (sljit_s32)GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds, 1);
+
+	tmp = compiler->scratches;
+	for (i = SLJIT_FIRST_SAVED_REG; i <= tmp; i++) {
+		FAIL_IF(push_inst(compiler, STACK_LOAD | base | T(i) | IMM(offs), DR(i)));
+		offs += (sljit_s32)(sizeof(sljit_sw));
+	}
+
+	tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG;
+	for (i = tmp; i <= SLJIT_S0; i++) {
+		FAIL_IF(push_inst(compiler, STACK_LOAD | base | T(i) | IMM(offs), DR(i)));
+		offs += (sljit_s32)(sizeof(sljit_sw));
+	}
+
+	SLJIT_ASSERT(offs == local_size - (sljit_sw)(sizeof(sljit_sw)));
+
+	FAIL_IF(push_inst(compiler, JR | SA(RETURN_ADDR_REG), UNMOVABLE_INS));
+	if (compiler->local_size <= SIMM_MAX)
+		return push_inst(compiler, ADDIU_W | S(SLJIT_SP) | T(SLJIT_SP) | IMM(compiler->local_size), UNMOVABLE_INS);
+	else
+		return push_inst(compiler, ADDU_W | S(TMP_REG1) | TA(0) | D(SLJIT_SP), UNMOVABLE_INS);
+}
+
+#undef STACK_STORE
+#undef STACK_LOAD
+
+/* --------------------------------------------------------------------- */
+/*  Operators                                                            */
+/* --------------------------------------------------------------------- */
+
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+#define ARCH_32_64(a, b)	a
+#else
+#define ARCH_32_64(a, b)	b
+#endif
+
+static const sljit_ins data_transfer_insts[16 + 4] = {
+/* u w s */ ARCH_32_64(HI(43) /* sw */, HI(63) /* sd */),
+/* u w l */ ARCH_32_64(HI(35) /* lw */, HI(55) /* ld */),
+/* u b s */ HI(40) /* sb */,
+/* u b l */ HI(36) /* lbu */,
+/* u h s */ HI(41) /* sh */,
+/* u h l */ HI(37) /* lhu */,
+/* u i s */ HI(43) /* sw */,
+/* u i l */ ARCH_32_64(HI(35) /* lw */, HI(39) /* lwu */),
+
+/* s w s */ ARCH_32_64(HI(43) /* sw */, HI(63) /* sd */),
+/* s w l */ ARCH_32_64(HI(35) /* lw */, HI(55) /* ld */),
+/* s b s */ HI(40) /* sb */,
+/* s b l */ HI(32) /* lb */,
+/* s h s */ HI(41) /* sh */,
+/* s h l */ HI(33) /* lh */,
+/* s i s */ HI(43) /* sw */,
+/* s i l */ HI(35) /* lw */,
+
+/* d   s */ HI(61) /* sdc1 */,
+/* d   l */ HI(53) /* ldc1 */,
+/* s   s */ HI(57) /* swc1 */,
+/* s   l */ HI(49) /* lwc1 */,
+};
+
+#undef ARCH_32_64
+
+/* reg_ar is an absoulute register! */
+
+/* Can perform an operation using at most 1 instruction. */
+static sljit_s32 getput_arg_fast(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg, sljit_sw argw)
+{
+	SLJIT_ASSERT(arg & SLJIT_MEM);
+
+	if (!(arg & OFFS_REG_MASK) && argw <= SIMM_MAX && argw >= SIMM_MIN) {
+		/* Works for both absoulte and relative addresses. */
+		if (SLJIT_UNLIKELY(flags & ARG_TEST))
+			return 1;
+		FAIL_IF(push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(arg & REG_MASK)
+			| TA(reg_ar) | IMM(argw), ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA)) ? reg_ar : MOVABLE_INS));
+		return -1;
+	}
+	return 0;
+}
+
+/* See getput_arg below.
+   Note: can_cache is called only for binary operators. Those
+   operators always uses word arguments without write back. */
+static sljit_s32 can_cache(sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
+{
+	SLJIT_ASSERT((arg & SLJIT_MEM) && (next_arg & SLJIT_MEM));
+
+	/* Simple operation except for updates. */
+	if (arg & OFFS_REG_MASK) {
+		argw &= 0x3;
+		next_argw &= 0x3;
+		if (argw && argw == next_argw && (arg == next_arg || (arg & OFFS_REG_MASK) == (next_arg & OFFS_REG_MASK)))
+			return 1;
+		return 0;
+	}
+
+	if (arg == next_arg) {
+		if (((next_argw - argw) <= SIMM_MAX && (next_argw - argw) >= SIMM_MIN))
+			return 1;
+		return 0;
+	}
+
+	return 0;
+}
+
+/* Emit the necessary instructions. See can_cache above. */
+static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
+{
+	sljit_s32 tmp_ar, base, delay_slot;
+
+	SLJIT_ASSERT(arg & SLJIT_MEM);
+	if (!(next_arg & SLJIT_MEM)) {
+		next_arg = 0;
+		next_argw = 0;
+	}
+
+	if ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA)) {
+		tmp_ar = reg_ar;
+		delay_slot = reg_ar;
+	}
+	else {
+		tmp_ar = DR(TMP_REG1);
+		delay_slot = MOVABLE_INS;
+	}
+	base = arg & REG_MASK;
+
+	if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
+		argw &= 0x3;
+
+		/* Using the cache. */
+		if (argw == compiler->cache_argw) {
+			if (arg == compiler->cache_arg)
+				return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), delay_slot);
+
+			if ((SLJIT_MEM | (arg & OFFS_REG_MASK)) == compiler->cache_arg) {
+				if (arg == next_arg && argw == (next_argw & 0x3)) {
+					compiler->cache_arg = arg;
+					compiler->cache_argw = argw;
+					FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(TMP_REG3) | D(TMP_REG3), DR(TMP_REG3)));
+					return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), delay_slot);
+				}
+				FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(TMP_REG3) | DA(tmp_ar), tmp_ar));
+				return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar), delay_slot);
+			}
+		}
+
+		if (SLJIT_UNLIKELY(argw)) {
+			compiler->cache_arg = SLJIT_MEM | (arg & OFFS_REG_MASK);
+			compiler->cache_argw = argw;
+			FAIL_IF(push_inst(compiler, SLL_W | T(OFFS_REG(arg)) | D(TMP_REG3) | SH_IMM(argw), DR(TMP_REG3)));
+		}
+
+		if (arg == next_arg && argw == (next_argw & 0x3)) {
+			compiler->cache_arg = arg;
+			compiler->cache_argw = argw;
+			FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(!argw ? OFFS_REG(arg) : TMP_REG3) | D(TMP_REG3), DR(TMP_REG3)));
+			tmp_ar = DR(TMP_REG3);
+		}
+		else
+			FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(!argw ? OFFS_REG(arg) : TMP_REG3) | DA(tmp_ar), tmp_ar));
+		return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar), delay_slot);
+	}
+
+	if (compiler->cache_arg == arg && argw - compiler->cache_argw <= SIMM_MAX && argw - compiler->cache_argw >= SIMM_MIN) {
+		if (argw != compiler->cache_argw) {
+			FAIL_IF(push_inst(compiler, ADDIU_W | S(TMP_REG3) | T(TMP_REG3) | IMM(argw - compiler->cache_argw), DR(TMP_REG3)));
+			compiler->cache_argw = argw;
+		}
+		return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), delay_slot);
+	}
+
+	if (compiler->cache_arg == SLJIT_MEM && argw - compiler->cache_argw <= SIMM_MAX && argw - compiler->cache_argw >= SIMM_MIN) {
+		if (argw != compiler->cache_argw)
+			FAIL_IF(push_inst(compiler, ADDIU_W | S(TMP_REG3) | T(TMP_REG3) | IMM(argw - compiler->cache_argw), DR(TMP_REG3)));
+	}
+	else {
+		compiler->cache_arg = SLJIT_MEM;
+		FAIL_IF(load_immediate(compiler, DR(TMP_REG3), argw));
+	}
+	compiler->cache_argw = argw;
+
+	if (!base)
+		return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), delay_slot);
+
+	if (arg == next_arg && next_argw - argw <= SIMM_MAX && next_argw - argw >= SIMM_MIN) {
+		compiler->cache_arg = arg;
+		FAIL_IF(push_inst(compiler, ADDU_W | S(TMP_REG3) | T(base) | D(TMP_REG3), DR(TMP_REG3)));
+		return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | S(TMP_REG3) | TA(reg_ar), delay_slot);
+	}
+
+	FAIL_IF(push_inst(compiler, ADDU_W | S(TMP_REG3) | T(base) | DA(tmp_ar), tmp_ar));
+	return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar), delay_slot);
+}
+
+static SLJIT_INLINE sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg, sljit_sw argw)
+{
+	sljit_s32 tmp_ar, base, delay_slot;
+
+	if (getput_arg_fast(compiler, flags, reg_ar, arg, argw))
+		return compiler->error;
+
+	if ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA)) {
+		tmp_ar = reg_ar;
+		delay_slot = reg_ar;
+	}
+	else {
+		tmp_ar = DR(TMP_REG1);
+		delay_slot = MOVABLE_INS;
+	}
+	base = arg & REG_MASK;
+
+	if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
+		argw &= 0x3;
+
+		if (SLJIT_UNLIKELY(argw)) {
+			FAIL_IF(push_inst(compiler, SLL_W | T(OFFS_REG(arg)) | DA(tmp_ar) | SH_IMM(argw), tmp_ar));
+			FAIL_IF(push_inst(compiler, ADDU_W | S(base) | TA(tmp_ar) | DA(tmp_ar), tmp_ar));
+		}
+		else
+			FAIL_IF(push_inst(compiler, ADDU_W | S(base) | T(OFFS_REG(arg)) | DA(tmp_ar), tmp_ar));
+		return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar), delay_slot);
+	}
+
+	FAIL_IF(load_immediate(compiler, tmp_ar, argw));
+
+	if (base != 0)
+		FAIL_IF(push_inst(compiler, ADDU_W | S(base) | TA(tmp_ar) | DA(tmp_ar), tmp_ar));
+
+	return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | SA(tmp_ar) | TA(reg_ar), delay_slot);
+}
+
+static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg1, sljit_sw arg1w, sljit_s32 arg2, sljit_sw arg2w)
+{
+	if (getput_arg_fast(compiler, flags, reg, arg1, arg1w))
+		return compiler->error;
+	return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w);
+}
+
+static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	/* arg1 goes to TMP_REG1 or src reg
+	   arg2 goes to TMP_REG2, imm or src reg
+	   TMP_REG3 can be used for caching
+	   result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */
+	sljit_s32 dst_r = TMP_REG2;
+	sljit_s32 src1_r;
+	sljit_sw src2_r = 0;
+	sljit_s32 sugg_src2_r = TMP_REG2;
+
+	if (!(flags & ALT_KEEP_CACHE)) {
+		compiler->cache_arg = 0;
+		compiler->cache_argw = 0;
+	}
+
+	if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) {
+		SLJIT_ASSERT(HAS_FLAGS(op));
+		flags |= UNUSED_DEST;
+	}
+	else if (FAST_IS_REG(dst)) {
+		dst_r = dst;
+		flags |= REG_DEST;
+		if (op >= SLJIT_MOV && op <= SLJIT_MOV_P)
+			sugg_src2_r = dst_r;
+	}
+	else if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, flags | ARG_TEST, DR(TMP_REG1), dst, dstw))
+		flags |= SLOW_DEST;
+
+	if (flags & IMM_OP) {
+		if ((src2 & SLJIT_IMM) && src2w) {
+			if ((!(flags & LOGICAL_OP) && (src2w <= SIMM_MAX && src2w >= SIMM_MIN))
+				|| ((flags & LOGICAL_OP) && !(src2w & ~UIMM_MAX))) {
+				flags |= SRC2_IMM;
+				src2_r = src2w;
+			}
+		}
+		if (!(flags & SRC2_IMM) && (flags & CUMULATIVE_OP) && (src1 & SLJIT_IMM) && src1w) {
+			if ((!(flags & LOGICAL_OP) && (src1w <= SIMM_MAX && src1w >= SIMM_MIN))
+				|| ((flags & LOGICAL_OP) && !(src1w & ~UIMM_MAX))) {
+				flags |= SRC2_IMM;
+				src2_r = src1w;
+
+				/* And swap arguments. */
+				src1 = src2;
+				src1w = src2w;
+				src2 = SLJIT_IMM;
+				/* src2w = src2_r unneeded. */
+			}
+		}
+	}
+
+	/* Source 1. */
+	if (FAST_IS_REG(src1)) {
+		src1_r = src1;
+		flags |= REG1_SOURCE;
+	}
+	else if (src1 & SLJIT_IMM) {
+		if (src1w) {
+			FAIL_IF(load_immediate(compiler, DR(TMP_REG1), src1w));
+			src1_r = TMP_REG1;
+		}
+		else
+			src1_r = 0;
+	}
+	else {
+		if (getput_arg_fast(compiler, flags | LOAD_DATA, DR(TMP_REG1), src1, src1w))
+			FAIL_IF(compiler->error);
+		else
+			flags |= SLOW_SRC1;
+		src1_r = TMP_REG1;
+	}
+
+	/* Source 2. */
+	if (FAST_IS_REG(src2)) {
+		src2_r = src2;
+		flags |= REG2_SOURCE;
+		if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOV_P)
+			dst_r = src2_r;
+	}
+	else if (src2 & SLJIT_IMM) {
+		if (!(flags & SRC2_IMM)) {
+			if (src2w) {
+				FAIL_IF(load_immediate(compiler, DR(sugg_src2_r), src2w));
+				src2_r = sugg_src2_r;
+			}
+			else {
+				src2_r = 0;
+				if ((op >= SLJIT_MOV && op <= SLJIT_MOV_P) && (dst & SLJIT_MEM))
+					dst_r = 0;
+			}
+		}
+	}
+	else {
+		if (getput_arg_fast(compiler, flags | LOAD_DATA, DR(sugg_src2_r), src2, src2w))
+			FAIL_IF(compiler->error);
+		else
+			flags |= SLOW_SRC2;
+		src2_r = sugg_src2_r;
+	}
+
+	if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) {
+		SLJIT_ASSERT(src2_r == TMP_REG2);
+		if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
+			FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(TMP_REG2), src2, src2w, src1, src1w));
+			FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(TMP_REG1), src1, src1w, dst, dstw));
+		}
+		else {
+			FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(TMP_REG1), src1, src1w, src2, src2w));
+			FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(TMP_REG2), src2, src2w, dst, dstw));
+		}
+	}
+	else if (flags & SLOW_SRC1)
+		FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(TMP_REG1), src1, src1w, dst, dstw));
+	else if (flags & SLOW_SRC2)
+		FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, DR(sugg_src2_r), src2, src2w, dst, dstw));
+
+	FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r));
+
+	if (dst & SLJIT_MEM) {
+		if (!(flags & SLOW_DEST)) {
+			getput_arg_fast(compiler, flags, DR(dst_r), dst, dstw);
+			return compiler->error;
+		}
+		return getput_arg(compiler, flags, DR(dst_r), dst, dstw, 0, 0);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
+{
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+	sljit_s32 int_op = op & SLJIT_I32_OP;
+#endif
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op0(compiler, op));
+
+	op = GET_OPCODE(op);
+	switch (op) {
+	case SLJIT_BREAKPOINT:
+		return push_inst(compiler, BREAK, UNMOVABLE_INS);
+	case SLJIT_NOP:
+		return push_inst(compiler, NOP, UNMOVABLE_INS);
+	case SLJIT_LMUL_UW:
+	case SLJIT_LMUL_SW:
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+		FAIL_IF(push_inst(compiler, (op == SLJIT_LMUL_UW ? DMULU : DMUL) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG3), DR(TMP_REG3)));
+		FAIL_IF(push_inst(compiler, (op == SLJIT_LMUL_UW ? DMUHU : DMUH) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG1), DR(TMP_REG1)));
+#else /* !SLJIT_CONFIG_MIPS_64 */
+		FAIL_IF(push_inst(compiler, (op == SLJIT_LMUL_UW ? MULU : MUL) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG3), DR(TMP_REG3)));
+		FAIL_IF(push_inst(compiler, (op == SLJIT_LMUL_UW ? MUHU : MUH) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG1), DR(TMP_REG1)));
+#endif /* SLJIT_CONFIG_MIPS_64 */
+		FAIL_IF(push_inst(compiler, ADDU_W | S(TMP_REG3) | TA(0) | D(SLJIT_R0), DR(SLJIT_R0)));
+		return push_inst(compiler, ADDU_W | S(TMP_REG1) | TA(0) | D(SLJIT_R1), DR(SLJIT_R1));
+#else /* SLJIT_MIPS_REV < 6 */
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+		FAIL_IF(push_inst(compiler, (op == SLJIT_LMUL_UW ? DMULTU : DMULT) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
+#else /* !SLJIT_CONFIG_MIPS_64 */
+		FAIL_IF(push_inst(compiler, (op == SLJIT_LMUL_UW ? MULTU : MULT) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
+#endif /* SLJIT_CONFIG_MIPS_64 */
+		FAIL_IF(push_inst(compiler, MFLO | D(SLJIT_R0), DR(SLJIT_R0)));
+		return push_inst(compiler, MFHI | D(SLJIT_R1), DR(SLJIT_R1));
+#endif /* SLJIT_MIPS_REV >= 6 */
+	case SLJIT_DIVMOD_UW:
+	case SLJIT_DIVMOD_SW:
+	case SLJIT_DIV_UW:
+	case SLJIT_DIV_SW:
+		SLJIT_COMPILE_ASSERT((SLJIT_DIVMOD_UW & 0x2) == 0 && SLJIT_DIV_UW - 0x2 == SLJIT_DIVMOD_UW, bad_div_opcode_assignments);
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+		if (int_op) {
+			FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG3), DR(TMP_REG3)));
+			FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? MODU : MOD) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG1), DR(TMP_REG1)));
+		}
+		else {
+			FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? DDIVU : DDIV) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG3), DR(TMP_REG3)));
+			FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? DMODU : DMOD) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG1), DR(TMP_REG1)));
+		}
+#else /* !SLJIT_CONFIG_MIPS_64 */
+		FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG3), DR(TMP_REG3)));
+		FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? MODU : MOD) | S(SLJIT_R0) | T(SLJIT_R1) | D(TMP_REG1), DR(TMP_REG1)));
+#endif /* SLJIT_CONFIG_MIPS_64 */
+		FAIL_IF(push_inst(compiler, ADDU_W | S(TMP_REG3) | TA(0) | D(SLJIT_R0), DR(SLJIT_R0)));
+		return (op >= SLJIT_DIV_UW) ? SLJIT_SUCCESS : push_inst(compiler, ADDU_W | S(TMP_REG1) | TA(0) | D(SLJIT_R1), DR(SLJIT_R1));
+#else /* SLJIT_MIPS_REV < 6 */
+#if !(defined SLJIT_MIPS_REV)
+		FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+		FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+#endif /* !SLJIT_MIPS_REV */
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+		if (int_op)
+			FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
+		else
+			FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? DDIVU : DDIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
+#else /* !SLJIT_CONFIG_MIPS_64 */
+		FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? DIVU : DIV) | S(SLJIT_R0) | T(SLJIT_R1), MOVABLE_INS));
+#endif /* SLJIT_CONFIG_MIPS_64 */
+		FAIL_IF(push_inst(compiler, MFLO | D(SLJIT_R0), DR(SLJIT_R0)));
+		return (op >= SLJIT_DIV_UW) ? SLJIT_SUCCESS : push_inst(compiler, MFHI | D(SLJIT_R1), DR(SLJIT_R1));
+#endif /* SLJIT_MIPS_REV >= 6 */
+	case SLJIT_ENDBR:
+	case SLJIT_SKIP_FRAMES_BEFORE_RETURN:
+		return SLJIT_SUCCESS;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
+static sljit_s32 emit_prefetch(struct sljit_compiler *compiler,
+        sljit_s32 src, sljit_sw srcw)
+{
+	if (!(src & OFFS_REG_MASK)) {
+		if (srcw <= SIMM_MAX && srcw >= SIMM_MIN)
+			return push_inst(compiler, PREF | S(src & REG_MASK) | IMM(srcw), MOVABLE_INS);
+
+		FAIL_IF(load_immediate(compiler, DR(TMP_REG1), srcw));
+		return push_inst(compiler, PREFX | S(src & REG_MASK) | T(TMP_REG1), MOVABLE_INS);
+	}
+
+	srcw &= 0x3;
+
+	if (SLJIT_UNLIKELY(srcw != 0)) {
+		FAIL_IF(push_inst(compiler, SLL_W | T(OFFS_REG(src)) | D(TMP_REG1) | SH_IMM(srcw), DR(TMP_REG1)));
+		return push_inst(compiler, PREFX | S(src & REG_MASK) | T(TMP_REG1), MOVABLE_INS);
+	}
+
+	return push_inst(compiler, PREFX | S(src & REG_MASK) | T(OFFS_REG(src)), MOVABLE_INS);
+}
+#endif /* SLJIT_MIPS_REV >= 1 */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+#	define flags 0
+#else
+	sljit_s32 flags = 0;
+#endif
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+	if ((op & SLJIT_I32_OP) && GET_OPCODE(op) >= SLJIT_NOT)
+		flags |= INT_DATA | SIGNED_DATA;
+#endif
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_P:
+		return emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_MOV_U32:
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+		return emit_op(compiler, SLJIT_MOV_U32, INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+#else
+		return emit_op(compiler, SLJIT_MOV_U32, INT_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u32)srcw : srcw);
+#endif
+
+	case SLJIT_MOV_S32:
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+		return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+#else
+		return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s32)srcw : srcw);
+#endif
+
+	case SLJIT_MOV_U8:
+		return emit_op(compiler, SLJIT_MOV_U8, BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8)srcw : srcw);
+
+	case SLJIT_MOV_S8:
+		return emit_op(compiler, SLJIT_MOV_S8, BYTE_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8)srcw : srcw);
+
+	case SLJIT_MOV_U16:
+		return emit_op(compiler, SLJIT_MOV_U16, HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16)srcw : srcw);
+
+	case SLJIT_MOV_S16:
+		return emit_op(compiler, SLJIT_MOV_S16, HALF_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16)srcw : srcw);
+
+	case SLJIT_NOT:
+		return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_NEG:
+		return emit_op(compiler, SLJIT_SUB | GET_ALL_FLAGS(op), flags | IMM_OP, dst, dstw, SLJIT_IMM, 0, src, srcw);
+
+	case SLJIT_CLZ:
+		return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw);
+	}
+
+	SLJIT_UNREACHABLE();
+	return SLJIT_SUCCESS;
+
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+#	undef flags
+#endif
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+#	define flags 0
+#else
+	sljit_s32 flags = 0;
+#endif
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
+		return SLJIT_SUCCESS;
+
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+	if (op & SLJIT_I32_OP) {
+		flags |= INT_DATA | SIGNED_DATA;
+		if (src1 & SLJIT_IMM)
+			src1w = (sljit_s32)src1w;
+		if (src2 & SLJIT_IMM)
+			src2w = (sljit_s32)src2w;
+	}
+#endif
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_ADD:
+	case SLJIT_ADDC:
+		return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_SUB:
+	case SLJIT_SUBC:
+		return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_MUL:
+		return emit_op(compiler, op, flags | CUMULATIVE_OP, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_AND:
+	case SLJIT_OR:
+	case SLJIT_XOR:
+		return emit_op(compiler, op, flags | CUMULATIVE_OP | LOGICAL_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_SHL:
+	case SLJIT_LSHR:
+	case SLJIT_ASHR:
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+		if (src2 & SLJIT_IMM)
+			src2w &= 0x1f;
+#else
+		if (src2 & SLJIT_IMM) {
+			if (op & SLJIT_I32_OP)
+				src2w &= 0x1f;
+			else
+				src2w &= 0x3f;
+		}
+#endif
+		return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+	}
+
+	SLJIT_UNREACHABLE();
+	return SLJIT_SUCCESS;
+
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+#	undef flags
+#endif
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_src(compiler, op, src, srcw));
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	switch (op) {
+	case SLJIT_FAST_RETURN:
+		if (FAST_IS_REG(src))
+			FAIL_IF(push_inst(compiler, ADDU_W | S(src) | TA(0) | DA(RETURN_ADDR_REG), RETURN_ADDR_REG));
+		else
+			FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, RETURN_ADDR_REG, src, srcw));
+
+		FAIL_IF(push_inst(compiler, JR | SA(RETURN_ADDR_REG), UNMOVABLE_INS));
+		return push_inst(compiler, NOP, UNMOVABLE_INS);
+	case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN:
+		return SLJIT_SUCCESS;
+	case SLJIT_PREFETCH_L1:
+	case SLJIT_PREFETCH_L2:
+	case SLJIT_PREFETCH_L3:
+	case SLJIT_PREFETCH_ONCE:
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
+		return emit_prefetch(compiler, src, srcw);
+#else /* SLJIT_MIPS_REV < 1 */
+		return SLJIT_SUCCESS;
+#endif /* SLJIT_MIPS_REV >= 1 */
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+{
+	CHECK_REG_INDEX(check_sljit_get_register_index(reg));
+	return reg_map[reg];
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
+{
+	CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
+	return FR(reg);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+	void *instruction, sljit_s32 size)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
+
+	return push_inst(compiler, *(sljit_ins*)instruction, UNMOVABLE_INS);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Floating point operators                                             */
+/* --------------------------------------------------------------------- */
+
+#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_F32_OP) >> 7))
+#define FMT(op) (((op & SLJIT_F32_OP) ^ SLJIT_F32_OP) << (21 - 8))
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+#	define flags 0
+#else
+	sljit_s32 flags = (GET_OPCODE(op) == SLJIT_CONV_SW_FROM_F64) << 21;
+#endif
+
+	if (src & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG1), src, srcw, dst, dstw));
+		src = TMP_FREG1;
+	}
+
+	FAIL_IF(push_inst(compiler, (TRUNC_W_S ^ (flags >> 19)) | FMT(op) | FS(src) | FD(TMP_FREG1), MOVABLE_INS));
+
+	if (FAST_IS_REG(dst))
+		return push_inst(compiler, MFC1 | flags | T(dst) | FS(TMP_FREG1), MOVABLE_INS);
+
+	/* Store the integer value from a VFP register. */
+	return emit_op_mem2(compiler, flags ? DOUBLE_DATA : SINGLE_DATA, FR(TMP_FREG1), dst, dstw, 0, 0);
+
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+#	undef is_long
+#endif
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+#	define flags 0
+#else
+	sljit_s32 flags = (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_SW) << 21;
+#endif
+
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	if (FAST_IS_REG(src))
+		FAIL_IF(push_inst(compiler, MTC1 | flags | T(src) | FS(TMP_FREG1), MOVABLE_INS));
+	else if (src & SLJIT_MEM) {
+		/* Load the integer value into a VFP register. */
+		FAIL_IF(emit_op_mem2(compiler, ((flags) ? DOUBLE_DATA : SINGLE_DATA) | LOAD_DATA, FR(TMP_FREG1), src, srcw, dst, dstw));
+	}
+	else {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+		if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
+			srcw = (sljit_s32)srcw;
+#endif
+		FAIL_IF(load_immediate(compiler, DR(TMP_REG1), srcw));
+		FAIL_IF(push_inst(compiler, MTC1 | flags | T(TMP_REG1) | FS(TMP_FREG1), MOVABLE_INS));
+	}
+
+	FAIL_IF(push_inst(compiler, CVT_S_S | flags | (4 << 21) | (((op & SLJIT_F32_OP) ^ SLJIT_F32_OP) >> 8) | FS(TMP_FREG1) | FD(dst_r), MOVABLE_INS));
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem2(compiler, FLOAT_DATA(op), FR(TMP_FREG1), dst, dstw, 0, 0);
+	return SLJIT_SUCCESS;
+
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+#	undef flags
+#endif
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_ins inst;
+
+	if (src1 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG1), src1, src1w, src2, src2w));
+		src1 = TMP_FREG1;
+	}
+
+	if (src2 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG2), src2, src2w, 0, 0));
+		src2 = TMP_FREG2;
+	}
+
+	switch (GET_FLAG_TYPE(op)) {
+	case SLJIT_EQUAL_F64:
+	case SLJIT_NOT_EQUAL_F64:
+		inst = C_UEQ_S;
+		break;
+	case SLJIT_LESS_F64:
+	case SLJIT_GREATER_EQUAL_F64:
+		inst = C_ULT_S;
+		break;
+	case SLJIT_GREATER_F64:
+	case SLJIT_LESS_EQUAL_F64:
+		inst = C_ULE_S;
+		break;
+	default:
+		SLJIT_ASSERT(GET_FLAG_TYPE(op) == SLJIT_UNORDERED_F64 || GET_FLAG_TYPE(op) == SLJIT_ORDERED_F64);
+		inst = C_UN_S;
+		break;
+	}
+	return push_inst(compiler, inst | FMT(op) | FT(src2) | FS(src1) | C_FD, UNMOVABLE_INS);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r;
+
+	CHECK_ERROR();
+	compiler->cache_arg = 0;
+	compiler->cache_argw = 0;
+
+	SLJIT_COMPILE_ASSERT((SLJIT_F32_OP == 0x100) && !(DOUBLE_DATA & 0x2), float_transfer_bit_error);
+	SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
+
+	if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32)
+		op ^= SLJIT_F32_OP;
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	if (src & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(dst_r), src, srcw, dst, dstw));
+		src = dst_r;
+	}
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_MOV_F64:
+		if (src != dst_r) {
+			if (dst_r != TMP_FREG1)
+				FAIL_IF(push_inst(compiler, MOV_S | FMT(op) | FS(src) | FD(dst_r), MOVABLE_INS));
+			else
+				dst_r = src;
+		}
+		break;
+	case SLJIT_NEG_F64:
+		FAIL_IF(push_inst(compiler, NEG_S | FMT(op) | FS(src) | FD(dst_r), MOVABLE_INS));
+		break;
+	case SLJIT_ABS_F64:
+		FAIL_IF(push_inst(compiler, ABS_S | FMT(op) | FS(src) | FD(dst_r), MOVABLE_INS));
+		break;
+	case SLJIT_CONV_F64_FROM_F32:
+		FAIL_IF(push_inst(compiler, CVT_S_S | ((op & SLJIT_F32_OP) ? 1 : (1 << 21)) | FS(src) | FD(dst_r), MOVABLE_INS));
+		op ^= SLJIT_F32_OP;
+		break;
+	}
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem2(compiler, FLOAT_DATA(op), FR(dst_r), dst, dstw, 0, 0);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_s32 dst_r, flags = 0;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	compiler->cache_arg = 0;
+	compiler->cache_argw = 0;
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG2;
+
+	if (src1 & SLJIT_MEM) {
+		if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG1), src1, src1w)) {
+			FAIL_IF(compiler->error);
+			src1 = TMP_FREG1;
+		} else
+			flags |= SLOW_SRC1;
+	}
+
+	if (src2 & SLJIT_MEM) {
+		if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG2), src2, src2w)) {
+			FAIL_IF(compiler->error);
+			src2 = TMP_FREG2;
+		} else
+			flags |= SLOW_SRC2;
+	}
+
+	if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) {
+		if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
+			FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG2), src2, src2w, src1, src1w));
+			FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG1), src1, src1w, dst, dstw));
+		}
+		else {
+			FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG1), src1, src1w, src2, src2w));
+			FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG2), src2, src2w, dst, dstw));
+		}
+	}
+	else if (flags & SLOW_SRC1)
+		FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG1), src1, src1w, dst, dstw));
+	else if (flags & SLOW_SRC2)
+		FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, FR(TMP_FREG2), src2, src2w, dst, dstw));
+
+	if (flags & SLOW_SRC1)
+		src1 = TMP_FREG1;
+	if (flags & SLOW_SRC2)
+		src2 = TMP_FREG2;
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_ADD_F64:
+		FAIL_IF(push_inst(compiler, ADD_S | FMT(op) | FT(src2) | FS(src1) | FD(dst_r), MOVABLE_INS));
+		break;
+
+	case SLJIT_SUB_F64:
+		FAIL_IF(push_inst(compiler, SUB_S | FMT(op) | FT(src2) | FS(src1) | FD(dst_r), MOVABLE_INS));
+		break;
+
+	case SLJIT_MUL_F64:
+		FAIL_IF(push_inst(compiler, MUL_S | FMT(op) | FT(src2) | FS(src1) | FD(dst_r), MOVABLE_INS));
+		break;
+
+	case SLJIT_DIV_F64:
+		FAIL_IF(push_inst(compiler, DIV_S | FMT(op) | FT(src2) | FS(src1) | FD(dst_r), MOVABLE_INS));
+		break;
+	}
+
+	if (dst_r == TMP_FREG2)
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), FR(TMP_FREG2), dst, dstw, 0, 0));
+
+	return SLJIT_SUCCESS;
+}
+
+/* --------------------------------------------------------------------- */
+/*  Other instructions                                                   */
+/* --------------------------------------------------------------------- */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	if (FAST_IS_REG(dst))
+		return push_inst(compiler, ADDU_W | SA(RETURN_ADDR_REG) | TA(0) | D(dst), UNMOVABLE_INS);
+
+	/* Memory. */
+	FAIL_IF(emit_op_mem(compiler, WORD_DATA, RETURN_ADDR_REG, dst, dstw));
+	compiler->delay_slot = UNMOVABLE_INS;
+	return SLJIT_SUCCESS;
+}
+
+/* --------------------------------------------------------------------- */
+/*  Conditional instructions                                             */
+/* --------------------------------------------------------------------- */
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
+{
+	struct sljit_label *label;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_label(compiler));
+
+	if (compiler->last_label && compiler->last_label->size == compiler->size)
+		return compiler->last_label;
+
+	label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));
+	PTR_FAIL_IF(!label);
+	set_label(label, compiler);
+	compiler->delay_slot = UNMOVABLE_INS;
+	return label;
+}
+
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+#define JUMP_LENGTH	4
+#else
+#define JUMP_LENGTH	8
+#endif
+
+#define BR_Z(src) \
+	inst = BEQ | SA(src) | TA(0) | JUMP_LENGTH; \
+	flags = IS_BIT26_COND; \
+	delay_check = src;
+
+#define BR_NZ(src) \
+	inst = BNE | SA(src) | TA(0) | JUMP_LENGTH; \
+	flags = IS_BIT26_COND; \
+	delay_check = src;
+
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
+
+#define BR_T() \
+	inst = BC1NEZ; \
+	flags = IS_BIT23_COND; \
+	delay_check = FCSR_FCC;
+#define BR_F() \
+	inst = BC1EQZ; \
+	flags = IS_BIT23_COND; \
+	delay_check = FCSR_FCC;
+
+#else /* SLJIT_MIPS_REV < 6 */
+
+#define BR_T() \
+	inst = BC1T | JUMP_LENGTH; \
+	flags = IS_BIT16_COND; \
+	delay_check = FCSR_FCC;
+#define BR_F() \
+	inst = BC1F | JUMP_LENGTH; \
+	flags = IS_BIT16_COND; \
+	delay_check = FCSR_FCC;
+
+#endif /* SLJIT_MIPS_REV >= 6 */
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
+{
+	struct sljit_jump *jump;
+	sljit_ins inst;
+	sljit_s32 flags = 0;
+	sljit_s32 delay_check = UNMOVABLE_INS;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_jump(compiler, type));
+
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	PTR_FAIL_IF(!jump);
+	set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
+	type &= 0xff;
+
+	switch (type) {
+	case SLJIT_EQUAL:
+		BR_NZ(EQUAL_FLAG);
+		break;
+	case SLJIT_NOT_EQUAL:
+		BR_Z(EQUAL_FLAG);
+		break;
+	case SLJIT_LESS:
+	case SLJIT_GREATER:
+	case SLJIT_SIG_LESS:
+	case SLJIT_SIG_GREATER:
+	case SLJIT_OVERFLOW:
+	case SLJIT_MUL_OVERFLOW:
+		BR_Z(OTHER_FLAG);
+		break;
+	case SLJIT_GREATER_EQUAL:
+	case SLJIT_LESS_EQUAL:
+	case SLJIT_SIG_GREATER_EQUAL:
+	case SLJIT_SIG_LESS_EQUAL:
+	case SLJIT_NOT_OVERFLOW:
+	case SLJIT_MUL_NOT_OVERFLOW:
+		BR_NZ(OTHER_FLAG);
+		break;
+	case SLJIT_NOT_EQUAL_F64:
+	case SLJIT_GREATER_EQUAL_F64:
+	case SLJIT_GREATER_F64:
+	case SLJIT_ORDERED_F64:
+		BR_T();
+		break;
+	case SLJIT_EQUAL_F64:
+	case SLJIT_LESS_F64:
+	case SLJIT_LESS_EQUAL_F64:
+	case SLJIT_UNORDERED_F64:
+		BR_F();
+		break;
+	default:
+		/* Not conditional branch. */
+		inst = 0;
+		break;
+	}
+
+	jump->flags |= flags;
+	if (compiler->delay_slot == MOVABLE_INS || (compiler->delay_slot != UNMOVABLE_INS && compiler->delay_slot != delay_check))
+		jump->flags |= IS_MOVABLE;
+
+	if (inst)
+		PTR_FAIL_IF(push_inst(compiler, inst, UNMOVABLE_INS));
+
+	PTR_FAIL_IF(emit_const(compiler, TMP_REG2, 0));
+
+	if (type <= SLJIT_JUMP)
+		PTR_FAIL_IF(push_inst(compiler, JR | S(TMP_REG2), UNMOVABLE_INS));
+	else {
+		jump->flags |= IS_JAL;
+		PTR_FAIL_IF(push_inst(compiler, JALR | S(TMP_REG2) | DA(RETURN_ADDR_REG), UNMOVABLE_INS));
+	}
+
+	jump->addr = compiler->size;
+	PTR_FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+	return jump;
+}
+
+#define RESOLVE_IMM1() \
+	if (src1 & SLJIT_IMM) { \
+		if (src1w) { \
+			PTR_FAIL_IF(load_immediate(compiler, DR(TMP_REG1), src1w)); \
+			src1 = TMP_REG1; \
+		} \
+		else \
+			src1 = 0; \
+	}
+
+#define RESOLVE_IMM2() \
+	if (src2 & SLJIT_IMM) { \
+		if (src2w) { \
+			PTR_FAIL_IF(load_immediate(compiler, DR(TMP_REG2), src2w)); \
+			src2 = TMP_REG2; \
+		} \
+		else \
+			src2 = 0; \
+	}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	struct sljit_jump *jump;
+	sljit_s32 flags;
+	sljit_ins inst;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_cmp(compiler, type, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	compiler->cache_arg = 0;
+	compiler->cache_argw = 0;
+	flags = ((type & SLJIT_I32_OP) ? INT_DATA : WORD_DATA) | LOAD_DATA;
+	if (src1 & SLJIT_MEM) {
+		PTR_FAIL_IF(emit_op_mem2(compiler, flags, DR(TMP_REG1), src1, src1w, src2, src2w));
+		src1 = TMP_REG1;
+	}
+	if (src2 & SLJIT_MEM) {
+		PTR_FAIL_IF(emit_op_mem2(compiler, flags, DR(TMP_REG2), src2, src2w, 0, 0));
+		src2 = TMP_REG2;
+	}
+
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	PTR_FAIL_IF(!jump);
+	set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
+	type &= 0xff;
+
+	if (type <= SLJIT_NOT_EQUAL) {
+		RESOLVE_IMM1();
+		RESOLVE_IMM2();
+		jump->flags |= IS_BIT26_COND;
+		if (compiler->delay_slot == MOVABLE_INS || (compiler->delay_slot != UNMOVABLE_INS && compiler->delay_slot != DR(src1) && compiler->delay_slot != DR(src2)))
+			jump->flags |= IS_MOVABLE;
+		PTR_FAIL_IF(push_inst(compiler, (type == SLJIT_EQUAL ? BNE : BEQ) | S(src1) | T(src2) | JUMP_LENGTH, UNMOVABLE_INS));
+	}
+	else if (type >= SLJIT_SIG_LESS && (((src1 & SLJIT_IMM) && (src1w == 0)) || ((src2 & SLJIT_IMM) && (src2w == 0)))) {
+		inst = NOP;
+		if ((src1 & SLJIT_IMM) && (src1w == 0)) {
+			RESOLVE_IMM2();
+			switch (type) {
+			case SLJIT_SIG_LESS:
+				inst = BLEZ;
+				jump->flags |= IS_BIT26_COND;
+				break;
+			case SLJIT_SIG_GREATER_EQUAL:
+				inst = BGTZ;
+				jump->flags |= IS_BIT26_COND;
+				break;
+			case SLJIT_SIG_GREATER:
+				inst = BGEZ;
+				jump->flags |= IS_BIT16_COND;
+				break;
+			case SLJIT_SIG_LESS_EQUAL:
+				inst = BLTZ;
+				jump->flags |= IS_BIT16_COND;
+				break;
+			}
+			src1 = src2;
+		}
+		else {
+			RESOLVE_IMM1();
+			switch (type) {
+			case SLJIT_SIG_LESS:
+				inst = BGEZ;
+				jump->flags |= IS_BIT16_COND;
+				break;
+			case SLJIT_SIG_GREATER_EQUAL:
+				inst = BLTZ;
+				jump->flags |= IS_BIT16_COND;
+				break;
+			case SLJIT_SIG_GREATER:
+				inst = BLEZ;
+				jump->flags |= IS_BIT26_COND;
+				break;
+			case SLJIT_SIG_LESS_EQUAL:
+				inst = BGTZ;
+				jump->flags |= IS_BIT26_COND;
+				break;
+			}
+		}
+		PTR_FAIL_IF(push_inst(compiler, inst | S(src1) | JUMP_LENGTH, UNMOVABLE_INS));
+	}
+	else {
+		if (type == SLJIT_LESS || type == SLJIT_GREATER_EQUAL || type == SLJIT_SIG_LESS || type == SLJIT_SIG_GREATER_EQUAL) {
+			RESOLVE_IMM1();
+			if ((src2 & SLJIT_IMM) && src2w <= SIMM_MAX && src2w >= SIMM_MIN)
+				PTR_FAIL_IF(push_inst(compiler, (type <= SLJIT_LESS_EQUAL ? SLTIU : SLTI) | S(src1) | T(TMP_REG1) | IMM(src2w), DR(TMP_REG1)));
+			else {
+				RESOLVE_IMM2();
+				PTR_FAIL_IF(push_inst(compiler, (type <= SLJIT_LESS_EQUAL ? SLTU : SLT) | S(src1) | T(src2) | D(TMP_REG1), DR(TMP_REG1)));
+			}
+			type = (type == SLJIT_LESS || type == SLJIT_SIG_LESS) ? SLJIT_NOT_EQUAL : SLJIT_EQUAL;
+		}
+		else {
+			RESOLVE_IMM2();
+			if ((src1 & SLJIT_IMM) && src1w <= SIMM_MAX && src1w >= SIMM_MIN)
+				PTR_FAIL_IF(push_inst(compiler, (type <= SLJIT_LESS_EQUAL ? SLTIU : SLTI) | S(src2) | T(TMP_REG1) | IMM(src1w), DR(TMP_REG1)));
+			else {
+				RESOLVE_IMM1();
+				PTR_FAIL_IF(push_inst(compiler, (type <= SLJIT_LESS_EQUAL ? SLTU : SLT) | S(src2) | T(src1) | D(TMP_REG1), DR(TMP_REG1)));
+			}
+			type = (type == SLJIT_GREATER || type == SLJIT_SIG_GREATER) ? SLJIT_NOT_EQUAL : SLJIT_EQUAL;
+		}
+
+		jump->flags |= IS_BIT26_COND;
+		PTR_FAIL_IF(push_inst(compiler, (type == SLJIT_EQUAL ? BNE : BEQ) | S(TMP_REG1) | TA(0) | JUMP_LENGTH, UNMOVABLE_INS));
+	}
+
+	PTR_FAIL_IF(emit_const(compiler, TMP_REG2, 0));
+	PTR_FAIL_IF(push_inst(compiler, JR | S(TMP_REG2), UNMOVABLE_INS));
+	jump->addr = compiler->size;
+	PTR_FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+	return jump;
+}
+
+#undef RESOLVE_IMM1
+#undef RESOLVE_IMM2
+
+#undef JUMP_LENGTH
+#undef BR_Z
+#undef BR_NZ
+#undef BR_T
+#undef BR_F
+
+#undef FLOAT_DATA
+#undef FMT
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
+{
+	struct sljit_jump *jump = NULL;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	if (src & SLJIT_IMM) {
+		jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+		FAIL_IF(!jump);
+		set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_JAL : 0));
+		jump->u.target = srcw;
+
+		if (compiler->delay_slot != UNMOVABLE_INS)
+			jump->flags |= IS_MOVABLE;
+
+		FAIL_IF(emit_const(compiler, TMP_REG2, 0));
+		src = TMP_REG2;
+	}
+	else if (src & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, DR(TMP_REG2), src, srcw));
+		src = TMP_REG2;
+	}
+
+	FAIL_IF(push_inst(compiler, JR | S(src), UNMOVABLE_INS));
+	if (jump)
+		jump->addr = compiler->size;
+	FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 type)
+{
+	sljit_s32 src_ar, dst_ar;
+	sljit_s32 saved_op = op;
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+	sljit_s32 mem_type = WORD_DATA;
+#else
+	sljit_s32 mem_type = (op & SLJIT_I32_OP) ? (INT_DATA | SIGNED_DATA) : WORD_DATA;
+#endif
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	op = GET_OPCODE(op);
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+	if (op == SLJIT_MOV_S32)
+		mem_type = INT_DATA | SIGNED_DATA;
+#endif
+	dst_ar = DR((op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2);
+
+	compiler->cache_arg = 0;
+	compiler->cache_argw = 0;
+
+	if (op >= SLJIT_ADD && (dst & SLJIT_MEM))
+		FAIL_IF(emit_op_mem2(compiler, mem_type | LOAD_DATA, DR(TMP_REG1), dst, dstw, dst, dstw));
+
+	switch (type & 0xff) {
+	case SLJIT_EQUAL:
+	case SLJIT_NOT_EQUAL:
+		FAIL_IF(push_inst(compiler, SLTIU | SA(EQUAL_FLAG) | TA(dst_ar) | IMM(1), dst_ar));
+		src_ar = dst_ar;
+		break;
+	case SLJIT_MUL_OVERFLOW:
+	case SLJIT_MUL_NOT_OVERFLOW:
+		FAIL_IF(push_inst(compiler, SLTIU | SA(OTHER_FLAG) | TA(dst_ar) | IMM(1), dst_ar));
+		src_ar = dst_ar;
+		type ^= 0x1; /* Flip type bit for the XORI below. */
+		break;
+	case SLJIT_GREATER_F64:
+	case SLJIT_LESS_EQUAL_F64:
+		type ^= 0x1; /* Flip type bit for the XORI below. */
+	case SLJIT_EQUAL_F64:
+	case SLJIT_NOT_EQUAL_F64:
+	case SLJIT_LESS_F64:
+	case SLJIT_GREATER_EQUAL_F64:
+	case SLJIT_UNORDERED_F64:
+	case SLJIT_ORDERED_F64:
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
+		FAIL_IF(push_inst(compiler, MFC1 | TA(dst_ar) | FS(TMP_FREG3), dst_ar));
+#else /* SLJIT_MIPS_REV < 6 */
+		FAIL_IF(push_inst(compiler, CFC1 | TA(dst_ar) | DA(FCSR_REG), dst_ar));
+#endif /* SLJIT_MIPS_REV >= 6 */
+		FAIL_IF(push_inst(compiler, SRL | TA(dst_ar) | DA(dst_ar) | SH_IMM(23), dst_ar));
+		FAIL_IF(push_inst(compiler, ANDI | SA(dst_ar) | TA(dst_ar) | IMM(1), dst_ar));
+		src_ar = dst_ar;
+		break;
+
+	default:
+		src_ar = OTHER_FLAG;
+		break;
+	}
+
+	if (type & 0x1) {
+		FAIL_IF(push_inst(compiler, XORI | SA(src_ar) | TA(dst_ar) | IMM(1), dst_ar));
+		src_ar = dst_ar;
+	}
+
+	if (op < SLJIT_ADD) {
+		if (dst & SLJIT_MEM)
+			return emit_op_mem(compiler, mem_type, src_ar, dst, dstw);
+
+		if (src_ar != dst_ar)
+			return push_inst(compiler, ADDU_W | SA(src_ar) | TA(0) | DA(dst_ar), dst_ar);
+		return SLJIT_SUCCESS;
+	}
+
+	/* OTHER_FLAG cannot be specified as src2 argument at the moment. */
+	if (DR(TMP_REG2) != src_ar)
+		FAIL_IF(push_inst(compiler, ADDU_W | SA(src_ar) | TA(0) | D(TMP_REG2), DR(TMP_REG2)));
+
+	mem_type |= CUMULATIVE_OP | LOGICAL_OP | IMM_OP | ALT_KEEP_CACHE;
+
+	if (dst & SLJIT_MEM)
+		return emit_op(compiler, saved_op, mem_type, dst, dstw, TMP_REG1, 0, TMP_REG2, 0);
+	return emit_op(compiler, saved_op, mem_type, dst, dstw, dst, dstw, TMP_REG2, 0);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 dst_reg,
+	sljit_s32 src, sljit_sw srcw)
+{
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
+	sljit_ins ins;
+#endif /* SLJIT_MIPS_REV >= 1 */
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
+
+	if (SLJIT_UNLIKELY(src & SLJIT_IMM)) {
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+		if (dst_reg & SLJIT_I32_OP)
+			srcw = (sljit_s32)srcw;
+#endif
+		FAIL_IF(load_immediate(compiler, DR(TMP_REG1), srcw));
+		src = TMP_REG1;
+		srcw = 0;
+	}
+
+	dst_reg &= ~SLJIT_I32_OP;
+
+	switch (type & 0xff) {
+	case SLJIT_EQUAL:
+		ins = MOVZ | TA(EQUAL_FLAG);
+		break;
+	case SLJIT_NOT_EQUAL:
+		ins = MOVN | TA(EQUAL_FLAG);
+		break;
+	case SLJIT_LESS:
+	case SLJIT_GREATER:
+	case SLJIT_SIG_LESS:
+	case SLJIT_SIG_GREATER:
+	case SLJIT_OVERFLOW:
+	case SLJIT_MUL_OVERFLOW:
+		ins = MOVN | TA(OTHER_FLAG);
+		break;
+	case SLJIT_GREATER_EQUAL:
+	case SLJIT_LESS_EQUAL:
+	case SLJIT_SIG_GREATER_EQUAL:
+	case SLJIT_SIG_LESS_EQUAL:
+	case SLJIT_NOT_OVERFLOW:
+	case SLJIT_MUL_NOT_OVERFLOW:
+		ins = MOVZ | TA(OTHER_FLAG);
+		break;
+	case SLJIT_EQUAL_F64:
+	case SLJIT_LESS_F64:
+	case SLJIT_LESS_EQUAL_F64:
+	case SLJIT_UNORDERED_F64:
+		ins = MOVT;
+		break;
+	case SLJIT_NOT_EQUAL_F64:
+	case SLJIT_GREATER_EQUAL_F64:
+	case SLJIT_GREATER_F64:
+	case SLJIT_ORDERED_F64:
+		ins = MOVF;
+		break;
+	default:
+		ins = MOVZ | TA(OTHER_FLAG);
+		SLJIT_UNREACHABLE();
+		break;
+	}
+
+	return push_inst(compiler, ins | S(src) | D(dst_reg), DR(dst_reg));
+
+#else /* SLJIT_MIPS_REV < 1 */
+	return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);
+#endif /* SLJIT_MIPS_REV >= 1 */
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
+{
+	struct sljit_const *const_;
+	sljit_s32 dst_r;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
+	PTR_FAIL_IF(!const_);
+	set_const(const_, compiler);
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+	PTR_FAIL_IF(emit_const(compiler, dst_r, init_value));
+
+	if (dst & SLJIT_MEM)
+		PTR_FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0));
+
+	return const_;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	struct sljit_put_label *put_label;
+	sljit_s32 dst_r;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label));
+	PTR_FAIL_IF(!put_label);
+	set_put_label(put_label, compiler, 0);
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+	PTR_FAIL_IF(emit_const(compiler, dst_r, 0));
+#else
+	PTR_FAIL_IF(push_inst(compiler, dst_r, UNMOVABLE_INS));
+	compiler->size += 5;
+#endif
+
+	if (dst & SLJIT_MEM)
+		PTR_FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0));
+
+	return put_label;
+}
diff --git a/src/c/pcre2/src/sljit/sljitNativePPC_32.c b/src/c/pcre2/src/sljit/sljitNativePPC_32.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitNativePPC_32.c
@@ -0,0 +1,275 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* ppc 32-bit arch dependent functions. */
+
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
+{
+	if (imm <= SIMM_MAX && imm >= SIMM_MIN)
+		return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm));
+
+	if (!(imm & ~0xffff))
+		return push_inst(compiler, ORI | S(TMP_ZERO) | A(reg) | IMM(imm));
+
+	FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 16)));
+	return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS;
+}
+
+#define INS_CLEAR_LEFT(dst, src, from) \
+	(RLWINM | S(src) | A(dst) | ((from) << 6) | (31 << 1))
+
+static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
+	sljit_s32 dst, sljit_s32 src1, sljit_s32 src2)
+{
+	switch (op) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_U32:
+	case SLJIT_MOV_S32:
+	case SLJIT_MOV_P:
+		SLJIT_ASSERT(src1 == TMP_REG1);
+		if (dst != src2)
+			return push_inst(compiler, OR | S(src2) | A(dst) | B(src2));
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U8:
+	case SLJIT_MOV_S8:
+		SLJIT_ASSERT(src1 == TMP_REG1);
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
+			if (op == SLJIT_MOV_S8)
+				return push_inst(compiler, EXTSB | S(src2) | A(dst));
+			return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24));
+		}
+		else if ((flags & REG_DEST) && op == SLJIT_MOV_S8)
+			return push_inst(compiler, EXTSB | S(src2) | A(dst));
+		else {
+			SLJIT_ASSERT(dst == src2);
+		}
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U16:
+	case SLJIT_MOV_S16:
+		SLJIT_ASSERT(src1 == TMP_REG1);
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
+			if (op == SLJIT_MOV_S16)
+				return push_inst(compiler, EXTSH | S(src2) | A(dst));
+			return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16));
+		}
+		else {
+			SLJIT_ASSERT(dst == src2);
+		}
+		return SLJIT_SUCCESS;
+
+	case SLJIT_NOT:
+		SLJIT_ASSERT(src1 == TMP_REG1);
+		return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
+
+	case SLJIT_NEG:
+		SLJIT_ASSERT(src1 == TMP_REG1);
+		/* Setting XER SO is not enough, CR SO is also needed. */
+		return push_inst(compiler, NEG | OE((flags & ALT_FORM1) ? ALT_SET_FLAGS : 0) | RC(flags) | D(dst) | A(src2));
+
+	case SLJIT_CLZ:
+		SLJIT_ASSERT(src1 == TMP_REG1);
+		return push_inst(compiler, CNTLZW | S(src2) | A(dst));
+
+	case SLJIT_ADD:
+		if (flags & ALT_FORM1) {
+			/* Setting XER SO is not enough, CR SO is also needed. */
+			return push_inst(compiler, ADD | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
+		}
+
+		if (flags & ALT_FORM2) {
+			/* Flags does not set: BIN_IMM_EXTS unnecessary. */
+			SLJIT_ASSERT(src2 == TMP_REG2);
+
+			if (flags & ALT_FORM3)
+				return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm);
+
+			if (flags & ALT_FORM4) {
+				FAIL_IF(push_inst(compiler, ADDIS | D(dst) | A(src1) | (((compiler->imm >> 16) & 0xffff) + ((compiler->imm >> 15) & 0x1))));
+				src1 = dst;
+			}
+
+			return push_inst(compiler, ADDI | D(dst) | A(src1) | (compiler->imm & 0xffff));
+		}
+		if (flags & ALT_FORM3) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
+		}
+		if (!(flags & ALT_SET_FLAGS))
+			return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
+		if (flags & ALT_FORM4)
+			return push_inst(compiler, ADDC | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
+		return push_inst(compiler, ADD | RC(flags) | D(dst) | A(src1) | B(src2));
+
+	case SLJIT_ADDC:
+		return push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2));
+
+	case SLJIT_SUB:
+		if (flags & ALT_FORM1) {
+			if (flags & ALT_FORM2) {
+				FAIL_IF(push_inst(compiler, CMPLI | CRD(0) | A(src1) | compiler->imm));
+				if (!(flags & ALT_FORM3))
+					return SLJIT_SUCCESS;
+				return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff));
+			}
+			FAIL_IF(push_inst(compiler, CMPL | CRD(0) | A(src1) | B(src2)));
+			if (!(flags & ALT_FORM3))
+				return SLJIT_SUCCESS;
+			return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
+		}
+
+		if (flags & ALT_FORM2) {
+			/* Setting XER SO is not enough, CR SO is also needed. */
+			return push_inst(compiler, SUBF | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
+		}
+
+		if (flags & ALT_FORM3) {
+			/* Flags does not set: BIN_IMM_EXTS unnecessary. */
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
+		}
+
+		if (flags & ALT_FORM4) {
+			if (flags & ALT_FORM5) {
+				SLJIT_ASSERT(src2 == TMP_REG2);
+				return push_inst(compiler, CMPI | CRD(0) | A(src1) | compiler->imm);
+			}
+			return push_inst(compiler, CMP | CRD(0) | A(src1) | B(src2));
+		}
+
+		if (!(flags & ALT_SET_FLAGS))
+			return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
+		if (flags & ALT_FORM5)
+			return push_inst(compiler, SUBFC | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
+		return push_inst(compiler, SUBF | RC(flags) | D(dst) | A(src2) | B(src1));
+
+	case SLJIT_SUBC:
+		return push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1));
+
+	case SLJIT_MUL:
+		if (flags & ALT_FORM1) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			return push_inst(compiler, MULLI | D(dst) | A(src1) | compiler->imm);
+		}
+		return push_inst(compiler, MULLW | OE(flags) | RC(flags) | D(dst) | A(src2) | B(src1));
+
+	case SLJIT_AND:
+		if (flags & ALT_FORM1) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			return push_inst(compiler, ANDI | S(src1) | A(dst) | compiler->imm);
+		}
+		if (flags & ALT_FORM2) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			return push_inst(compiler, ANDIS | S(src1) | A(dst) | compiler->imm);
+		}
+		return push_inst(compiler, AND | RC(flags) | S(src1) | A(dst) | B(src2));
+
+	case SLJIT_OR:
+		if (flags & ALT_FORM1) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			return push_inst(compiler, ORI | S(src1) | A(dst) | compiler->imm);
+		}
+		if (flags & ALT_FORM2) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			return push_inst(compiler, ORIS | S(src1) | A(dst) | compiler->imm);
+		}
+		if (flags & ALT_FORM3) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			FAIL_IF(push_inst(compiler, ORI | S(src1) | A(dst) | IMM(compiler->imm)));
+			return push_inst(compiler, ORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
+		}
+		return push_inst(compiler, OR | RC(flags) | S(src1) | A(dst) | B(src2));
+
+	case SLJIT_XOR:
+		if (flags & ALT_FORM1) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			return push_inst(compiler, XORI | S(src1) | A(dst) | compiler->imm);
+		}
+		if (flags & ALT_FORM2) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			return push_inst(compiler, XORIS | S(src1) | A(dst) | compiler->imm);
+		}
+		if (flags & ALT_FORM3) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(compiler->imm)));
+			return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
+		}
+		return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2));
+
+	case SLJIT_SHL:
+		if (flags & ALT_FORM1) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			compiler->imm &= 0x1f;
+			return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11) | ((31 - compiler->imm) << 1));
+		}
+		return push_inst(compiler, SLW | RC(flags) | S(src1) | A(dst) | B(src2));
+
+	case SLJIT_LSHR:
+		if (flags & ALT_FORM1) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			compiler->imm &= 0x1f;
+			return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (((32 - compiler->imm) & 0x1f) << 11) | (compiler->imm << 6) | (31 << 1));
+		}
+		return push_inst(compiler, SRW | RC(flags) | S(src1) | A(dst) | B(src2));
+
+	case SLJIT_ASHR:
+		if (flags & ALT_FORM1) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			compiler->imm &= 0x1f;
+			return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11));
+		}
+		return push_inst(compiler, SRAW | RC(flags) | S(src1) | A(dst) | B(src2));
+	}
+
+	SLJIT_UNREACHABLE();
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw init_value)
+{
+	FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 16)));
+	return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
+{
+	sljit_ins *inst = (sljit_ins *)addr;
+	SLJIT_UNUSED_ARG(executable_offset);
+
+	SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);
+	SLJIT_ASSERT((inst[0] & 0xfc1f0000) == ADDIS && (inst[1] & 0xfc000000) == ORI);
+	inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 16) & 0xffff);
+	inst[1] = (inst[1] & 0xffff0000) | (new_target & 0xffff);
+	SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
+	inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+	SLJIT_CACHE_FLUSH(inst, inst + 2);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
+{
+	sljit_set_jump_addr(addr, new_constant, executable_offset);
+}
diff --git a/src/c/pcre2/src/sljit/sljitNativePPC_64.c b/src/c/pcre2/src/sljit/sljitNativePPC_64.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitNativePPC_64.c
@@ -0,0 +1,495 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* ppc 64-bit arch dependent functions. */
+
+#if defined(__GNUC__) || (defined(__IBM_GCC_ASM) && __IBM_GCC_ASM)
+#define ASM_SLJIT_CLZ(src, dst) \
+	__asm__ volatile ( "cntlzd %0, %1" : "=r"(dst) : "r"(src) )
+#elif defined(__xlc__)
+#error "Please enable GCC syntax for inline assembly statements"
+#else
+#error "Must implement count leading zeroes"
+#endif
+
+#define PUSH_RLDICR(reg, shift) \
+	push_inst(compiler, RLDI(reg, reg, 63 - shift, shift, 1))
+
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
+{
+	sljit_uw tmp;
+	sljit_uw shift;
+	sljit_uw tmp2;
+	sljit_uw shift2;
+
+	if (imm <= SIMM_MAX && imm >= SIMM_MIN)
+		return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm));
+
+	if (!(imm & ~0xffff))
+		return push_inst(compiler, ORI | S(TMP_ZERO) | A(reg) | IMM(imm));
+
+	if (imm <= 0x7fffffffl && imm >= -0x80000000l) {
+		FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 16)));
+		return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS;
+	}
+
+	/* Count leading zeroes. */
+	tmp = (imm >= 0) ? imm : ~imm;
+	ASM_SLJIT_CLZ(tmp, shift);
+	SLJIT_ASSERT(shift > 0);
+	shift--;
+	tmp = (imm << shift);
+
+	if ((tmp & ~0xffff000000000000ul) == 0) {
+		FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
+		shift += 15;
+		return PUSH_RLDICR(reg, shift);
+	}
+
+	if ((tmp & ~0xffffffff00000000ul) == 0) {
+		FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(tmp >> 48)));
+		FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(tmp >> 32)));
+		shift += 31;
+		return PUSH_RLDICR(reg, shift);
+	}
+
+	/* Cut out the 16 bit from immediate. */
+	shift += 15;
+	tmp2 = imm & ((1ul << (63 - shift)) - 1);
+
+	if (tmp2 <= 0xffff) {
+		FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
+		FAIL_IF(PUSH_RLDICR(reg, shift));
+		return push_inst(compiler, ORI | S(reg) | A(reg) | tmp2);
+	}
+
+	if (tmp2 <= 0xffffffff) {
+		FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
+		FAIL_IF(PUSH_RLDICR(reg, shift));
+		FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | (tmp2 >> 16)));
+		return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(tmp2)) : SLJIT_SUCCESS;
+	}
+
+	ASM_SLJIT_CLZ(tmp2, shift2);
+	tmp2 <<= shift2;
+
+	if ((tmp2 & ~0xffff000000000000ul) == 0) {
+		FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
+		shift2 += 15;
+		shift += (63 - shift2);
+		FAIL_IF(PUSH_RLDICR(reg, shift));
+		FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | (tmp2 >> 48)));
+		return PUSH_RLDICR(reg, shift2);
+	}
+
+	/* The general version. */
+	FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 48)));
+	FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm >> 32)));
+	FAIL_IF(PUSH_RLDICR(reg, 31));
+	FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | IMM(imm >> 16)));
+	return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm));
+}
+
+/* Simplified mnemonics: clrldi. */
+#define INS_CLEAR_LEFT(dst, src, from) \
+	(RLDICL | S(src) | A(dst) | ((from) << 6) | (1 << 5))
+
+/* Sign extension for integer operations. */
+#define UN_EXTS() \
+	if ((flags & (ALT_SIGN_EXT | REG2_SOURCE)) == (ALT_SIGN_EXT | REG2_SOURCE)) { \
+		FAIL_IF(push_inst(compiler, EXTSW | S(src2) | A(TMP_REG2))); \
+		src2 = TMP_REG2; \
+	}
+
+#define BIN_EXTS() \
+	if (flags & ALT_SIGN_EXT) { \
+		if (flags & REG1_SOURCE) { \
+			FAIL_IF(push_inst(compiler, EXTSW | S(src1) | A(TMP_REG1))); \
+			src1 = TMP_REG1; \
+		} \
+		if (flags & REG2_SOURCE) { \
+			FAIL_IF(push_inst(compiler, EXTSW | S(src2) | A(TMP_REG2))); \
+			src2 = TMP_REG2; \
+		} \
+	}
+
+#define BIN_IMM_EXTS() \
+	if ((flags & (ALT_SIGN_EXT | REG1_SOURCE)) == (ALT_SIGN_EXT | REG1_SOURCE)) { \
+		FAIL_IF(push_inst(compiler, EXTSW | S(src1) | A(TMP_REG1))); \
+		src1 = TMP_REG1; \
+	}
+
+static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
+	sljit_s32 dst, sljit_s32 src1, sljit_s32 src2)
+{
+	switch (op) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_P:
+		SLJIT_ASSERT(src1 == TMP_REG1);
+		if (dst != src2)
+			return push_inst(compiler, OR | S(src2) | A(dst) | B(src2));
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U32:
+	case SLJIT_MOV_S32:
+		SLJIT_ASSERT(src1 == TMP_REG1);
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
+			if (op == SLJIT_MOV_S32)
+				return push_inst(compiler, EXTSW | S(src2) | A(dst));
+			return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 0));
+		}
+		else {
+			SLJIT_ASSERT(dst == src2);
+		}
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U8:
+	case SLJIT_MOV_S8:
+		SLJIT_ASSERT(src1 == TMP_REG1);
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
+			if (op == SLJIT_MOV_S8)
+				return push_inst(compiler, EXTSB | S(src2) | A(dst));
+			return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24));
+		}
+		else if ((flags & REG_DEST) && op == SLJIT_MOV_S8)
+			return push_inst(compiler, EXTSB | S(src2) | A(dst));
+		else {
+			SLJIT_ASSERT(dst == src2);
+		}
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U16:
+	case SLJIT_MOV_S16:
+		SLJIT_ASSERT(src1 == TMP_REG1);
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
+			if (op == SLJIT_MOV_S16)
+				return push_inst(compiler, EXTSH | S(src2) | A(dst));
+			return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16));
+		}
+		else {
+			SLJIT_ASSERT(dst == src2);
+		}
+		return SLJIT_SUCCESS;
+
+	case SLJIT_NOT:
+		SLJIT_ASSERT(src1 == TMP_REG1);
+		UN_EXTS();
+		return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
+
+	case SLJIT_NEG:
+		SLJIT_ASSERT(src1 == TMP_REG1);
+
+		if ((flags & (ALT_FORM1 | ALT_SIGN_EXT)) == (ALT_FORM1 | ALT_SIGN_EXT)) {
+			FAIL_IF(push_inst(compiler, RLDI(TMP_REG2, src2, 32, 31, 1)));
+			FAIL_IF(push_inst(compiler, NEG | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(TMP_REG2)));
+			return push_inst(compiler, RLDI(dst, dst, 32, 32, 0));
+		}
+
+		UN_EXTS();
+		/* Setting XER SO is not enough, CR SO is also needed. */
+		return push_inst(compiler, NEG | OE((flags & ALT_FORM1) ? ALT_SET_FLAGS : 0) | RC(flags) | D(dst) | A(src2));
+
+	case SLJIT_CLZ:
+		SLJIT_ASSERT(src1 == TMP_REG1);
+		if (flags & ALT_FORM1)
+			return push_inst(compiler, CNTLZW | S(src2) | A(dst));
+		return push_inst(compiler, CNTLZD | S(src2) | A(dst));
+
+	case SLJIT_ADD:
+		if (flags & ALT_FORM1) {
+			if (flags & ALT_SIGN_EXT) {
+				FAIL_IF(push_inst(compiler, RLDI(TMP_REG1, src1, 32, 31, 1)));
+				src1 = TMP_REG1;
+				FAIL_IF(push_inst(compiler, RLDI(TMP_REG2, src2, 32, 31, 1)));
+				src2 = TMP_REG2;
+			}
+			/* Setting XER SO is not enough, CR SO is also needed. */
+			FAIL_IF(push_inst(compiler, ADD | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2)));
+			if (flags & ALT_SIGN_EXT)
+				return push_inst(compiler, RLDI(dst, dst, 32, 32, 0));
+			return SLJIT_SUCCESS;
+		}
+
+		if (flags & ALT_FORM2) {
+			/* Flags does not set: BIN_IMM_EXTS unnecessary. */
+			SLJIT_ASSERT(src2 == TMP_REG2);
+
+			if (flags & ALT_FORM3)
+				return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm);
+
+			if (flags & ALT_FORM4) {
+				FAIL_IF(push_inst(compiler, ADDIS | D(dst) | A(src1) | (((compiler->imm >> 16) & 0xffff) + ((compiler->imm >> 15) & 0x1))));
+				src1 = dst;
+			}
+
+			return push_inst(compiler, ADDI | D(dst) | A(src1) | (compiler->imm & 0xffff));
+		}
+		if (flags & ALT_FORM3) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			BIN_IMM_EXTS();
+			return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
+		}
+		if (!(flags & ALT_SET_FLAGS))
+			return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
+		BIN_EXTS();
+		if (flags & ALT_FORM4)
+			return push_inst(compiler, ADDC | RC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
+		return push_inst(compiler, ADD | RC(flags) | D(dst) | A(src1) | B(src2));
+
+	case SLJIT_ADDC:
+		BIN_EXTS();
+		return push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2));
+
+	case SLJIT_SUB:
+		if (flags & ALT_FORM1) {
+			if (flags & ALT_FORM2) {
+				FAIL_IF(push_inst(compiler, CMPLI | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm));
+				if (!(flags & ALT_FORM3))
+					return SLJIT_SUCCESS;
+				return push_inst(compiler, ADDI | D(dst) | A(src1) | (-compiler->imm & 0xffff));
+			}
+			FAIL_IF(push_inst(compiler, CMPL | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2)));
+			if (!(flags & ALT_FORM3))
+				return SLJIT_SUCCESS;
+			return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
+		}
+
+		if (flags & ALT_FORM2) {
+			if (flags & ALT_SIGN_EXT) {
+				FAIL_IF(push_inst(compiler, RLDI(TMP_REG1, src1, 32, 31, 1)));
+				src1 = TMP_REG1;
+				FAIL_IF(push_inst(compiler, RLDI(TMP_REG2, src2, 32, 31, 1)));
+				src2 = TMP_REG2;
+			}
+			/* Setting XER SO is not enough, CR SO is also needed. */
+			FAIL_IF(push_inst(compiler, SUBF | OE(ALT_SET_FLAGS) | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1)));
+			if (flags & ALT_SIGN_EXT)
+				return push_inst(compiler, RLDI(dst, dst, 32, 32, 0));
+			return SLJIT_SUCCESS;
+		}
+
+		if (flags & ALT_FORM3) {
+			/* Flags does not set: BIN_IMM_EXTS unnecessary. */
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
+		}
+
+		if (flags & ALT_FORM4) {
+			if (flags & ALT_FORM5) {
+				SLJIT_ASSERT(src2 == TMP_REG2);
+				return push_inst(compiler, CMPI | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm);
+			}
+			return push_inst(compiler, CMP | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2));
+		}
+
+		if (!(flags & ALT_SET_FLAGS))
+			return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
+		BIN_EXTS();
+		if (flags & ALT_FORM5)
+			return push_inst(compiler, SUBFC | RC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
+		return push_inst(compiler, SUBF | RC(flags) | D(dst) | A(src2) | B(src1));
+
+	case SLJIT_SUBC:
+		BIN_EXTS();
+		return push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1));
+
+	case SLJIT_MUL:
+		if (flags & ALT_FORM1) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			return push_inst(compiler, MULLI | D(dst) | A(src1) | compiler->imm);
+		}
+		BIN_EXTS();
+		if (flags & ALT_FORM2)
+			return push_inst(compiler, MULLW | OE(flags) | RC(flags) | D(dst) | A(src2) | B(src1));
+		return push_inst(compiler, MULLD | OE(flags) | RC(flags) | D(dst) | A(src2) | B(src1));
+
+	case SLJIT_AND:
+		if (flags & ALT_FORM1) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			return push_inst(compiler, ANDI | S(src1) | A(dst) | compiler->imm);
+		}
+		if (flags & ALT_FORM2) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			return push_inst(compiler, ANDIS | S(src1) | A(dst) | compiler->imm);
+		}
+		return push_inst(compiler, AND | RC(flags) | S(src1) | A(dst) | B(src2));
+
+	case SLJIT_OR:
+		if (flags & ALT_FORM1) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			return push_inst(compiler, ORI | S(src1) | A(dst) | compiler->imm);
+		}
+		if (flags & ALT_FORM2) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			return push_inst(compiler, ORIS | S(src1) | A(dst) | compiler->imm);
+		}
+		if (flags & ALT_FORM3) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			FAIL_IF(push_inst(compiler, ORI | S(src1) | A(dst) | IMM(compiler->imm)));
+			return push_inst(compiler, ORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
+		}
+		return push_inst(compiler, OR | RC(flags) | S(src1) | A(dst) | B(src2));
+
+	case SLJIT_XOR:
+		if (flags & ALT_FORM1) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			return push_inst(compiler, XORI | S(src1) | A(dst) | compiler->imm);
+		}
+		if (flags & ALT_FORM2) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			return push_inst(compiler, XORIS | S(src1) | A(dst) | compiler->imm);
+		}
+		if (flags & ALT_FORM3) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(compiler->imm)));
+			return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
+		}
+		return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2));
+
+	case SLJIT_SHL:
+		if (flags & ALT_FORM1) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			if (flags & ALT_FORM2) {
+				compiler->imm &= 0x1f;
+				return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11) | ((31 - compiler->imm) << 1));
+			}
+			compiler->imm &= 0x3f;
+			return push_inst(compiler, RLDI(dst, src1, compiler->imm, 63 - compiler->imm, 1) | RC(flags));
+		}
+		return push_inst(compiler, ((flags & ALT_FORM2) ? SLW : SLD) | RC(flags) | S(src1) | A(dst) | B(src2));
+
+	case SLJIT_LSHR:
+		if (flags & ALT_FORM1) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			if (flags & ALT_FORM2) {
+				compiler->imm &= 0x1f;
+				return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (((32 - compiler->imm) & 0x1f) << 11) | (compiler->imm << 6) | (31 << 1));
+			}
+			compiler->imm &= 0x3f;
+			return push_inst(compiler, RLDI(dst, src1, 64 - compiler->imm, compiler->imm, 0) | RC(flags));
+		}
+		return push_inst(compiler, ((flags & ALT_FORM2) ? SRW : SRD) | RC(flags) | S(src1) | A(dst) | B(src2));
+
+	case SLJIT_ASHR:
+		if (flags & ALT_FORM1) {
+			SLJIT_ASSERT(src2 == TMP_REG2);
+			if (flags & ALT_FORM2) {
+				compiler->imm &= 0x1f;
+				return push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11));
+			}
+			compiler->imm &= 0x3f;
+			return push_inst(compiler, SRADI | RC(flags) | S(src1) | A(dst) | ((compiler->imm & 0x1f) << 11) | ((compiler->imm & 0x20) >> 4));
+		}
+		return push_inst(compiler, ((flags & ALT_FORM2) ? SRAW : SRAD) | RC(flags) | S(src1) | A(dst) | B(src2));
+	}
+
+	SLJIT_UNREACHABLE();
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *src)
+{
+	sljit_s32 arg_count = 0;
+	sljit_s32 word_arg_count = 0;
+	sljit_s32 types = 0;
+	sljit_s32 reg = 0;
+
+	if (src)
+		reg = *src & REG_MASK;
+
+	arg_types >>= SLJIT_DEF_SHIFT;
+
+	while (arg_types) {
+		types = (types << SLJIT_DEF_SHIFT) | (arg_types & SLJIT_DEF_MASK);
+
+		switch (arg_types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+		case SLJIT_ARG_TYPE_F64:
+			arg_count++;
+			break;
+		default:
+			arg_count++;
+			word_arg_count++;
+
+			if (arg_count != word_arg_count && arg_count == reg) {
+				FAIL_IF(push_inst(compiler, OR | S(reg) | A(TMP_CALL_REG) | B(reg)));
+				*src = TMP_CALL_REG;
+			}
+			break;
+		}
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	while (types) {
+		switch (types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+		case SLJIT_ARG_TYPE_F64:
+			arg_count--;
+			break;
+		default:
+			if (arg_count != word_arg_count)
+				FAIL_IF(push_inst(compiler, OR | S(word_arg_count) | A(arg_count) | B(word_arg_count)));
+
+			arg_count--;
+			word_arg_count--;
+			break;
+		}
+
+		types >>= SLJIT_DEF_SHIFT;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw init_value)
+{
+	FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 48)));
+	FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value >> 32)));
+	FAIL_IF(PUSH_RLDICR(reg, 31));
+	FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | IMM(init_value >> 16)));
+	return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
+{
+	sljit_ins *inst = (sljit_ins*)addr;
+	SLJIT_UNUSED_ARG(executable_offset);
+
+	SLJIT_UPDATE_WX_FLAGS(inst, inst + 5, 0);
+	inst[0] = (inst[0] & 0xffff0000) | ((new_target >> 48) & 0xffff);
+	inst[1] = (inst[1] & 0xffff0000) | ((new_target >> 32) & 0xffff);
+	inst[3] = (inst[3] & 0xffff0000) | ((new_target >> 16) & 0xffff);
+	inst[4] = (inst[4] & 0xffff0000) | (new_target & 0xffff);
+	SLJIT_UPDATE_WX_FLAGS(inst, inst + 5, 1);
+	inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+	SLJIT_CACHE_FLUSH(inst, inst + 5);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
+{
+	sljit_set_jump_addr(addr, new_constant, executable_offset);
+}
diff --git a/src/c/pcre2/src/sljit/sljitNativePPC_common.c b/src/c/pcre2/src/sljit/sljitNativePPC_common.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitNativePPC_common.c
@@ -0,0 +1,2408 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
+{
+	return "PowerPC" SLJIT_CPUINFO;
+}
+
+/* Length of an instruction word.
+   Both for ppc-32 and ppc-64. */
+typedef sljit_u32 sljit_ins;
+
+#if ((defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) && (defined _AIX)) \
+	|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+#define SLJIT_PPC_STACK_FRAME_V2 1
+#endif
+
+#ifdef _AIX
+#include <sys/cache.h>
+#endif
+
+#if (defined _CALL_ELF && _CALL_ELF == 2)
+#define SLJIT_PASS_ENTRY_ADDR_TO_CALL 1
+#endif
+
+#if (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL)
+
+static void ppc_cache_flush(sljit_ins *from, sljit_ins *to)
+{
+#ifdef _AIX
+	_sync_cache_range((caddr_t)from, (int)((size_t)to - (size_t)from));
+#elif defined(__GNUC__) || (defined(__IBM_GCC_ASM) && __IBM_GCC_ASM)
+#	if defined(_ARCH_PWR) || defined(_ARCH_PWR2)
+	/* Cache flush for POWER architecture. */
+	while (from < to) {
+		__asm__ volatile (
+			"clf 0, %0\n"
+			"dcs\n"
+			: : "r"(from)
+		);
+		from++;
+	}
+	__asm__ volatile ( "ics" );
+#	elif defined(_ARCH_COM) && !defined(_ARCH_PPC)
+#	error "Cache flush is not implemented for PowerPC/POWER common mode."
+#	else
+	/* Cache flush for PowerPC architecture. */
+	while (from < to) {
+		__asm__ volatile (
+			"dcbf 0, %0\n"
+			"sync\n"
+			"icbi 0, %0\n"
+			: : "r"(from)
+		);
+		from++;
+	}
+	__asm__ volatile ( "isync" );
+#	endif
+#	ifdef __xlc__
+#	warning "This file may fail to compile if -qfuncsect is used"
+#	endif
+#elif defined(__xlc__)
+#error "Please enable GCC syntax for inline assembly statements with -qasm=gcc"
+#else
+#error "This platform requires a cache flush implementation."
+#endif /* _AIX */
+}
+
+#endif /* (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL) */
+
+#define TMP_REG1	(SLJIT_NUMBER_OF_REGISTERS + 2)
+#define TMP_REG2	(SLJIT_NUMBER_OF_REGISTERS + 3)
+#define TMP_ZERO	(SLJIT_NUMBER_OF_REGISTERS + 4)
+
+#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
+#define TMP_CALL_REG	(SLJIT_NUMBER_OF_REGISTERS + 5)
+#else
+#define TMP_CALL_REG	TMP_REG2
+#endif
+
+#define TMP_FREG1	(SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
+#define TMP_FREG2	(SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2)
+
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 7] = {
+	0, 3, 4, 5, 6, 7, 8, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 1, 9, 10, 31, 12
+};
+
+static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
+	0, 1, 2, 3, 4, 5, 6, 0, 7
+};
+
+/* --------------------------------------------------------------------- */
+/*  Instrucion forms                                                     */
+/* --------------------------------------------------------------------- */
+#define D(d)		(reg_map[d] << 21)
+#define S(s)		(reg_map[s] << 21)
+#define A(a)		(reg_map[a] << 16)
+#define B(b)		(reg_map[b] << 11)
+#define C(c)		(reg_map[c] << 6)
+#define FD(fd)		(freg_map[fd] << 21)
+#define FS(fs)		(freg_map[fs] << 21)
+#define FA(fa)		(freg_map[fa] << 16)
+#define FB(fb)		(freg_map[fb] << 11)
+#define FC(fc)		(freg_map[fc] << 6)
+#define IMM(imm)	((imm) & 0xffff)
+#define CRD(d)		((d) << 21)
+
+/* Instruction bit sections.
+   OE and Rc flag (see ALT_SET_FLAGS). */
+#define OE(flags)	((flags) & ALT_SET_FLAGS)
+/* Rc flag (see ALT_SET_FLAGS). */
+#define RC(flags)	(((flags) & ALT_SET_FLAGS) >> 10)
+#define HI(opcode)	((opcode) << 26)
+#define LO(opcode)	((opcode) << 1)
+
+#define ADD		(HI(31) | LO(266))
+#define ADDC		(HI(31) | LO(10))
+#define ADDE		(HI(31) | LO(138))
+#define ADDI		(HI(14))
+#define ADDIC		(HI(13))
+#define ADDIS		(HI(15))
+#define ADDME		(HI(31) | LO(234))
+#define AND		(HI(31) | LO(28))
+#define ANDI		(HI(28))
+#define ANDIS		(HI(29))
+#define Bx		(HI(18))
+#define BCx		(HI(16))
+#define BCCTR		(HI(19) | LO(528) | (3 << 11))
+#define BLR		(HI(19) | LO(16) | (0x14 << 21))
+#define CNTLZD		(HI(31) | LO(58))
+#define CNTLZW		(HI(31) | LO(26))
+#define CMP		(HI(31) | LO(0))
+#define CMPI		(HI(11))
+#define CMPL		(HI(31) | LO(32))
+#define CMPLI		(HI(10))
+#define CROR		(HI(19) | LO(449))
+#define DCBT		(HI(31) | LO(278))
+#define DIVD		(HI(31) | LO(489))
+#define DIVDU		(HI(31) | LO(457))
+#define DIVW		(HI(31) | LO(491))
+#define DIVWU		(HI(31) | LO(459))
+#define EXTSB		(HI(31) | LO(954))
+#define EXTSH		(HI(31) | LO(922))
+#define EXTSW		(HI(31) | LO(986))
+#define FABS		(HI(63) | LO(264))
+#define FADD		(HI(63) | LO(21))
+#define FADDS		(HI(59) | LO(21))
+#define FCFID		(HI(63) | LO(846))
+#define FCMPU		(HI(63) | LO(0))
+#define FCTIDZ		(HI(63) | LO(815))
+#define FCTIWZ		(HI(63) | LO(15))
+#define FDIV		(HI(63) | LO(18))
+#define FDIVS		(HI(59) | LO(18))
+#define FMR		(HI(63) | LO(72))
+#define FMUL		(HI(63) | LO(25))
+#define FMULS		(HI(59) | LO(25))
+#define FNEG		(HI(63) | LO(40))
+#define FRSP		(HI(63) | LO(12))
+#define FSUB		(HI(63) | LO(20))
+#define FSUBS		(HI(59) | LO(20))
+#define LD		(HI(58) | 0)
+#define LWZ		(HI(32))
+#define MFCR		(HI(31) | LO(19))
+#define MFLR		(HI(31) | LO(339) | 0x80000)
+#define MFXER		(HI(31) | LO(339) | 0x10000)
+#define MTCTR		(HI(31) | LO(467) | 0x90000)
+#define MTLR		(HI(31) | LO(467) | 0x80000)
+#define MTXER		(HI(31) | LO(467) | 0x10000)
+#define MULHD		(HI(31) | LO(73))
+#define MULHDU		(HI(31) | LO(9))
+#define MULHW		(HI(31) | LO(75))
+#define MULHWU		(HI(31) | LO(11))
+#define MULLD		(HI(31) | LO(233))
+#define MULLI		(HI(7))
+#define MULLW		(HI(31) | LO(235))
+#define NEG		(HI(31) | LO(104))
+#define NOP		(HI(24))
+#define NOR		(HI(31) | LO(124))
+#define OR		(HI(31) | LO(444))
+#define ORI		(HI(24))
+#define ORIS		(HI(25))
+#define RLDICL		(HI(30))
+#define RLWINM		(HI(21))
+#define SLD		(HI(31) | LO(27))
+#define SLW		(HI(31) | LO(24))
+#define SRAD		(HI(31) | LO(794))
+#define SRADI		(HI(31) | LO(413 << 1))
+#define SRAW		(HI(31) | LO(792))
+#define SRAWI		(HI(31) | LO(824))
+#define SRD		(HI(31) | LO(539))
+#define SRW		(HI(31) | LO(536))
+#define STD		(HI(62) | 0)
+#define STDU		(HI(62) | 1)
+#define STDUX		(HI(31) | LO(181))
+#define STFIWX		(HI(31) | LO(983))
+#define STW		(HI(36))
+#define STWU		(HI(37))
+#define STWUX		(HI(31) | LO(183))
+#define SUBF		(HI(31) | LO(40))
+#define SUBFC		(HI(31) | LO(8))
+#define SUBFE		(HI(31) | LO(136))
+#define SUBFIC		(HI(8))
+#define XOR		(HI(31) | LO(316))
+#define XORI		(HI(26))
+#define XORIS		(HI(27))
+
+#define SIMM_MAX	(0x7fff)
+#define SIMM_MIN	(-0x8000)
+#define UIMM_MAX	(0xffff)
+
+#define RLDI(dst, src, sh, mb, type) \
+	(HI(30) | S(src) | A(dst) | ((type) << 2) | (((sh) & 0x1f) << 11) | (((sh) & 0x20) >> 4) | (((mb) & 0x1f) << 6) | ((mb) & 0x20))
+
+#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_function_context(void** func_ptr, struct sljit_function_context* context, sljit_sw addr, void* func)
+{
+	sljit_sw* ptrs;
+	if (func_ptr)
+		*func_ptr = (void*)context;
+	ptrs = (sljit_sw*)func;
+	context->addr = addr ? addr : ptrs[0];
+	context->r2 = ptrs[1];
+	context->r11 = ptrs[2];
+}
+#endif
+
+static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins)
+{
+	sljit_ins *ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
+	FAIL_IF(!ptr);
+	*ptr = ins;
+	compiler->size++;
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
+{
+	sljit_sw diff;
+	sljit_uw target_addr;
+	sljit_sw extra_jump_flags;
+
+#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) && (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+	if (jump->flags & (SLJIT_REWRITABLE_JUMP | IS_CALL))
+		return 0;
+#else
+	if (jump->flags & SLJIT_REWRITABLE_JUMP)
+		return 0;
+#endif
+
+	if (jump->flags & JUMP_ADDR)
+		target_addr = jump->u.target;
+	else {
+		SLJIT_ASSERT(jump->flags & JUMP_LABEL);
+		target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset;
+	}
+
+#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL) && (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+	if (jump->flags & IS_CALL)
+		goto keep_address;
+#endif
+
+	diff = ((sljit_sw)target_addr - (sljit_sw)(code_ptr) - executable_offset) & ~0x3l;
+
+	extra_jump_flags = 0;
+	if (jump->flags & IS_COND) {
+		if (diff <= 0x7fff && diff >= -0x8000) {
+			jump->flags |= PATCH_B;
+			return 1;
+		}
+		if (target_addr <= 0xffff) {
+			jump->flags |= PATCH_B | PATCH_ABS_B;
+			return 1;
+		}
+		extra_jump_flags = REMOVE_COND;
+
+		diff -= sizeof(sljit_ins);
+	}
+
+	if (diff <= 0x01ffffff && diff >= -0x02000000) {
+		jump->flags |= PATCH_B | extra_jump_flags;
+		return 1;
+	}
+
+	if (target_addr <= 0x03ffffff) {
+		jump->flags |= PATCH_B | PATCH_ABS_B | extra_jump_flags;
+		return 1;
+	}
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
+keep_address:
+#endif
+	if (target_addr <= 0x7fffffff) {
+		jump->flags |= PATCH_ABS32;
+		return 1;
+	}
+
+	if (target_addr <= 0x7fffffffffffl) {
+		jump->flags |= PATCH_ABS48;
+		return 1;
+	}
+#endif
+
+	return 0;
+}
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+
+static SLJIT_INLINE sljit_sw put_label_get_length(struct sljit_put_label *put_label, sljit_uw max_label)
+{
+	if (max_label < 0x100000000l) {
+		put_label->flags = 0;
+		return 1;
+	}
+
+	if (max_label < 0x1000000000000l) {
+		put_label->flags = 1;
+		return 3;
+	}
+
+	put_label->flags = 2;
+	return 4;
+}
+
+static SLJIT_INLINE void put_label_set(struct sljit_put_label *put_label)
+{
+	sljit_uw addr = put_label->label->addr;
+	sljit_ins *inst = (sljit_ins *)put_label->addr;
+	sljit_s32 reg = *inst;
+
+	if (put_label->flags == 0) {
+		SLJIT_ASSERT(addr < 0x100000000l);
+		inst[0] = ORIS | S(TMP_ZERO) | A(reg) | IMM(addr >> 16);
+	}
+	else {
+		if (put_label->flags == 1) {
+			SLJIT_ASSERT(addr < 0x1000000000000l);
+			inst[0] = ORI | S(TMP_ZERO) | A(reg) | IMM(addr >> 32);
+		}
+		else {
+			inst[0] = ORIS | S(TMP_ZERO) | A(reg) | IMM(addr >> 48);
+			inst[1] = ORI | S(reg) | A(reg) | IMM((addr >> 32) & 0xffff);
+			inst ++;
+		}
+
+		inst[1] = RLDI(reg, reg, 32, 31, 1);
+		inst[2] = ORIS | S(reg) | A(reg) | IMM((addr >> 16) & 0xffff);
+		inst += 2;
+	}
+
+	inst[1] = ORI | S(reg) | A(reg) | IMM(addr & 0xffff);
+}
+
+#endif
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+{
+	struct sljit_memory_fragment *buf;
+	sljit_ins *code;
+	sljit_ins *code_ptr;
+	sljit_ins *buf_ptr;
+	sljit_ins *buf_end;
+	sljit_uw word_count;
+	sljit_uw next_addr;
+	sljit_sw executable_offset;
+	sljit_uw addr;
+
+	struct sljit_label *label;
+	struct sljit_jump *jump;
+	struct sljit_const *const_;
+	struct sljit_put_label *put_label;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_generate_code(compiler));
+	reverse_buf(compiler);
+
+#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+	compiler->size += (compiler->size & 0x1) + (sizeof(struct sljit_function_context) / sizeof(sljit_ins));
+#else
+	compiler->size += (sizeof(struct sljit_function_context) / sizeof(sljit_ins));
+#endif
+#endif
+	code = (sljit_ins*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins), compiler->exec_allocator_data);
+	PTR_FAIL_WITH_EXEC_IF(code);
+	buf = compiler->buf;
+
+	code_ptr = code;
+	word_count = 0;
+	next_addr = 0;
+	executable_offset = SLJIT_EXEC_OFFSET(code);
+
+	label = compiler->labels;
+	jump = compiler->jumps;
+	const_ = compiler->consts;
+	put_label = compiler->put_labels;
+
+	do {
+		buf_ptr = (sljit_ins*)buf->memory;
+		buf_end = buf_ptr + (buf->used_size >> 2);
+		do {
+			*code_ptr = *buf_ptr++;
+			if (next_addr == word_count) {
+				SLJIT_ASSERT(!label || label->size >= word_count);
+				SLJIT_ASSERT(!jump || jump->addr >= word_count);
+				SLJIT_ASSERT(!const_ || const_->addr >= word_count);
+				SLJIT_ASSERT(!put_label || put_label->addr >= word_count);
+
+				/* These structures are ordered by their address. */
+				if (label && label->size == word_count) {
+					/* Just recording the address. */
+					label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+					label->size = code_ptr - code;
+					label = label->next;
+				}
+				if (jump && jump->addr == word_count) {
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+					jump->addr = (sljit_uw)(code_ptr - 3);
+#else
+					jump->addr = (sljit_uw)(code_ptr - 6);
+#endif
+					if (detect_jump_type(jump, code_ptr, code, executable_offset)) {
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+						code_ptr[-3] = code_ptr[0];
+						code_ptr -= 3;
+#else
+						if (jump->flags & PATCH_ABS32) {
+							code_ptr -= 3;
+							code_ptr[-1] = code_ptr[2];
+							code_ptr[0] = code_ptr[3];
+						}
+						else if (jump->flags & PATCH_ABS48) {
+							code_ptr--;
+							code_ptr[-1] = code_ptr[0];
+							code_ptr[0] = code_ptr[1];
+							/* rldicr rX,rX,32,31 -> rX,rX,16,47 */
+							SLJIT_ASSERT((code_ptr[-3] & 0xfc00ffff) == 0x780007c6);
+							code_ptr[-3] ^= 0x8422;
+							/* oris -> ori */
+							code_ptr[-2] ^= 0x4000000;
+						}
+						else {
+							code_ptr[-6] = code_ptr[0];
+							code_ptr -= 6;
+						}
+#endif
+						if (jump->flags & REMOVE_COND) {
+							code_ptr[0] = BCx | (2 << 2) | ((code_ptr[0] ^ (8 << 21)) & 0x03ff0001);
+							code_ptr++;
+							jump->addr += sizeof(sljit_ins);
+							code_ptr[0] = Bx;
+							jump->flags -= IS_COND;
+						}
+					}
+					jump = jump->next;
+				}
+				if (const_ && const_->addr == word_count) {
+					const_->addr = (sljit_uw)code_ptr;
+					const_ = const_->next;
+				}
+				if (put_label && put_label->addr == word_count) {
+					SLJIT_ASSERT(put_label->label);
+					put_label->addr = (sljit_uw)code_ptr;
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+					code_ptr += put_label_get_length(put_label, (sljit_uw)(SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + put_label->label->size));
+					word_count += 4;
+#endif
+					put_label = put_label->next;
+				}
+				next_addr = compute_next_addr(label, jump, const_, put_label);
+			}
+			code_ptr ++;
+			word_count ++;
+		} while (buf_ptr < buf_end);
+
+		buf = buf->next;
+	} while (buf);
+
+	if (label && label->size == word_count) {
+		label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+		label->size = code_ptr - code;
+		label = label->next;
+	}
+
+	SLJIT_ASSERT(!label);
+	SLJIT_ASSERT(!jump);
+	SLJIT_ASSERT(!const_);
+	SLJIT_ASSERT(!put_label);
+
+#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
+	SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size - (sizeof(struct sljit_function_context) / sizeof(sljit_ins)));
+#else
+	SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size);
+#endif
+
+	jump = compiler->jumps;
+	while (jump) {
+		do {
+			addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
+			buf_ptr = (sljit_ins *)jump->addr;
+
+			if (jump->flags & PATCH_B) {
+				if (jump->flags & IS_COND) {
+					if (!(jump->flags & PATCH_ABS_B)) {
+						addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset);
+						SLJIT_ASSERT((sljit_sw)addr <= 0x7fff && (sljit_sw)addr >= -0x8000);
+						*buf_ptr = BCx | (addr & 0xfffc) | ((*buf_ptr) & 0x03ff0001);
+					}
+					else {
+						SLJIT_ASSERT(addr <= 0xffff);
+						*buf_ptr = BCx | (addr & 0xfffc) | 0x2 | ((*buf_ptr) & 0x03ff0001);
+					}
+				}
+				else {
+					if (!(jump->flags & PATCH_ABS_B)) {
+						addr -= (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset);
+						SLJIT_ASSERT((sljit_sw)addr <= 0x01ffffff && (sljit_sw)addr >= -0x02000000);
+						*buf_ptr = Bx | (addr & 0x03fffffc) | ((*buf_ptr) & 0x1);
+					}
+					else {
+						SLJIT_ASSERT(addr <= 0x03ffffff);
+						*buf_ptr = Bx | (addr & 0x03fffffc) | 0x2 | ((*buf_ptr) & 0x1);
+					}
+				}
+				break;
+			}
+
+			/* Set the fields of immediate loads. */
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+			buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | ((addr >> 16) & 0xffff);
+			buf_ptr[1] = (buf_ptr[1] & 0xffff0000) | (addr & 0xffff);
+#else
+			if (jump->flags & PATCH_ABS32) {
+				SLJIT_ASSERT(addr <= 0x7fffffff);
+				buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | ((addr >> 16) & 0xffff);
+				buf_ptr[1] = (buf_ptr[1] & 0xffff0000) | (addr & 0xffff);
+				break;
+			}
+			if (jump->flags & PATCH_ABS48) {
+				SLJIT_ASSERT(addr <= 0x7fffffffffff);
+				buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | ((addr >> 32) & 0xffff);
+				buf_ptr[1] = (buf_ptr[1] & 0xffff0000) | ((addr >> 16) & 0xffff);
+				buf_ptr[3] = (buf_ptr[3] & 0xffff0000) | (addr & 0xffff);
+				break;
+			}
+			buf_ptr[0] = (buf_ptr[0] & 0xffff0000) | ((addr >> 48) & 0xffff);
+			buf_ptr[1] = (buf_ptr[1] & 0xffff0000) | ((addr >> 32) & 0xffff);
+			buf_ptr[3] = (buf_ptr[3] & 0xffff0000) | ((addr >> 16) & 0xffff);
+			buf_ptr[4] = (buf_ptr[4] & 0xffff0000) | (addr & 0xffff);
+#endif
+		} while (0);
+		jump = jump->next;
+	}
+
+	put_label = compiler->put_labels;
+	while (put_label) {
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+		addr = put_label->label->addr;
+		buf_ptr = (sljit_ins *)put_label->addr;
+
+		SLJIT_ASSERT((buf_ptr[0] & 0xfc1f0000) == ADDIS && (buf_ptr[1] & 0xfc000000) == ORI);
+		buf_ptr[0] |= (addr >> 16) & 0xffff;
+		buf_ptr[1] |= addr & 0xffff;
+#else
+		put_label_set(put_label);
+#endif
+		put_label = put_label->next;
+	}
+
+	compiler->error = SLJIT_ERR_COMPILED;
+	compiler->executable_offset = executable_offset;
+	compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins);
+
+	code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
+
+#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+	if (((sljit_sw)code_ptr) & 0x4)
+		code_ptr++;
+#endif
+	sljit_set_function_context(NULL, (struct sljit_function_context*)code_ptr, (sljit_sw)code, (void*)sljit_generate_code);
+#endif
+
+	code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+
+	SLJIT_CACHE_FLUSH(code, code_ptr);
+	SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);
+
+#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
+	return code_ptr;
+#else
+	return code;
+#endif
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
+{
+	switch (feature_type) {
+	case SLJIT_HAS_FPU:
+#ifdef SLJIT_IS_FPU_AVAILABLE
+		return SLJIT_IS_FPU_AVAILABLE;
+#else
+		/* Available by default. */
+		return 1;
+#endif
+
+	/* A saved register is set to a zero value. */
+	case SLJIT_HAS_ZERO_REGISTER:
+	case SLJIT_HAS_CLZ:
+	case SLJIT_HAS_PREFETCH:
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+/*  Entry, exit                                                          */
+/* --------------------------------------------------------------------- */
+
+/* inp_flags: */
+
+/* Creates an index in data_transfer_insts array. */
+#define LOAD_DATA	0x01
+#define INDEXED		0x02
+#define SIGNED_DATA	0x04
+
+#define WORD_DATA	0x00
+#define BYTE_DATA	0x08
+#define HALF_DATA	0x10
+#define INT_DATA	0x18
+/* Separates integer and floating point registers */
+#define GPR_REG		0x1f
+#define DOUBLE_DATA	0x20
+
+#define MEM_MASK	0x7f
+
+/* Other inp_flags. */
+
+/* Integer opertion and set flags -> requires exts on 64 bit systems. */
+#define ALT_SIGN_EXT	0x000100
+/* This flag affects the RC() and OERC() macros. */
+#define ALT_SET_FLAGS	0x000400
+#define ALT_FORM1	0x001000
+#define ALT_FORM2	0x002000
+#define ALT_FORM3	0x004000
+#define ALT_FORM4	0x008000
+#define ALT_FORM5	0x010000
+
+/* Source and destination is register. */
+#define REG_DEST	0x000001
+#define REG1_SOURCE	0x000002
+#define REG2_SOURCE	0x000004
+/*
+ALT_SIGN_EXT		0x000100
+ALT_SET_FLAGS		0x000200
+ALT_FORM1		0x001000
+...
+ALT_FORM5		0x010000 */
+
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+#include "sljitNativePPC_32.c"
+#else
+#include "sljitNativePPC_64.c"
+#endif
+
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+#define STACK_STORE	STW
+#define STACK_LOAD	LWZ
+#else
+#define STACK_STORE	STD
+#define STACK_LOAD	LD
+#endif
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	sljit_s32 args, i, tmp, offs;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+	FAIL_IF(push_inst(compiler, MFLR | D(0)));
+	offs = -(sljit_s32)(sizeof(sljit_sw));
+	FAIL_IF(push_inst(compiler, STACK_STORE | S(TMP_ZERO) | A(SLJIT_SP) | IMM(offs)));
+
+	tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
+	for (i = SLJIT_S0; i >= tmp; i--) {
+		offs -= (sljit_s32)(sizeof(sljit_sw));
+		FAIL_IF(push_inst(compiler, STACK_STORE | S(i) | A(SLJIT_SP) | IMM(offs)));
+	}
+
+	for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
+		offs -= (sljit_s32)(sizeof(sljit_sw));
+		FAIL_IF(push_inst(compiler, STACK_STORE | S(i) | A(SLJIT_SP) | IMM(offs)));
+	}
+
+	SLJIT_ASSERT(offs == -(sljit_s32)GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds, 1));
+
+#if (defined SLJIT_PPC_STACK_FRAME_V2 && SLJIT_PPC_STACK_FRAME_V2)
+	FAIL_IF(push_inst(compiler, STACK_STORE | S(0) | A(SLJIT_SP) | IMM(2 * sizeof(sljit_sw))));
+#else
+	FAIL_IF(push_inst(compiler, STACK_STORE | S(0) | A(SLJIT_SP) | IMM(sizeof(sljit_sw))));
+#endif
+
+	FAIL_IF(push_inst(compiler, ADDI | D(TMP_ZERO) | A(0) | 0));
+
+	args = get_arg_count(arg_types);
+
+	if (args >= 1)
+		FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0) | A(SLJIT_S0) | B(SLJIT_R0)));
+	if (args >= 2)
+		FAIL_IF(push_inst(compiler, OR | S(SLJIT_R1) | A(SLJIT_S1) | B(SLJIT_R1)));
+	if (args >= 3)
+		FAIL_IF(push_inst(compiler, OR | S(SLJIT_R2) | A(SLJIT_S2) | B(SLJIT_R2)));
+
+	local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1) + SLJIT_LOCALS_OFFSET;
+	local_size = (local_size + 15) & ~0xf;
+	compiler->local_size = local_size;
+
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+	if (local_size <= SIMM_MAX)
+		FAIL_IF(push_inst(compiler, STWU | S(SLJIT_SP) | A(SLJIT_SP) | IMM(-local_size)));
+	else {
+		FAIL_IF(load_immediate(compiler, 0, -local_size));
+		FAIL_IF(push_inst(compiler, STWUX | S(SLJIT_SP) | A(SLJIT_SP) | B(0)));
+	}
+#else
+	if (local_size <= SIMM_MAX)
+		FAIL_IF(push_inst(compiler, STDU | S(SLJIT_SP) | A(SLJIT_SP) | IMM(-local_size)));
+	else {
+		FAIL_IF(load_immediate(compiler, 0, -local_size));
+		FAIL_IF(push_inst(compiler, STDUX | S(SLJIT_SP) | A(SLJIT_SP) | B(0)));
+	}
+#endif
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+	local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1) + SLJIT_LOCALS_OFFSET;
+	compiler->local_size = (local_size + 15) & ~0xf;
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 i, tmp, offs;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_return(compiler, op, src, srcw));
+
+	FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
+
+	if (compiler->local_size <= SIMM_MAX)
+		FAIL_IF(push_inst(compiler, ADDI | D(SLJIT_SP) | A(SLJIT_SP) | IMM(compiler->local_size)));
+	else {
+		FAIL_IF(load_immediate(compiler, 0, compiler->local_size));
+		FAIL_IF(push_inst(compiler, ADD | D(SLJIT_SP) | A(SLJIT_SP) | B(0)));
+	}
+
+#if (defined SLJIT_PPC_STACK_FRAME_V2 && SLJIT_PPC_STACK_FRAME_V2)
+	FAIL_IF(push_inst(compiler, STACK_LOAD | D(0) | A(SLJIT_SP) | IMM(2 * sizeof(sljit_sw))));
+#else
+	FAIL_IF(push_inst(compiler, STACK_LOAD | D(0) | A(SLJIT_SP) | IMM(sizeof(sljit_sw))));
+#endif
+
+	offs = -(sljit_s32)GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds, 1);
+
+	tmp = compiler->scratches;
+	for (i = SLJIT_FIRST_SAVED_REG; i <= tmp; i++) {
+		FAIL_IF(push_inst(compiler, STACK_LOAD | D(i) | A(SLJIT_SP) | IMM(offs)));
+		offs += (sljit_s32)(sizeof(sljit_sw));
+	}
+
+	tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG;
+	for (i = tmp; i <= SLJIT_S0; i++) {
+		FAIL_IF(push_inst(compiler, STACK_LOAD | D(i) | A(SLJIT_SP) | IMM(offs)));
+		offs += (sljit_s32)(sizeof(sljit_sw));
+	}
+
+	FAIL_IF(push_inst(compiler, STACK_LOAD | D(TMP_ZERO) | A(SLJIT_SP) | IMM(offs)));
+	SLJIT_ASSERT(offs == -(sljit_sw)(sizeof(sljit_sw)));
+
+	FAIL_IF(push_inst(compiler, MTLR | S(0)));
+	FAIL_IF(push_inst(compiler, BLR));
+
+	return SLJIT_SUCCESS;
+}
+
+#undef STACK_STORE
+#undef STACK_LOAD
+
+/* --------------------------------------------------------------------- */
+/*  Operators                                                            */
+/* --------------------------------------------------------------------- */
+
+/* s/l - store/load (1 bit)
+   i/x - immediate/indexed form
+   u/s - signed/unsigned (1 bit)
+   w/b/h/i - word/byte/half/int allowed (2 bit)
+
+   Some opcodes are repeated (e.g. store signed / unsigned byte is the same instruction). */
+
+/* 64 bit only: [reg+imm] must be aligned to 4 bytes. */
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+#define INT_ALIGNED	0x10000
+#endif
+
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+#define ARCH_32_64(a, b)	a
+#define INST_CODE_AND_DST(inst, flags, reg) \
+	((inst) | (((flags) & MEM_MASK) <= GPR_REG ? D(reg) : FD(reg)))
+#else
+#define ARCH_32_64(a, b)	b
+#define INST_CODE_AND_DST(inst, flags, reg) \
+	(((inst) & ~INT_ALIGNED) | (((flags) & MEM_MASK) <= GPR_REG ? D(reg) : FD(reg)))
+#endif
+
+static const sljit_ins data_transfer_insts[64 + 16] = {
+
+/* -------- Integer -------- */
+
+/* Word. */
+
+/* w u i s */ ARCH_32_64(HI(36) /* stw */, HI(62) | INT_ALIGNED | 0x0 /* std */),
+/* w u i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | INT_ALIGNED | 0x0 /* ld */),
+/* w u x s */ ARCH_32_64(HI(31) | LO(151) /* stwx */, HI(31) | LO(149) /* stdx */),
+/* w u x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(21) /* ldx */),
+
+/* w s i s */ ARCH_32_64(HI(36) /* stw */, HI(62) | INT_ALIGNED | 0x0 /* std */),
+/* w s i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | INT_ALIGNED | 0x0 /* ld */),
+/* w s x s */ ARCH_32_64(HI(31) | LO(151) /* stwx */, HI(31) | LO(149) /* stdx */),
+/* w s x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(21) /* ldx */),
+
+/* Byte. */
+
+/* b u i s */ HI(38) /* stb */,
+/* b u i l */ HI(34) /* lbz */,
+/* b u x s */ HI(31) | LO(215) /* stbx */,
+/* b u x l */ HI(31) | LO(87) /* lbzx */,
+
+/* b s i s */ HI(38) /* stb */,
+/* b s i l */ HI(34) /* lbz */ /* EXTS_REQ */,
+/* b s x s */ HI(31) | LO(215) /* stbx */,
+/* b s x l */ HI(31) | LO(87) /* lbzx */ /* EXTS_REQ */,
+
+/* Half. */
+
+/* h u i s */ HI(44) /* sth */,
+/* h u i l */ HI(40) /* lhz */,
+/* h u x s */ HI(31) | LO(407) /* sthx */,
+/* h u x l */ HI(31) | LO(279) /* lhzx */,
+
+/* h s i s */ HI(44) /* sth */,
+/* h s i l */ HI(42) /* lha */,
+/* h s x s */ HI(31) | LO(407) /* sthx */,
+/* h s x l */ HI(31) | LO(343) /* lhax */,
+
+/* Int. */
+
+/* i u i s */ HI(36) /* stw */,
+/* i u i l */ HI(32) /* lwz */,
+/* i u x s */ HI(31) | LO(151) /* stwx */,
+/* i u x l */ HI(31) | LO(23) /* lwzx */,
+
+/* i s i s */ HI(36) /* stw */,
+/* i s i l */ ARCH_32_64(HI(32) /* lwz */, HI(58) | INT_ALIGNED | 0x2 /* lwa */),
+/* i s x s */ HI(31) | LO(151) /* stwx */,
+/* i s x l */ ARCH_32_64(HI(31) | LO(23) /* lwzx */, HI(31) | LO(341) /* lwax */),
+
+/* -------- Floating point -------- */
+
+/* d   i s */ HI(54) /* stfd */,
+/* d   i l */ HI(50) /* lfd */,
+/* d   x s */ HI(31) | LO(727) /* stfdx */,
+/* d   x l */ HI(31) | LO(599) /* lfdx */,
+
+/* s   i s */ HI(52) /* stfs */,
+/* s   i l */ HI(48) /* lfs */,
+/* s   x s */ HI(31) | LO(663) /* stfsx */,
+/* s   x l */ HI(31) | LO(535) /* lfsx */,
+};
+
+static const sljit_ins updated_data_transfer_insts[64] = {
+
+/* -------- Integer -------- */
+
+/* Word. */
+
+/* w u i s */ ARCH_32_64(HI(37) /* stwu */, HI(62) | INT_ALIGNED | 0x1 /* stdu */),
+/* w u i l */ ARCH_32_64(HI(33) /* lwzu */, HI(58) | INT_ALIGNED | 0x1 /* ldu */),
+/* w u x s */ ARCH_32_64(HI(31) | LO(183) /* stwux */, HI(31) | LO(181) /* stdux */),
+/* w u x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(53) /* ldux */),
+
+/* w s i s */ ARCH_32_64(HI(37) /* stwu */, HI(62) | INT_ALIGNED | 0x1 /* stdu */),
+/* w s i l */ ARCH_32_64(HI(33) /* lwzu */, HI(58) | INT_ALIGNED | 0x1 /* ldu */),
+/* w s x s */ ARCH_32_64(HI(31) | LO(183) /* stwux */, HI(31) | LO(181) /* stdux */),
+/* w s x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(53) /* ldux */),
+
+/* Byte. */
+
+/* b u i s */ HI(39) /* stbu */,
+/* b u i l */ HI(35) /* lbzu */,
+/* b u x s */ HI(31) | LO(247) /* stbux */,
+/* b u x l */ HI(31) | LO(119) /* lbzux */,
+
+/* b s i s */ HI(39) /* stbu */,
+/* b s i l */ 0 /* no such instruction */,
+/* b s x s */ HI(31) | LO(247) /* stbux */,
+/* b s x l */ 0 /* no such instruction */,
+
+/* Half. */
+
+/* h u i s */ HI(45) /* sthu */,
+/* h u i l */ HI(41) /* lhzu */,
+/* h u x s */ HI(31) | LO(439) /* sthux */,
+/* h u x l */ HI(31) | LO(311) /* lhzux */,
+
+/* h s i s */ HI(45) /* sthu */,
+/* h s i l */ HI(43) /* lhau */,
+/* h s x s */ HI(31) | LO(439) /* sthux */,
+/* h s x l */ HI(31) | LO(375) /* lhaux */,
+
+/* Int. */
+
+/* i u i s */ HI(37) /* stwu */,
+/* i u i l */ HI(33) /* lwzu */,
+/* i u x s */ HI(31) | LO(183) /* stwux */,
+/* i u x l */ HI(31) | LO(55) /* lwzux */,
+
+/* i s i s */ HI(37) /* stwu */,
+/* i s i l */ ARCH_32_64(HI(33) /* lwzu */, 0 /* no such instruction */),
+/* i s x s */ HI(31) | LO(183) /* stwux */,
+/* i s x l */ ARCH_32_64(HI(31) | LO(55) /* lwzux */, HI(31) | LO(373) /* lwaux */),
+
+/* -------- Floating point -------- */
+
+/* d   i s */ HI(55) /* stfdu */,
+/* d   i l */ HI(51) /* lfdu */,
+/* d   x s */ HI(31) | LO(759) /* stfdux */,
+/* d   x l */ HI(31) | LO(631) /* lfdux */,
+
+/* s   i s */ HI(53) /* stfsu */,
+/* s   i l */ HI(49) /* lfsu */,
+/* s   x s */ HI(31) | LO(695) /* stfsux */,
+/* s   x l */ HI(31) | LO(567) /* lfsux */,
+};
+
+#undef ARCH_32_64
+
+/* Simple cases, (no caching is required). */
+static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 inp_flags, sljit_s32 reg,
+	sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg)
+{
+	sljit_ins inst;
+	sljit_s32 offs_reg;
+	sljit_sw high_short;
+
+	/* Should work when (arg & REG_MASK) == 0. */
+	SLJIT_ASSERT(A(0) == 0);
+	SLJIT_ASSERT(arg & SLJIT_MEM);
+
+	if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
+		argw &= 0x3;
+		offs_reg = OFFS_REG(arg);
+
+		if (argw != 0) {
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+			FAIL_IF(push_inst(compiler, RLWINM | S(OFFS_REG(arg)) | A(tmp_reg) | (argw << 11) | ((31 - argw) << 1)));
+#else
+			FAIL_IF(push_inst(compiler, RLDI(tmp_reg, OFFS_REG(arg), argw, 63 - argw, 1)));
+#endif
+			offs_reg = tmp_reg;
+		}
+
+		inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+		SLJIT_ASSERT(!(inst & INT_ALIGNED));
+#endif
+
+		return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg & REG_MASK) | B(offs_reg));
+	}
+
+	inst = data_transfer_insts[inp_flags & MEM_MASK];
+	arg &= REG_MASK;
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+	if ((inst & INT_ALIGNED) && (argw & 0x3) != 0) {
+		FAIL_IF(load_immediate(compiler, tmp_reg, argw));
+
+		inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];
+		return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg) | B(tmp_reg));
+	}
+#endif
+
+	if (argw <= SIMM_MAX && argw >= SIMM_MIN)
+		return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg) | IMM(argw));
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+	if (argw <= 0x7fff7fffl && argw >= -0x80000000l) {
+#endif
+
+		high_short = (sljit_s32)(argw + ((argw & 0x8000) << 1)) & ~0xffff;
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+		SLJIT_ASSERT(high_short && high_short <= 0x7fffffffl && high_short >= -0x80000000l);
+#else
+		SLJIT_ASSERT(high_short);
+#endif
+
+		FAIL_IF(push_inst(compiler, ADDIS | D(tmp_reg) | A(arg) | IMM(high_short >> 16)));
+		return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(tmp_reg) | IMM(argw));
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+	}
+
+	/* The rest is PPC-64 only. */
+
+	FAIL_IF(load_immediate(compiler, tmp_reg, argw));
+
+	inst = data_transfer_insts[(inp_flags | INDEXED) & MEM_MASK];
+	return push_inst(compiler, INST_CODE_AND_DST(inst, inp_flags, reg) | A(arg) | B(tmp_reg));
+#endif
+}
+
+static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 input_flags,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	/* arg1 goes to TMP_REG1 or src reg
+	   arg2 goes to TMP_REG2, imm or src reg
+	   result goes to TMP_REG2, so put result can use TMP_REG1. */
+	sljit_s32 dst_r = TMP_REG2;
+	sljit_s32 src1_r;
+	sljit_s32 src2_r;
+	sljit_s32 sugg_src2_r = TMP_REG2;
+	sljit_s32 flags = input_flags & (ALT_FORM1 | ALT_FORM2 | ALT_FORM3 | ALT_FORM4 | ALT_FORM5 | ALT_SIGN_EXT | ALT_SET_FLAGS);
+
+	/* Destination check. */
+	if (SLOW_IS_REG(dst)) {
+		dst_r = dst;
+		flags |= REG_DEST;
+
+		if (op >= SLJIT_MOV && op <= SLJIT_MOV_P)
+			sugg_src2_r = dst_r;
+	}
+
+	/* Source 1. */
+	if (FAST_IS_REG(src1)) {
+		src1_r = src1;
+		flags |= REG1_SOURCE;
+	}
+	else if (src1 & SLJIT_IMM) {
+		FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
+		src1_r = TMP_REG1;
+	}
+	else {
+		FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1));
+		src1_r = TMP_REG1;
+	}
+
+	/* Source 2. */
+	if (FAST_IS_REG(src2)) {
+		src2_r = src2;
+		flags |= REG2_SOURCE;
+
+		if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOV_P)
+			dst_r = src2_r;
+	}
+	else if (src2 & SLJIT_IMM) {
+		FAIL_IF(load_immediate(compiler, sugg_src2_r, src2w));
+		src2_r = sugg_src2_r;
+	}
+	else {
+		FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, sugg_src2_r, src2, src2w, TMP_REG2));
+		src2_r = sugg_src2_r;
+	}
+
+	FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r));
+
+	if (!(dst & SLJIT_MEM))
+		return SLJIT_SUCCESS;
+
+	return emit_op_mem(compiler, input_flags, dst_r, dst, dstw, TMP_REG1);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
+{
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+	sljit_s32 int_op = op & SLJIT_I32_OP;
+#endif
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op0(compiler, op));
+
+	op = GET_OPCODE(op);
+	switch (op) {
+	case SLJIT_BREAKPOINT:
+	case SLJIT_NOP:
+		return push_inst(compiler, NOP);
+	case SLJIT_LMUL_UW:
+	case SLJIT_LMUL_SW:
+		FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R0)));
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+		FAIL_IF(push_inst(compiler, MULLD | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1)));
+		return push_inst(compiler, (op == SLJIT_LMUL_UW ? MULHDU : MULHD) | D(SLJIT_R1) | A(TMP_REG1) | B(SLJIT_R1));
+#else
+		FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R1)));
+		return push_inst(compiler, (op == SLJIT_LMUL_UW ? MULHWU : MULHW) | D(SLJIT_R1) | A(TMP_REG1) | B(SLJIT_R1));
+#endif
+	case SLJIT_DIVMOD_UW:
+	case SLJIT_DIVMOD_SW:
+		FAIL_IF(push_inst(compiler, OR | S(SLJIT_R0) | A(TMP_REG1) | B(SLJIT_R0)));
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+		FAIL_IF(push_inst(compiler, (int_op ? (op == SLJIT_DIVMOD_UW ? DIVWU : DIVW) : (op == SLJIT_DIVMOD_UW ? DIVDU : DIVD)) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)));
+		FAIL_IF(push_inst(compiler, (int_op ? MULLW : MULLD) | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1)));
+#else
+		FAIL_IF(push_inst(compiler, (op == SLJIT_DIVMOD_UW ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1)));
+		FAIL_IF(push_inst(compiler, MULLW | D(SLJIT_R1) | A(SLJIT_R0) | B(SLJIT_R1)));
+#endif
+		return push_inst(compiler, SUBF | D(SLJIT_R1) | A(SLJIT_R1) | B(TMP_REG1));
+	case SLJIT_DIV_UW:
+	case SLJIT_DIV_SW:
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+		return push_inst(compiler, (int_op ? (op == SLJIT_DIV_UW ? DIVWU : DIVW) : (op == SLJIT_DIV_UW ? DIVDU : DIVD)) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1));
+#else
+		return push_inst(compiler, (op == SLJIT_DIV_UW ? DIVWU : DIVW) | D(SLJIT_R0) | A(SLJIT_R0) | B(SLJIT_R1));
+#endif
+	case SLJIT_ENDBR:
+	case SLJIT_SKIP_FRAMES_BEFORE_RETURN:
+		return SLJIT_SUCCESS;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_prefetch(struct sljit_compiler *compiler,
+        sljit_s32 src, sljit_sw srcw)
+{
+	if (!(src & OFFS_REG_MASK)) {
+		if (srcw == 0 && (src & REG_MASK) != SLJIT_UNUSED)
+			return push_inst(compiler, DCBT | A(0) | B(src & REG_MASK));
+
+		FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+		/* Works with SLJIT_MEM0() case as well. */
+		return push_inst(compiler, DCBT | A(src & REG_MASK) | B(TMP_REG1));
+	}
+
+	srcw &= 0x3;
+
+	if (srcw == 0)
+		return push_inst(compiler, DCBT | A(src & REG_MASK) | B(OFFS_REG(src)));
+
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+	FAIL_IF(push_inst(compiler, RLWINM | S(OFFS_REG(src)) | A(TMP_REG1) | (srcw << 11) | ((31 - srcw) << 1)));
+#else
+	FAIL_IF(push_inst(compiler, RLDI(TMP_REG1, OFFS_REG(src), srcw, 63 - srcw, 1)));
+#endif
+	return push_inst(compiler, DCBT | A(src & REG_MASK) | B(TMP_REG1));
+}
+
+#define EMIT_MOV(type, type_flags, type_cast) \
+	emit_op(compiler, (src & SLJIT_IMM) ? SLJIT_MOV : type, flags | (type_flags), dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? type_cast srcw : srcw)
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 flags = HAS_FLAGS(op) ? ALT_SET_FLAGS : 0;
+	sljit_s32 op_flags = GET_ALL_FLAGS(op);
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	op = GET_OPCODE(op);
+	if ((src & SLJIT_IMM) && srcw == 0)
+		src = TMP_ZERO;
+
+	if (GET_FLAG_TYPE(op_flags) == SLJIT_OVERFLOW)
+		FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO)));
+
+	if (op < SLJIT_NOT && FAST_IS_REG(src) && src == dst) {
+		if (!TYPE_CAST_NEEDED(op))
+			return SLJIT_SUCCESS;
+	}
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+	if (op_flags & SLJIT_I32_OP) {
+		if (op < SLJIT_NOT) {
+			if (src & SLJIT_MEM) {
+				if (op == SLJIT_MOV_S32)
+					op = SLJIT_MOV_U32;
+			}
+			else if (src & SLJIT_IMM) {
+				if (op == SLJIT_MOV_U32)
+					op = SLJIT_MOV_S32;
+			}
+		}
+		else {
+			/* Most operations expect sign extended arguments. */
+			flags |= INT_DATA | SIGNED_DATA;
+			if (HAS_FLAGS(op_flags))
+				flags |= ALT_SIGN_EXT;
+		}
+	}
+#endif
+
+	switch (op) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_P:
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+	case SLJIT_MOV_U32:
+	case SLJIT_MOV_S32:
+#endif
+		return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+	case SLJIT_MOV_U32:
+		return EMIT_MOV(SLJIT_MOV_U32, INT_DATA, (sljit_u32));
+
+	case SLJIT_MOV_S32:
+		return EMIT_MOV(SLJIT_MOV_S32, INT_DATA | SIGNED_DATA, (sljit_s32));
+#endif
+
+	case SLJIT_MOV_U8:
+		return EMIT_MOV(SLJIT_MOV_U8, BYTE_DATA, (sljit_u8));
+
+	case SLJIT_MOV_S8:
+		return EMIT_MOV(SLJIT_MOV_S8, BYTE_DATA | SIGNED_DATA, (sljit_s8));
+
+	case SLJIT_MOV_U16:
+		return EMIT_MOV(SLJIT_MOV_U16, HALF_DATA, (sljit_u16));
+
+	case SLJIT_MOV_S16:
+		return EMIT_MOV(SLJIT_MOV_S16, HALF_DATA | SIGNED_DATA, (sljit_s16));
+
+	case SLJIT_NOT:
+		return emit_op(compiler, SLJIT_NOT, flags, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_NEG:
+		return emit_op(compiler, SLJIT_NEG, flags | (GET_FLAG_TYPE(op_flags) ? ALT_FORM1 : 0), dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_CLZ:
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+		return emit_op(compiler, SLJIT_CLZ, flags | (!(op_flags & SLJIT_I32_OP) ? 0 : ALT_FORM1), dst, dstw, TMP_REG1, 0, src, srcw);
+#else
+		return emit_op(compiler, SLJIT_CLZ, flags, dst, dstw, TMP_REG1, 0, src, srcw);
+#endif
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+#undef EMIT_MOV
+
+#define TEST_SL_IMM(src, srcw) \
+	(((src) & SLJIT_IMM) && (srcw) <= SIMM_MAX && (srcw) >= SIMM_MIN)
+
+#define TEST_UL_IMM(src, srcw) \
+	(((src) & SLJIT_IMM) && !((srcw) & ~0xffff))
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+#define TEST_SH_IMM(src, srcw) \
+	(((src) & SLJIT_IMM) && !((srcw) & 0xffff) && (srcw) <= 0x7fffffffl && (srcw) >= -0x80000000l)
+#else
+#define TEST_SH_IMM(src, srcw) \
+	(((src) & SLJIT_IMM) && !((srcw) & 0xffff))
+#endif
+
+#define TEST_UH_IMM(src, srcw) \
+	(((src) & SLJIT_IMM) && !((srcw) & ~0xffff0000))
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+#define TEST_ADD_IMM(src, srcw) \
+	(((src) & SLJIT_IMM) && (srcw) <= 0x7fff7fffl && (srcw) >= -0x80000000l)
+#else
+#define TEST_ADD_IMM(src, srcw) \
+	((src) & SLJIT_IMM)
+#endif
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+#define TEST_UI_IMM(src, srcw) \
+	(((src) & SLJIT_IMM) && !((srcw) & ~0xffffffff))
+#else
+#define TEST_UI_IMM(src, srcw) \
+	((src) & SLJIT_IMM)
+#endif
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_s32 flags = HAS_FLAGS(op) ? ALT_SET_FLAGS : 0;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
+		return SLJIT_SUCCESS;
+
+	if ((src1 & SLJIT_IMM) && src1w == 0)
+		src1 = TMP_ZERO;
+	if ((src2 & SLJIT_IMM) && src2w == 0)
+		src2 = TMP_ZERO;
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+	if (op & SLJIT_I32_OP) {
+		/* Most operations expect sign extended arguments. */
+		flags |= INT_DATA | SIGNED_DATA;
+		if (src1 & SLJIT_IMM)
+			src1w = (sljit_s32)(src1w);
+		if (src2 & SLJIT_IMM)
+			src2w = (sljit_s32)(src2w);
+		if (HAS_FLAGS(op))
+			flags |= ALT_SIGN_EXT;
+	}
+#endif
+	if (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)
+		FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO)));
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_ADD:
+		if (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)
+			return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM1, dst, dstw, src1, src1w, src2, src2w);
+
+		if (!HAS_FLAGS(op) && ((src1 | src2) & SLJIT_IMM)) {
+			if (TEST_SL_IMM(src2, src2w)) {
+				compiler->imm = src2w & 0xffff;
+				return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
+			}
+			if (TEST_SL_IMM(src1, src1w)) {
+				compiler->imm = src1w & 0xffff;
+				return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0);
+			}
+			if (TEST_SH_IMM(src2, src2w)) {
+				compiler->imm = (src2w >> 16) & 0xffff;
+				return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
+			}
+			if (TEST_SH_IMM(src1, src1w)) {
+				compiler->imm = (src1w >> 16) & 0xffff;
+				return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);
+			}
+			/* Range between -1 and -32768 is covered above. */
+			if (TEST_ADD_IMM(src2, src2w)) {
+				compiler->imm = src2w & 0xffffffff;
+				return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0);
+			}
+			if (TEST_ADD_IMM(src1, src1w)) {
+				compiler->imm = src1w & 0xffffffff;
+				return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src2, src2w, TMP_REG2, 0);
+			}
+		}
+		if (HAS_FLAGS(op)) {
+			if (TEST_SL_IMM(src2, src2w)) {
+				compiler->imm = src2w & 0xffff;
+				return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
+			}
+			if (TEST_SL_IMM(src1, src1w)) {
+				compiler->imm = src1w & 0xffff;
+				return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);
+			}
+		}
+		return emit_op(compiler, SLJIT_ADD, flags | ((GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY)) ? ALT_FORM4 : 0), dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_ADDC:
+		return emit_op(compiler, SLJIT_ADDC, flags, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_SUB:
+		if (GET_FLAG_TYPE(op) >= SLJIT_LESS && GET_FLAG_TYPE(op) <= SLJIT_LESS_EQUAL) {
+			if (dst == SLJIT_UNUSED) {
+				if (TEST_UL_IMM(src2, src2w)) {
+					compiler->imm = src2w & 0xffff;
+					return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
+				}
+				return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1, dst, dstw, src1, src1w, src2, src2w);
+			}
+
+			if ((src2 & SLJIT_IMM) && src2w >= 0 && src2w <= (SIMM_MAX + 1)) {
+				compiler->imm = src2w;
+				return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
+			}
+			return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM3, dst, dstw, src1, src1w, src2, src2w);
+		}
+
+		if (GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)
+			return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2, dst, dstw, src1, src1w, src2, src2w);
+
+		if (!HAS_FLAGS(op) && ((src1 | src2) & SLJIT_IMM)) {
+			if (TEST_SL_IMM(src2, -src2w)) {
+				compiler->imm = (-src2w) & 0xffff;
+				return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
+			}
+			if (TEST_SL_IMM(src1, src1w)) {
+				compiler->imm = src1w & 0xffff;
+				return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);
+			}
+			if (TEST_SH_IMM(src2, -src2w)) {
+				compiler->imm = ((-src2w) >> 16) & 0xffff;
+				return emit_op(compiler, SLJIT_ADD, flags |  ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
+			}
+			/* Range between -1 and -32768 is covered above. */
+			if (TEST_ADD_IMM(src2, -src2w)) {
+				compiler->imm = -src2w & 0xffffffff;
+				return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2 | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0);
+			}
+		}
+
+		if (dst == SLJIT_UNUSED && GET_FLAG_TYPE(op) != GET_FLAG_TYPE(SLJIT_SET_CARRY)) {
+			if (TEST_SL_IMM(src2, src2w)) {
+				compiler->imm = src2w & 0xffff;
+				return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM4 | ALT_FORM5, dst, dstw, src1, src1w, TMP_REG2, 0);
+			}
+			return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM4, dst, dstw, src1, src1w, src2, src2w);
+		}
+
+		if (TEST_SL_IMM(src2, -src2w)) {
+			compiler->imm = (-src2w) & 0xffff;
+			return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
+		}
+		/* We know ALT_SIGN_EXT is set if it is an SLJIT_I32_OP on 64 bit systems. */
+		return emit_op(compiler, SLJIT_SUB, flags | ((GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY)) ? ALT_FORM5 : 0), dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_SUBC:
+		return emit_op(compiler, SLJIT_SUBC, flags, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_MUL:
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+		if (op & SLJIT_I32_OP)
+			flags |= ALT_FORM2;
+#endif
+		if (!HAS_FLAGS(op)) {
+			if (TEST_SL_IMM(src2, src2w)) {
+				compiler->imm = src2w & 0xffff;
+				return emit_op(compiler, SLJIT_MUL, flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);
+			}
+			if (TEST_SL_IMM(src1, src1w)) {
+				compiler->imm = src1w & 0xffff;
+				return emit_op(compiler, SLJIT_MUL, flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0);
+			}
+		}
+		else
+			FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO)));
+		return emit_op(compiler, SLJIT_MUL, flags, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_AND:
+	case SLJIT_OR:
+	case SLJIT_XOR:
+		/* Commutative unsigned operations. */
+		if (!HAS_FLAGS(op) || GET_OPCODE(op) == SLJIT_AND) {
+			if (TEST_UL_IMM(src2, src2w)) {
+				compiler->imm = src2w;
+				return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);
+			}
+			if (TEST_UL_IMM(src1, src1w)) {
+				compiler->imm = src1w;
+				return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src2, src2w, TMP_REG2, 0);
+			}
+			if (TEST_UH_IMM(src2, src2w)) {
+				compiler->imm = (src2w >> 16) & 0xffff;
+				return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
+			}
+			if (TEST_UH_IMM(src1, src1w)) {
+				compiler->imm = (src1w >> 16) & 0xffff;
+				return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM2, dst, dstw, src2, src2w, TMP_REG2, 0);
+			}
+		}
+		if (GET_OPCODE(op) != SLJIT_AND && GET_OPCODE(op) != SLJIT_AND) {
+			/* Unlike or and xor, and resets unwanted bits as well. */
+			if (TEST_UI_IMM(src2, src2w)) {
+				compiler->imm = src2w;
+				return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
+			}
+			if (TEST_UI_IMM(src1, src1w)) {
+				compiler->imm = src1w;
+				return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);
+			}
+		}
+		return emit_op(compiler, GET_OPCODE(op), flags, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_SHL:
+	case SLJIT_LSHR:
+	case SLJIT_ASHR:
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+		if (op & SLJIT_I32_OP)
+			flags |= ALT_FORM2;
+#endif
+		if (src2 & SLJIT_IMM) {
+			compiler->imm = src2w;
+			return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);
+		}
+		return emit_op(compiler, GET_OPCODE(op), flags, dst, dstw, src1, src1w, src2, src2w);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_src(compiler, op, src, srcw));
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	switch (op) {
+	case SLJIT_FAST_RETURN:
+		if (FAST_IS_REG(src))
+			FAIL_IF(push_inst(compiler, MTLR | S(src)));
+		else {
+			FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, TMP_REG2, 0, TMP_REG1, 0, src, srcw));
+			FAIL_IF(push_inst(compiler, MTLR | S(TMP_REG2)));
+		}
+
+		return push_inst(compiler, BLR);
+	case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN:
+		return SLJIT_SUCCESS;
+	case SLJIT_PREFETCH_L1:
+	case SLJIT_PREFETCH_L2:
+	case SLJIT_PREFETCH_L3:
+	case SLJIT_PREFETCH_ONCE:
+		return emit_prefetch(compiler, src, srcw);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+{
+	CHECK_REG_INDEX(check_sljit_get_register_index(reg));
+	return reg_map[reg];
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
+{
+	CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
+	return freg_map[reg];
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+	void *instruction, sljit_s32 size)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
+
+	return push_inst(compiler, *(sljit_ins*)instruction);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Floating point operators                                             */
+/* --------------------------------------------------------------------- */
+
+#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_F32_OP) >> 6))
+#define SELECT_FOP(op, single, double) ((op & SLJIT_F32_OP) ? single : double)
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+#define FLOAT_TMP_MEM_OFFSET (6 * sizeof(sljit_sw))
+#else
+#define FLOAT_TMP_MEM_OFFSET (2 * sizeof(sljit_sw))
+
+#if (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
+#define FLOAT_TMP_MEM_OFFSET_LOW (2 * sizeof(sljit_sw))
+#define FLOAT_TMP_MEM_OFFSET_HI (3 * sizeof(sljit_sw))
+#else
+#define FLOAT_TMP_MEM_OFFSET_LOW (3 * sizeof(sljit_sw))
+#define FLOAT_TMP_MEM_OFFSET_HI (2 * sizeof(sljit_sw))
+#endif
+
+#endif /* SLJIT_CONFIG_PPC_64 */
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	if (src & SLJIT_MEM) {
+		/* We can ignore the temporary data store on the stack from caching point of view. */
+		FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src, srcw, TMP_REG1));
+		src = TMP_FREG1;
+	}
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+	op = GET_OPCODE(op);
+	FAIL_IF(push_inst(compiler, (op == SLJIT_CONV_S32_FROM_F64 ? FCTIWZ : FCTIDZ) | FD(TMP_FREG1) | FB(src)));
+
+	if (op == SLJIT_CONV_SW_FROM_F64) {
+		if (FAST_IS_REG(dst)) {
+			FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1));
+			return emit_op_mem(compiler, WORD_DATA | LOAD_DATA, dst, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1);
+		}
+		return emit_op_mem(compiler, DOUBLE_DATA, TMP_FREG1, dst, dstw, TMP_REG1);
+	}
+#else
+	FAIL_IF(push_inst(compiler, FCTIWZ | FD(TMP_FREG1) | FB(src)));
+#endif
+
+	if (FAST_IS_REG(dst)) {
+		FAIL_IF(load_immediate(compiler, TMP_REG1, FLOAT_TMP_MEM_OFFSET));
+		FAIL_IF(push_inst(compiler, STFIWX | FS(TMP_FREG1) | A(SLJIT_SP) | B(TMP_REG1)));
+		return emit_op_mem(compiler, INT_DATA | LOAD_DATA, dst, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1);
+	}
+
+	SLJIT_ASSERT(dst & SLJIT_MEM);
+
+	if (dst & OFFS_REG_MASK) {
+		dstw &= 0x3;
+		if (dstw) {
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+			FAIL_IF(push_inst(compiler, RLWINM | S(OFFS_REG(dst)) | A(TMP_REG1) | (dstw << 11) | ((31 - dstw) << 1)));
+#else
+			FAIL_IF(push_inst(compiler, RLDI(TMP_REG1, OFFS_REG(dst), dstw, 63 - dstw, 1)));
+#endif
+			dstw = TMP_REG1;
+		}
+		else
+			dstw = OFFS_REG(dst);
+	}
+	else {
+		if ((dst & REG_MASK) && !dstw) {
+			dstw = dst & REG_MASK;
+			dst = 0;
+		}
+		else {
+			/* This works regardless we have SLJIT_MEM1 or SLJIT_MEM0. */
+			FAIL_IF(load_immediate(compiler, TMP_REG1, dstw));
+			dstw = TMP_REG1;
+		}
+	}
+
+	return push_inst(compiler, STFIWX | FS(TMP_FREG1) | A(dst & REG_MASK) | B(dstw));
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	if (src & SLJIT_IMM) {
+		if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
+			srcw = (sljit_s32)srcw;
+		FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+		src = TMP_REG1;
+	}
+	else if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) {
+		if (FAST_IS_REG(src))
+			FAIL_IF(push_inst(compiler, EXTSW | S(src) | A(TMP_REG1)));
+		else
+			FAIL_IF(emit_op_mem(compiler, INT_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
+		src = TMP_REG1;
+	}
+
+	if (FAST_IS_REG(src)) {
+		FAIL_IF(emit_op_mem(compiler, WORD_DATA, src, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1));
+		FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1));
+	}
+	else
+		FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, src, srcw, TMP_REG1));
+
+	FAIL_IF(push_inst(compiler, FCFID | FD(dst_r) | FB(TMP_FREG1)));
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1);
+	if (op & SLJIT_F32_OP)
+		return push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r));
+	return SLJIT_SUCCESS;
+
+#else
+
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+	sljit_s32 invert_sign = 1;
+
+	if (src & SLJIT_IMM) {
+		FAIL_IF(load_immediate(compiler, TMP_REG1, srcw ^ 0x80000000));
+		src = TMP_REG1;
+		invert_sign = 0;
+	}
+	else if (!FAST_IS_REG(src)) {
+		FAIL_IF(emit_op_mem(compiler, WORD_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
+		src = TMP_REG1;
+	}
+
+	/* First, a special double floating point value is constructed: (2^53 + (input xor (2^31)))
+	   The double precision format has exactly 53 bit precision, so the lower 32 bit represents
+	   the lower 32 bit of such value. The result of xor 2^31 is the same as adding 0x80000000
+	   to the input, which shifts it into the 0 - 0xffffffff range. To get the converted floating
+	   point value, we need to substract 2^53 + 2^31 from the constructed value. */
+	FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG2) | A(0) | 0x4330));
+	if (invert_sign)
+		FAIL_IF(push_inst(compiler, XORIS | S(src) | A(TMP_REG1) | 0x8000));
+	FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_HI, TMP_REG1));
+	FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_LOW, TMP_REG2));
+	FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG1) | A(0) | 0x8000));
+	FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1));
+	FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_LOW, TMP_REG2));
+	FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG2, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1));
+
+	FAIL_IF(push_inst(compiler, FSUB | FD(dst_r) | FA(TMP_FREG1) | FB(TMP_FREG2)));
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1);
+	if (op & SLJIT_F32_OP)
+		return push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r));
+	return SLJIT_SUCCESS;
+
+#endif
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	if (src1 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, TMP_REG1));
+		src1 = TMP_FREG1;
+	}
+
+	if (src2 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, TMP_REG2));
+		src2 = TMP_FREG2;
+	}
+
+	return push_inst(compiler, FCMPU | CRD(4) | FA(src1) | FB(src2));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r;
+
+	CHECK_ERROR();
+
+	SLJIT_COMPILE_ASSERT((SLJIT_F32_OP == 0x100) && !(DOUBLE_DATA & 0x4), float_transfer_bit_error);
+	SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
+
+	if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32)
+		op ^= SLJIT_F32_OP;
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	if (src & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, dst_r, src, srcw, TMP_REG1));
+		src = dst_r;
+	}
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_CONV_F64_FROM_F32:
+		op ^= SLJIT_F32_OP;
+		if (op & SLJIT_F32_OP) {
+			FAIL_IF(push_inst(compiler, FRSP | FD(dst_r) | FB(src)));
+			break;
+		}
+		/* Fall through. */
+	case SLJIT_MOV_F64:
+		if (src != dst_r) {
+			if (dst_r != TMP_FREG1)
+				FAIL_IF(push_inst(compiler, FMR | FD(dst_r) | FB(src)));
+			else
+				dst_r = src;
+		}
+		break;
+	case SLJIT_NEG_F64:
+		FAIL_IF(push_inst(compiler, FNEG | FD(dst_r) | FB(src)));
+		break;
+	case SLJIT_ABS_F64:
+		FAIL_IF(push_inst(compiler, FABS | FD(dst_r) | FB(src)));
+		break;
+	}
+
+	if (dst & SLJIT_MEM)
+		FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op), dst_r, dst, dstw, TMP_REG1));
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_s32 dst_r;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG2;
+
+	if (src1 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, TMP_REG1));
+		src1 = TMP_FREG1;
+	}
+
+	if (src2 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, TMP_REG2));
+		src2 = TMP_FREG2;
+	}
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_ADD_F64:
+		FAIL_IF(push_inst(compiler, SELECT_FOP(op, FADDS, FADD) | FD(dst_r) | FA(src1) | FB(src2)));
+		break;
+
+	case SLJIT_SUB_F64:
+		FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSUBS, FSUB) | FD(dst_r) | FA(src1) | FB(src2)));
+		break;
+
+	case SLJIT_MUL_F64:
+		FAIL_IF(push_inst(compiler, SELECT_FOP(op, FMULS, FMUL) | FD(dst_r) | FA(src1) | FC(src2) /* FMUL use FC as src2 */));
+		break;
+
+	case SLJIT_DIV_F64:
+		FAIL_IF(push_inst(compiler, SELECT_FOP(op, FDIVS, FDIV) | FD(dst_r) | FA(src1) | FB(src2)));
+		break;
+	}
+
+	if (dst & SLJIT_MEM)
+		FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG2, dst, dstw, TMP_REG1));
+
+	return SLJIT_SUCCESS;
+}
+
+#undef SELECT_FOP
+
+/* --------------------------------------------------------------------- */
+/*  Other instructions                                                   */
+/* --------------------------------------------------------------------- */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	if (FAST_IS_REG(dst))
+		return push_inst(compiler, MFLR | D(dst));
+
+	/* Memory. */
+	FAIL_IF(push_inst(compiler, MFLR | D(TMP_REG2)));
+	return emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Conditional instructions                                             */
+/* --------------------------------------------------------------------- */
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
+{
+	struct sljit_label *label;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_label(compiler));
+
+	if (compiler->last_label && compiler->last_label->size == compiler->size)
+		return compiler->last_label;
+
+	label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));
+	PTR_FAIL_IF(!label);
+	set_label(label, compiler);
+	return label;
+}
+
+static sljit_ins get_bo_bi_flags(sljit_s32 type)
+{
+	switch (type) {
+	case SLJIT_EQUAL:
+		return (12 << 21) | (2 << 16);
+
+	case SLJIT_NOT_EQUAL:
+		return (4 << 21) | (2 << 16);
+
+	case SLJIT_LESS:
+	case SLJIT_SIG_LESS:
+		return (12 << 21) | (0 << 16);
+
+	case SLJIT_GREATER_EQUAL:
+	case SLJIT_SIG_GREATER_EQUAL:
+		return (4 << 21) | (0 << 16);
+
+	case SLJIT_GREATER:
+	case SLJIT_SIG_GREATER:
+		return (12 << 21) | (1 << 16);
+
+	case SLJIT_LESS_EQUAL:
+	case SLJIT_SIG_LESS_EQUAL:
+		return (4 << 21) | (1 << 16);
+
+	case SLJIT_LESS_F64:
+		return (12 << 21) | ((4 + 0) << 16);
+
+	case SLJIT_GREATER_EQUAL_F64:
+		return (4 << 21) | ((4 + 0) << 16);
+
+	case SLJIT_GREATER_F64:
+		return (12 << 21) | ((4 + 1) << 16);
+
+	case SLJIT_LESS_EQUAL_F64:
+		return (4 << 21) | ((4 + 1) << 16);
+
+	case SLJIT_OVERFLOW:
+	case SLJIT_MUL_OVERFLOW:
+		return (12 << 21) | (3 << 16);
+
+	case SLJIT_NOT_OVERFLOW:
+	case SLJIT_MUL_NOT_OVERFLOW:
+		return (4 << 21) | (3 << 16);
+
+	case SLJIT_EQUAL_F64:
+		return (12 << 21) | ((4 + 2) << 16);
+
+	case SLJIT_NOT_EQUAL_F64:
+		return (4 << 21) | ((4 + 2) << 16);
+
+	case SLJIT_UNORDERED_F64:
+		return (12 << 21) | ((4 + 3) << 16);
+
+	case SLJIT_ORDERED_F64:
+		return (4 << 21) | ((4 + 3) << 16);
+
+	default:
+		SLJIT_ASSERT(type >= SLJIT_JUMP && type <= SLJIT_CALL_CDECL);
+		return (20 << 21);
+	}
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
+{
+	struct sljit_jump *jump;
+	sljit_ins bo_bi_flags;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_jump(compiler, type));
+
+	bo_bi_flags = get_bo_bi_flags(type & 0xff);
+	if (!bo_bi_flags)
+		return NULL;
+
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	PTR_FAIL_IF(!jump);
+	set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
+	type &= 0xff;
+
+	/* In PPC, we don't need to touch the arguments. */
+	if (type < SLJIT_JUMP)
+		jump->flags |= IS_COND;
+#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
+	if (type >= SLJIT_CALL)
+		jump->flags |= IS_CALL;
+#endif
+
+	PTR_FAIL_IF(emit_const(compiler, TMP_CALL_REG, 0));
+	PTR_FAIL_IF(push_inst(compiler, MTCTR | S(TMP_CALL_REG)));
+	jump->addr = compiler->size;
+	PTR_FAIL_IF(push_inst(compiler, BCCTR | bo_bi_flags | (type >= SLJIT_FAST_CALL ? 1 : 0)));
+	return jump;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types)
+{
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+	PTR_FAIL_IF(call_with_args(compiler, arg_types, NULL));
+#endif
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+
+	return sljit_emit_jump(compiler, type);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
+{
+	struct sljit_jump *jump = NULL;
+	sljit_s32 src_r;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	if (FAST_IS_REG(src)) {
+#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
+		if (type >= SLJIT_CALL) {
+			FAIL_IF(push_inst(compiler, OR | S(src) | A(TMP_CALL_REG) | B(src)));
+			src_r = TMP_CALL_REG;
+		}
+		else
+			src_r = src;
+#else
+		src_r = src;
+#endif
+	} else if (src & SLJIT_IMM) {
+		/* These jumps are converted to jump/call instructions when possible. */
+		jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+		FAIL_IF(!jump);
+		set_jump(jump, compiler, JUMP_ADDR);
+		jump->u.target = srcw;
+#if (defined SLJIT_PASS_ENTRY_ADDR_TO_CALL && SLJIT_PASS_ENTRY_ADDR_TO_CALL)
+		if (type >= SLJIT_CALL)
+			jump->flags |= IS_CALL;
+#endif
+		FAIL_IF(emit_const(compiler, TMP_CALL_REG, 0));
+		src_r = TMP_CALL_REG;
+	}
+	else {
+		FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, TMP_CALL_REG, 0, TMP_REG1, 0, src, srcw));
+		src_r = TMP_CALL_REG;
+	}
+
+	FAIL_IF(push_inst(compiler, MTCTR | S(src_r)));
+	if (jump)
+		jump->addr = compiler->size;
+	return push_inst(compiler, BCCTR | (20 << 21) | (type >= SLJIT_FAST_CALL ? 1 : 0));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+	if (src & SLJIT_MEM) {
+		ADJUST_LOCAL_OFFSET(src, srcw);
+		FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, TMP_CALL_REG, 0, TMP_REG1, 0, src, srcw));
+		src = TMP_CALL_REG;
+	}
+
+	FAIL_IF(call_with_args(compiler, arg_types, &src));
+#endif
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+
+	return sljit_emit_ijump(compiler, type, src, srcw);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 type)
+{
+	sljit_s32 reg, input_flags, cr_bit, invert;
+	sljit_s32 saved_op = op;
+	sljit_sw saved_dstw = dstw;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+	input_flags = (op & SLJIT_I32_OP) ? INT_DATA : WORD_DATA;
+#else
+	input_flags = WORD_DATA;
+#endif
+
+	op = GET_OPCODE(op);
+	reg = (op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2;
+
+	if (op >= SLJIT_ADD && (dst & SLJIT_MEM))
+		FAIL_IF(emit_op_mem(compiler, input_flags | LOAD_DATA, TMP_REG1, dst, dstw, TMP_REG1));
+
+	invert = 0;
+	cr_bit = 0;
+
+	switch (type & 0xff) {
+	case SLJIT_LESS:
+	case SLJIT_SIG_LESS:
+		break;
+
+	case SLJIT_GREATER_EQUAL:
+	case SLJIT_SIG_GREATER_EQUAL:
+		invert = 1;
+		break;
+
+	case SLJIT_GREATER:
+	case SLJIT_SIG_GREATER:
+		cr_bit = 1;
+		break;
+
+	case SLJIT_LESS_EQUAL:
+	case SLJIT_SIG_LESS_EQUAL:
+		cr_bit = 1;
+		invert = 1;
+		break;
+
+	case SLJIT_EQUAL:
+		cr_bit = 2;
+		break;
+
+	case SLJIT_NOT_EQUAL:
+		cr_bit = 2;
+		invert = 1;
+		break;
+
+	case SLJIT_OVERFLOW:
+	case SLJIT_MUL_OVERFLOW:
+		cr_bit = 3;
+		break;
+
+	case SLJIT_NOT_OVERFLOW:
+	case SLJIT_MUL_NOT_OVERFLOW:
+		cr_bit = 3;
+		invert = 1;
+		break;
+
+	case SLJIT_LESS_F64:
+		cr_bit = 4 + 0;
+		break;
+
+	case SLJIT_GREATER_EQUAL_F64:
+		cr_bit = 4 + 0;
+		invert = 1;
+		break;
+
+	case SLJIT_GREATER_F64:
+		cr_bit = 4 + 1;
+		break;
+
+	case SLJIT_LESS_EQUAL_F64:
+		cr_bit = 4 + 1;
+		invert = 1;
+		break;
+
+	case SLJIT_EQUAL_F64:
+		cr_bit = 4 + 2;
+		break;
+
+	case SLJIT_NOT_EQUAL_F64:
+		cr_bit = 4 + 2;
+		invert = 1;
+		break;
+
+	case SLJIT_UNORDERED_F64:
+		cr_bit = 4 + 3;
+		break;
+
+	case SLJIT_ORDERED_F64:
+		cr_bit = 4 + 3;
+		invert = 1;
+		break;
+
+	default:
+		SLJIT_UNREACHABLE();
+		break;
+	}
+
+	FAIL_IF(push_inst(compiler, MFCR | D(reg)));
+	FAIL_IF(push_inst(compiler, RLWINM | S(reg) | A(reg) | ((1 + (cr_bit)) << 11) | (31 << 6) | (31 << 1)));
+
+	if (invert)
+		FAIL_IF(push_inst(compiler, XORI | S(reg) | A(reg) | 0x1));
+
+	if (op < SLJIT_ADD) {
+		if (!(dst & SLJIT_MEM))
+			return SLJIT_SUCCESS;
+		return emit_op_mem(compiler, input_flags, reg, dst, dstw, TMP_REG1);
+	}
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+	if (dst & SLJIT_MEM)
+		return sljit_emit_op2(compiler, saved_op, dst, saved_dstw, TMP_REG1, 0, TMP_REG2, 0);
+	return sljit_emit_op2(compiler, saved_op, dst, 0, dst, 0, TMP_REG2, 0);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 dst_reg,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+
+	return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 reg,
+	sljit_s32 mem, sljit_sw memw)
+{
+	sljit_s32 mem_flags;
+	sljit_ins inst;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw));
+
+	if (type & SLJIT_MEM_POST)
+		return SLJIT_ERR_UNSUPPORTED;
+
+	switch (type & 0xff) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_P:
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+	case SLJIT_MOV_U32:
+	case SLJIT_MOV_S32:
+#endif
+		mem_flags = WORD_DATA;
+		break;
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+	case SLJIT_MOV_U32:
+		mem_flags = INT_DATA;
+		break;
+
+	case SLJIT_MOV_S32:
+		mem_flags = INT_DATA;
+
+		if (!(type & SLJIT_MEM_STORE) && !(type & SLJIT_I32_OP)) {
+			if (mem & OFFS_REG_MASK)
+				mem_flags |= SIGNED_DATA;
+			else
+				return SLJIT_ERR_UNSUPPORTED;
+		}
+		break;
+#endif
+
+	case SLJIT_MOV_U8:
+	case SLJIT_MOV_S8:
+		mem_flags = BYTE_DATA;
+		break;
+
+	case SLJIT_MOV_U16:
+		mem_flags = HALF_DATA;
+		break;
+
+	case SLJIT_MOV_S16:
+		mem_flags = HALF_DATA | SIGNED_DATA;
+		break;
+
+	default:
+		SLJIT_UNREACHABLE();
+		mem_flags = WORD_DATA;
+		break;
+	}
+
+	if (!(type & SLJIT_MEM_STORE))
+		mem_flags |= LOAD_DATA;
+
+	if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {
+		if (memw != 0)
+			return SLJIT_ERR_UNSUPPORTED;
+
+		if (type & SLJIT_MEM_SUPP)
+			return SLJIT_SUCCESS;
+
+		inst = updated_data_transfer_insts[mem_flags | INDEXED];
+		FAIL_IF(push_inst(compiler, INST_CODE_AND_DST(inst, 0, reg) | A(mem & REG_MASK) | B(OFFS_REG(mem))));
+	}
+	else {
+		if (memw > SIMM_MAX || memw < SIMM_MIN)
+			return SLJIT_ERR_UNSUPPORTED;
+
+		inst = updated_data_transfer_insts[mem_flags];
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+		if ((inst & INT_ALIGNED) && (memw & 0x3) != 0)
+			return SLJIT_ERR_UNSUPPORTED;
+#endif
+
+		if (type & SLJIT_MEM_SUPP)
+			return SLJIT_SUCCESS;
+
+		FAIL_IF(push_inst(compiler, INST_CODE_AND_DST(inst, 0, reg) | A(mem & REG_MASK) | IMM(memw)));
+	}
+
+	if ((mem_flags & LOAD_DATA) && (type & 0xff) == SLJIT_MOV_S8)
+		return push_inst(compiler, EXTSB | S(reg) | A(reg));
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 freg,
+	sljit_s32 mem, sljit_sw memw)
+{
+	sljit_s32 mem_flags;
+	sljit_ins inst;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fmem(compiler, type, freg, mem, memw));
+
+	if (type & SLJIT_MEM_POST)
+		return SLJIT_ERR_UNSUPPORTED;
+
+	if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {
+		if (memw != 0)
+			return SLJIT_ERR_UNSUPPORTED;
+	}
+	else {
+		if (memw > SIMM_MAX || memw < SIMM_MIN)
+			return SLJIT_ERR_UNSUPPORTED;
+	}
+
+	if (type & SLJIT_MEM_SUPP)
+		return SLJIT_SUCCESS;
+
+	mem_flags = FLOAT_DATA(type);
+
+	if (!(type & SLJIT_MEM_STORE))
+		mem_flags |= LOAD_DATA;
+
+	if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {
+		inst = updated_data_transfer_insts[mem_flags | INDEXED];
+		return push_inst(compiler, INST_CODE_AND_DST(inst, DOUBLE_DATA, freg) | A(mem & REG_MASK) | B(OFFS_REG(mem)));
+	}
+
+	inst = updated_data_transfer_insts[mem_flags];
+	return push_inst(compiler, INST_CODE_AND_DST(inst, DOUBLE_DATA, freg) | A(mem & REG_MASK) | IMM(memw));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
+{
+	struct sljit_const *const_;
+	sljit_s32 dst_r;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
+	PTR_FAIL_IF(!const_);
+	set_const(const_, compiler);
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+	PTR_FAIL_IF(emit_const(compiler, dst_r, init_value));
+
+	if (dst & SLJIT_MEM)
+		PTR_FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0));
+
+	return const_;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	struct sljit_put_label *put_label;
+	sljit_s32 dst_r;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label));
+	PTR_FAIL_IF(!put_label);
+	set_put_label(put_label, compiler, 0);
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+	PTR_FAIL_IF(emit_const(compiler, dst_r, 0));
+#else
+	PTR_FAIL_IF(push_inst(compiler, dst_r));
+	compiler->size += 4;
+#endif
+
+	if (dst & SLJIT_MEM)
+		PTR_FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0));
+
+	return put_label;
+}
diff --git a/src/c/pcre2/src/sljit/sljitNativeSPARC_32.c b/src/c/pcre2/src/sljit/sljitNativeSPARC_32.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitNativeSPARC_32.c
@@ -0,0 +1,283 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw imm)
+{
+	if (imm <= SIMM_MAX && imm >= SIMM_MIN)
+		return push_inst(compiler, OR | D(dst) | S1(0) | IMM(imm), DR(dst));
+
+	FAIL_IF(push_inst(compiler, SETHI | D(dst) | ((imm >> 10) & 0x3fffff), DR(dst)));
+	return (imm & 0x3ff) ? push_inst(compiler, OR | D(dst) | S1(dst) | IMM_ARG | (imm & 0x3ff), DR(dst)) : SLJIT_SUCCESS;
+}
+
+#define ARG2(flags, src2) ((flags & SRC2_IMM) ? IMM(src2) : S2(src2))
+
+static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
+	sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
+{
+	SLJIT_COMPILE_ASSERT(ICC_IS_SET == SET_FLAGS, icc_is_set_and_set_flags_must_be_the_same);
+
+	switch (op) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_U32:
+	case SLJIT_MOV_S32:
+	case SLJIT_MOV_P:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if (dst != src2)
+			return push_inst(compiler, OR | D(dst) | S1(0) | S2(src2), DR(dst));
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U8:
+	case SLJIT_MOV_S8:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
+			if (op == SLJIT_MOV_U8)
+				return push_inst(compiler, AND | D(dst) | S1(src2) | IMM(0xff), DR(dst));
+			FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src2) | IMM(24), DR(dst)));
+			return push_inst(compiler, SRA | D(dst) | S1(dst) | IMM(24), DR(dst));
+		}
+		else if (dst != src2)
+			SLJIT_UNREACHABLE();
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U16:
+	case SLJIT_MOV_S16:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
+			FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src2) | IMM(16), DR(dst)));
+			return push_inst(compiler, (op == SLJIT_MOV_S16 ? SRA : SRL) | D(dst) | S1(dst) | IMM(16), DR(dst));
+		}
+		else if (dst != src2)
+			SLJIT_UNREACHABLE();
+		return SLJIT_SUCCESS;
+
+	case SLJIT_NOT:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		return push_inst(compiler, XNOR | (flags & SET_FLAGS) | D(dst) | S1(0) | S2(src2), DR(dst) | (flags & SET_FLAGS));
+
+	case SLJIT_CLZ:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		FAIL_IF(push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(src2) | S2(0), SET_FLAGS));
+		FAIL_IF(push_inst(compiler, OR | D(TMP_REG1) | S1(0) | S2(src2), DR(TMP_REG1)));
+		FAIL_IF(push_inst(compiler, BICC | DA(0x1) | (7 & DISP_MASK), UNMOVABLE_INS));
+		FAIL_IF(push_inst(compiler, OR | D(dst) | S1(0) | IMM(32), UNMOVABLE_INS));
+		FAIL_IF(push_inst(compiler, OR | D(dst) | S1(0) | IMM(-1), DR(dst)));
+
+		/* Loop. */
+		FAIL_IF(push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(TMP_REG1) | S2(0), SET_FLAGS));
+		FAIL_IF(push_inst(compiler, SLL | D(TMP_REG1) | S1(TMP_REG1) | IMM(1), DR(TMP_REG1)));
+		FAIL_IF(push_inst(compiler, BICC | DA(0xe) | (-2 & DISP_MASK), UNMOVABLE_INS));
+		return push_inst(compiler, ADD | D(dst) | S1(dst) | IMM(1), UNMOVABLE_INS);
+
+	case SLJIT_ADD:
+		return push_inst(compiler, ADD | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
+
+	case SLJIT_ADDC:
+		return push_inst(compiler, ADDC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
+
+	case SLJIT_SUB:
+		return push_inst(compiler, SUB | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
+
+	case SLJIT_SUBC:
+		return push_inst(compiler, SUBC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
+
+	case SLJIT_MUL:
+		FAIL_IF(push_inst(compiler, SMUL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
+		if (!(flags & SET_FLAGS))
+			return SLJIT_SUCCESS;
+		FAIL_IF(push_inst(compiler, SRA | D(TMP_REG1) | S1(dst) | IMM(31), DR(TMP_REG1)));
+		FAIL_IF(push_inst(compiler, RDY | D(TMP_LINK), DR(TMP_LINK)));
+		return push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(TMP_REG1) | S2(TMP_LINK), MOVABLE_INS | SET_FLAGS);
+
+	case SLJIT_AND:
+		return push_inst(compiler, AND | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
+
+	case SLJIT_OR:
+		return push_inst(compiler, OR | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
+
+	case SLJIT_XOR:
+		return push_inst(compiler, XOR | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
+
+	case SLJIT_SHL:
+		FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
+		return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
+
+	case SLJIT_LSHR:
+		FAIL_IF(push_inst(compiler, SRL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
+		return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
+
+	case SLJIT_ASHR:
+		FAIL_IF(push_inst(compiler, SRA | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
+		return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
+	}
+
+	SLJIT_UNREACHABLE();
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *src)
+{
+	sljit_s32 reg_index = 8;
+	sljit_s32 word_reg_index = 8;
+	sljit_s32 float_arg_index = 1;
+	sljit_s32 double_arg_count = 0;
+	sljit_s32 float_offset = (16 + 6) * sizeof(sljit_sw);
+	sljit_s32 types = 0;
+	sljit_s32 reg = 0;
+	sljit_s32 move_to_tmp2 = 0;
+
+	if (src)
+		reg = reg_map[*src & REG_MASK];
+
+	arg_types >>= SLJIT_DEF_SHIFT;
+
+	while (arg_types) {
+		types = (types << SLJIT_DEF_SHIFT) | (arg_types & SLJIT_DEF_MASK);
+
+		switch (arg_types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			float_arg_index++;
+			if (reg_index == reg)
+				move_to_tmp2 = 1;
+			reg_index++;
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			float_arg_index++;
+			double_arg_count++;
+			if (reg_index == reg || reg_index + 1 == reg)
+				move_to_tmp2 = 1;
+			reg_index += 2;
+			break;
+		default:
+			if (reg_index != word_reg_index && reg_index < 14 && reg_index == reg)
+				move_to_tmp2 = 1;
+			reg_index++;
+			word_reg_index++;
+			break;
+		}
+
+		if (move_to_tmp2) {
+			move_to_tmp2 = 0;
+			if (reg < 14)
+				FAIL_IF(push_inst(compiler, OR | D(TMP_REG1) | S1(0) | S2A(reg), DR(TMP_REG1)));
+			*src = TMP_REG1;
+		}
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	arg_types = types;
+
+	while (arg_types) {
+		switch (arg_types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			float_arg_index--;
+			FAIL_IF(push_inst(compiler, STF | FD(float_arg_index) | S1(SLJIT_SP) | IMM(float_offset), MOVABLE_INS));
+			float_offset -= sizeof(sljit_f64);
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			float_arg_index--;
+			if (float_arg_index == 4 && double_arg_count == 4) {
+				FAIL_IF(push_inst(compiler, STF | FD(float_arg_index) | S1(SLJIT_SP) | IMM((16 + 7) * sizeof(sljit_sw)), MOVABLE_INS));
+				FAIL_IF(push_inst(compiler, STF | FD(float_arg_index) | (1 << 25) | S1(SLJIT_SP) | IMM((16 + 8) * sizeof(sljit_sw)), MOVABLE_INS));
+			}
+			else
+				FAIL_IF(push_inst(compiler, STDF | FD(float_arg_index) | S1(SLJIT_SP) | IMM(float_offset), MOVABLE_INS));
+			float_offset -= sizeof(sljit_f64);
+			break;
+		default:
+			break;
+		}
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	float_offset = (16 + 6) * sizeof(sljit_sw);
+
+	while (types) {
+		switch (types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			reg_index--;
+			if (reg_index < 14)
+				FAIL_IF(push_inst(compiler, LDUW | DA(reg_index) | S1(SLJIT_SP) | IMM(float_offset), reg_index));
+			float_offset -= sizeof(sljit_f64);
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			reg_index -= 2;
+			if (reg_index < 14) {
+				if ((reg_index & 0x1) != 0) {
+					FAIL_IF(push_inst(compiler, LDUW | DA(reg_index) | S1(SLJIT_SP) | IMM(float_offset), reg_index));
+					if (reg_index < 13)
+						FAIL_IF(push_inst(compiler, LDUW | DA(reg_index + 1) | S1(SLJIT_SP) | IMM(float_offset + sizeof(sljit_sw)), reg_index + 1));
+				}
+				else 
+					FAIL_IF(push_inst(compiler, LDD | DA(reg_index) | S1(SLJIT_SP) | IMM(float_offset), reg_index));
+			}
+			float_offset -= sizeof(sljit_f64);
+			break;
+		default:
+			reg_index--;
+			word_reg_index--;
+
+			if (reg_index != word_reg_index) {
+				if (reg_index < 14)
+					FAIL_IF(push_inst(compiler, OR | DA(reg_index) | S1(0) | S2A(word_reg_index), reg_index));
+				else
+					FAIL_IF(push_inst(compiler, STW | DA(word_reg_index) | S1(SLJIT_SP) | IMM(92), word_reg_index));
+			}
+			break;
+		}
+
+		types >>= SLJIT_DEF_SHIFT;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value)
+{
+	FAIL_IF(push_inst(compiler, SETHI | D(dst) | ((init_value >> 10) & 0x3fffff), DR(dst)));
+	return push_inst(compiler, OR | D(dst) | S1(dst) | IMM_ARG | (init_value & 0x3ff), DR(dst));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
+{
+	sljit_ins *inst = (sljit_ins *)addr;
+	SLJIT_UNUSED_ARG(executable_offset);
+
+	SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 0);
+	SLJIT_ASSERT(((inst[0] & 0xc1c00000) == 0x01000000) && ((inst[1] & 0xc1f82000) == 0x80102000));
+	inst[0] = (inst[0] & 0xffc00000) | ((new_target >> 10) & 0x3fffff);
+	inst[1] = (inst[1] & 0xfffffc00) | (new_target & 0x3ff);
+	SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
+	inst = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+	SLJIT_CACHE_FLUSH(inst, inst + 2);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
+{
+	sljit_set_jump_addr(addr, new_constant, executable_offset);
+}
diff --git a/src/c/pcre2/src/sljit/sljitNativeSPARC_common.c b/src/c/pcre2/src/sljit/sljitNativeSPARC_common.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitNativeSPARC_common.c
@@ -0,0 +1,1554 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
+{
+	return "SPARC" SLJIT_CPUINFO;
+}
+
+/* Length of an instruction word
+   Both for sparc-32 and sparc-64 */
+typedef sljit_u32 sljit_ins;
+
+#if (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL)
+
+static void sparc_cache_flush(sljit_ins *from, sljit_ins *to)
+{
+#if defined(__SUNPRO_C) && __SUNPRO_C < 0x590
+	__asm (
+		/* if (from == to) return */
+		"cmp %i0, %i1\n"
+		"be .leave\n"
+		"nop\n"
+
+		/* loop until from >= to */
+		".mainloop:\n"
+		"flush %i0\n"
+		"add %i0, 8, %i0\n"
+		"cmp %i0, %i1\n"
+		"bcs .mainloop\n"
+		"nop\n"
+
+		/* The comparison was done above. */
+		"bne .leave\n"
+		/* nop is not necessary here, since the
+		   sub operation has no side effect. */
+		"sub %i0, 4, %i0\n"
+		"flush %i0\n"
+		".leave:"
+	);
+#else
+	if (SLJIT_UNLIKELY(from == to))
+		return;
+
+	do {
+		__asm__ volatile (
+			"flush %0\n"
+			: : "r"(from)
+		);
+		/* Operates at least on doubleword. */
+		from += 2;
+	} while (from < to);
+
+	if (from == to) {
+		/* Flush the last word. */
+		from --;
+		__asm__ volatile (
+			"flush %0\n"
+			: : "r"(from)
+		);
+	}
+#endif
+}
+
+#endif /* (defined SLJIT_CACHE_FLUSH_OWN_IMPL && SLJIT_CACHE_FLUSH_OWN_IMPL) */
+
+/* TMP_REG2 is not used by getput_arg */
+#define TMP_REG1	(SLJIT_NUMBER_OF_REGISTERS + 2)
+#define TMP_REG2	(SLJIT_NUMBER_OF_REGISTERS + 3)
+#define TMP_REG3	(SLJIT_NUMBER_OF_REGISTERS + 4)
+/* This register is modified by calls, which affects the instruction
+   in the delay slot if it is used as a source register. */
+#define TMP_LINK	(SLJIT_NUMBER_OF_REGISTERS + 5)
+
+#define TMP_FREG1	(SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
+#define TMP_FREG2	(SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2)
+
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 6] = {
+	0, 8, 9, 10, 11, 29, 28, 27, 23, 22, 21, 20, 19, 18, 17, 16, 26, 25, 24, 14, 1, 12, 13, 15
+};
+
+static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
+	0, 0, 2, 4, 6, 8, 10, 12, 14
+};
+
+/* --------------------------------------------------------------------- */
+/*  Instrucion forms                                                     */
+/* --------------------------------------------------------------------- */
+
+#define D(d)		(reg_map[d] << 25)
+#define FD(d)		(freg_map[d] << 25)
+#define FDN(d)		((freg_map[d] | 0x1) << 25)
+#define DA(d)		((d) << 25)
+#define S1(s1)		(reg_map[s1] << 14)
+#define FS1(s1)		(freg_map[s1] << 14)
+#define S1A(s1)		((s1) << 14)
+#define S2(s2)		(reg_map[s2])
+#define FS2(s2)		(freg_map[s2])
+#define FS2N(s2)	(freg_map[s2] | 0x1)
+#define S2A(s2)		(s2)
+#define IMM_ARG		0x2000
+#define DOP(op)		((op) << 5)
+#define IMM(imm)	(((imm) & 0x1fff) | IMM_ARG)
+
+#define DR(dr)		(reg_map[dr])
+#define OPC1(opcode)	((opcode) << 30)
+#define OPC2(opcode)	((opcode) << 22)
+#define OPC3(opcode)	((opcode) << 19)
+#define SET_FLAGS	OPC3(0x10)
+
+#define ADD		(OPC1(0x2) | OPC3(0x00))
+#define ADDC		(OPC1(0x2) | OPC3(0x08))
+#define AND		(OPC1(0x2) | OPC3(0x01))
+#define ANDN		(OPC1(0x2) | OPC3(0x05))
+#define CALL		(OPC1(0x1))
+#define FABSS		(OPC1(0x2) | OPC3(0x34) | DOP(0x09))
+#define FADDD		(OPC1(0x2) | OPC3(0x34) | DOP(0x42))
+#define FADDS		(OPC1(0x2) | OPC3(0x34) | DOP(0x41))
+#define FCMPD		(OPC1(0x2) | OPC3(0x35) | DOP(0x52))
+#define FCMPS		(OPC1(0x2) | OPC3(0x35) | DOP(0x51))
+#define FDIVD		(OPC1(0x2) | OPC3(0x34) | DOP(0x4e))
+#define FDIVS		(OPC1(0x2) | OPC3(0x34) | DOP(0x4d))
+#define FDTOI		(OPC1(0x2) | OPC3(0x34) | DOP(0xd2))
+#define FDTOS		(OPC1(0x2) | OPC3(0x34) | DOP(0xc6))
+#define FITOD		(OPC1(0x2) | OPC3(0x34) | DOP(0xc8))
+#define FITOS		(OPC1(0x2) | OPC3(0x34) | DOP(0xc4))
+#define FMOVS		(OPC1(0x2) | OPC3(0x34) | DOP(0x01))
+#define FMULD		(OPC1(0x2) | OPC3(0x34) | DOP(0x4a))
+#define FMULS		(OPC1(0x2) | OPC3(0x34) | DOP(0x49))
+#define FNEGS		(OPC1(0x2) | OPC3(0x34) | DOP(0x05))
+#define FSTOD		(OPC1(0x2) | OPC3(0x34) | DOP(0xc9))
+#define FSTOI		(OPC1(0x2) | OPC3(0x34) | DOP(0xd1))
+#define FSUBD		(OPC1(0x2) | OPC3(0x34) | DOP(0x46))
+#define FSUBS		(OPC1(0x2) | OPC3(0x34) | DOP(0x45))
+#define JMPL		(OPC1(0x2) | OPC3(0x38))
+#define LDD		(OPC1(0x3) | OPC3(0x03))
+#define LDUW		(OPC1(0x3) | OPC3(0x00))
+#define NOP		(OPC1(0x0) | OPC2(0x04))
+#define OR		(OPC1(0x2) | OPC3(0x02))
+#define ORN		(OPC1(0x2) | OPC3(0x06))
+#define RDY		(OPC1(0x2) | OPC3(0x28) | S1A(0))
+#define RESTORE		(OPC1(0x2) | OPC3(0x3d))
+#define SAVE		(OPC1(0x2) | OPC3(0x3c))
+#define SETHI		(OPC1(0x0) | OPC2(0x04))
+#define SLL		(OPC1(0x2) | OPC3(0x25))
+#define SLLX		(OPC1(0x2) | OPC3(0x25) | (1 << 12))
+#define SRA		(OPC1(0x2) | OPC3(0x27))
+#define SRAX		(OPC1(0x2) | OPC3(0x27) | (1 << 12))
+#define SRL		(OPC1(0x2) | OPC3(0x26))
+#define SRLX		(OPC1(0x2) | OPC3(0x26) | (1 << 12))
+#define STDF		(OPC1(0x3) | OPC3(0x27))
+#define STF		(OPC1(0x3) | OPC3(0x24))
+#define STW		(OPC1(0x3) | OPC3(0x04))
+#define SUB		(OPC1(0x2) | OPC3(0x04))
+#define SUBC		(OPC1(0x2) | OPC3(0x0c))
+#define TA		(OPC1(0x2) | OPC3(0x3a) | (8 << 25))
+#define WRY		(OPC1(0x2) | OPC3(0x30) | DA(0))
+#define XOR		(OPC1(0x2) | OPC3(0x03))
+#define XNOR		(OPC1(0x2) | OPC3(0x07))
+
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+#define MAX_DISP	(0x1fffff)
+#define MIN_DISP	(-0x200000)
+#define DISP_MASK	(0x3fffff)
+
+#define BICC		(OPC1(0x0) | OPC2(0x2))
+#define FBFCC		(OPC1(0x0) | OPC2(0x6))
+#define SLL_W		SLL
+#define SDIV		(OPC1(0x2) | OPC3(0x0f))
+#define SMUL		(OPC1(0x2) | OPC3(0x0b))
+#define UDIV		(OPC1(0x2) | OPC3(0x0e))
+#define UMUL		(OPC1(0x2) | OPC3(0x0a))
+#else
+#define SLL_W		SLLX
+#endif
+
+#define SIMM_MAX	(0x0fff)
+#define SIMM_MIN	(-0x1000)
+
+/* dest_reg is the absolute name of the register
+   Useful for reordering instructions in the delay slot. */
+static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins, sljit_s32 delay_slot)
+{
+	sljit_ins *ptr;
+	SLJIT_ASSERT((delay_slot & DST_INS_MASK) == UNMOVABLE_INS
+		|| (delay_slot & DST_INS_MASK) == MOVABLE_INS
+		|| (delay_slot & DST_INS_MASK) == ((ins >> 25) & 0x1f));
+	ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
+	FAIL_IF(!ptr);
+	*ptr = ins;
+	compiler->size++;
+	compiler->delay_slot = delay_slot;
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_ins* detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code, sljit_sw executable_offset)
+{
+	sljit_sw diff;
+	sljit_uw target_addr;
+	sljit_ins *inst;
+	sljit_ins saved_inst;
+
+	if (jump->flags & SLJIT_REWRITABLE_JUMP)
+		return code_ptr;
+
+	if (jump->flags & JUMP_ADDR)
+		target_addr = jump->u.target;
+	else {
+		SLJIT_ASSERT(jump->flags & JUMP_LABEL);
+		target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset;
+	}
+	inst = (sljit_ins*)jump->addr;
+
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+	if (jump->flags & IS_CALL) {
+		/* Call is always patchable on sparc 32. */
+		jump->flags |= PATCH_CALL;
+		if (jump->flags & IS_MOVABLE) {
+			inst[0] = inst[-1];
+			inst[-1] = CALL;
+			jump->addr -= sizeof(sljit_ins);
+			return inst;
+		}
+		inst[0] = CALL;
+		inst[1] = NOP;
+		return inst + 1;
+	}
+#else
+	/* Both calls and BPr instructions shall not pass this point. */
+#error "Implementation required"
+#endif
+
+	if (jump->flags & IS_COND)
+		inst--;
+
+	diff = ((sljit_sw)target_addr - (sljit_sw)(inst - 1) - executable_offset) >> 2;
+
+	if (jump->flags & IS_MOVABLE) {
+		if (diff <= MAX_DISP && diff >= MIN_DISP) {
+			jump->flags |= PATCH_B;
+			inst--;
+			if (jump->flags & IS_COND) {
+				saved_inst = inst[0];
+				inst[0] = inst[1] ^ (1 << 28);
+				inst[1] = saved_inst;
+			} else {
+				inst[1] = inst[0];
+				inst[0] = BICC | DA(0x8);
+			}
+			jump->addr = (sljit_uw)inst;
+			return inst + 1;
+		}
+	}
+
+	diff += sizeof(sljit_ins);
+
+	if (diff <= MAX_DISP && diff >= MIN_DISP) {
+		jump->flags |= PATCH_B;
+		if (jump->flags & IS_COND)
+			inst[0] ^= (1 << 28);
+		else
+			inst[0] = BICC | DA(0x8);
+		inst[1] = NOP;
+		jump->addr = (sljit_uw)inst;
+		return inst + 1;
+	}
+
+	return code_ptr;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+{
+	struct sljit_memory_fragment *buf;
+	sljit_ins *code;
+	sljit_ins *code_ptr;
+	sljit_ins *buf_ptr;
+	sljit_ins *buf_end;
+	sljit_uw word_count;
+	sljit_uw next_addr;
+	sljit_sw executable_offset;
+	sljit_uw addr;
+
+	struct sljit_label *label;
+	struct sljit_jump *jump;
+	struct sljit_const *const_;
+	struct sljit_put_label *put_label;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_generate_code(compiler));
+	reverse_buf(compiler);
+
+	code = (sljit_ins*)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins), compiler->exec_allocator_data);
+	PTR_FAIL_WITH_EXEC_IF(code);
+	buf = compiler->buf;
+
+	code_ptr = code;
+	word_count = 0;
+	next_addr = 0;
+	executable_offset = SLJIT_EXEC_OFFSET(code);
+
+	label = compiler->labels;
+	jump = compiler->jumps;
+	const_ = compiler->consts;
+	put_label = compiler->put_labels;
+
+	do {
+		buf_ptr = (sljit_ins*)buf->memory;
+		buf_end = buf_ptr + (buf->used_size >> 2);
+		do {
+			*code_ptr = *buf_ptr++;
+			if (next_addr == word_count) {
+				SLJIT_ASSERT(!label || label->size >= word_count);
+				SLJIT_ASSERT(!jump || jump->addr >= word_count);
+				SLJIT_ASSERT(!const_ || const_->addr >= word_count);
+				SLJIT_ASSERT(!put_label || put_label->addr >= word_count);
+
+				/* These structures are ordered by their address. */
+				if (label && label->size == word_count) {
+					/* Just recording the address. */
+					label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+					label->size = code_ptr - code;
+					label = label->next;
+				}
+				if (jump && jump->addr == word_count) {
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+					jump->addr = (sljit_uw)(code_ptr - 3);
+#else
+					jump->addr = (sljit_uw)(code_ptr - 6);
+#endif
+					code_ptr = detect_jump_type(jump, code_ptr, code, executable_offset);
+					jump = jump->next;
+				}
+				if (const_ && const_->addr == word_count) {
+					/* Just recording the address. */
+					const_->addr = (sljit_uw)code_ptr;
+					const_ = const_->next;
+				}
+				if (put_label && put_label->addr == word_count) {
+					SLJIT_ASSERT(put_label->label);
+					put_label->addr = (sljit_uw)code_ptr;
+					put_label = put_label->next;
+				}
+				next_addr = compute_next_addr(label, jump, const_, put_label);
+			}
+			code_ptr ++;
+			word_count ++;
+		} while (buf_ptr < buf_end);
+
+		buf = buf->next;
+	} while (buf);
+
+	if (label && label->size == word_count) {
+		label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+		label->size = code_ptr - code;
+		label = label->next;
+	}
+
+	SLJIT_ASSERT(!label);
+	SLJIT_ASSERT(!jump);
+	SLJIT_ASSERT(!const_);
+	SLJIT_ASSERT(!put_label);
+	SLJIT_ASSERT(code_ptr - code <= (sljit_s32)compiler->size);
+
+	jump = compiler->jumps;
+	while (jump) {
+		do {
+			addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
+			buf_ptr = (sljit_ins *)jump->addr;
+
+			if (jump->flags & PATCH_CALL) {
+				addr = (sljit_sw)(addr - (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2;
+				SLJIT_ASSERT((sljit_sw)addr <= 0x1fffffff && (sljit_sw)addr >= -0x20000000);
+				buf_ptr[0] = CALL | (addr & 0x3fffffff);
+				break;
+			}
+			if (jump->flags & PATCH_B) {
+				addr = (sljit_sw)(addr - (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr, executable_offset)) >> 2;
+				SLJIT_ASSERT((sljit_sw)addr <= MAX_DISP && (sljit_sw)addr >= MIN_DISP);
+				buf_ptr[0] = (buf_ptr[0] & ~DISP_MASK) | (addr & DISP_MASK);
+				break;
+			}
+
+			/* Set the fields of immediate loads. */
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+			SLJIT_ASSERT(((buf_ptr[0] & 0xc1cfffff) == 0x01000000) && ((buf_ptr[1] & 0xc1f83fff) == 0x80102000));
+			buf_ptr[0] |= (addr >> 10) & 0x3fffff;
+			buf_ptr[1] |= addr & 0x3ff;
+#else
+#error "Implementation required"
+#endif
+		} while (0);
+		jump = jump->next;
+	}
+
+	put_label = compiler->put_labels;
+	while (put_label) {
+		addr = put_label->label->addr;
+		buf_ptr = (sljit_ins *)put_label->addr;
+
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+		SLJIT_ASSERT(((buf_ptr[0] & 0xc1cfffff) == 0x01000000) && ((buf_ptr[1] & 0xc1f83fff) == 0x80102000));
+		buf_ptr[0] |= (addr >> 10) & 0x3fffff;
+		buf_ptr[1] |= addr & 0x3ff;
+#else
+#error "Implementation required"
+#endif
+		put_label = put_label->next;
+	}
+
+	compiler->error = SLJIT_ERR_COMPILED;
+	compiler->executable_offset = executable_offset;
+	compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins);
+
+	code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
+	code_ptr = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+
+	SLJIT_CACHE_FLUSH(code, code_ptr);
+	SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);
+	return code;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
+{
+	switch (feature_type) {
+	case SLJIT_HAS_FPU:
+#ifdef SLJIT_IS_FPU_AVAILABLE
+		return SLJIT_IS_FPU_AVAILABLE;
+#else
+		/* Available by default. */
+		return 1;
+#endif
+
+	case SLJIT_HAS_ZERO_REGISTER:
+		return 1;
+
+#if (defined SLJIT_CONFIG_SPARC_64 && SLJIT_CONFIG_SPARC_64)
+	case SLJIT_HAS_CMOV:
+		return 1;
+#endif
+
+	default:
+		return 0;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+/*  Entry, exit                                                          */
+/* --------------------------------------------------------------------- */
+
+/* Creates an index in data_transfer_insts array. */
+#define LOAD_DATA	0x01
+#define WORD_DATA	0x00
+#define BYTE_DATA	0x02
+#define HALF_DATA	0x04
+#define INT_DATA	0x06
+#define SIGNED_DATA	0x08
+/* Separates integer and floating point registers */
+#define GPR_REG		0x0f
+#define DOUBLE_DATA	0x10
+#define SINGLE_DATA	0x12
+
+#define MEM_MASK	0x1f
+
+#define ARG_TEST	0x00020
+#define ALT_KEEP_CACHE	0x00040
+#define CUMULATIVE_OP	0x00080
+#define IMM_OP		0x00100
+#define SRC2_IMM	0x00200
+
+#define REG_DEST	0x00400
+#define REG2_SOURCE	0x00800
+#define SLOW_SRC1	0x01000
+#define SLOW_SRC2	0x02000
+#define SLOW_DEST	0x04000
+
+/* SET_FLAGS (0x10 << 19) also belong here! */
+
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+#include "sljitNativeSPARC_32.c"
+#else
+#include "sljitNativeSPARC_64.c"
+#endif
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+	local_size = (local_size + SLJIT_LOCALS_OFFSET + 7) & ~0x7;
+	compiler->local_size = local_size;
+
+	if (local_size <= SIMM_MAX) {
+		FAIL_IF(push_inst(compiler, SAVE | D(SLJIT_SP) | S1(SLJIT_SP) | IMM(-local_size), UNMOVABLE_INS));
+	}
+	else {
+		FAIL_IF(load_immediate(compiler, TMP_REG1, -local_size));
+		FAIL_IF(push_inst(compiler, SAVE | D(SLJIT_SP) | S1(SLJIT_SP) | S2(TMP_REG1), UNMOVABLE_INS));
+	}
+
+	/* Arguments are in their appropriate registers. */
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+	compiler->local_size = (local_size + SLJIT_LOCALS_OFFSET + 7) & ~0x7;
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_return(compiler, op, src, srcw));
+
+	if (op != SLJIT_MOV || !FAST_IS_REG(src)) {
+		FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
+		src = SLJIT_R0;
+	}
+
+	FAIL_IF(push_inst(compiler, JMPL | D(0) | S1A(31) | IMM(8), UNMOVABLE_INS));
+	return push_inst(compiler, RESTORE | D(SLJIT_R0) | S1(src) | S2(0), UNMOVABLE_INS);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Operators                                                            */
+/* --------------------------------------------------------------------- */
+
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+#define ARCH_32_64(a, b)	a
+#else
+#define ARCH_32_64(a, b)	b
+#endif
+
+static const sljit_ins data_transfer_insts[16 + 4] = {
+/* u w s */ ARCH_32_64(OPC1(3) | OPC3(0x04) /* stw */, OPC1(3) | OPC3(0x0e) /* stx */),
+/* u w l */ ARCH_32_64(OPC1(3) | OPC3(0x00) /* lduw */, OPC1(3) | OPC3(0x0b) /* ldx */),
+/* u b s */ OPC1(3) | OPC3(0x05) /* stb */,
+/* u b l */ OPC1(3) | OPC3(0x01) /* ldub */,
+/* u h s */ OPC1(3) | OPC3(0x06) /* sth */,
+/* u h l */ OPC1(3) | OPC3(0x02) /* lduh */,
+/* u i s */ OPC1(3) | OPC3(0x04) /* stw */,
+/* u i l */ OPC1(3) | OPC3(0x00) /* lduw */,
+
+/* s w s */ ARCH_32_64(OPC1(3) | OPC3(0x04) /* stw */, OPC1(3) | OPC3(0x0e) /* stx */),
+/* s w l */ ARCH_32_64(OPC1(3) | OPC3(0x00) /* lduw */, OPC1(3) | OPC3(0x0b) /* ldx */),
+/* s b s */ OPC1(3) | OPC3(0x05) /* stb */,
+/* s b l */ OPC1(3) | OPC3(0x09) /* ldsb */,
+/* s h s */ OPC1(3) | OPC3(0x06) /* sth */,
+/* s h l */ OPC1(3) | OPC3(0x0a) /* ldsh */,
+/* s i s */ OPC1(3) | OPC3(0x04) /* stw */,
+/* s i l */ ARCH_32_64(OPC1(3) | OPC3(0x00) /* lduw */, OPC1(3) | OPC3(0x08) /* ldsw */),
+
+/* d   s */ OPC1(3) | OPC3(0x27),
+/* d   l */ OPC1(3) | OPC3(0x23),
+/* s   s */ OPC1(3) | OPC3(0x24),
+/* s   l */ OPC1(3) | OPC3(0x20),
+};
+
+#undef ARCH_32_64
+
+/* Can perform an operation using at most 1 instruction. */
+static sljit_s32 getput_arg_fast(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
+{
+	SLJIT_ASSERT(arg & SLJIT_MEM);
+
+	if ((!(arg & OFFS_REG_MASK) && argw <= SIMM_MAX && argw >= SIMM_MIN)
+			|| ((arg & OFFS_REG_MASK) && (argw & 0x3) == 0)) {
+		/* Works for both absoulte and relative addresses (immediate case). */
+		if (SLJIT_UNLIKELY(flags & ARG_TEST))
+			return 1;
+		FAIL_IF(push_inst(compiler, data_transfer_insts[flags & MEM_MASK]
+			| ((flags & MEM_MASK) <= GPR_REG ? D(reg) : FD(reg))
+			| S1(arg & REG_MASK) | ((arg & OFFS_REG_MASK) ? S2(OFFS_REG(arg)) : IMM(argw)),
+			((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA)) ? DR(reg) : MOVABLE_INS));
+		return -1;
+	}
+	return 0;
+}
+
+/* See getput_arg below.
+   Note: can_cache is called only for binary operators. Those
+   operators always uses word arguments without write back. */
+static sljit_s32 can_cache(sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
+{
+	SLJIT_ASSERT((arg & SLJIT_MEM) && (next_arg & SLJIT_MEM));
+
+	/* Simple operation except for updates. */
+	if (arg & OFFS_REG_MASK) {
+		argw &= 0x3;
+		SLJIT_ASSERT(argw);
+		next_argw &= 0x3;
+		if ((arg & OFFS_REG_MASK) == (next_arg & OFFS_REG_MASK) && argw == next_argw)
+			return 1;
+		return 0;
+	}
+
+	if (((next_argw - argw) <= SIMM_MAX && (next_argw - argw) >= SIMM_MIN))
+		return 1;
+	return 0;
+}
+
+/* Emit the necessary instructions. See can_cache above. */
+static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
+{
+	sljit_s32 base, arg2, delay_slot;
+	sljit_ins dest;
+
+	SLJIT_ASSERT(arg & SLJIT_MEM);
+	if (!(next_arg & SLJIT_MEM)) {
+		next_arg = 0;
+		next_argw = 0;
+	}
+
+	base = arg & REG_MASK;
+	if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
+		argw &= 0x3;
+
+		/* Using the cache. */
+		if (((SLJIT_MEM | (arg & OFFS_REG_MASK)) == compiler->cache_arg) && (argw == compiler->cache_argw))
+			arg2 = TMP_REG3;
+		else {
+			if ((arg & OFFS_REG_MASK) == (next_arg & OFFS_REG_MASK) && argw == (next_argw & 0x3)) {
+				compiler->cache_arg = SLJIT_MEM | (arg & OFFS_REG_MASK);
+				compiler->cache_argw = argw;
+				arg2 = TMP_REG3;
+			}
+			else if ((flags & LOAD_DATA) && ((flags & MEM_MASK) <= GPR_REG) && reg != base && reg != OFFS_REG(arg))
+				arg2 = reg;
+			else /* It must be a mov operation, so tmp1 must be free to use. */
+				arg2 = TMP_REG1;
+			FAIL_IF(push_inst(compiler, SLL_W | D(arg2) | S1(OFFS_REG(arg)) | IMM_ARG | argw, DR(arg2)));
+		}
+	}
+	else {
+		/* Using the cache. */
+		if ((compiler->cache_arg == SLJIT_MEM) && (argw - compiler->cache_argw) <= SIMM_MAX && (argw - compiler->cache_argw) >= SIMM_MIN) {
+			if (argw != compiler->cache_argw) {
+				FAIL_IF(push_inst(compiler, ADD | D(TMP_REG3) | S1(TMP_REG3) | IMM(argw - compiler->cache_argw), DR(TMP_REG3)));
+				compiler->cache_argw = argw;
+			}
+			arg2 = TMP_REG3;
+		} else {
+			if ((next_argw - argw) <= SIMM_MAX && (next_argw - argw) >= SIMM_MIN) {
+				compiler->cache_arg = SLJIT_MEM;
+				compiler->cache_argw = argw;
+				arg2 = TMP_REG3;
+			}
+			else if ((flags & LOAD_DATA) && ((flags & MEM_MASK) <= GPR_REG) && reg != base)
+				arg2 = reg;
+			else /* It must be a mov operation, so tmp1 must be free to use. */
+				arg2 = TMP_REG1;
+			FAIL_IF(load_immediate(compiler, arg2, argw));
+		}
+	}
+
+	dest = ((flags & MEM_MASK) <= GPR_REG ? D(reg) : FD(reg));
+	delay_slot = ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA)) ? DR(reg) : MOVABLE_INS;
+	if (!base)
+		return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | dest | S1(arg2) | IMM(0), delay_slot);
+	return push_inst(compiler, data_transfer_insts[flags & MEM_MASK] | dest | S1(base) | S2(arg2), delay_slot);
+}
+
+static SLJIT_INLINE sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
+{
+	if (getput_arg_fast(compiler, flags, reg, arg, argw))
+		return compiler->error;
+	compiler->cache_arg = 0;
+	compiler->cache_argw = 0;
+	return getput_arg(compiler, flags, reg, arg, argw, 0, 0);
+}
+
+static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg1, sljit_sw arg1w, sljit_s32 arg2, sljit_sw arg2w)
+{
+	if (getput_arg_fast(compiler, flags, reg, arg1, arg1w))
+		return compiler->error;
+	return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w);
+}
+
+static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	/* arg1 goes to TMP_REG1 or src reg
+	   arg2 goes to TMP_REG2, imm or src reg
+	   TMP_REG3 can be used for caching
+	   result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */
+	sljit_s32 dst_r = TMP_REG2;
+	sljit_s32 src1_r;
+	sljit_sw src2_r = 0;
+	sljit_s32 sugg_src2_r = TMP_REG2;
+
+	if (!(flags & ALT_KEEP_CACHE)) {
+		compiler->cache_arg = 0;
+		compiler->cache_argw = 0;
+	}
+
+	if (dst != SLJIT_UNUSED) {
+		if (FAST_IS_REG(dst)) {
+			dst_r = dst;
+			flags |= REG_DEST;
+			if (op >= SLJIT_MOV && op <= SLJIT_MOV_P)
+				sugg_src2_r = dst_r;
+		}
+		else if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, flags | ARG_TEST, TMP_REG1, dst, dstw))
+			flags |= SLOW_DEST;
+	}
+
+	if (flags & IMM_OP) {
+		if ((src2 & SLJIT_IMM) && src2w) {
+			if (src2w <= SIMM_MAX && src2w >= SIMM_MIN) {
+				flags |= SRC2_IMM;
+				src2_r = src2w;
+			}
+		}
+		if (!(flags & SRC2_IMM) && (flags & CUMULATIVE_OP) && (src1 & SLJIT_IMM) && src1w) {
+			if (src1w <= SIMM_MAX && src1w >= SIMM_MIN) {
+				flags |= SRC2_IMM;
+				src2_r = src1w;
+
+				/* And swap arguments. */
+				src1 = src2;
+				src1w = src2w;
+				src2 = SLJIT_IMM;
+				/* src2w = src2_r unneeded. */
+			}
+		}
+	}
+
+	/* Source 1. */
+	if (FAST_IS_REG(src1))
+		src1_r = src1;
+	else if (src1 & SLJIT_IMM) {
+		if (src1w) {
+			FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
+			src1_r = TMP_REG1;
+		}
+		else
+			src1_r = 0;
+	}
+	else {
+		if (getput_arg_fast(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w))
+			FAIL_IF(compiler->error);
+		else
+			flags |= SLOW_SRC1;
+		src1_r = TMP_REG1;
+	}
+
+	/* Source 2. */
+	if (FAST_IS_REG(src2)) {
+		src2_r = src2;
+		flags |= REG2_SOURCE;
+		if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOV_P)
+			dst_r = src2_r;
+	}
+	else if (src2 & SLJIT_IMM) {
+		if (!(flags & SRC2_IMM)) {
+			if (src2w) {
+				FAIL_IF(load_immediate(compiler, sugg_src2_r, src2w));
+				src2_r = sugg_src2_r;
+			}
+			else {
+				src2_r = 0;
+				if ((op >= SLJIT_MOV && op <= SLJIT_MOV_P) && (dst & SLJIT_MEM))
+					dst_r = 0;
+			}
+		}
+	}
+	else {
+		if (getput_arg_fast(compiler, flags | LOAD_DATA, sugg_src2_r, src2, src2w))
+			FAIL_IF(compiler->error);
+		else
+			flags |= SLOW_SRC2;
+		src2_r = sugg_src2_r;
+	}
+
+	if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) {
+		SLJIT_ASSERT(src2_r == TMP_REG2);
+		if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
+			FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG2, src2, src2w, src1, src1w));
+			FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw));
+		}
+		else {
+			FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w));
+			FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG2, src2, src2w, dst, dstw));
+		}
+	}
+	else if (flags & SLOW_SRC1)
+		FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw));
+	else if (flags & SLOW_SRC2)
+		FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, sugg_src2_r, src2, src2w, dst, dstw));
+
+	FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r));
+
+	if (dst & SLJIT_MEM) {
+		if (!(flags & SLOW_DEST)) {
+			getput_arg_fast(compiler, flags, dst_r, dst, dstw);
+			return compiler->error;
+		}
+		return getput_arg(compiler, flags, dst_r, dst, dstw, 0, 0);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op0(compiler, op));
+
+	op = GET_OPCODE(op);
+	switch (op) {
+	case SLJIT_BREAKPOINT:
+		return push_inst(compiler, TA, UNMOVABLE_INS);
+	case SLJIT_NOP:
+		return push_inst(compiler, NOP, UNMOVABLE_INS);
+	case SLJIT_LMUL_UW:
+	case SLJIT_LMUL_SW:
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+		FAIL_IF(push_inst(compiler, (op == SLJIT_LMUL_UW ? UMUL : SMUL) | D(SLJIT_R0) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R0)));
+		return push_inst(compiler, RDY | D(SLJIT_R1), DR(SLJIT_R1));
+#else
+#error "Implementation required"
+#endif
+	case SLJIT_DIVMOD_UW:
+	case SLJIT_DIVMOD_SW:
+	case SLJIT_DIV_UW:
+	case SLJIT_DIV_SW:
+		SLJIT_COMPILE_ASSERT((SLJIT_DIVMOD_UW & 0x2) == 0 && SLJIT_DIV_UW - 0x2 == SLJIT_DIVMOD_UW, bad_div_opcode_assignments);
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+		if ((op | 0x2) == SLJIT_DIV_UW)
+			FAIL_IF(push_inst(compiler, WRY | S1(0), MOVABLE_INS));
+		else {
+			FAIL_IF(push_inst(compiler, SRA | D(TMP_REG1) | S1(SLJIT_R0) | IMM(31), DR(TMP_REG1)));
+			FAIL_IF(push_inst(compiler, WRY | S1(TMP_REG1), MOVABLE_INS));
+		}
+		if (op <= SLJIT_DIVMOD_SW)
+			FAIL_IF(push_inst(compiler, OR | D(TMP_REG2) | S1(0) | S2(SLJIT_R0), DR(TMP_REG2)));
+		FAIL_IF(push_inst(compiler, ((op | 0x2) == SLJIT_DIV_UW ? UDIV : SDIV) | D(SLJIT_R0) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R0)));
+		if (op >= SLJIT_DIV_UW)
+			return SLJIT_SUCCESS;
+		FAIL_IF(push_inst(compiler, SMUL | D(SLJIT_R1) | S1(SLJIT_R0) | S2(SLJIT_R1), DR(SLJIT_R1)));
+		return push_inst(compiler, SUB | D(SLJIT_R1) | S1(TMP_REG2) | S2(SLJIT_R1), DR(SLJIT_R1));
+#else
+#error "Implementation required"
+#endif
+	case SLJIT_ENDBR:
+	case SLJIT_SKIP_FRAMES_BEFORE_RETURN:
+		return SLJIT_SUCCESS;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	op = GET_OPCODE(op);
+	switch (op) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_P:
+		return emit_op(compiler, SLJIT_MOV, flags | WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_MOV_U32:
+		return emit_op(compiler, SLJIT_MOV_U32, flags | INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_MOV_S32:
+		return emit_op(compiler, SLJIT_MOV_S32, flags | INT_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_MOV_U8:
+		return emit_op(compiler, SLJIT_MOV_U8, flags | BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8)srcw : srcw);
+
+	case SLJIT_MOV_S8:
+		return emit_op(compiler, SLJIT_MOV_S8, flags | BYTE_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8)srcw : srcw);
+
+	case SLJIT_MOV_U16:
+		return emit_op(compiler, SLJIT_MOV_U16, flags | HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16)srcw : srcw);
+
+	case SLJIT_MOV_S16:
+		return emit_op(compiler, SLJIT_MOV_S16, flags | HALF_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16)srcw : srcw);
+
+	case SLJIT_NOT:
+	case SLJIT_CLZ:
+		return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_NEG:
+		return emit_op(compiler, SLJIT_SUB, flags | IMM_OP, dst, dstw, SLJIT_IMM, 0, src, srcw);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_s32 flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
+		return SLJIT_SUCCESS;
+
+	op = GET_OPCODE(op);
+	switch (op) {
+	case SLJIT_ADD:
+	case SLJIT_ADDC:
+	case SLJIT_MUL:
+	case SLJIT_AND:
+	case SLJIT_OR:
+	case SLJIT_XOR:
+		return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_SUB:
+	case SLJIT_SUBC:
+		return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_SHL:
+	case SLJIT_LSHR:
+	case SLJIT_ASHR:
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+		if (src2 & SLJIT_IMM)
+			src2w &= 0x1f;
+#else
+		SLJIT_UNREACHABLE();
+#endif
+		return emit_op(compiler, op, flags | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_src(compiler, op, src, srcw));
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	switch (op) {
+	case SLJIT_FAST_RETURN:
+		if (FAST_IS_REG(src))
+			FAIL_IF(push_inst(compiler, OR | D(TMP_LINK) | S1(0) | S2(src), DR(TMP_LINK)));
+		else
+			FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_LINK, src, srcw));
+
+		FAIL_IF(push_inst(compiler, JMPL | D(0) | S1(TMP_LINK) | IMM(8), UNMOVABLE_INS));
+		return push_inst(compiler, NOP, UNMOVABLE_INS);
+	case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN:
+	case SLJIT_PREFETCH_L1:
+	case SLJIT_PREFETCH_L2:
+	case SLJIT_PREFETCH_L3:
+	case SLJIT_PREFETCH_ONCE:
+		return SLJIT_SUCCESS;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+{
+	CHECK_REG_INDEX(check_sljit_get_register_index(reg));
+	return reg_map[reg];
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
+{
+	CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
+	return freg_map[reg];
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+	void *instruction, sljit_s32 size)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
+
+	return push_inst(compiler, *(sljit_ins*)instruction, UNMOVABLE_INS);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Floating point operators                                             */
+/* --------------------------------------------------------------------- */
+
+#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_F32_OP) >> 7))
+#define SELECT_FOP(op, single, double) ((op & SLJIT_F32_OP) ? single : double)
+#define FLOAT_TMP_MEM_OFFSET (22 * sizeof(sljit_sw))
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	if (src & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src, srcw, dst, dstw));
+		src = TMP_FREG1;
+	}
+
+	FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSTOI, FDTOI) | FD(TMP_FREG1) | FS2(src), MOVABLE_INS));
+
+	if (FAST_IS_REG(dst)) {
+		FAIL_IF(emit_op_mem2(compiler, SINGLE_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET));
+		return emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, dst, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET);
+	}
+
+	/* Store the integer value from a VFP register. */
+	return emit_op_mem2(compiler, SINGLE_DATA, TMP_FREG1, dst, dstw, 0, 0);
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	if (src & SLJIT_IMM) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+		if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
+			srcw = (sljit_s32)srcw;
+#endif
+		FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+		src = TMP_REG1;
+		srcw = 0;
+	}
+
+	if (FAST_IS_REG(src)) {
+		FAIL_IF(emit_op_mem2(compiler, WORD_DATA, src, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET));
+		src = SLJIT_MEM1(SLJIT_SP);
+		srcw = FLOAT_TMP_MEM_OFFSET;
+	}
+
+	FAIL_IF(emit_op_mem2(compiler, SINGLE_DATA | LOAD_DATA, TMP_FREG1, src, srcw, dst, dstw));
+	FAIL_IF(push_inst(compiler, SELECT_FOP(op, FITOS, FITOD) | FD(dst_r) | FS2(TMP_FREG1), MOVABLE_INS));
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, 0, 0);
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	if (src1 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w));
+		src1 = TMP_FREG1;
+	}
+
+	if (src2 & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, 0, 0));
+		src2 = TMP_FREG2;
+	}
+
+	return push_inst(compiler, SELECT_FOP(op, FCMPS, FCMPD) | FS1(src1) | FS2(src2), FCC_IS_SET | MOVABLE_INS);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r;
+
+	CHECK_ERROR();
+	compiler->cache_arg = 0;
+	compiler->cache_argw = 0;
+
+	SLJIT_COMPILE_ASSERT((SLJIT_F32_OP == 0x100) && !(DOUBLE_DATA & 0x2), float_transfer_bit_error);
+	SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
+
+	if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32)
+		op ^= SLJIT_F32_OP;
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+	if (src & SLJIT_MEM) {
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op) | LOAD_DATA, dst_r, src, srcw, dst, dstw));
+		src = dst_r;
+	}
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_MOV_F64:
+		if (src != dst_r) {
+			if (dst_r != TMP_FREG1) {
+				FAIL_IF(push_inst(compiler, FMOVS | FD(dst_r) | FS2(src), MOVABLE_INS));
+				if (!(op & SLJIT_F32_OP))
+					FAIL_IF(push_inst(compiler, FMOVS | FDN(dst_r) | FS2N(src), MOVABLE_INS));
+			}
+			else
+				dst_r = src;
+		}
+		break;
+	case SLJIT_NEG_F64:
+		FAIL_IF(push_inst(compiler, FNEGS | FD(dst_r) | FS2(src), MOVABLE_INS));
+		if (dst_r != src && !(op & SLJIT_F32_OP))
+			FAIL_IF(push_inst(compiler, FMOVS | FDN(dst_r) | FS2N(src), MOVABLE_INS));
+		break;
+	case SLJIT_ABS_F64:
+		FAIL_IF(push_inst(compiler, FABSS | FD(dst_r) | FS2(src), MOVABLE_INS));
+		if (dst_r != src && !(op & SLJIT_F32_OP))
+			FAIL_IF(push_inst(compiler, FMOVS | FDN(dst_r) | FS2N(src), MOVABLE_INS));
+		break;
+	case SLJIT_CONV_F64_FROM_F32:
+		FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSTOD, FDTOS) | FD(dst_r) | FS2(src), MOVABLE_INS));
+		op ^= SLJIT_F32_OP;
+		break;
+	}
+
+	if (dst & SLJIT_MEM)
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), dst_r, dst, dstw, 0, 0));
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_s32 dst_r, flags = 0;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	compiler->cache_arg = 0;
+	compiler->cache_argw = 0;
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG2;
+
+	if (src1 & SLJIT_MEM) {
+		if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w)) {
+			FAIL_IF(compiler->error);
+			src1 = TMP_FREG1;
+		} else
+			flags |= SLOW_SRC1;
+	}
+
+	if (src2 & SLJIT_MEM) {
+		if (getput_arg_fast(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w)) {
+			FAIL_IF(compiler->error);
+			src2 = TMP_FREG2;
+		} else
+			flags |= SLOW_SRC2;
+	}
+
+	if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) {
+		if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
+			FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, src1, src1w));
+			FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw));
+		}
+		else {
+			FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, src2, src2w));
+			FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw));
+		}
+	}
+	else if (flags & SLOW_SRC1)
+		FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG1, src1, src1w, dst, dstw));
+	else if (flags & SLOW_SRC2)
+		FAIL_IF(getput_arg(compiler, FLOAT_DATA(op) | LOAD_DATA, TMP_FREG2, src2, src2w, dst, dstw));
+
+	if (flags & SLOW_SRC1)
+		src1 = TMP_FREG1;
+	if (flags & SLOW_SRC2)
+		src2 = TMP_FREG2;
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_ADD_F64:
+		FAIL_IF(push_inst(compiler, SELECT_FOP(op, FADDS, FADDD) | FD(dst_r) | FS1(src1) | FS2(src2), MOVABLE_INS));
+		break;
+
+	case SLJIT_SUB_F64:
+		FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSUBS, FSUBD) | FD(dst_r) | FS1(src1) | FS2(src2), MOVABLE_INS));
+		break;
+
+	case SLJIT_MUL_F64:
+		FAIL_IF(push_inst(compiler, SELECT_FOP(op, FMULS, FMULD) | FD(dst_r) | FS1(src1) | FS2(src2), MOVABLE_INS));
+		break;
+
+	case SLJIT_DIV_F64:
+		FAIL_IF(push_inst(compiler, SELECT_FOP(op, FDIVS, FDIVD) | FD(dst_r) | FS1(src1) | FS2(src2), MOVABLE_INS));
+		break;
+	}
+
+	if (dst_r == TMP_FREG2)
+		FAIL_IF(emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG2, dst, dstw, 0, 0));
+
+	return SLJIT_SUCCESS;
+}
+
+#undef FLOAT_DATA
+#undef SELECT_FOP
+
+/* --------------------------------------------------------------------- */
+/*  Other instructions                                                   */
+/* --------------------------------------------------------------------- */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	if (FAST_IS_REG(dst))
+		return push_inst(compiler, OR | D(dst) | S1(0) | S2(TMP_LINK), UNMOVABLE_INS);
+
+	/* Memory. */
+	FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_LINK, dst, dstw));
+	compiler->delay_slot = UNMOVABLE_INS;
+	return SLJIT_SUCCESS;
+}
+
+/* --------------------------------------------------------------------- */
+/*  Conditional instructions                                             */
+/* --------------------------------------------------------------------- */
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
+{
+	struct sljit_label *label;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_label(compiler));
+
+	if (compiler->last_label && compiler->last_label->size == compiler->size)
+		return compiler->last_label;
+
+	label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));
+	PTR_FAIL_IF(!label);
+	set_label(label, compiler);
+	compiler->delay_slot = UNMOVABLE_INS;
+	return label;
+}
+
+static sljit_ins get_cc(sljit_s32 type)
+{
+	switch (type) {
+	case SLJIT_EQUAL:
+	case SLJIT_MUL_NOT_OVERFLOW:
+	case SLJIT_NOT_EQUAL_F64: /* Unordered. */
+		return DA(0x1);
+
+	case SLJIT_NOT_EQUAL:
+	case SLJIT_MUL_OVERFLOW:
+	case SLJIT_EQUAL_F64:
+		return DA(0x9);
+
+	case SLJIT_LESS:
+	case SLJIT_GREATER_F64: /* Unordered. */
+		return DA(0x5);
+
+	case SLJIT_GREATER_EQUAL:
+	case SLJIT_LESS_EQUAL_F64:
+		return DA(0xd);
+
+	case SLJIT_GREATER:
+	case SLJIT_GREATER_EQUAL_F64: /* Unordered. */
+		return DA(0xc);
+
+	case SLJIT_LESS_EQUAL:
+	case SLJIT_LESS_F64:
+		return DA(0x4);
+
+	case SLJIT_SIG_LESS:
+		return DA(0x3);
+
+	case SLJIT_SIG_GREATER_EQUAL:
+		return DA(0xb);
+
+	case SLJIT_SIG_GREATER:
+		return DA(0xa);
+
+	case SLJIT_SIG_LESS_EQUAL:
+		return DA(0x2);
+
+	case SLJIT_OVERFLOW:
+	case SLJIT_UNORDERED_F64:
+		return DA(0x7);
+
+	case SLJIT_NOT_OVERFLOW:
+	case SLJIT_ORDERED_F64:
+		return DA(0xf);
+
+	default:
+		SLJIT_UNREACHABLE();
+		return DA(0x8);
+	}
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
+{
+	struct sljit_jump *jump;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_jump(compiler, type));
+
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	PTR_FAIL_IF(!jump);
+	set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
+	type &= 0xff;
+
+	if (type < SLJIT_EQUAL_F64) {
+		jump->flags |= IS_COND;
+		if (((compiler->delay_slot & DST_INS_MASK) != UNMOVABLE_INS) && !(compiler->delay_slot & ICC_IS_SET))
+			jump->flags |= IS_MOVABLE;
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+		PTR_FAIL_IF(push_inst(compiler, BICC | get_cc(type ^ 1) | 5, UNMOVABLE_INS));
+#else
+#error "Implementation required"
+#endif
+	}
+	else if (type < SLJIT_JUMP) {
+		jump->flags |= IS_COND;
+		if (((compiler->delay_slot & DST_INS_MASK) != UNMOVABLE_INS) && !(compiler->delay_slot & FCC_IS_SET))
+			jump->flags |= IS_MOVABLE;
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+		PTR_FAIL_IF(push_inst(compiler, FBFCC | get_cc(type ^ 1) | 5, UNMOVABLE_INS));
+#else
+#error "Implementation required"
+#endif
+	}
+	else {
+		if ((compiler->delay_slot & DST_INS_MASK) != UNMOVABLE_INS)
+			jump->flags |= IS_MOVABLE;
+		if (type >= SLJIT_FAST_CALL)
+			jump->flags |= IS_CALL;
+	}
+
+	PTR_FAIL_IF(emit_const(compiler, TMP_REG1, 0));
+	PTR_FAIL_IF(push_inst(compiler, JMPL | D(type >= SLJIT_FAST_CALL ? TMP_LINK : 0) | S1(TMP_REG1) | IMM(0), UNMOVABLE_INS));
+	jump->addr = compiler->size;
+	PTR_FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+
+	return jump;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types)
+{
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
+
+	PTR_FAIL_IF(call_with_args(compiler, arg_types, NULL));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+
+	return sljit_emit_jump(compiler, type);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
+{
+	struct sljit_jump *jump = NULL;
+	sljit_s32 src_r;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	if (FAST_IS_REG(src))
+		src_r = src;
+	else if (src & SLJIT_IMM) {
+		jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+		FAIL_IF(!jump);
+		set_jump(jump, compiler, JUMP_ADDR);
+		jump->u.target = srcw;
+
+		if ((compiler->delay_slot & DST_INS_MASK) != UNMOVABLE_INS)
+			jump->flags |= IS_MOVABLE;
+		if (type >= SLJIT_FAST_CALL)
+			jump->flags |= IS_CALL;
+
+		FAIL_IF(emit_const(compiler, TMP_REG1, 0));
+		src_r = TMP_REG1;
+	}
+	else {
+		FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw));
+		src_r = TMP_REG1;
+	}
+
+	FAIL_IF(push_inst(compiler, JMPL | D(type >= SLJIT_FAST_CALL ? TMP_LINK : 0) | S1(src_r) | IMM(0), UNMOVABLE_INS));
+	if (jump)
+		jump->addr = compiler->size;
+	return push_inst(compiler, NOP, UNMOVABLE_INS);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
+
+	if (src & SLJIT_MEM) {
+		ADJUST_LOCAL_OFFSET(src, srcw);
+		FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw));
+		src = TMP_REG1;
+	}
+
+	FAIL_IF(call_with_args(compiler, arg_types, &src));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+
+	return sljit_emit_ijump(compiler, type, src, srcw);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 type)
+{
+	sljit_s32 reg, flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+	op = GET_OPCODE(op);
+	reg = (op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2;
+
+	compiler->cache_arg = 0;
+	compiler->cache_argw = 0;
+
+	if (op >= SLJIT_ADD && (dst & SLJIT_MEM))
+		FAIL_IF(emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, dst, dstw, dst, dstw));
+
+	type &= 0xff;
+	if (type < SLJIT_EQUAL_F64)
+		FAIL_IF(push_inst(compiler, BICC | get_cc(type) | 3, UNMOVABLE_INS));
+	else
+		FAIL_IF(push_inst(compiler, FBFCC | get_cc(type) | 3, UNMOVABLE_INS));
+
+	FAIL_IF(push_inst(compiler, OR | D(reg) | S1(0) | IMM(1), UNMOVABLE_INS));
+	FAIL_IF(push_inst(compiler, OR | D(reg) | S1(0) | IMM(0), UNMOVABLE_INS));
+
+	if (op >= SLJIT_ADD) {
+		flags |= CUMULATIVE_OP | IMM_OP | ALT_KEEP_CACHE;
+		if (dst & SLJIT_MEM)
+			return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, TMP_REG2, 0);
+		return emit_op(compiler, op, flags, dst, 0, dst, 0, TMP_REG2, 0);
+	}
+
+	if (!(dst & SLJIT_MEM))
+		return SLJIT_SUCCESS;
+
+	return emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw);
+#else
+#error "Implementation required"
+#endif
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 dst_reg,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+
+#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
+	return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);;
+#else
+#error "Implementation required"
+#endif
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
+{
+	struct sljit_const *const_;
+	sljit_s32 dst_r;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
+	PTR_FAIL_IF(!const_);
+	set_const(const_, compiler);
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+	PTR_FAIL_IF(emit_const(compiler, dst_r, init_value));
+
+	if (dst & SLJIT_MEM)
+		PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw));
+	return const_;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	struct sljit_put_label *put_label;
+	sljit_s32 dst_r;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label));
+	PTR_FAIL_IF(!put_label);
+	set_put_label(put_label, compiler, 0);
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+	PTR_FAIL_IF(emit_const(compiler, dst_r, 0));
+
+	if (dst & SLJIT_MEM)
+		PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw));
+	return put_label;
+}
diff --git a/src/c/pcre2/src/sljit/sljitNativeTILEGX-encoder.c b/src/c/pcre2/src/sljit/sljitNativeTILEGX-encoder.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitNativeTILEGX-encoder.c
@@ -0,0 +1,10159 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright 2013-2013 Tilera Corporation(jiwang@tilera.com). All rights reserved.
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* This code is owned by Tilera Corporation, and distributed as part
+   of multiple projects. In sljit, the code is under BSD licence.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define BFD_RELOC(x) R_##x
+
+/* Special registers. */
+#define TREG_LR 55
+#define TREG_SN 56
+#define TREG_ZERO 63
+
+/* Canonical name of each register. */
+const char *const tilegx_register_names[] =
+{
+  "r0",   "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
+  "r8",   "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
+  "r16",  "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+  "r24",  "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+  "r32",  "r33", "r34", "r35", "r36", "r37", "r38", "r39",
+  "r40",  "r41", "r42", "r43", "r44", "r45", "r46", "r47",
+  "r48",  "r49", "r50", "r51", "r52", "tp",  "sp",  "lr",
+  "sn",  "idn0", "idn1", "udn0", "udn1", "udn2", "udn3", "zero"
+};
+
+enum
+{
+  R_NONE = 0,
+  R_TILEGX_NONE = 0,
+  R_TILEGX_64 = 1,
+  R_TILEGX_32 = 2,
+  R_TILEGX_16 = 3,
+  R_TILEGX_8 = 4,
+  R_TILEGX_64_PCREL = 5,
+  R_TILEGX_32_PCREL = 6,
+  R_TILEGX_16_PCREL = 7,
+  R_TILEGX_8_PCREL = 8,
+  R_TILEGX_HW0 = 9,
+  R_TILEGX_HW1 = 10,
+  R_TILEGX_HW2 = 11,
+  R_TILEGX_HW3 = 12,
+  R_TILEGX_HW0_LAST = 13,
+  R_TILEGX_HW1_LAST = 14,
+  R_TILEGX_HW2_LAST = 15,
+  R_TILEGX_COPY = 16,
+  R_TILEGX_GLOB_DAT = 17,
+  R_TILEGX_JMP_SLOT = 18,
+  R_TILEGX_RELATIVE = 19,
+  R_TILEGX_BROFF_X1 = 20,
+  R_TILEGX_JUMPOFF_X1 = 21,
+  R_TILEGX_JUMPOFF_X1_PLT = 22,
+  R_TILEGX_IMM8_X0 = 23,
+  R_TILEGX_IMM8_Y0 = 24,
+  R_TILEGX_IMM8_X1 = 25,
+  R_TILEGX_IMM8_Y1 = 26,
+  R_TILEGX_DEST_IMM8_X1 = 27,
+  R_TILEGX_MT_IMM14_X1 = 28,
+  R_TILEGX_MF_IMM14_X1 = 29,
+  R_TILEGX_MMSTART_X0 = 30,
+  R_TILEGX_MMEND_X0 = 31,
+  R_TILEGX_SHAMT_X0 = 32,
+  R_TILEGX_SHAMT_X1 = 33,
+  R_TILEGX_SHAMT_Y0 = 34,
+  R_TILEGX_SHAMT_Y1 = 35,
+  R_TILEGX_IMM16_X0_HW0 = 36,
+  R_TILEGX_IMM16_X1_HW0 = 37,
+  R_TILEGX_IMM16_X0_HW1 = 38,
+  R_TILEGX_IMM16_X1_HW1 = 39,
+  R_TILEGX_IMM16_X0_HW2 = 40,
+  R_TILEGX_IMM16_X1_HW2 = 41,
+  R_TILEGX_IMM16_X0_HW3 = 42,
+  R_TILEGX_IMM16_X1_HW3 = 43,
+  R_TILEGX_IMM16_X0_HW0_LAST = 44,
+  R_TILEGX_IMM16_X1_HW0_LAST = 45,
+  R_TILEGX_IMM16_X0_HW1_LAST = 46,
+  R_TILEGX_IMM16_X1_HW1_LAST = 47,
+  R_TILEGX_IMM16_X0_HW2_LAST = 48,
+  R_TILEGX_IMM16_X1_HW2_LAST = 49,
+  R_TILEGX_IMM16_X0_HW0_PCREL = 50,
+  R_TILEGX_IMM16_X1_HW0_PCREL = 51,
+  R_TILEGX_IMM16_X0_HW1_PCREL = 52,
+  R_TILEGX_IMM16_X1_HW1_PCREL = 53,
+  R_TILEGX_IMM16_X0_HW2_PCREL = 54,
+  R_TILEGX_IMM16_X1_HW2_PCREL = 55,
+  R_TILEGX_IMM16_X0_HW3_PCREL = 56,
+  R_TILEGX_IMM16_X1_HW3_PCREL = 57,
+  R_TILEGX_IMM16_X0_HW0_LAST_PCREL = 58,
+  R_TILEGX_IMM16_X1_HW0_LAST_PCREL = 59,
+  R_TILEGX_IMM16_X0_HW1_LAST_PCREL = 60,
+  R_TILEGX_IMM16_X1_HW1_LAST_PCREL = 61,
+  R_TILEGX_IMM16_X0_HW2_LAST_PCREL = 62,
+  R_TILEGX_IMM16_X1_HW2_LAST_PCREL = 63,
+  R_TILEGX_IMM16_X0_HW0_GOT = 64,
+  R_TILEGX_IMM16_X1_HW0_GOT = 65,
+
+  R_TILEGX_IMM16_X0_HW0_PLT_PCREL = 66,
+  R_TILEGX_IMM16_X1_HW0_PLT_PCREL = 67,
+  R_TILEGX_IMM16_X0_HW1_PLT_PCREL = 68,
+  R_TILEGX_IMM16_X1_HW1_PLT_PCREL = 69,
+  R_TILEGX_IMM16_X0_HW2_PLT_PCREL = 70,
+  R_TILEGX_IMM16_X1_HW2_PLT_PCREL = 71,
+
+  R_TILEGX_IMM16_X0_HW0_LAST_GOT = 72,
+  R_TILEGX_IMM16_X1_HW0_LAST_GOT = 73,
+  R_TILEGX_IMM16_X0_HW1_LAST_GOT = 74,
+  R_TILEGX_IMM16_X1_HW1_LAST_GOT = 75,
+  R_TILEGX_IMM16_X0_HW0_TLS_GD = 78,
+  R_TILEGX_IMM16_X1_HW0_TLS_GD = 79,
+  R_TILEGX_IMM16_X0_HW0_TLS_LE = 80,
+  R_TILEGX_IMM16_X1_HW0_TLS_LE = 81,
+  R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE = 82,
+  R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE = 83,
+  R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE = 84,
+  R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE = 85,
+  R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD = 86,
+  R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD = 87,
+  R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD = 88,
+  R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD = 89,
+  R_TILEGX_IMM16_X0_HW0_TLS_IE = 92,
+  R_TILEGX_IMM16_X1_HW0_TLS_IE = 93,
+
+  R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL = 94,
+  R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL = 95,
+  R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL = 96,
+  R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL = 97,
+  R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL = 98,
+  R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL = 99,
+
+  R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE = 100,
+  R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE = 101,
+  R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE = 102,
+  R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE = 103,
+  R_TILEGX_TLS_DTPMOD64 = 106,
+  R_TILEGX_TLS_DTPOFF64 = 107,
+  R_TILEGX_TLS_TPOFF64 = 108,
+  R_TILEGX_TLS_DTPMOD32 = 109,
+  R_TILEGX_TLS_DTPOFF32 = 110,
+  R_TILEGX_TLS_TPOFF32 = 111,
+  R_TILEGX_TLS_GD_CALL = 112,
+  R_TILEGX_IMM8_X0_TLS_GD_ADD = 113,
+  R_TILEGX_IMM8_X1_TLS_GD_ADD = 114,
+  R_TILEGX_IMM8_Y0_TLS_GD_ADD = 115,
+  R_TILEGX_IMM8_Y1_TLS_GD_ADD = 116,
+  R_TILEGX_TLS_IE_LOAD = 117,
+  R_TILEGX_IMM8_X0_TLS_ADD = 118,
+  R_TILEGX_IMM8_X1_TLS_ADD = 119,
+  R_TILEGX_IMM8_Y0_TLS_ADD = 120,
+  R_TILEGX_IMM8_Y1_TLS_ADD = 121,
+  R_TILEGX_GNU_VTINHERIT = 128,
+  R_TILEGX_GNU_VTENTRY = 129,
+  R_TILEGX_IRELATIVE = 130,
+  R_TILEGX_NUM = 131
+};
+
+typedef enum
+{
+  TILEGX_PIPELINE_X0,
+  TILEGX_PIPELINE_X1,
+  TILEGX_PIPELINE_Y0,
+  TILEGX_PIPELINE_Y1,
+  TILEGX_PIPELINE_Y2,
+} tilegx_pipeline;
+
+typedef unsigned long long tilegx_bundle_bits;
+
+/* These are the bits that determine if a bundle is in the X encoding. */
+#define TILEGX_BUNDLE_MODE_MASK ((tilegx_bundle_bits)3 << 62)
+
+enum
+{
+  /* Maximum number of instructions in a bundle (2 for X, 3 for Y). */
+  TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE = 3,
+
+  /* How many different pipeline encodings are there? X0, X1, Y0, Y1, Y2. */
+  TILEGX_NUM_PIPELINE_ENCODINGS = 5,
+
+  /* Log base 2 of TILEGX_BUNDLE_SIZE_IN_BYTES. */
+  TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES = 3,
+
+  /* Instructions take this many bytes. */
+  TILEGX_BUNDLE_SIZE_IN_BYTES = 1 << TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES,
+
+  /* Log base 2 of TILEGX_BUNDLE_ALIGNMENT_IN_BYTES. */
+  TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES = 3,
+
+  /* Bundles should be aligned modulo this number of bytes. */
+  TILEGX_BUNDLE_ALIGNMENT_IN_BYTES =
+    (1 << TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES),
+
+  /* Number of registers (some are magic, such as network I/O). */
+  TILEGX_NUM_REGISTERS = 64,
+};
+
+/* Make a few "tile_" variables to simplify common code between
+   architectures.  */
+
+typedef tilegx_bundle_bits tile_bundle_bits;
+#define TILE_BUNDLE_SIZE_IN_BYTES TILEGX_BUNDLE_SIZE_IN_BYTES
+#define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES
+#define TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES \
+  TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES
+
+/* 64-bit pattern for a { bpt ; nop } bundle. */
+#define TILEGX_BPT_BUNDLE 0x286a44ae51485000ULL
+
+typedef enum
+{
+  TILEGX_OP_TYPE_REGISTER,
+  TILEGX_OP_TYPE_IMMEDIATE,
+  TILEGX_OP_TYPE_ADDRESS,
+  TILEGX_OP_TYPE_SPR
+} tilegx_operand_type;
+
+struct tilegx_operand
+{
+  /* Is this operand a register, immediate or address? */
+  tilegx_operand_type type;
+
+  /* The default relocation type for this operand.  */
+  signed int default_reloc : 16;
+
+  /* How many bits is this value? (used for range checking) */
+  unsigned int num_bits : 5;
+
+  /* Is the value signed? (used for range checking) */
+  unsigned int is_signed : 1;
+
+  /* Is this operand a source register? */
+  unsigned int is_src_reg : 1;
+
+  /* Is this operand written? (i.e. is it a destination register) */
+  unsigned int is_dest_reg : 1;
+
+  /* Is this operand PC-relative? */
+  unsigned int is_pc_relative : 1;
+
+  /* By how many bits do we right shift the value before inserting? */
+  unsigned int rightshift : 2;
+
+  /* Return the bits for this operand to be ORed into an existing bundle. */
+  tilegx_bundle_bits (*insert) (int op);
+
+  /* Extract this operand and return it. */
+  unsigned int (*extract) (tilegx_bundle_bits bundle);
+};
+
+typedef enum
+{
+  TILEGX_OPC_BPT,
+  TILEGX_OPC_INFO,
+  TILEGX_OPC_INFOL,
+  TILEGX_OPC_LD4S_TLS,
+  TILEGX_OPC_LD_TLS,
+  TILEGX_OPC_MOVE,
+  TILEGX_OPC_MOVEI,
+  TILEGX_OPC_MOVELI,
+  TILEGX_OPC_PREFETCH,
+  TILEGX_OPC_PREFETCH_ADD_L1,
+  TILEGX_OPC_PREFETCH_ADD_L1_FAULT,
+  TILEGX_OPC_PREFETCH_ADD_L2,
+  TILEGX_OPC_PREFETCH_ADD_L2_FAULT,
+  TILEGX_OPC_PREFETCH_ADD_L3,
+  TILEGX_OPC_PREFETCH_ADD_L3_FAULT,
+  TILEGX_OPC_PREFETCH_L1,
+  TILEGX_OPC_PREFETCH_L1_FAULT,
+  TILEGX_OPC_PREFETCH_L2,
+  TILEGX_OPC_PREFETCH_L2_FAULT,
+  TILEGX_OPC_PREFETCH_L3,
+  TILEGX_OPC_PREFETCH_L3_FAULT,
+  TILEGX_OPC_RAISE,
+  TILEGX_OPC_ADD,
+  TILEGX_OPC_ADDI,
+  TILEGX_OPC_ADDLI,
+  TILEGX_OPC_ADDX,
+  TILEGX_OPC_ADDXI,
+  TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXSC,
+  TILEGX_OPC_AND,
+  TILEGX_OPC_ANDI,
+  TILEGX_OPC_BEQZ,
+  TILEGX_OPC_BEQZT,
+  TILEGX_OPC_BFEXTS,
+  TILEGX_OPC_BFEXTU,
+  TILEGX_OPC_BFINS,
+  TILEGX_OPC_BGEZ,
+  TILEGX_OPC_BGEZT,
+  TILEGX_OPC_BGTZ,
+  TILEGX_OPC_BGTZT,
+  TILEGX_OPC_BLBC,
+  TILEGX_OPC_BLBCT,
+  TILEGX_OPC_BLBS,
+  TILEGX_OPC_BLBST,
+  TILEGX_OPC_BLEZ,
+  TILEGX_OPC_BLEZT,
+  TILEGX_OPC_BLTZ,
+  TILEGX_OPC_BLTZT,
+  TILEGX_OPC_BNEZ,
+  TILEGX_OPC_BNEZT,
+  TILEGX_OPC_CLZ,
+  TILEGX_OPC_CMOVEQZ,
+  TILEGX_OPC_CMOVNEZ,
+  TILEGX_OPC_CMPEQ,
+  TILEGX_OPC_CMPEQI,
+  TILEGX_OPC_CMPEXCH,
+  TILEGX_OPC_CMPEXCH4,
+  TILEGX_OPC_CMPLES,
+  TILEGX_OPC_CMPLEU,
+  TILEGX_OPC_CMPLTS,
+  TILEGX_OPC_CMPLTSI,
+  TILEGX_OPC_CMPLTU,
+  TILEGX_OPC_CMPLTUI,
+  TILEGX_OPC_CMPNE,
+  TILEGX_OPC_CMUL,
+  TILEGX_OPC_CMULA,
+  TILEGX_OPC_CMULAF,
+  TILEGX_OPC_CMULF,
+  TILEGX_OPC_CMULFR,
+  TILEGX_OPC_CMULH,
+  TILEGX_OPC_CMULHR,
+  TILEGX_OPC_CRC32_32,
+  TILEGX_OPC_CRC32_8,
+  TILEGX_OPC_CTZ,
+  TILEGX_OPC_DBLALIGN,
+  TILEGX_OPC_DBLALIGN2,
+  TILEGX_OPC_DBLALIGN4,
+  TILEGX_OPC_DBLALIGN6,
+  TILEGX_OPC_DRAIN,
+  TILEGX_OPC_DTLBPR,
+  TILEGX_OPC_EXCH,
+  TILEGX_OPC_EXCH4,
+  TILEGX_OPC_FDOUBLE_ADD_FLAGS,
+  TILEGX_OPC_FDOUBLE_ADDSUB,
+  TILEGX_OPC_FDOUBLE_MUL_FLAGS,
+  TILEGX_OPC_FDOUBLE_PACK1,
+  TILEGX_OPC_FDOUBLE_PACK2,
+  TILEGX_OPC_FDOUBLE_SUB_FLAGS,
+  TILEGX_OPC_FDOUBLE_UNPACK_MAX,
+  TILEGX_OPC_FDOUBLE_UNPACK_MIN,
+  TILEGX_OPC_FETCHADD,
+  TILEGX_OPC_FETCHADD4,
+  TILEGX_OPC_FETCHADDGEZ,
+  TILEGX_OPC_FETCHADDGEZ4,
+  TILEGX_OPC_FETCHAND,
+  TILEGX_OPC_FETCHAND4,
+  TILEGX_OPC_FETCHOR,
+  TILEGX_OPC_FETCHOR4,
+  TILEGX_OPC_FINV,
+  TILEGX_OPC_FLUSH,
+  TILEGX_OPC_FLUSHWB,
+  TILEGX_OPC_FNOP,
+  TILEGX_OPC_FSINGLE_ADD1,
+  TILEGX_OPC_FSINGLE_ADDSUB2,
+  TILEGX_OPC_FSINGLE_MUL1,
+  TILEGX_OPC_FSINGLE_MUL2,
+  TILEGX_OPC_FSINGLE_PACK1,
+  TILEGX_OPC_FSINGLE_PACK2,
+  TILEGX_OPC_FSINGLE_SUB1,
+  TILEGX_OPC_ICOH,
+  TILEGX_OPC_ILL,
+  TILEGX_OPC_INV,
+  TILEGX_OPC_IRET,
+  TILEGX_OPC_J,
+  TILEGX_OPC_JAL,
+  TILEGX_OPC_JALR,
+  TILEGX_OPC_JALRP,
+  TILEGX_OPC_JR,
+  TILEGX_OPC_JRP,
+  TILEGX_OPC_LD,
+  TILEGX_OPC_LD1S,
+  TILEGX_OPC_LD1S_ADD,
+  TILEGX_OPC_LD1U,
+  TILEGX_OPC_LD1U_ADD,
+  TILEGX_OPC_LD2S,
+  TILEGX_OPC_LD2S_ADD,
+  TILEGX_OPC_LD2U,
+  TILEGX_OPC_LD2U_ADD,
+  TILEGX_OPC_LD4S,
+  TILEGX_OPC_LD4S_ADD,
+  TILEGX_OPC_LD4U,
+  TILEGX_OPC_LD4U_ADD,
+  TILEGX_OPC_LD_ADD,
+  TILEGX_OPC_LDNA,
+  TILEGX_OPC_LDNA_ADD,
+  TILEGX_OPC_LDNT,
+  TILEGX_OPC_LDNT1S,
+  TILEGX_OPC_LDNT1S_ADD,
+  TILEGX_OPC_LDNT1U,
+  TILEGX_OPC_LDNT1U_ADD,
+  TILEGX_OPC_LDNT2S,
+  TILEGX_OPC_LDNT2S_ADD,
+  TILEGX_OPC_LDNT2U,
+  TILEGX_OPC_LDNT2U_ADD,
+  TILEGX_OPC_LDNT4S,
+  TILEGX_OPC_LDNT4S_ADD,
+  TILEGX_OPC_LDNT4U,
+  TILEGX_OPC_LDNT4U_ADD,
+  TILEGX_OPC_LDNT_ADD,
+  TILEGX_OPC_LNK,
+  TILEGX_OPC_MF,
+  TILEGX_OPC_MFSPR,
+  TILEGX_OPC_MM,
+  TILEGX_OPC_MNZ,
+  TILEGX_OPC_MTSPR,
+  TILEGX_OPC_MUL_HS_HS,
+  TILEGX_OPC_MUL_HS_HU,
+  TILEGX_OPC_MUL_HS_LS,
+  TILEGX_OPC_MUL_HS_LU,
+  TILEGX_OPC_MUL_HU_HU,
+  TILEGX_OPC_MUL_HU_LS,
+  TILEGX_OPC_MUL_HU_LU,
+  TILEGX_OPC_MUL_LS_LS,
+  TILEGX_OPC_MUL_LS_LU,
+  TILEGX_OPC_MUL_LU_LU,
+  TILEGX_OPC_MULA_HS_HS,
+  TILEGX_OPC_MULA_HS_HU,
+  TILEGX_OPC_MULA_HS_LS,
+  TILEGX_OPC_MULA_HS_LU,
+  TILEGX_OPC_MULA_HU_HU,
+  TILEGX_OPC_MULA_HU_LS,
+  TILEGX_OPC_MULA_HU_LU,
+  TILEGX_OPC_MULA_LS_LS,
+  TILEGX_OPC_MULA_LS_LU,
+  TILEGX_OPC_MULA_LU_LU,
+  TILEGX_OPC_MULAX,
+  TILEGX_OPC_MULX,
+  TILEGX_OPC_MZ,
+  TILEGX_OPC_NAP,
+  TILEGX_OPC_NOP,
+  TILEGX_OPC_NOR,
+  TILEGX_OPC_OR,
+  TILEGX_OPC_ORI,
+  TILEGX_OPC_PCNT,
+  TILEGX_OPC_REVBITS,
+  TILEGX_OPC_REVBYTES,
+  TILEGX_OPC_ROTL,
+  TILEGX_OPC_ROTLI,
+  TILEGX_OPC_SHL,
+  TILEGX_OPC_SHL16INSLI,
+  TILEGX_OPC_SHL1ADD,
+  TILEGX_OPC_SHL1ADDX,
+  TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL2ADDX,
+  TILEGX_OPC_SHL3ADD,
+  TILEGX_OPC_SHL3ADDX,
+  TILEGX_OPC_SHLI,
+  TILEGX_OPC_SHLX,
+  TILEGX_OPC_SHLXI,
+  TILEGX_OPC_SHRS,
+  TILEGX_OPC_SHRSI,
+  TILEGX_OPC_SHRU,
+  TILEGX_OPC_SHRUI,
+  TILEGX_OPC_SHRUX,
+  TILEGX_OPC_SHRUXI,
+  TILEGX_OPC_SHUFFLEBYTES,
+  TILEGX_OPC_ST,
+  TILEGX_OPC_ST1,
+  TILEGX_OPC_ST1_ADD,
+  TILEGX_OPC_ST2,
+  TILEGX_OPC_ST2_ADD,
+  TILEGX_OPC_ST4,
+  TILEGX_OPC_ST4_ADD,
+  TILEGX_OPC_ST_ADD,
+  TILEGX_OPC_STNT,
+  TILEGX_OPC_STNT1,
+  TILEGX_OPC_STNT1_ADD,
+  TILEGX_OPC_STNT2,
+  TILEGX_OPC_STNT2_ADD,
+  TILEGX_OPC_STNT4,
+  TILEGX_OPC_STNT4_ADD,
+  TILEGX_OPC_STNT_ADD,
+  TILEGX_OPC_SUB,
+  TILEGX_OPC_SUBX,
+  TILEGX_OPC_SUBXSC,
+  TILEGX_OPC_SWINT0,
+  TILEGX_OPC_SWINT1,
+  TILEGX_OPC_SWINT2,
+  TILEGX_OPC_SWINT3,
+  TILEGX_OPC_TBLIDXB0,
+  TILEGX_OPC_TBLIDXB1,
+  TILEGX_OPC_TBLIDXB2,
+  TILEGX_OPC_TBLIDXB3,
+  TILEGX_OPC_V1ADD,
+  TILEGX_OPC_V1ADDI,
+  TILEGX_OPC_V1ADDUC,
+  TILEGX_OPC_V1ADIFFU,
+  TILEGX_OPC_V1AVGU,
+  TILEGX_OPC_V1CMPEQ,
+  TILEGX_OPC_V1CMPEQI,
+  TILEGX_OPC_V1CMPLES,
+  TILEGX_OPC_V1CMPLEU,
+  TILEGX_OPC_V1CMPLTS,
+  TILEGX_OPC_V1CMPLTSI,
+  TILEGX_OPC_V1CMPLTU,
+  TILEGX_OPC_V1CMPLTUI,
+  TILEGX_OPC_V1CMPNE,
+  TILEGX_OPC_V1DDOTPU,
+  TILEGX_OPC_V1DDOTPUA,
+  TILEGX_OPC_V1DDOTPUS,
+  TILEGX_OPC_V1DDOTPUSA,
+  TILEGX_OPC_V1DOTP,
+  TILEGX_OPC_V1DOTPA,
+  TILEGX_OPC_V1DOTPU,
+  TILEGX_OPC_V1DOTPUA,
+  TILEGX_OPC_V1DOTPUS,
+  TILEGX_OPC_V1DOTPUSA,
+  TILEGX_OPC_V1INT_H,
+  TILEGX_OPC_V1INT_L,
+  TILEGX_OPC_V1MAXU,
+  TILEGX_OPC_V1MAXUI,
+  TILEGX_OPC_V1MINU,
+  TILEGX_OPC_V1MINUI,
+  TILEGX_OPC_V1MNZ,
+  TILEGX_OPC_V1MULTU,
+  TILEGX_OPC_V1MULU,
+  TILEGX_OPC_V1MULUS,
+  TILEGX_OPC_V1MZ,
+  TILEGX_OPC_V1SADAU,
+  TILEGX_OPC_V1SADU,
+  TILEGX_OPC_V1SHL,
+  TILEGX_OPC_V1SHLI,
+  TILEGX_OPC_V1SHRS,
+  TILEGX_OPC_V1SHRSI,
+  TILEGX_OPC_V1SHRU,
+  TILEGX_OPC_V1SHRUI,
+  TILEGX_OPC_V1SUB,
+  TILEGX_OPC_V1SUBUC,
+  TILEGX_OPC_V2ADD,
+  TILEGX_OPC_V2ADDI,
+  TILEGX_OPC_V2ADDSC,
+  TILEGX_OPC_V2ADIFFS,
+  TILEGX_OPC_V2AVGS,
+  TILEGX_OPC_V2CMPEQ,
+  TILEGX_OPC_V2CMPEQI,
+  TILEGX_OPC_V2CMPLES,
+  TILEGX_OPC_V2CMPLEU,
+  TILEGX_OPC_V2CMPLTS,
+  TILEGX_OPC_V2CMPLTSI,
+  TILEGX_OPC_V2CMPLTU,
+  TILEGX_OPC_V2CMPLTUI,
+  TILEGX_OPC_V2CMPNE,
+  TILEGX_OPC_V2DOTP,
+  TILEGX_OPC_V2DOTPA,
+  TILEGX_OPC_V2INT_H,
+  TILEGX_OPC_V2INT_L,
+  TILEGX_OPC_V2MAXS,
+  TILEGX_OPC_V2MAXSI,
+  TILEGX_OPC_V2MINS,
+  TILEGX_OPC_V2MINSI,
+  TILEGX_OPC_V2MNZ,
+  TILEGX_OPC_V2MULFSC,
+  TILEGX_OPC_V2MULS,
+  TILEGX_OPC_V2MULTS,
+  TILEGX_OPC_V2MZ,
+  TILEGX_OPC_V2PACKH,
+  TILEGX_OPC_V2PACKL,
+  TILEGX_OPC_V2PACKUC,
+  TILEGX_OPC_V2SADAS,
+  TILEGX_OPC_V2SADAU,
+  TILEGX_OPC_V2SADS,
+  TILEGX_OPC_V2SADU,
+  TILEGX_OPC_V2SHL,
+  TILEGX_OPC_V2SHLI,
+  TILEGX_OPC_V2SHLSC,
+  TILEGX_OPC_V2SHRS,
+  TILEGX_OPC_V2SHRSI,
+  TILEGX_OPC_V2SHRU,
+  TILEGX_OPC_V2SHRUI,
+  TILEGX_OPC_V2SUB,
+  TILEGX_OPC_V2SUBSC,
+  TILEGX_OPC_V4ADD,
+  TILEGX_OPC_V4ADDSC,
+  TILEGX_OPC_V4INT_H,
+  TILEGX_OPC_V4INT_L,
+  TILEGX_OPC_V4PACKSC,
+  TILEGX_OPC_V4SHL,
+  TILEGX_OPC_V4SHLSC,
+  TILEGX_OPC_V4SHRS,
+  TILEGX_OPC_V4SHRU,
+  TILEGX_OPC_V4SUB,
+  TILEGX_OPC_V4SUBSC,
+  TILEGX_OPC_WH64,
+  TILEGX_OPC_XOR,
+  TILEGX_OPC_XORI,
+  TILEGX_OPC_NONE
+} tilegx_mnemonic;
+
+enum
+{
+  TILEGX_MAX_OPERANDS = 4 /* bfexts */
+};
+
+struct tilegx_opcode
+{
+  /* The opcode mnemonic, e.g. "add" */
+  const char *name;
+
+  /* The enum value for this mnemonic. */
+  tilegx_mnemonic mnemonic;
+
+  /* A bit mask of which of the five pipes this instruction
+     is compatible with:
+     X0  0x01
+     X1  0x02
+     Y0  0x04
+     Y1  0x08
+     Y2  0x10 */
+  unsigned char pipes;
+
+  /* How many operands are there? */
+  unsigned char num_operands;
+
+  /* Which register does this write implicitly, or TREG_ZERO if none? */
+  unsigned char implicitly_written_register;
+
+  /* Can this be bundled with other instructions (almost always true). */
+  unsigned char can_bundle;
+
+  /* The description of the operands. Each of these is an
+   * index into the tilegx_operands[] table. */
+  unsigned char operands[TILEGX_NUM_PIPELINE_ENCODINGS][TILEGX_MAX_OPERANDS];
+
+  /* A mask of which bits have predefined values for each pipeline.
+   * This is useful for disassembly. */
+  tilegx_bundle_bits fixed_bit_masks[TILEGX_NUM_PIPELINE_ENCODINGS];
+
+  /* For each bit set in fixed_bit_masks, what the value is for this
+   * instruction. */
+  tilegx_bundle_bits fixed_bit_values[TILEGX_NUM_PIPELINE_ENCODINGS];
+};
+
+/* Used for non-textual disassembly into structs. */
+struct tilegx_decoded_instruction
+{
+  const struct tilegx_opcode *opcode;
+  const struct tilegx_operand *operands[TILEGX_MAX_OPERANDS];
+  long long operand_values[TILEGX_MAX_OPERANDS];
+};
+
+enum
+{
+  ADDI_IMM8_OPCODE_X0 = 1,
+  ADDI_IMM8_OPCODE_X1 = 1,
+  ADDI_OPCODE_Y0 = 0,
+  ADDI_OPCODE_Y1 = 1,
+  ADDLI_OPCODE_X0 = 1,
+  ADDLI_OPCODE_X1 = 0,
+  ADDXI_IMM8_OPCODE_X0 = 2,
+  ADDXI_IMM8_OPCODE_X1 = 2,
+  ADDXI_OPCODE_Y0 = 1,
+  ADDXI_OPCODE_Y1 = 2,
+  ADDXLI_OPCODE_X0 = 2,
+  ADDXLI_OPCODE_X1 = 1,
+  ADDXSC_RRR_0_OPCODE_X0 = 1,
+  ADDXSC_RRR_0_OPCODE_X1 = 1,
+  ADDX_RRR_0_OPCODE_X0 = 2,
+  ADDX_RRR_0_OPCODE_X1 = 2,
+  ADDX_RRR_0_OPCODE_Y0 = 0,
+  ADDX_SPECIAL_0_OPCODE_Y1 = 0,
+  ADD_RRR_0_OPCODE_X0 = 3,
+  ADD_RRR_0_OPCODE_X1 = 3,
+  ADD_RRR_0_OPCODE_Y0 = 1,
+  ADD_SPECIAL_0_OPCODE_Y1 = 1,
+  ANDI_IMM8_OPCODE_X0 = 3,
+  ANDI_IMM8_OPCODE_X1 = 3,
+  ANDI_OPCODE_Y0 = 2,
+  ANDI_OPCODE_Y1 = 3,
+  AND_RRR_0_OPCODE_X0 = 4,
+  AND_RRR_0_OPCODE_X1 = 4,
+  AND_RRR_5_OPCODE_Y0 = 0,
+  AND_RRR_5_OPCODE_Y1 = 0,
+  BEQZT_BRANCH_OPCODE_X1 = 16,
+  BEQZ_BRANCH_OPCODE_X1 = 17,
+  BFEXTS_BF_OPCODE_X0 = 4,
+  BFEXTU_BF_OPCODE_X0 = 5,
+  BFINS_BF_OPCODE_X0 = 6,
+  BF_OPCODE_X0 = 3,
+  BGEZT_BRANCH_OPCODE_X1 = 18,
+  BGEZ_BRANCH_OPCODE_X1 = 19,
+  BGTZT_BRANCH_OPCODE_X1 = 20,
+  BGTZ_BRANCH_OPCODE_X1 = 21,
+  BLBCT_BRANCH_OPCODE_X1 = 22,
+  BLBC_BRANCH_OPCODE_X1 = 23,
+  BLBST_BRANCH_OPCODE_X1 = 24,
+  BLBS_BRANCH_OPCODE_X1 = 25,
+  BLEZT_BRANCH_OPCODE_X1 = 26,
+  BLEZ_BRANCH_OPCODE_X1 = 27,
+  BLTZT_BRANCH_OPCODE_X1 = 28,
+  BLTZ_BRANCH_OPCODE_X1 = 29,
+  BNEZT_BRANCH_OPCODE_X1 = 30,
+  BNEZ_BRANCH_OPCODE_X1 = 31,
+  BRANCH_OPCODE_X1 = 2,
+  CMOVEQZ_RRR_0_OPCODE_X0 = 5,
+  CMOVEQZ_RRR_4_OPCODE_Y0 = 0,
+  CMOVNEZ_RRR_0_OPCODE_X0 = 6,
+  CMOVNEZ_RRR_4_OPCODE_Y0 = 1,
+  CMPEQI_IMM8_OPCODE_X0 = 4,
+  CMPEQI_IMM8_OPCODE_X1 = 4,
+  CMPEQI_OPCODE_Y0 = 3,
+  CMPEQI_OPCODE_Y1 = 4,
+  CMPEQ_RRR_0_OPCODE_X0 = 7,
+  CMPEQ_RRR_0_OPCODE_X1 = 5,
+  CMPEQ_RRR_3_OPCODE_Y0 = 0,
+  CMPEQ_RRR_3_OPCODE_Y1 = 2,
+  CMPEXCH4_RRR_0_OPCODE_X1 = 6,
+  CMPEXCH_RRR_0_OPCODE_X1 = 7,
+  CMPLES_RRR_0_OPCODE_X0 = 8,
+  CMPLES_RRR_0_OPCODE_X1 = 8,
+  CMPLES_RRR_2_OPCODE_Y0 = 0,
+  CMPLES_RRR_2_OPCODE_Y1 = 0,
+  CMPLEU_RRR_0_OPCODE_X0 = 9,
+  CMPLEU_RRR_0_OPCODE_X1 = 9,
+  CMPLEU_RRR_2_OPCODE_Y0 = 1,
+  CMPLEU_RRR_2_OPCODE_Y1 = 1,
+  CMPLTSI_IMM8_OPCODE_X0 = 5,
+  CMPLTSI_IMM8_OPCODE_X1 = 5,
+  CMPLTSI_OPCODE_Y0 = 4,
+  CMPLTSI_OPCODE_Y1 = 5,
+  CMPLTS_RRR_0_OPCODE_X0 = 10,
+  CMPLTS_RRR_0_OPCODE_X1 = 10,
+  CMPLTS_RRR_2_OPCODE_Y0 = 2,
+  CMPLTS_RRR_2_OPCODE_Y1 = 2,
+  CMPLTUI_IMM8_OPCODE_X0 = 6,
+  CMPLTUI_IMM8_OPCODE_X1 = 6,
+  CMPLTU_RRR_0_OPCODE_X0 = 11,
+  CMPLTU_RRR_0_OPCODE_X1 = 11,
+  CMPLTU_RRR_2_OPCODE_Y0 = 3,
+  CMPLTU_RRR_2_OPCODE_Y1 = 3,
+  CMPNE_RRR_0_OPCODE_X0 = 12,
+  CMPNE_RRR_0_OPCODE_X1 = 12,
+  CMPNE_RRR_3_OPCODE_Y0 = 1,
+  CMPNE_RRR_3_OPCODE_Y1 = 3,
+  CMULAF_RRR_0_OPCODE_X0 = 13,
+  CMULA_RRR_0_OPCODE_X0 = 14,
+  CMULFR_RRR_0_OPCODE_X0 = 15,
+  CMULF_RRR_0_OPCODE_X0 = 16,
+  CMULHR_RRR_0_OPCODE_X0 = 17,
+  CMULH_RRR_0_OPCODE_X0 = 18,
+  CMUL_RRR_0_OPCODE_X0 = 19,
+  CNTLZ_UNARY_OPCODE_X0 = 1,
+  CNTLZ_UNARY_OPCODE_Y0 = 1,
+  CNTTZ_UNARY_OPCODE_X0 = 2,
+  CNTTZ_UNARY_OPCODE_Y0 = 2,
+  CRC32_32_RRR_0_OPCODE_X0 = 20,
+  CRC32_8_RRR_0_OPCODE_X0 = 21,
+  DBLALIGN2_RRR_0_OPCODE_X0 = 22,
+  DBLALIGN2_RRR_0_OPCODE_X1 = 13,
+  DBLALIGN4_RRR_0_OPCODE_X0 = 23,
+  DBLALIGN4_RRR_0_OPCODE_X1 = 14,
+  DBLALIGN6_RRR_0_OPCODE_X0 = 24,
+  DBLALIGN6_RRR_0_OPCODE_X1 = 15,
+  DBLALIGN_RRR_0_OPCODE_X0 = 25,
+  DRAIN_UNARY_OPCODE_X1 = 1,
+  DTLBPR_UNARY_OPCODE_X1 = 2,
+  EXCH4_RRR_0_OPCODE_X1 = 16,
+  EXCH_RRR_0_OPCODE_X1 = 17,
+  FDOUBLE_ADDSUB_RRR_0_OPCODE_X0 = 26,
+  FDOUBLE_ADD_FLAGS_RRR_0_OPCODE_X0 = 27,
+  FDOUBLE_MUL_FLAGS_RRR_0_OPCODE_X0 = 28,
+  FDOUBLE_PACK1_RRR_0_OPCODE_X0 = 29,
+  FDOUBLE_PACK2_RRR_0_OPCODE_X0 = 30,
+  FDOUBLE_SUB_FLAGS_RRR_0_OPCODE_X0 = 31,
+  FDOUBLE_UNPACK_MAX_RRR_0_OPCODE_X0 = 32,
+  FDOUBLE_UNPACK_MIN_RRR_0_OPCODE_X0 = 33,
+  FETCHADD4_RRR_0_OPCODE_X1 = 18,
+  FETCHADDGEZ4_RRR_0_OPCODE_X1 = 19,
+  FETCHADDGEZ_RRR_0_OPCODE_X1 = 20,
+  FETCHADD_RRR_0_OPCODE_X1 = 21,
+  FETCHAND4_RRR_0_OPCODE_X1 = 22,
+  FETCHAND_RRR_0_OPCODE_X1 = 23,
+  FETCHOR4_RRR_0_OPCODE_X1 = 24,
+  FETCHOR_RRR_0_OPCODE_X1 = 25,
+  FINV_UNARY_OPCODE_X1 = 3,
+  FLUSHWB_UNARY_OPCODE_X1 = 4,
+  FLUSH_UNARY_OPCODE_X1 = 5,
+  FNOP_UNARY_OPCODE_X0 = 3,
+  FNOP_UNARY_OPCODE_X1 = 6,
+  FNOP_UNARY_OPCODE_Y0 = 3,
+  FNOP_UNARY_OPCODE_Y1 = 8,
+  FSINGLE_ADD1_RRR_0_OPCODE_X0 = 34,
+  FSINGLE_ADDSUB2_RRR_0_OPCODE_X0 = 35,
+  FSINGLE_MUL1_RRR_0_OPCODE_X0 = 36,
+  FSINGLE_MUL2_RRR_0_OPCODE_X0 = 37,
+  FSINGLE_PACK1_UNARY_OPCODE_X0 = 4,
+  FSINGLE_PACK1_UNARY_OPCODE_Y0 = 4,
+  FSINGLE_PACK2_RRR_0_OPCODE_X0 = 38,
+  FSINGLE_SUB1_RRR_0_OPCODE_X0 = 39,
+  ICOH_UNARY_OPCODE_X1 = 7,
+  ILL_UNARY_OPCODE_X1 = 8,
+  ILL_UNARY_OPCODE_Y1 = 9,
+  IMM8_OPCODE_X0 = 4,
+  IMM8_OPCODE_X1 = 3,
+  INV_UNARY_OPCODE_X1 = 9,
+  IRET_UNARY_OPCODE_X1 = 10,
+  JALRP_UNARY_OPCODE_X1 = 11,
+  JALRP_UNARY_OPCODE_Y1 = 10,
+  JALR_UNARY_OPCODE_X1 = 12,
+  JALR_UNARY_OPCODE_Y1 = 11,
+  JAL_JUMP_OPCODE_X1 = 0,
+  JRP_UNARY_OPCODE_X1 = 13,
+  JRP_UNARY_OPCODE_Y1 = 12,
+  JR_UNARY_OPCODE_X1 = 14,
+  JR_UNARY_OPCODE_Y1 = 13,
+  JUMP_OPCODE_X1 = 4,
+  J_JUMP_OPCODE_X1 = 1,
+  LD1S_ADD_IMM8_OPCODE_X1 = 7,
+  LD1S_OPCODE_Y2 = 0,
+  LD1S_UNARY_OPCODE_X1 = 15,
+  LD1U_ADD_IMM8_OPCODE_X1 = 8,
+  LD1U_OPCODE_Y2 = 1,
+  LD1U_UNARY_OPCODE_X1 = 16,
+  LD2S_ADD_IMM8_OPCODE_X1 = 9,
+  LD2S_OPCODE_Y2 = 2,
+  LD2S_UNARY_OPCODE_X1 = 17,
+  LD2U_ADD_IMM8_OPCODE_X1 = 10,
+  LD2U_OPCODE_Y2 = 3,
+  LD2U_UNARY_OPCODE_X1 = 18,
+  LD4S_ADD_IMM8_OPCODE_X1 = 11,
+  LD4S_OPCODE_Y2 = 1,
+  LD4S_UNARY_OPCODE_X1 = 19,
+  LD4U_ADD_IMM8_OPCODE_X1 = 12,
+  LD4U_OPCODE_Y2 = 2,
+  LD4U_UNARY_OPCODE_X1 = 20,
+  LDNA_UNARY_OPCODE_X1 = 21,
+  LDNT1S_ADD_IMM8_OPCODE_X1 = 13,
+  LDNT1S_UNARY_OPCODE_X1 = 22,
+  LDNT1U_ADD_IMM8_OPCODE_X1 = 14,
+  LDNT1U_UNARY_OPCODE_X1 = 23,
+  LDNT2S_ADD_IMM8_OPCODE_X1 = 15,
+  LDNT2S_UNARY_OPCODE_X1 = 24,
+  LDNT2U_ADD_IMM8_OPCODE_X1 = 16,
+  LDNT2U_UNARY_OPCODE_X1 = 25,
+  LDNT4S_ADD_IMM8_OPCODE_X1 = 17,
+  LDNT4S_UNARY_OPCODE_X1 = 26,
+  LDNT4U_ADD_IMM8_OPCODE_X1 = 18,
+  LDNT4U_UNARY_OPCODE_X1 = 27,
+  LDNT_ADD_IMM8_OPCODE_X1 = 19,
+  LDNT_UNARY_OPCODE_X1 = 28,
+  LD_ADD_IMM8_OPCODE_X1 = 20,
+  LD_OPCODE_Y2 = 3,
+  LD_UNARY_OPCODE_X1 = 29,
+  LNK_UNARY_OPCODE_X1 = 30,
+  LNK_UNARY_OPCODE_Y1 = 14,
+  LWNA_ADD_IMM8_OPCODE_X1 = 21,
+  MFSPR_IMM8_OPCODE_X1 = 22,
+  MF_UNARY_OPCODE_X1 = 31,
+  MM_BF_OPCODE_X0 = 7,
+  MNZ_RRR_0_OPCODE_X0 = 40,
+  MNZ_RRR_0_OPCODE_X1 = 26,
+  MNZ_RRR_4_OPCODE_Y0 = 2,
+  MNZ_RRR_4_OPCODE_Y1 = 2,
+  MODE_OPCODE_YA2 = 1,
+  MODE_OPCODE_YB2 = 2,
+  MODE_OPCODE_YC2 = 3,
+  MTSPR_IMM8_OPCODE_X1 = 23,
+  MULAX_RRR_0_OPCODE_X0 = 41,
+  MULAX_RRR_3_OPCODE_Y0 = 2,
+  MULA_HS_HS_RRR_0_OPCODE_X0 = 42,
+  MULA_HS_HS_RRR_9_OPCODE_Y0 = 0,
+  MULA_HS_HU_RRR_0_OPCODE_X0 = 43,
+  MULA_HS_LS_RRR_0_OPCODE_X0 = 44,
+  MULA_HS_LU_RRR_0_OPCODE_X0 = 45,
+  MULA_HU_HU_RRR_0_OPCODE_X0 = 46,
+  MULA_HU_HU_RRR_9_OPCODE_Y0 = 1,
+  MULA_HU_LS_RRR_0_OPCODE_X0 = 47,
+  MULA_HU_LU_RRR_0_OPCODE_X0 = 48,
+  MULA_LS_LS_RRR_0_OPCODE_X0 = 49,
+  MULA_LS_LS_RRR_9_OPCODE_Y0 = 2,
+  MULA_LS_LU_RRR_0_OPCODE_X0 = 50,
+  MULA_LU_LU_RRR_0_OPCODE_X0 = 51,
+  MULA_LU_LU_RRR_9_OPCODE_Y0 = 3,
+  MULX_RRR_0_OPCODE_X0 = 52,
+  MULX_RRR_3_OPCODE_Y0 = 3,
+  MUL_HS_HS_RRR_0_OPCODE_X0 = 53,
+  MUL_HS_HS_RRR_8_OPCODE_Y0 = 0,
+  MUL_HS_HU_RRR_0_OPCODE_X0 = 54,
+  MUL_HS_LS_RRR_0_OPCODE_X0 = 55,
+  MUL_HS_LU_RRR_0_OPCODE_X0 = 56,
+  MUL_HU_HU_RRR_0_OPCODE_X0 = 57,
+  MUL_HU_HU_RRR_8_OPCODE_Y0 = 1,
+  MUL_HU_LS_RRR_0_OPCODE_X0 = 58,
+  MUL_HU_LU_RRR_0_OPCODE_X0 = 59,
+  MUL_LS_LS_RRR_0_OPCODE_X0 = 60,
+  MUL_LS_LS_RRR_8_OPCODE_Y0 = 2,
+  MUL_LS_LU_RRR_0_OPCODE_X0 = 61,
+  MUL_LU_LU_RRR_0_OPCODE_X0 = 62,
+  MUL_LU_LU_RRR_8_OPCODE_Y0 = 3,
+  MZ_RRR_0_OPCODE_X0 = 63,
+  MZ_RRR_0_OPCODE_X1 = 27,
+  MZ_RRR_4_OPCODE_Y0 = 3,
+  MZ_RRR_4_OPCODE_Y1 = 3,
+  NAP_UNARY_OPCODE_X1 = 32,
+  NOP_UNARY_OPCODE_X0 = 5,
+  NOP_UNARY_OPCODE_X1 = 33,
+  NOP_UNARY_OPCODE_Y0 = 5,
+  NOP_UNARY_OPCODE_Y1 = 15,
+  NOR_RRR_0_OPCODE_X0 = 64,
+  NOR_RRR_0_OPCODE_X1 = 28,
+  NOR_RRR_5_OPCODE_Y0 = 1,
+  NOR_RRR_5_OPCODE_Y1 = 1,
+  ORI_IMM8_OPCODE_X0 = 7,
+  ORI_IMM8_OPCODE_X1 = 24,
+  OR_RRR_0_OPCODE_X0 = 65,
+  OR_RRR_0_OPCODE_X1 = 29,
+  OR_RRR_5_OPCODE_Y0 = 2,
+  OR_RRR_5_OPCODE_Y1 = 2,
+  PCNT_UNARY_OPCODE_X0 = 6,
+  PCNT_UNARY_OPCODE_Y0 = 6,
+  REVBITS_UNARY_OPCODE_X0 = 7,
+  REVBITS_UNARY_OPCODE_Y0 = 7,
+  REVBYTES_UNARY_OPCODE_X0 = 8,
+  REVBYTES_UNARY_OPCODE_Y0 = 8,
+  ROTLI_SHIFT_OPCODE_X0 = 1,
+  ROTLI_SHIFT_OPCODE_X1 = 1,
+  ROTLI_SHIFT_OPCODE_Y0 = 0,
+  ROTLI_SHIFT_OPCODE_Y1 = 0,
+  ROTL_RRR_0_OPCODE_X0 = 66,
+  ROTL_RRR_0_OPCODE_X1 = 30,
+  ROTL_RRR_6_OPCODE_Y0 = 0,
+  ROTL_RRR_6_OPCODE_Y1 = 0,
+  RRR_0_OPCODE_X0 = 5,
+  RRR_0_OPCODE_X1 = 5,
+  RRR_0_OPCODE_Y0 = 5,
+  RRR_0_OPCODE_Y1 = 6,
+  RRR_1_OPCODE_Y0 = 6,
+  RRR_1_OPCODE_Y1 = 7,
+  RRR_2_OPCODE_Y0 = 7,
+  RRR_2_OPCODE_Y1 = 8,
+  RRR_3_OPCODE_Y0 = 8,
+  RRR_3_OPCODE_Y1 = 9,
+  RRR_4_OPCODE_Y0 = 9,
+  RRR_4_OPCODE_Y1 = 10,
+  RRR_5_OPCODE_Y0 = 10,
+  RRR_5_OPCODE_Y1 = 11,
+  RRR_6_OPCODE_Y0 = 11,
+  RRR_6_OPCODE_Y1 = 12,
+  RRR_7_OPCODE_Y0 = 12,
+  RRR_7_OPCODE_Y1 = 13,
+  RRR_8_OPCODE_Y0 = 13,
+  RRR_9_OPCODE_Y0 = 14,
+  SHIFT_OPCODE_X0 = 6,
+  SHIFT_OPCODE_X1 = 6,
+  SHIFT_OPCODE_Y0 = 15,
+  SHIFT_OPCODE_Y1 = 14,
+  SHL16INSLI_OPCODE_X0 = 7,
+  SHL16INSLI_OPCODE_X1 = 7,
+  SHL1ADDX_RRR_0_OPCODE_X0 = 67,
+  SHL1ADDX_RRR_0_OPCODE_X1 = 31,
+  SHL1ADDX_RRR_7_OPCODE_Y0 = 1,
+  SHL1ADDX_RRR_7_OPCODE_Y1 = 1,
+  SHL1ADD_RRR_0_OPCODE_X0 = 68,
+  SHL1ADD_RRR_0_OPCODE_X1 = 32,
+  SHL1ADD_RRR_1_OPCODE_Y0 = 0,
+  SHL1ADD_RRR_1_OPCODE_Y1 = 0,
+  SHL2ADDX_RRR_0_OPCODE_X0 = 69,
+  SHL2ADDX_RRR_0_OPCODE_X1 = 33,
+  SHL2ADDX_RRR_7_OPCODE_Y0 = 2,
+  SHL2ADDX_RRR_7_OPCODE_Y1 = 2,
+  SHL2ADD_RRR_0_OPCODE_X0 = 70,
+  SHL2ADD_RRR_0_OPCODE_X1 = 34,
+  SHL2ADD_RRR_1_OPCODE_Y0 = 1,
+  SHL2ADD_RRR_1_OPCODE_Y1 = 1,
+  SHL3ADDX_RRR_0_OPCODE_X0 = 71,
+  SHL3ADDX_RRR_0_OPCODE_X1 = 35,
+  SHL3ADDX_RRR_7_OPCODE_Y0 = 3,
+  SHL3ADDX_RRR_7_OPCODE_Y1 = 3,
+  SHL3ADD_RRR_0_OPCODE_X0 = 72,
+  SHL3ADD_RRR_0_OPCODE_X1 = 36,
+  SHL3ADD_RRR_1_OPCODE_Y0 = 2,
+  SHL3ADD_RRR_1_OPCODE_Y1 = 2,
+  SHLI_SHIFT_OPCODE_X0 = 2,
+  SHLI_SHIFT_OPCODE_X1 = 2,
+  SHLI_SHIFT_OPCODE_Y0 = 1,
+  SHLI_SHIFT_OPCODE_Y1 = 1,
+  SHLXI_SHIFT_OPCODE_X0 = 3,
+  SHLXI_SHIFT_OPCODE_X1 = 3,
+  SHLX_RRR_0_OPCODE_X0 = 73,
+  SHLX_RRR_0_OPCODE_X1 = 37,
+  SHL_RRR_0_OPCODE_X0 = 74,
+  SHL_RRR_0_OPCODE_X1 = 38,
+  SHL_RRR_6_OPCODE_Y0 = 1,
+  SHL_RRR_6_OPCODE_Y1 = 1,
+  SHRSI_SHIFT_OPCODE_X0 = 4,
+  SHRSI_SHIFT_OPCODE_X1 = 4,
+  SHRSI_SHIFT_OPCODE_Y0 = 2,
+  SHRSI_SHIFT_OPCODE_Y1 = 2,
+  SHRS_RRR_0_OPCODE_X0 = 75,
+  SHRS_RRR_0_OPCODE_X1 = 39,
+  SHRS_RRR_6_OPCODE_Y0 = 2,
+  SHRS_RRR_6_OPCODE_Y1 = 2,
+  SHRUI_SHIFT_OPCODE_X0 = 5,
+  SHRUI_SHIFT_OPCODE_X1 = 5,
+  SHRUI_SHIFT_OPCODE_Y0 = 3,
+  SHRUI_SHIFT_OPCODE_Y1 = 3,
+  SHRUXI_SHIFT_OPCODE_X0 = 6,
+  SHRUXI_SHIFT_OPCODE_X1 = 6,
+  SHRUX_RRR_0_OPCODE_X0 = 76,
+  SHRUX_RRR_0_OPCODE_X1 = 40,
+  SHRU_RRR_0_OPCODE_X0 = 77,
+  SHRU_RRR_0_OPCODE_X1 = 41,
+  SHRU_RRR_6_OPCODE_Y0 = 3,
+  SHRU_RRR_6_OPCODE_Y1 = 3,
+  SHUFFLEBYTES_RRR_0_OPCODE_X0 = 78,
+  ST1_ADD_IMM8_OPCODE_X1 = 25,
+  ST1_OPCODE_Y2 = 0,
+  ST1_RRR_0_OPCODE_X1 = 42,
+  ST2_ADD_IMM8_OPCODE_X1 = 26,
+  ST2_OPCODE_Y2 = 1,
+  ST2_RRR_0_OPCODE_X1 = 43,
+  ST4_ADD_IMM8_OPCODE_X1 = 27,
+  ST4_OPCODE_Y2 = 2,
+  ST4_RRR_0_OPCODE_X1 = 44,
+  STNT1_ADD_IMM8_OPCODE_X1 = 28,
+  STNT1_RRR_0_OPCODE_X1 = 45,
+  STNT2_ADD_IMM8_OPCODE_X1 = 29,
+  STNT2_RRR_0_OPCODE_X1 = 46,
+  STNT4_ADD_IMM8_OPCODE_X1 = 30,
+  STNT4_RRR_0_OPCODE_X1 = 47,
+  STNT_ADD_IMM8_OPCODE_X1 = 31,
+  STNT_RRR_0_OPCODE_X1 = 48,
+  ST_ADD_IMM8_OPCODE_X1 = 32,
+  ST_OPCODE_Y2 = 3,
+  ST_RRR_0_OPCODE_X1 = 49,
+  SUBXSC_RRR_0_OPCODE_X0 = 79,
+  SUBXSC_RRR_0_OPCODE_X1 = 50,
+  SUBX_RRR_0_OPCODE_X0 = 80,
+  SUBX_RRR_0_OPCODE_X1 = 51,
+  SUBX_RRR_0_OPCODE_Y0 = 2,
+  SUBX_RRR_0_OPCODE_Y1 = 2,
+  SUB_RRR_0_OPCODE_X0 = 81,
+  SUB_RRR_0_OPCODE_X1 = 52,
+  SUB_RRR_0_OPCODE_Y0 = 3,
+  SUB_RRR_0_OPCODE_Y1 = 3,
+  SWINT0_UNARY_OPCODE_X1 = 34,
+  SWINT1_UNARY_OPCODE_X1 = 35,
+  SWINT2_UNARY_OPCODE_X1 = 36,
+  SWINT3_UNARY_OPCODE_X1 = 37,
+  TBLIDXB0_UNARY_OPCODE_X0 = 9,
+  TBLIDXB0_UNARY_OPCODE_Y0 = 9,
+  TBLIDXB1_UNARY_OPCODE_X0 = 10,
+  TBLIDXB1_UNARY_OPCODE_Y0 = 10,
+  TBLIDXB2_UNARY_OPCODE_X0 = 11,
+  TBLIDXB2_UNARY_OPCODE_Y0 = 11,
+  TBLIDXB3_UNARY_OPCODE_X0 = 12,
+  TBLIDXB3_UNARY_OPCODE_Y0 = 12,
+  UNARY_RRR_0_OPCODE_X0 = 82,
+  UNARY_RRR_0_OPCODE_X1 = 53,
+  UNARY_RRR_1_OPCODE_Y0 = 3,
+  UNARY_RRR_1_OPCODE_Y1 = 3,
+  V1ADDI_IMM8_OPCODE_X0 = 8,
+  V1ADDI_IMM8_OPCODE_X1 = 33,
+  V1ADDUC_RRR_0_OPCODE_X0 = 83,
+  V1ADDUC_RRR_0_OPCODE_X1 = 54,
+  V1ADD_RRR_0_OPCODE_X0 = 84,
+  V1ADD_RRR_0_OPCODE_X1 = 55,
+  V1ADIFFU_RRR_0_OPCODE_X0 = 85,
+  V1AVGU_RRR_0_OPCODE_X0 = 86,
+  V1CMPEQI_IMM8_OPCODE_X0 = 9,
+  V1CMPEQI_IMM8_OPCODE_X1 = 34,
+  V1CMPEQ_RRR_0_OPCODE_X0 = 87,
+  V1CMPEQ_RRR_0_OPCODE_X1 = 56,
+  V1CMPLES_RRR_0_OPCODE_X0 = 88,
+  V1CMPLES_RRR_0_OPCODE_X1 = 57,
+  V1CMPLEU_RRR_0_OPCODE_X0 = 89,
+  V1CMPLEU_RRR_0_OPCODE_X1 = 58,
+  V1CMPLTSI_IMM8_OPCODE_X0 = 10,
+  V1CMPLTSI_IMM8_OPCODE_X1 = 35,
+  V1CMPLTS_RRR_0_OPCODE_X0 = 90,
+  V1CMPLTS_RRR_0_OPCODE_X1 = 59,
+  V1CMPLTUI_IMM8_OPCODE_X0 = 11,
+  V1CMPLTUI_IMM8_OPCODE_X1 = 36,
+  V1CMPLTU_RRR_0_OPCODE_X0 = 91,
+  V1CMPLTU_RRR_0_OPCODE_X1 = 60,
+  V1CMPNE_RRR_0_OPCODE_X0 = 92,
+  V1CMPNE_RRR_0_OPCODE_X1 = 61,
+  V1DDOTPUA_RRR_0_OPCODE_X0 = 161,
+  V1DDOTPUSA_RRR_0_OPCODE_X0 = 93,
+  V1DDOTPUS_RRR_0_OPCODE_X0 = 94,
+  V1DDOTPU_RRR_0_OPCODE_X0 = 162,
+  V1DOTPA_RRR_0_OPCODE_X0 = 95,
+  V1DOTPUA_RRR_0_OPCODE_X0 = 163,
+  V1DOTPUSA_RRR_0_OPCODE_X0 = 96,
+  V1DOTPUS_RRR_0_OPCODE_X0 = 97,
+  V1DOTPU_RRR_0_OPCODE_X0 = 164,
+  V1DOTP_RRR_0_OPCODE_X0 = 98,
+  V1INT_H_RRR_0_OPCODE_X0 = 99,
+  V1INT_H_RRR_0_OPCODE_X1 = 62,
+  V1INT_L_RRR_0_OPCODE_X0 = 100,
+  V1INT_L_RRR_0_OPCODE_X1 = 63,
+  V1MAXUI_IMM8_OPCODE_X0 = 12,
+  V1MAXUI_IMM8_OPCODE_X1 = 37,
+  V1MAXU_RRR_0_OPCODE_X0 = 101,
+  V1MAXU_RRR_0_OPCODE_X1 = 64,
+  V1MINUI_IMM8_OPCODE_X0 = 13,
+  V1MINUI_IMM8_OPCODE_X1 = 38,
+  V1MINU_RRR_0_OPCODE_X0 = 102,
+  V1MINU_RRR_0_OPCODE_X1 = 65,
+  V1MNZ_RRR_0_OPCODE_X0 = 103,
+  V1MNZ_RRR_0_OPCODE_X1 = 66,
+  V1MULTU_RRR_0_OPCODE_X0 = 104,
+  V1MULUS_RRR_0_OPCODE_X0 = 105,
+  V1MULU_RRR_0_OPCODE_X0 = 106,
+  V1MZ_RRR_0_OPCODE_X0 = 107,
+  V1MZ_RRR_0_OPCODE_X1 = 67,
+  V1SADAU_RRR_0_OPCODE_X0 = 108,
+  V1SADU_RRR_0_OPCODE_X0 = 109,
+  V1SHLI_SHIFT_OPCODE_X0 = 7,
+  V1SHLI_SHIFT_OPCODE_X1 = 7,
+  V1SHL_RRR_0_OPCODE_X0 = 110,
+  V1SHL_RRR_0_OPCODE_X1 = 68,
+  V1SHRSI_SHIFT_OPCODE_X0 = 8,
+  V1SHRSI_SHIFT_OPCODE_X1 = 8,
+  V1SHRS_RRR_0_OPCODE_X0 = 111,
+  V1SHRS_RRR_0_OPCODE_X1 = 69,
+  V1SHRUI_SHIFT_OPCODE_X0 = 9,
+  V1SHRUI_SHIFT_OPCODE_X1 = 9,
+  V1SHRU_RRR_0_OPCODE_X0 = 112,
+  V1SHRU_RRR_0_OPCODE_X1 = 70,
+  V1SUBUC_RRR_0_OPCODE_X0 = 113,
+  V1SUBUC_RRR_0_OPCODE_X1 = 71,
+  V1SUB_RRR_0_OPCODE_X0 = 114,
+  V1SUB_RRR_0_OPCODE_X1 = 72,
+  V2ADDI_IMM8_OPCODE_X0 = 14,
+  V2ADDI_IMM8_OPCODE_X1 = 39,
+  V2ADDSC_RRR_0_OPCODE_X0 = 115,
+  V2ADDSC_RRR_0_OPCODE_X1 = 73,
+  V2ADD_RRR_0_OPCODE_X0 = 116,
+  V2ADD_RRR_0_OPCODE_X1 = 74,
+  V2ADIFFS_RRR_0_OPCODE_X0 = 117,
+  V2AVGS_RRR_0_OPCODE_X0 = 118,
+  V2CMPEQI_IMM8_OPCODE_X0 = 15,
+  V2CMPEQI_IMM8_OPCODE_X1 = 40,
+  V2CMPEQ_RRR_0_OPCODE_X0 = 119,
+  V2CMPEQ_RRR_0_OPCODE_X1 = 75,
+  V2CMPLES_RRR_0_OPCODE_X0 = 120,
+  V2CMPLES_RRR_0_OPCODE_X1 = 76,
+  V2CMPLEU_RRR_0_OPCODE_X0 = 121,
+  V2CMPLEU_RRR_0_OPCODE_X1 = 77,
+  V2CMPLTSI_IMM8_OPCODE_X0 = 16,
+  V2CMPLTSI_IMM8_OPCODE_X1 = 41,
+  V2CMPLTS_RRR_0_OPCODE_X0 = 122,
+  V2CMPLTS_RRR_0_OPCODE_X1 = 78,
+  V2CMPLTUI_IMM8_OPCODE_X0 = 17,
+  V2CMPLTUI_IMM8_OPCODE_X1 = 42,
+  V2CMPLTU_RRR_0_OPCODE_X0 = 123,
+  V2CMPLTU_RRR_0_OPCODE_X1 = 79,
+  V2CMPNE_RRR_0_OPCODE_X0 = 124,
+  V2CMPNE_RRR_0_OPCODE_X1 = 80,
+  V2DOTPA_RRR_0_OPCODE_X0 = 125,
+  V2DOTP_RRR_0_OPCODE_X0 = 126,
+  V2INT_H_RRR_0_OPCODE_X0 = 127,
+  V2INT_H_RRR_0_OPCODE_X1 = 81,
+  V2INT_L_RRR_0_OPCODE_X0 = 128,
+  V2INT_L_RRR_0_OPCODE_X1 = 82,
+  V2MAXSI_IMM8_OPCODE_X0 = 18,
+  V2MAXSI_IMM8_OPCODE_X1 = 43,
+  V2MAXS_RRR_0_OPCODE_X0 = 129,
+  V2MAXS_RRR_0_OPCODE_X1 = 83,
+  V2MINSI_IMM8_OPCODE_X0 = 19,
+  V2MINSI_IMM8_OPCODE_X1 = 44,
+  V2MINS_RRR_0_OPCODE_X0 = 130,
+  V2MINS_RRR_0_OPCODE_X1 = 84,
+  V2MNZ_RRR_0_OPCODE_X0 = 131,
+  V2MNZ_RRR_0_OPCODE_X1 = 85,
+  V2MULFSC_RRR_0_OPCODE_X0 = 132,
+  V2MULS_RRR_0_OPCODE_X0 = 133,
+  V2MULTS_RRR_0_OPCODE_X0 = 134,
+  V2MZ_RRR_0_OPCODE_X0 = 135,
+  V2MZ_RRR_0_OPCODE_X1 = 86,
+  V2PACKH_RRR_0_OPCODE_X0 = 136,
+  V2PACKH_RRR_0_OPCODE_X1 = 87,
+  V2PACKL_RRR_0_OPCODE_X0 = 137,
+  V2PACKL_RRR_0_OPCODE_X1 = 88,
+  V2PACKUC_RRR_0_OPCODE_X0 = 138,
+  V2PACKUC_RRR_0_OPCODE_X1 = 89,
+  V2SADAS_RRR_0_OPCODE_X0 = 139,
+  V2SADAU_RRR_0_OPCODE_X0 = 140,
+  V2SADS_RRR_0_OPCODE_X0 = 141,
+  V2SADU_RRR_0_OPCODE_X0 = 142,
+  V2SHLI_SHIFT_OPCODE_X0 = 10,
+  V2SHLI_SHIFT_OPCODE_X1 = 10,
+  V2SHLSC_RRR_0_OPCODE_X0 = 143,
+  V2SHLSC_RRR_0_OPCODE_X1 = 90,
+  V2SHL_RRR_0_OPCODE_X0 = 144,
+  V2SHL_RRR_0_OPCODE_X1 = 91,
+  V2SHRSI_SHIFT_OPCODE_X0 = 11,
+  V2SHRSI_SHIFT_OPCODE_X1 = 11,
+  V2SHRS_RRR_0_OPCODE_X0 = 145,
+  V2SHRS_RRR_0_OPCODE_X1 = 92,
+  V2SHRUI_SHIFT_OPCODE_X0 = 12,
+  V2SHRUI_SHIFT_OPCODE_X1 = 12,
+  V2SHRU_RRR_0_OPCODE_X0 = 146,
+  V2SHRU_RRR_0_OPCODE_X1 = 93,
+  V2SUBSC_RRR_0_OPCODE_X0 = 147,
+  V2SUBSC_RRR_0_OPCODE_X1 = 94,
+  V2SUB_RRR_0_OPCODE_X0 = 148,
+  V2SUB_RRR_0_OPCODE_X1 = 95,
+  V4ADDSC_RRR_0_OPCODE_X0 = 149,
+  V4ADDSC_RRR_0_OPCODE_X1 = 96,
+  V4ADD_RRR_0_OPCODE_X0 = 150,
+  V4ADD_RRR_0_OPCODE_X1 = 97,
+  V4INT_H_RRR_0_OPCODE_X0 = 151,
+  V4INT_H_RRR_0_OPCODE_X1 = 98,
+  V4INT_L_RRR_0_OPCODE_X0 = 152,
+  V4INT_L_RRR_0_OPCODE_X1 = 99,
+  V4PACKSC_RRR_0_OPCODE_X0 = 153,
+  V4PACKSC_RRR_0_OPCODE_X1 = 100,
+  V4SHLSC_RRR_0_OPCODE_X0 = 154,
+  V4SHLSC_RRR_0_OPCODE_X1 = 101,
+  V4SHL_RRR_0_OPCODE_X0 = 155,
+  V4SHL_RRR_0_OPCODE_X1 = 102,
+  V4SHRS_RRR_0_OPCODE_X0 = 156,
+  V4SHRS_RRR_0_OPCODE_X1 = 103,
+  V4SHRU_RRR_0_OPCODE_X0 = 157,
+  V4SHRU_RRR_0_OPCODE_X1 = 104,
+  V4SUBSC_RRR_0_OPCODE_X0 = 158,
+  V4SUBSC_RRR_0_OPCODE_X1 = 105,
+  V4SUB_RRR_0_OPCODE_X0 = 159,
+  V4SUB_RRR_0_OPCODE_X1 = 106,
+  WH64_UNARY_OPCODE_X1 = 38,
+  XORI_IMM8_OPCODE_X0 = 20,
+  XORI_IMM8_OPCODE_X1 = 45,
+  XOR_RRR_0_OPCODE_X0 = 160,
+  XOR_RRR_0_OPCODE_X1 = 107,
+  XOR_RRR_5_OPCODE_Y0 = 3,
+  XOR_RRR_5_OPCODE_Y1 = 3
+};
+
+static __inline unsigned int
+get_BFEnd_X0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 12)) & 0x3f);
+}
+
+static __inline unsigned int
+get_BFOpcodeExtension_X0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 24)) & 0xf);
+}
+
+static __inline unsigned int
+get_BFStart_X0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 18)) & 0x3f);
+}
+
+static __inline unsigned int
+get_BrOff_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 31)) & 0x0000003f) |
+         (((unsigned int)(n >> 37)) & 0x0001ffc0);
+}
+
+static __inline unsigned int
+get_BrType_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 54)) & 0x1f);
+}
+
+static __inline unsigned int
+get_Dest_Imm8_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 31)) & 0x0000003f) |
+         (((unsigned int)(n >> 43)) & 0x000000c0);
+}
+
+static __inline unsigned int
+get_Dest_X0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 0)) & 0x3f);
+}
+
+static __inline unsigned int
+get_Dest_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 31)) & 0x3f);
+}
+
+static __inline unsigned int
+get_Dest_Y0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 0)) & 0x3f);
+}
+
+static __inline unsigned int
+get_Dest_Y1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 31)) & 0x3f);
+}
+
+static __inline unsigned int
+get_Imm16_X0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 12)) & 0xffff);
+}
+
+static __inline unsigned int
+get_Imm16_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 43)) & 0xffff);
+}
+
+static __inline unsigned int
+get_Imm8OpcodeExtension_X0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 20)) & 0xff);
+}
+
+static __inline unsigned int
+get_Imm8OpcodeExtension_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 51)) & 0xff);
+}
+
+static __inline unsigned int
+get_Imm8_X0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 12)) & 0xff);
+}
+
+static __inline unsigned int
+get_Imm8_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 43)) & 0xff);
+}
+
+static __inline unsigned int
+get_Imm8_Y0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 12)) & 0xff);
+}
+
+static __inline unsigned int
+get_Imm8_Y1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 43)) & 0xff);
+}
+
+static __inline unsigned int
+get_JumpOff_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 31)) & 0x7ffffff);
+}
+
+static __inline unsigned int
+get_JumpOpcodeExtension_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 58)) & 0x1);
+}
+
+static __inline unsigned int
+get_MF_Imm14_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 37)) & 0x3fff);
+}
+
+static __inline unsigned int
+get_MT_Imm14_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 31)) & 0x0000003f) |
+         (((unsigned int)(n >> 37)) & 0x00003fc0);
+}
+
+static __inline unsigned int
+get_Mode(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 62)) & 0x3);
+}
+
+static __inline unsigned int
+get_Opcode_X0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 28)) & 0x7);
+}
+
+static __inline unsigned int
+get_Opcode_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 59)) & 0x7);
+}
+
+static __inline unsigned int
+get_Opcode_Y0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 27)) & 0xf);
+}
+
+static __inline unsigned int
+get_Opcode_Y1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 58)) & 0xf);
+}
+
+static __inline unsigned int
+get_Opcode_Y2(tilegx_bundle_bits n)
+{
+  return (((n >> 26)) & 0x00000001) |
+         (((unsigned int)(n >> 56)) & 0x00000002);
+}
+
+static __inline unsigned int
+get_RRROpcodeExtension_X0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 18)) & 0x3ff);
+}
+
+static __inline unsigned int
+get_RRROpcodeExtension_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 49)) & 0x3ff);
+}
+
+static __inline unsigned int
+get_RRROpcodeExtension_Y0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 18)) & 0x3);
+}
+
+static __inline unsigned int
+get_RRROpcodeExtension_Y1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 49)) & 0x3);
+}
+
+static __inline unsigned int
+get_ShAmt_X0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 12)) & 0x3f);
+}
+
+static __inline unsigned int
+get_ShAmt_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 43)) & 0x3f);
+}
+
+static __inline unsigned int
+get_ShAmt_Y0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 12)) & 0x3f);
+}
+
+static __inline unsigned int
+get_ShAmt_Y1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 43)) & 0x3f);
+}
+
+static __inline unsigned int
+get_ShiftOpcodeExtension_X0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 18)) & 0x3ff);
+}
+
+static __inline unsigned int
+get_ShiftOpcodeExtension_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 49)) & 0x3ff);
+}
+
+static __inline unsigned int
+get_ShiftOpcodeExtension_Y0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 18)) & 0x3);
+}
+
+static __inline unsigned int
+get_ShiftOpcodeExtension_Y1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 49)) & 0x3);
+}
+
+static __inline unsigned int
+get_SrcA_X0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 6)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcA_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 37)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcA_Y0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 6)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcA_Y1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 37)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcA_Y2(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 20)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcBDest_Y2(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 51)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcB_X0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 12)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcB_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 43)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcB_Y0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 12)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcB_Y1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 43)) & 0x3f);
+}
+
+static __inline unsigned int
+get_UnaryOpcodeExtension_X0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 12)) & 0x3f);
+}
+
+static __inline unsigned int
+get_UnaryOpcodeExtension_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 43)) & 0x3f);
+}
+
+static __inline unsigned int
+get_UnaryOpcodeExtension_Y0(tilegx_bundle_bits num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 12)) & 0x3f);
+}
+
+static __inline unsigned int
+get_UnaryOpcodeExtension_Y1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 43)) & 0x3f);
+}
+
+static __inline int
+sign_extend(int n, int num_bits)
+{
+  int shift = (int)(sizeof(int) * 8 - num_bits);
+  return (n << shift) >> shift;
+}
+
+static __inline tilegx_bundle_bits
+create_BFEnd_X0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x3f) << 12);
+}
+
+static __inline tilegx_bundle_bits
+create_BFOpcodeExtension_X0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0xf) << 24);
+}
+
+static __inline tilegx_bundle_bits
+create_BFStart_X0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x3f) << 18);
+}
+
+static __inline tilegx_bundle_bits
+create_BrOff_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) |
+         (((tilegx_bundle_bits)(n & 0x0001ffc0)) << 37);
+}
+
+static __inline tilegx_bundle_bits
+create_BrType_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x1f)) << 54);
+}
+
+static __inline tilegx_bundle_bits
+create_Dest_Imm8_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) |
+         (((tilegx_bundle_bits)(n & 0x000000c0)) << 43);
+}
+
+static __inline tilegx_bundle_bits
+create_Dest_X0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x3f) << 0);
+}
+
+static __inline tilegx_bundle_bits
+create_Dest_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 31);
+}
+
+static __inline tilegx_bundle_bits
+create_Dest_Y0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x3f) << 0);
+}
+
+static __inline tilegx_bundle_bits
+create_Dest_Y1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 31);
+}
+
+static __inline tilegx_bundle_bits
+create_Imm16_X0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0xffff) << 12);
+}
+
+static __inline tilegx_bundle_bits
+create_Imm16_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0xffff)) << 43);
+}
+
+static __inline tilegx_bundle_bits
+create_Imm8OpcodeExtension_X0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0xff) << 20);
+}
+
+static __inline tilegx_bundle_bits
+create_Imm8OpcodeExtension_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0xff)) << 51);
+}
+
+static __inline tilegx_bundle_bits
+create_Imm8_X0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0xff) << 12);
+}
+
+static __inline tilegx_bundle_bits
+create_Imm8_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0xff)) << 43);
+}
+
+static __inline tilegx_bundle_bits
+create_Imm8_Y0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0xff) << 12);
+}
+
+static __inline tilegx_bundle_bits
+create_Imm8_Y1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0xff)) << 43);
+}
+
+static __inline tilegx_bundle_bits
+create_JumpOff_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x7ffffff)) << 31);
+}
+
+static __inline tilegx_bundle_bits
+create_JumpOpcodeExtension_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x1)) << 58);
+}
+
+static __inline tilegx_bundle_bits
+create_MF_Imm14_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3fff)) << 37);
+}
+
+static __inline tilegx_bundle_bits
+create_MT_Imm14_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) |
+         (((tilegx_bundle_bits)(n & 0x00003fc0)) << 37);
+}
+
+static __inline tilegx_bundle_bits
+create_Mode(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3)) << 62);
+}
+
+static __inline tilegx_bundle_bits
+create_Opcode_X0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x7) << 28);
+}
+
+static __inline tilegx_bundle_bits
+create_Opcode_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x7)) << 59);
+}
+
+static __inline tilegx_bundle_bits
+create_Opcode_Y0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0xf) << 27);
+}
+
+static __inline tilegx_bundle_bits
+create_Opcode_Y1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0xf)) << 58);
+}
+
+static __inline tilegx_bundle_bits
+create_Opcode_Y2(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x00000001) << 26) |
+         (((tilegx_bundle_bits)(n & 0x00000002)) << 56);
+}
+
+static __inline tilegx_bundle_bits
+create_RRROpcodeExtension_X0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x3ff) << 18);
+}
+
+static __inline tilegx_bundle_bits
+create_RRROpcodeExtension_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3ff)) << 49);
+}
+
+static __inline tilegx_bundle_bits
+create_RRROpcodeExtension_Y0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x3) << 18);
+}
+
+static __inline tilegx_bundle_bits
+create_RRROpcodeExtension_Y1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3)) << 49);
+}
+
+static __inline tilegx_bundle_bits
+create_ShAmt_X0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x3f) << 12);
+}
+
+static __inline tilegx_bundle_bits
+create_ShAmt_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
+}
+
+static __inline tilegx_bundle_bits
+create_ShAmt_Y0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x3f) << 12);
+}
+
+static __inline tilegx_bundle_bits
+create_ShAmt_Y1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
+}
+
+static __inline tilegx_bundle_bits
+create_ShiftOpcodeExtension_X0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x3ff) << 18);
+}
+
+static __inline tilegx_bundle_bits
+create_ShiftOpcodeExtension_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3ff)) << 49);
+}
+
+static __inline tilegx_bundle_bits
+create_ShiftOpcodeExtension_Y0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x3) << 18);
+}
+
+static __inline tilegx_bundle_bits
+create_ShiftOpcodeExtension_Y1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3)) << 49);
+}
+
+static __inline tilegx_bundle_bits
+create_SrcA_X0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x3f) << 6);
+}
+
+static __inline tilegx_bundle_bits
+create_SrcA_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 37);
+}
+
+static __inline tilegx_bundle_bits
+create_SrcA_Y0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x3f) << 6);
+}
+
+static __inline tilegx_bundle_bits
+create_SrcA_Y1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 37);
+}
+
+static __inline tilegx_bundle_bits
+create_SrcA_Y2(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x3f) << 20);
+}
+
+static __inline tilegx_bundle_bits
+create_SrcBDest_Y2(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 51);
+}
+
+static __inline tilegx_bundle_bits
+create_SrcB_X0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x3f) << 12);
+}
+
+static __inline tilegx_bundle_bits
+create_SrcB_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
+}
+
+static __inline tilegx_bundle_bits
+create_SrcB_Y0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x3f) << 12);
+}
+
+static __inline tilegx_bundle_bits
+create_SrcB_Y1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
+}
+
+static __inline tilegx_bundle_bits
+create_UnaryOpcodeExtension_X0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x3f) << 12);
+}
+
+static __inline tilegx_bundle_bits
+create_UnaryOpcodeExtension_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
+}
+
+static __inline tilegx_bundle_bits
+create_UnaryOpcodeExtension_Y0(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return ((n & 0x3f) << 12);
+}
+
+static __inline tilegx_bundle_bits
+create_UnaryOpcodeExtension_Y1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
+}
+
+const struct tilegx_opcode tilegx_opcodes[336] =
+{
+ { "bpt", TILEGX_OPC_BPT, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffffffff80000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286a44ae00000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "info", TILEGX_OPC_INFO, 0xf, 1, TREG_ZERO, 1,
+    { { 0 }, { 1 }, { 2 }, { 3 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00fffULL,
+      0xfff807ff80000000ULL,
+      0x0000000078000fffULL,
+      0x3c0007ff80000000ULL,
+      0ULL
+    },
+    {
+      0x0000000040300fffULL,
+      0x181807ff80000000ULL,
+      0x0000000010000fffULL,
+      0x0c0007ff80000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "infol", TILEGX_OPC_INFOL, 0x3, 1, TREG_ZERO, 1,
+    { { 4 }, { 5 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc000000070000fffULL,
+      0xf80007ff80000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000070000fffULL,
+      0x380007ff80000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ld4s_tls", TILEGX_OPC_LD4S_TLS, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 7, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1858000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ld_tls", TILEGX_OPC_LD_TLS, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 7, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x18a0000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "move", TILEGX_OPC_MOVE, 0xf, 2, TREG_ZERO, 1,
+    { { 8, 9 }, { 6, 7 }, { 10, 11 }, { 12, 13 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffff000ULL,
+      0xfffff80000000000ULL,
+      0x00000000780ff000ULL,
+      0x3c07f80000000000ULL,
+      0ULL
+    },
+    {
+      0x000000005107f000ULL,
+      0x283bf80000000000ULL,
+      0x00000000500bf000ULL,
+      0x2c05f80000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "movei", TILEGX_OPC_MOVEI, 0xf, 2, TREG_ZERO, 1,
+    { { 8, 0 }, { 6, 1 }, { 10, 2 }, { 12, 3 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00fc0ULL,
+      0xfff807e000000000ULL,
+      0x0000000078000fc0ULL,
+      0x3c0007e000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000040100fc0ULL,
+      0x180807e000000000ULL,
+      0x0000000000000fc0ULL,
+      0x040007e000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "moveli", TILEGX_OPC_MOVELI, 0x3, 2, TREG_ZERO, 1,
+    { { 8, 4 }, { 6, 5 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc000000070000fc0ULL,
+      0xf80007e000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000010000fc0ULL,
+      0x000007e000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "prefetch", TILEGX_OPC_PREFETCH, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 7 }, { 0, }, { 0, }, { 14 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff81f80000000ULL,
+      0ULL,
+      0ULL,
+      0xc3f8000004000000ULL
+    },
+    {
+      -1ULL,
+      0x286a801f80000000ULL,
+      -1ULL,
+      -1ULL,
+      0x41f8000004000000ULL
+    }
+#endif
+  },
+  { "prefetch_add_l1", TILEGX_OPC_PREFETCH_ADD_L1, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8001f80000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1840001f80000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "prefetch_add_l1_fault", TILEGX_OPC_PREFETCH_ADD_L1_FAULT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8001f80000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1838001f80000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "prefetch_add_l2", TILEGX_OPC_PREFETCH_ADD_L2, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8001f80000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1850001f80000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "prefetch_add_l2_fault", TILEGX_OPC_PREFETCH_ADD_L2_FAULT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8001f80000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1848001f80000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "prefetch_add_l3", TILEGX_OPC_PREFETCH_ADD_L3, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8001f80000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1860001f80000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "prefetch_add_l3_fault", TILEGX_OPC_PREFETCH_ADD_L3_FAULT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8001f80000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1858001f80000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "prefetch_l1", TILEGX_OPC_PREFETCH_L1, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 7 }, { 0, }, { 0, }, { 14 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff81f80000000ULL,
+      0ULL,
+      0ULL,
+      0xc3f8000004000000ULL
+    },
+    {
+      -1ULL,
+      0x286a801f80000000ULL,
+      -1ULL,
+      -1ULL,
+      0x41f8000004000000ULL
+    }
+#endif
+  },
+  { "prefetch_l1_fault", TILEGX_OPC_PREFETCH_L1_FAULT, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 7 }, { 0, }, { 0, }, { 14 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff81f80000000ULL,
+      0ULL,
+      0ULL,
+      0xc3f8000004000000ULL
+    },
+    {
+      -1ULL,
+      0x286a781f80000000ULL,
+      -1ULL,
+      -1ULL,
+      0x41f8000000000000ULL
+    }
+#endif
+  },
+  { "prefetch_l2", TILEGX_OPC_PREFETCH_L2, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 7 }, { 0, }, { 0, }, { 14 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff81f80000000ULL,
+      0ULL,
+      0ULL,
+      0xc3f8000004000000ULL
+    },
+    {
+      -1ULL,
+      0x286a901f80000000ULL,
+      -1ULL,
+      -1ULL,
+      0x43f8000004000000ULL
+    }
+#endif
+  },
+  { "prefetch_l2_fault", TILEGX_OPC_PREFETCH_L2_FAULT, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 7 }, { 0, }, { 0, }, { 14 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff81f80000000ULL,
+      0ULL,
+      0ULL,
+      0xc3f8000004000000ULL
+    },
+    {
+      -1ULL,
+      0x286a881f80000000ULL,
+      -1ULL,
+      -1ULL,
+      0x43f8000000000000ULL
+    }
+#endif
+  },
+  { "prefetch_l3", TILEGX_OPC_PREFETCH_L3, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 7 }, { 0, }, { 0, }, { 14 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff81f80000000ULL,
+      0ULL,
+      0ULL,
+      0xc3f8000004000000ULL
+    },
+    {
+      -1ULL,
+      0x286aa01f80000000ULL,
+      -1ULL,
+      -1ULL,
+      0x83f8000000000000ULL
+    }
+#endif
+  },
+  { "prefetch_l3_fault", TILEGX_OPC_PREFETCH_L3_FAULT, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 7 }, { 0, }, { 0, }, { 14 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff81f80000000ULL,
+      0ULL,
+      0ULL,
+      0xc3f8000004000000ULL
+    },
+    {
+      -1ULL,
+      0x286a981f80000000ULL,
+      -1ULL,
+      -1ULL,
+      0x81f8000004000000ULL
+    }
+#endif
+  },
+  { "raise", TILEGX_OPC_RAISE, 0x2, 0, TREG_ZERO, 1,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffffffff80000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286a44ae80000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "add", TILEGX_OPC_ADD, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x00000000500c0000ULL,
+      0x2806000000000000ULL,
+      0x0000000028040000ULL,
+      0x1802000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "addi", TILEGX_OPC_ADDI, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0x0000000078000000ULL,
+      0x3c00000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000040100000ULL,
+      0x1808000000000000ULL,
+      0ULL,
+      0x0400000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "addli", TILEGX_OPC_ADDLI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 4 }, { 6, 7, 5 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc000000070000000ULL,
+      0xf800000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000010000000ULL,
+      0ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "addx", TILEGX_OPC_ADDX, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000050080000ULL,
+      0x2804000000000000ULL,
+      0x0000000028000000ULL,
+      0x1800000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "addxi", TILEGX_OPC_ADDXI, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0x0000000078000000ULL,
+      0x3c00000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000040200000ULL,
+      0x1810000000000000ULL,
+      0x0000000008000000ULL,
+      0x0800000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "addxli", TILEGX_OPC_ADDXLI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 4 }, { 6, 7, 5 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc000000070000000ULL,
+      0xf800000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000020000000ULL,
+      0x0800000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "addxsc", TILEGX_OPC_ADDXSC, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050040000ULL,
+      0x2802000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "and", TILEGX_OPC_AND, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000050100000ULL,
+      0x2808000000000000ULL,
+      0x0000000050000000ULL,
+      0x2c00000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "andi", TILEGX_OPC_ANDI, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0x0000000078000000ULL,
+      0x3c00000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000040300000ULL,
+      0x1818000000000000ULL,
+      0x0000000010000000ULL,
+      0x0c00000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "beqz", TILEGX_OPC_BEQZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 20 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffc0000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1440000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "beqzt", TILEGX_OPC_BEQZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 20 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffc0000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1400000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "bfexts", TILEGX_OPC_BFEXTS, 0x1, 4, TREG_ZERO, 1,
+    { { 8, 9, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007f000000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000034000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "bfextu", TILEGX_OPC_BFEXTU, 0x1, 4, TREG_ZERO, 1,
+    { { 8, 9, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007f000000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000035000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "bfins", TILEGX_OPC_BFINS, 0x1, 4, TREG_ZERO, 1,
+    { { 23, 9, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007f000000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000036000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "bgez", TILEGX_OPC_BGEZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 20 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffc0000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x14c0000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "bgezt", TILEGX_OPC_BGEZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 20 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffc0000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1480000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "bgtz", TILEGX_OPC_BGTZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 20 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffc0000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1540000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "bgtzt", TILEGX_OPC_BGTZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 20 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffc0000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1500000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "blbc", TILEGX_OPC_BLBC, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 20 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffc0000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x15c0000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "blbct", TILEGX_OPC_BLBCT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 20 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffc0000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1580000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "blbs", TILEGX_OPC_BLBS, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 20 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffc0000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1640000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "blbst", TILEGX_OPC_BLBST, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 20 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffc0000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1600000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "blez", TILEGX_OPC_BLEZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 20 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffc0000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x16c0000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "blezt", TILEGX_OPC_BLEZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 20 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffc0000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1680000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "bltz", TILEGX_OPC_BLTZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 20 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffc0000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1740000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "bltzt", TILEGX_OPC_BLTZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 20 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffc0000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1700000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "bnez", TILEGX_OPC_BNEZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 20 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffc0000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x17c0000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "bnezt", TILEGX_OPC_BNEZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 20 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xffc0000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1780000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "clz", TILEGX_OPC_CLZ, 0x5, 2, TREG_ZERO, 1,
+    { { 8, 9 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffff000ULL,
+      0ULL,
+      0x00000000780ff000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051481000ULL,
+      -1ULL,
+      0x00000000300c1000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmoveqz", TILEGX_OPC_CMOVEQZ, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0x00000000780c0000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050140000ULL,
+      -1ULL,
+      0x0000000048000000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmovnez", TILEGX_OPC_CMOVNEZ, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0x00000000780c0000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050180000ULL,
+      -1ULL,
+      0x0000000048040000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmpeq", TILEGX_OPC_CMPEQ, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x00000000501c0000ULL,
+      0x280a000000000000ULL,
+      0x0000000040000000ULL,
+      0x2404000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmpeqi", TILEGX_OPC_CMPEQI, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0x0000000078000000ULL,
+      0x3c00000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000040400000ULL,
+      0x1820000000000000ULL,
+      0x0000000018000000ULL,
+      0x1000000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmpexch", TILEGX_OPC_CMPEXCH, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x280e000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmpexch4", TILEGX_OPC_CMPEXCH4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x280c000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmples", TILEGX_OPC_CMPLES, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000050200000ULL,
+      0x2810000000000000ULL,
+      0x0000000038000000ULL,
+      0x2000000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmpleu", TILEGX_OPC_CMPLEU, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000050240000ULL,
+      0x2812000000000000ULL,
+      0x0000000038040000ULL,
+      0x2002000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmplts", TILEGX_OPC_CMPLTS, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000050280000ULL,
+      0x2814000000000000ULL,
+      0x0000000038080000ULL,
+      0x2004000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmpltsi", TILEGX_OPC_CMPLTSI, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0x0000000078000000ULL,
+      0x3c00000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000040500000ULL,
+      0x1828000000000000ULL,
+      0x0000000020000000ULL,
+      0x1400000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmpltu", TILEGX_OPC_CMPLTU, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x00000000502c0000ULL,
+      0x2816000000000000ULL,
+      0x00000000380c0000ULL,
+      0x2006000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmpltui", TILEGX_OPC_CMPLTUI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000040600000ULL,
+      0x1830000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmpne", TILEGX_OPC_CMPNE, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000050300000ULL,
+      0x2818000000000000ULL,
+      0x0000000040040000ULL,
+      0x2406000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmul", TILEGX_OPC_CMUL, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000504c0000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmula", TILEGX_OPC_CMULA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050380000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmulaf", TILEGX_OPC_CMULAF, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050340000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmulf", TILEGX_OPC_CMULF, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050400000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmulfr", TILEGX_OPC_CMULFR, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000503c0000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmulh", TILEGX_OPC_CMULH, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050480000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "cmulhr", TILEGX_OPC_CMULHR, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050440000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "crc32_32", TILEGX_OPC_CRC32_32, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050500000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "crc32_8", TILEGX_OPC_CRC32_8, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050540000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ctz", TILEGX_OPC_CTZ, 0x5, 2, TREG_ZERO, 1,
+    { { 8, 9 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffff000ULL,
+      0ULL,
+      0x00000000780ff000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051482000ULL,
+      -1ULL,
+      0x00000000300c2000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "dblalign", TILEGX_OPC_DBLALIGN, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050640000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "dblalign2", TILEGX_OPC_DBLALIGN2, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050580000ULL,
+      0x281a000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "dblalign4", TILEGX_OPC_DBLALIGN4, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000505c0000ULL,
+      0x281c000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "dblalign6", TILEGX_OPC_DBLALIGN6, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050600000ULL,
+      0x281e000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "drain", TILEGX_OPC_DRAIN, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286a080000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "dtlbpr", TILEGX_OPC_DTLBPR, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 7 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286a100000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "exch", TILEGX_OPC_EXCH, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x2822000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "exch4", TILEGX_OPC_EXCH4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x2820000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fdouble_add_flags", TILEGX_OPC_FDOUBLE_ADD_FLAGS, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000506c0000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fdouble_addsub", TILEGX_OPC_FDOUBLE_ADDSUB, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050680000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fdouble_mul_flags", TILEGX_OPC_FDOUBLE_MUL_FLAGS, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050700000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fdouble_pack1", TILEGX_OPC_FDOUBLE_PACK1, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050740000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fdouble_pack2", TILEGX_OPC_FDOUBLE_PACK2, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050780000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fdouble_sub_flags", TILEGX_OPC_FDOUBLE_SUB_FLAGS, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000507c0000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fdouble_unpack_max", TILEGX_OPC_FDOUBLE_UNPACK_MAX, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050800000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fdouble_unpack_min", TILEGX_OPC_FDOUBLE_UNPACK_MIN, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050840000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fetchadd", TILEGX_OPC_FETCHADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x282a000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fetchadd4", TILEGX_OPC_FETCHADD4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x2824000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fetchaddgez", TILEGX_OPC_FETCHADDGEZ, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x2828000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fetchaddgez4", TILEGX_OPC_FETCHADDGEZ4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x2826000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fetchand", TILEGX_OPC_FETCHAND, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x282e000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fetchand4", TILEGX_OPC_FETCHAND4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x282c000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fetchor", TILEGX_OPC_FETCHOR, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x2832000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fetchor4", TILEGX_OPC_FETCHOR4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x2830000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "finv", TILEGX_OPC_FINV, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 7 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286a180000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "flush", TILEGX_OPC_FLUSH, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 7 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286a280000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "flushwb", TILEGX_OPC_FLUSHWB, 0x2, 0, TREG_ZERO, 1,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286a200000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fnop", TILEGX_OPC_FNOP, 0xf, 0, TREG_ZERO, 1,
+    { {  }, {  }, {  }, {  }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffff000ULL,
+      0xfffff80000000000ULL,
+      0x00000000780ff000ULL,
+      0x3c07f80000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000051483000ULL,
+      0x286a300000000000ULL,
+      0x00000000300c3000ULL,
+      0x1c06400000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fsingle_add1", TILEGX_OPC_FSINGLE_ADD1, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050880000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fsingle_addsub2", TILEGX_OPC_FSINGLE_ADDSUB2, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000508c0000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fsingle_mul1", TILEGX_OPC_FSINGLE_MUL1, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050900000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fsingle_mul2", TILEGX_OPC_FSINGLE_MUL2, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050940000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fsingle_pack1", TILEGX_OPC_FSINGLE_PACK1, 0x5, 2, TREG_ZERO, 1,
+    { { 8, 9 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffff000ULL,
+      0ULL,
+      0x00000000780ff000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051484000ULL,
+      -1ULL,
+      0x00000000300c4000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fsingle_pack2", TILEGX_OPC_FSINGLE_PACK2, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050980000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "fsingle_sub1", TILEGX_OPC_FSINGLE_SUB1, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000509c0000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "icoh", TILEGX_OPC_ICOH, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 7 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286a380000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ill", TILEGX_OPC_ILL, 0xa, 0, TREG_ZERO, 1,
+    { { 0, }, {  }, { 0, }, {  }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0x3c07f80000000000ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286a400000000000ULL,
+      -1ULL,
+      0x1c06480000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "inv", TILEGX_OPC_INV, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 7 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286a480000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "iret", TILEGX_OPC_IRET, 0x2, 0, TREG_ZERO, 1,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286a500000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "j", TILEGX_OPC_J, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 25 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfc00000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x2400000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "jal", TILEGX_OPC_JAL, 0x2, 1, TREG_LR, 1,
+    { { 0, }, { 25 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfc00000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x2000000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "jalr", TILEGX_OPC_JALR, 0xa, 1, TREG_LR, 1,
+    { { 0, }, { 7 }, { 0, }, { 13 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0x3c07f80000000000ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286a600000000000ULL,
+      -1ULL,
+      0x1c06580000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "jalrp", TILEGX_OPC_JALRP, 0xa, 1, TREG_LR, 1,
+    { { 0, }, { 7 }, { 0, }, { 13 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0x3c07f80000000000ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286a580000000000ULL,
+      -1ULL,
+      0x1c06500000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "jr", TILEGX_OPC_JR, 0xa, 1, TREG_ZERO, 1,
+    { { 0, }, { 7 }, { 0, }, { 13 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0x3c07f80000000000ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286a700000000000ULL,
+      -1ULL,
+      0x1c06680000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "jrp", TILEGX_OPC_JRP, 0xa, 1, TREG_ZERO, 1,
+    { { 0, }, { 7 }, { 0, }, { 13 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0x3c07f80000000000ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286a680000000000ULL,
+      -1ULL,
+      0x1c06600000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ld", TILEGX_OPC_LD, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 6, 7 }, { 0, }, { 0, }, { 26, 14 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0xc200000004000000ULL
+    },
+    {
+      -1ULL,
+      0x286ae80000000000ULL,
+      -1ULL,
+      -1ULL,
+      0x8200000004000000ULL
+    }
+#endif
+  },
+  { "ld1s", TILEGX_OPC_LD1S, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 6, 7 }, { 0, }, { 0, }, { 26, 14 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0xc200000004000000ULL
+    },
+    {
+      -1ULL,
+      0x286a780000000000ULL,
+      -1ULL,
+      -1ULL,
+      0x4000000000000000ULL
+    }
+#endif
+  },
+  { "ld1s_add", TILEGX_OPC_LD1S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1838000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ld1u", TILEGX_OPC_LD1U, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 6, 7 }, { 0, }, { 0, }, { 26, 14 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0xc200000004000000ULL
+    },
+    {
+      -1ULL,
+      0x286a800000000000ULL,
+      -1ULL,
+      -1ULL,
+      0x4000000004000000ULL
+    }
+#endif
+  },
+  { "ld1u_add", TILEGX_OPC_LD1U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1840000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ld2s", TILEGX_OPC_LD2S, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 6, 7 }, { 0, }, { 0, }, { 26, 14 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0xc200000004000000ULL
+    },
+    {
+      -1ULL,
+      0x286a880000000000ULL,
+      -1ULL,
+      -1ULL,
+      0x4200000000000000ULL
+    }
+#endif
+  },
+  { "ld2s_add", TILEGX_OPC_LD2S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1848000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ld2u", TILEGX_OPC_LD2U, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 6, 7 }, { 0, }, { 0, }, { 26, 14 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0xc200000004000000ULL
+    },
+    {
+      -1ULL,
+      0x286a900000000000ULL,
+      -1ULL,
+      -1ULL,
+      0x4200000004000000ULL
+    }
+#endif
+  },
+  { "ld2u_add", TILEGX_OPC_LD2U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1850000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ld4s", TILEGX_OPC_LD4S, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 6, 7 }, { 0, }, { 0, }, { 26, 14 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0xc200000004000000ULL
+    },
+    {
+      -1ULL,
+      0x286a980000000000ULL,
+      -1ULL,
+      -1ULL,
+      0x8000000004000000ULL
+    }
+#endif
+  },
+  { "ld4s_add", TILEGX_OPC_LD4S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1858000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ld4u", TILEGX_OPC_LD4U, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 6, 7 }, { 0, }, { 0, }, { 26, 14 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0xc200000004000000ULL
+    },
+    {
+      -1ULL,
+      0x286aa00000000000ULL,
+      -1ULL,
+      -1ULL,
+      0x8200000000000000ULL
+    }
+#endif
+  },
+  { "ld4u_add", TILEGX_OPC_LD4U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1860000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ld_add", TILEGX_OPC_LD_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x18a0000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ldna", TILEGX_OPC_LDNA, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 6, 7 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286aa80000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ldna_add", TILEGX_OPC_LDNA_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x18a8000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ldnt", TILEGX_OPC_LDNT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 6, 7 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286ae00000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ldnt1s", TILEGX_OPC_LDNT1S, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 6, 7 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286ab00000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ldnt1s_add", TILEGX_OPC_LDNT1S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1868000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ldnt1u", TILEGX_OPC_LDNT1U, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 6, 7 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286ab80000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ldnt1u_add", TILEGX_OPC_LDNT1U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1870000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ldnt2s", TILEGX_OPC_LDNT2S, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 6, 7 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286ac00000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ldnt2s_add", TILEGX_OPC_LDNT2S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1878000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ldnt2u", TILEGX_OPC_LDNT2U, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 6, 7 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286ac80000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ldnt2u_add", TILEGX_OPC_LDNT2U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1880000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ldnt4s", TILEGX_OPC_LDNT4S, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 6, 7 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286ad00000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ldnt4s_add", TILEGX_OPC_LDNT4S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1888000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ldnt4u", TILEGX_OPC_LDNT4U, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 6, 7 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286ad80000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ldnt4u_add", TILEGX_OPC_LDNT4U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1890000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ldnt_add", TILEGX_OPC_LDNT_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 6, 15, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1898000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "lnk", TILEGX_OPC_LNK, 0xa, 1, TREG_ZERO, 1,
+    { { 0, }, { 6 }, { 0, }, { 12 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0x3c07f80000000000ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286af00000000000ULL,
+      -1ULL,
+      0x1c06700000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mf", TILEGX_OPC_MF, 0x2, 0, TREG_ZERO, 1,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286af80000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mfspr", TILEGX_OPC_MFSPR, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 6, 27 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x18b0000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mm", TILEGX_OPC_MM, 0x1, 4, TREG_ZERO, 1,
+    { { 23, 9, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007f000000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000037000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mnz", TILEGX_OPC_MNZ, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000050a00000ULL,
+      0x2834000000000000ULL,
+      0x0000000048080000ULL,
+      0x2804000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mtspr", TILEGX_OPC_MTSPR, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 28, 7 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x18b8000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mul_hs_hs", TILEGX_OPC_MUL_HS_HS, 0x5, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0x00000000780c0000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050d40000ULL,
+      -1ULL,
+      0x0000000068000000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mul_hs_hu", TILEGX_OPC_MUL_HS_HU, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050d80000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mul_hs_ls", TILEGX_OPC_MUL_HS_LS, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050dc0000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mul_hs_lu", TILEGX_OPC_MUL_HS_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050e00000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mul_hu_hu", TILEGX_OPC_MUL_HU_HU, 0x5, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0x00000000780c0000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050e40000ULL,
+      -1ULL,
+      0x0000000068040000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mul_hu_ls", TILEGX_OPC_MUL_HU_LS, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050e80000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mul_hu_lu", TILEGX_OPC_MUL_HU_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050ec0000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mul_ls_ls", TILEGX_OPC_MUL_LS_LS, 0x5, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0x00000000780c0000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050f00000ULL,
+      -1ULL,
+      0x0000000068080000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mul_ls_lu", TILEGX_OPC_MUL_LS_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050f40000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mul_lu_lu", TILEGX_OPC_MUL_LU_LU, 0x5, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0x00000000780c0000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050f80000ULL,
+      -1ULL,
+      0x00000000680c0000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mula_hs_hs", TILEGX_OPC_MULA_HS_HS, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0x00000000780c0000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050a80000ULL,
+      -1ULL,
+      0x0000000070000000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mula_hs_hu", TILEGX_OPC_MULA_HS_HU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050ac0000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mula_hs_ls", TILEGX_OPC_MULA_HS_LS, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050b00000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mula_hs_lu", TILEGX_OPC_MULA_HS_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050b40000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mula_hu_hu", TILEGX_OPC_MULA_HU_HU, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0x00000000780c0000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050b80000ULL,
+      -1ULL,
+      0x0000000070040000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mula_hu_ls", TILEGX_OPC_MULA_HU_LS, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050bc0000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mula_hu_lu", TILEGX_OPC_MULA_HU_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050c00000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mula_ls_ls", TILEGX_OPC_MULA_LS_LS, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0x00000000780c0000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050c40000ULL,
+      -1ULL,
+      0x0000000070080000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mula_ls_lu", TILEGX_OPC_MULA_LS_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050c80000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mula_lu_lu", TILEGX_OPC_MULA_LU_LU, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0x00000000780c0000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050cc0000ULL,
+      -1ULL,
+      0x00000000700c0000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mulax", TILEGX_OPC_MULAX, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0x00000000780c0000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050a40000ULL,
+      -1ULL,
+      0x0000000040080000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mulx", TILEGX_OPC_MULX, 0x5, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0x00000000780c0000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000050d00000ULL,
+      -1ULL,
+      0x00000000400c0000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "mz", TILEGX_OPC_MZ, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000050fc0000ULL,
+      0x2836000000000000ULL,
+      0x00000000480c0000ULL,
+      0x2806000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "nap", TILEGX_OPC_NAP, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286b000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "nop", TILEGX_OPC_NOP, 0xf, 0, TREG_ZERO, 1,
+    { {  }, {  }, {  }, {  }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffff000ULL,
+      0xfffff80000000000ULL,
+      0x00000000780ff000ULL,
+      0x3c07f80000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000051485000ULL,
+      0x286b080000000000ULL,
+      0x00000000300c5000ULL,
+      0x1c06780000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "nor", TILEGX_OPC_NOR, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000051000000ULL,
+      0x2838000000000000ULL,
+      0x0000000050040000ULL,
+      0x2c02000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "or", TILEGX_OPC_OR, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000051040000ULL,
+      0x283a000000000000ULL,
+      0x0000000050080000ULL,
+      0x2c04000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "ori", TILEGX_OPC_ORI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000040700000ULL,
+      0x18c0000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "pcnt", TILEGX_OPC_PCNT, 0x5, 2, TREG_ZERO, 1,
+    { { 8, 9 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffff000ULL,
+      0ULL,
+      0x00000000780ff000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051486000ULL,
+      -1ULL,
+      0x00000000300c6000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "revbits", TILEGX_OPC_REVBITS, 0x5, 2, TREG_ZERO, 1,
+    { { 8, 9 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffff000ULL,
+      0ULL,
+      0x00000000780ff000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051487000ULL,
+      -1ULL,
+      0x00000000300c7000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "revbytes", TILEGX_OPC_REVBYTES, 0x5, 2, TREG_ZERO, 1,
+    { { 8, 9 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffff000ULL,
+      0ULL,
+      0x00000000780ff000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051488000ULL,
+      -1ULL,
+      0x00000000300c8000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "rotl", TILEGX_OPC_ROTL, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000051080000ULL,
+      0x283c000000000000ULL,
+      0x0000000058000000ULL,
+      0x3000000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "rotli", TILEGX_OPC_ROTLI, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 29 }, { 6, 7, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000060040000ULL,
+      0x3002000000000000ULL,
+      0x0000000078000000ULL,
+      0x3800000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shl", TILEGX_OPC_SHL, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000051280000ULL,
+      0x284c000000000000ULL,
+      0x0000000058040000ULL,
+      0x3002000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shl16insli", TILEGX_OPC_SHL16INSLI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 4 }, { 6, 7, 5 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc000000070000000ULL,
+      0xf800000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000070000000ULL,
+      0x3800000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shl1add", TILEGX_OPC_SHL1ADD, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000051100000ULL,
+      0x2840000000000000ULL,
+      0x0000000030000000ULL,
+      0x1c00000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shl1addx", TILEGX_OPC_SHL1ADDX, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x00000000510c0000ULL,
+      0x283e000000000000ULL,
+      0x0000000060040000ULL,
+      0x3402000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shl2add", TILEGX_OPC_SHL2ADD, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000051180000ULL,
+      0x2844000000000000ULL,
+      0x0000000030040000ULL,
+      0x1c02000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shl2addx", TILEGX_OPC_SHL2ADDX, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000051140000ULL,
+      0x2842000000000000ULL,
+      0x0000000060080000ULL,
+      0x3404000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shl3add", TILEGX_OPC_SHL3ADD, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000051200000ULL,
+      0x2848000000000000ULL,
+      0x0000000030080000ULL,
+      0x1c04000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shl3addx", TILEGX_OPC_SHL3ADDX, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x00000000511c0000ULL,
+      0x2846000000000000ULL,
+      0x00000000600c0000ULL,
+      0x3406000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shli", TILEGX_OPC_SHLI, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 29 }, { 6, 7, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000060080000ULL,
+      0x3004000000000000ULL,
+      0x0000000078040000ULL,
+      0x3802000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shlx", TILEGX_OPC_SHLX, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051240000ULL,
+      0x284a000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shlxi", TILEGX_OPC_SHLXI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 29 }, { 6, 7, 30 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000600c0000ULL,
+      0x3006000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shrs", TILEGX_OPC_SHRS, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x00000000512c0000ULL,
+      0x284e000000000000ULL,
+      0x0000000058080000ULL,
+      0x3004000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shrsi", TILEGX_OPC_SHRSI, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 29 }, { 6, 7, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000060100000ULL,
+      0x3008000000000000ULL,
+      0x0000000078080000ULL,
+      0x3804000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shru", TILEGX_OPC_SHRU, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000051340000ULL,
+      0x2852000000000000ULL,
+      0x00000000580c0000ULL,
+      0x3006000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shrui", TILEGX_OPC_SHRUI, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 29 }, { 6, 7, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000060140000ULL,
+      0x300a000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3806000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shrux", TILEGX_OPC_SHRUX, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051300000ULL,
+      0x2850000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shruxi", TILEGX_OPC_SHRUXI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 29 }, { 6, 7, 30 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000060180000ULL,
+      0x300c000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "shufflebytes", TILEGX_OPC_SHUFFLEBYTES, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051380000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "st", TILEGX_OPC_ST, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 17 }, { 0, }, { 0, }, { 14, 33 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0xc200000004000000ULL
+    },
+    {
+      -1ULL,
+      0x2862000000000000ULL,
+      -1ULL,
+      -1ULL,
+      0xc200000004000000ULL
+    }
+#endif
+  },
+  { "st1", TILEGX_OPC_ST1, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 17 }, { 0, }, { 0, }, { 14, 33 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0xc200000004000000ULL
+    },
+    {
+      -1ULL,
+      0x2854000000000000ULL,
+      -1ULL,
+      -1ULL,
+      0xc000000000000000ULL
+    }
+#endif
+  },
+  { "st1_add", TILEGX_OPC_ST1_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x18c8000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "st2", TILEGX_OPC_ST2, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 17 }, { 0, }, { 0, }, { 14, 33 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0xc200000004000000ULL
+    },
+    {
+      -1ULL,
+      0x2856000000000000ULL,
+      -1ULL,
+      -1ULL,
+      0xc000000004000000ULL
+    }
+#endif
+  },
+  { "st2_add", TILEGX_OPC_ST2_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x18d0000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "st4", TILEGX_OPC_ST4, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 17 }, { 0, }, { 0, }, { 14, 33 } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0xc200000004000000ULL
+    },
+    {
+      -1ULL,
+      0x2858000000000000ULL,
+      -1ULL,
+      -1ULL,
+      0xc200000000000000ULL
+    }
+#endif
+  },
+  { "st4_add", TILEGX_OPC_ST4_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x18d8000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "st_add", TILEGX_OPC_ST_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x1900000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "stnt", TILEGX_OPC_STNT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x2860000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "stnt1", TILEGX_OPC_STNT1, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x285a000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "stnt1_add", TILEGX_OPC_STNT1_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x18e0000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "stnt2", TILEGX_OPC_STNT2, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x285c000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "stnt2_add", TILEGX_OPC_STNT2_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x18e8000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "stnt4", TILEGX_OPC_STNT4, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x285e000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "stnt4_add", TILEGX_OPC_STNT4_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x18f0000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "stnt_add", TILEGX_OPC_STNT_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x18f8000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "sub", TILEGX_OPC_SUB, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000051440000ULL,
+      0x2868000000000000ULL,
+      0x00000000280c0000ULL,
+      0x1806000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "subx", TILEGX_OPC_SUBX, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000051400000ULL,
+      0x2866000000000000ULL,
+      0x0000000028080000ULL,
+      0x1804000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "subxsc", TILEGX_OPC_SUBXSC, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000513c0000ULL,
+      0x2864000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "swint0", TILEGX_OPC_SWINT0, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286b100000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "swint1", TILEGX_OPC_SWINT1, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286b180000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "swint2", TILEGX_OPC_SWINT2, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286b200000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "swint3", TILEGX_OPC_SWINT3, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286b280000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "tblidxb0", TILEGX_OPC_TBLIDXB0, 0x5, 2, TREG_ZERO, 1,
+    { { 23, 9 }, { 0, }, { 24, 11 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffff000ULL,
+      0ULL,
+      0x00000000780ff000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051489000ULL,
+      -1ULL,
+      0x00000000300c9000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "tblidxb1", TILEGX_OPC_TBLIDXB1, 0x5, 2, TREG_ZERO, 1,
+    { { 23, 9 }, { 0, }, { 24, 11 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffff000ULL,
+      0ULL,
+      0x00000000780ff000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x000000005148a000ULL,
+      -1ULL,
+      0x00000000300ca000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "tblidxb2", TILEGX_OPC_TBLIDXB2, 0x5, 2, TREG_ZERO, 1,
+    { { 23, 9 }, { 0, }, { 24, 11 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffff000ULL,
+      0ULL,
+      0x00000000780ff000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x000000005148b000ULL,
+      -1ULL,
+      0x00000000300cb000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "tblidxb3", TILEGX_OPC_TBLIDXB3, 0x5, 2, TREG_ZERO, 1,
+    { { 23, 9 }, { 0, }, { 24, 11 }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffff000ULL,
+      0ULL,
+      0x00000000780ff000ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x000000005148c000ULL,
+      -1ULL,
+      0x00000000300cc000ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1add", TILEGX_OPC_V1ADD, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051500000ULL,
+      0x286e000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1addi", TILEGX_OPC_V1ADDI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000040800000ULL,
+      0x1908000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1adduc", TILEGX_OPC_V1ADDUC, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000514c0000ULL,
+      0x286c000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1adiffu", TILEGX_OPC_V1ADIFFU, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051540000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1avgu", TILEGX_OPC_V1AVGU, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051580000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1cmpeq", TILEGX_OPC_V1CMPEQ, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000515c0000ULL,
+      0x2870000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1cmpeqi", TILEGX_OPC_V1CMPEQI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000040900000ULL,
+      0x1910000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1cmples", TILEGX_OPC_V1CMPLES, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051600000ULL,
+      0x2872000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1cmpleu", TILEGX_OPC_V1CMPLEU, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051640000ULL,
+      0x2874000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1cmplts", TILEGX_OPC_V1CMPLTS, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051680000ULL,
+      0x2876000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1cmpltsi", TILEGX_OPC_V1CMPLTSI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000040a00000ULL,
+      0x1918000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1cmpltu", TILEGX_OPC_V1CMPLTU, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000516c0000ULL,
+      0x2878000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1cmpltui", TILEGX_OPC_V1CMPLTUI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000040b00000ULL,
+      0x1920000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1cmpne", TILEGX_OPC_V1CMPNE, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051700000ULL,
+      0x287a000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1ddotpu", TILEGX_OPC_V1DDOTPU, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052880000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1ddotpua", TILEGX_OPC_V1DDOTPUA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052840000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1ddotpus", TILEGX_OPC_V1DDOTPUS, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051780000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1ddotpusa", TILEGX_OPC_V1DDOTPUSA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051740000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1dotp", TILEGX_OPC_V1DOTP, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051880000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1dotpa", TILEGX_OPC_V1DOTPA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000517c0000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1dotpu", TILEGX_OPC_V1DOTPU, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052900000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1dotpua", TILEGX_OPC_V1DOTPUA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000528c0000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1dotpus", TILEGX_OPC_V1DOTPUS, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051840000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1dotpusa", TILEGX_OPC_V1DOTPUSA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051800000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1int_h", TILEGX_OPC_V1INT_H, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000518c0000ULL,
+      0x287c000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1int_l", TILEGX_OPC_V1INT_L, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051900000ULL,
+      0x287e000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1maxu", TILEGX_OPC_V1MAXU, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051940000ULL,
+      0x2880000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1maxui", TILEGX_OPC_V1MAXUI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000040c00000ULL,
+      0x1928000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1minu", TILEGX_OPC_V1MINU, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051980000ULL,
+      0x2882000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1minui", TILEGX_OPC_V1MINUI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000040d00000ULL,
+      0x1930000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1mnz", TILEGX_OPC_V1MNZ, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000519c0000ULL,
+      0x2884000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1multu", TILEGX_OPC_V1MULTU, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051a00000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1mulu", TILEGX_OPC_V1MULU, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051a80000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1mulus", TILEGX_OPC_V1MULUS, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051a40000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1mz", TILEGX_OPC_V1MZ, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051ac0000ULL,
+      0x2886000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1sadau", TILEGX_OPC_V1SADAU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051b00000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1sadu", TILEGX_OPC_V1SADU, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051b40000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1shl", TILEGX_OPC_V1SHL, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051b80000ULL,
+      0x2888000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1shli", TILEGX_OPC_V1SHLI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 29 }, { 6, 7, 30 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000601c0000ULL,
+      0x300e000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1shrs", TILEGX_OPC_V1SHRS, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051bc0000ULL,
+      0x288a000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1shrsi", TILEGX_OPC_V1SHRSI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 29 }, { 6, 7, 30 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000060200000ULL,
+      0x3010000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1shru", TILEGX_OPC_V1SHRU, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051c00000ULL,
+      0x288c000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1shrui", TILEGX_OPC_V1SHRUI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 29 }, { 6, 7, 30 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000060240000ULL,
+      0x3012000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1sub", TILEGX_OPC_V1SUB, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051c80000ULL,
+      0x2890000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v1subuc", TILEGX_OPC_V1SUBUC, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051c40000ULL,
+      0x288e000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2add", TILEGX_OPC_V2ADD, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051d00000ULL,
+      0x2894000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2addi", TILEGX_OPC_V2ADDI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000040e00000ULL,
+      0x1938000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2addsc", TILEGX_OPC_V2ADDSC, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051cc0000ULL,
+      0x2892000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2adiffs", TILEGX_OPC_V2ADIFFS, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051d40000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2avgs", TILEGX_OPC_V2AVGS, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051d80000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2cmpeq", TILEGX_OPC_V2CMPEQ, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051dc0000ULL,
+      0x2896000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2cmpeqi", TILEGX_OPC_V2CMPEQI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000040f00000ULL,
+      0x1940000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2cmples", TILEGX_OPC_V2CMPLES, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051e00000ULL,
+      0x2898000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2cmpleu", TILEGX_OPC_V2CMPLEU, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051e40000ULL,
+      0x289a000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2cmplts", TILEGX_OPC_V2CMPLTS, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051e80000ULL,
+      0x289c000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2cmpltsi", TILEGX_OPC_V2CMPLTSI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000041000000ULL,
+      0x1948000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2cmpltu", TILEGX_OPC_V2CMPLTU, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051ec0000ULL,
+      0x289e000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2cmpltui", TILEGX_OPC_V2CMPLTUI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000041100000ULL,
+      0x1950000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2cmpne", TILEGX_OPC_V2CMPNE, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051f00000ULL,
+      0x28a0000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2dotp", TILEGX_OPC_V2DOTP, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051f80000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2dotpa", TILEGX_OPC_V2DOTPA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051f40000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2int_h", TILEGX_OPC_V2INT_H, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000051fc0000ULL,
+      0x28a2000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2int_l", TILEGX_OPC_V2INT_L, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052000000ULL,
+      0x28a4000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2maxs", TILEGX_OPC_V2MAXS, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052040000ULL,
+      0x28a6000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2maxsi", TILEGX_OPC_V2MAXSI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000041200000ULL,
+      0x1958000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2mins", TILEGX_OPC_V2MINS, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052080000ULL,
+      0x28a8000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2minsi", TILEGX_OPC_V2MINSI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000041300000ULL,
+      0x1960000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2mnz", TILEGX_OPC_V2MNZ, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000520c0000ULL,
+      0x28aa000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2mulfsc", TILEGX_OPC_V2MULFSC, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052100000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2muls", TILEGX_OPC_V2MULS, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052140000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2mults", TILEGX_OPC_V2MULTS, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052180000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2mz", TILEGX_OPC_V2MZ, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000521c0000ULL,
+      0x28ac000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2packh", TILEGX_OPC_V2PACKH, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052200000ULL,
+      0x28ae000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2packl", TILEGX_OPC_V2PACKL, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052240000ULL,
+      0x28b0000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2packuc", TILEGX_OPC_V2PACKUC, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052280000ULL,
+      0x28b2000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2sadas", TILEGX_OPC_V2SADAS, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000522c0000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2sadau", TILEGX_OPC_V2SADAU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052300000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2sads", TILEGX_OPC_V2SADS, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052340000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2sadu", TILEGX_OPC_V2SADU, 0x1, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052380000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2shl", TILEGX_OPC_V2SHL, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052400000ULL,
+      0x28b6000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2shli", TILEGX_OPC_V2SHLI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 29 }, { 6, 7, 30 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000060280000ULL,
+      0x3014000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2shlsc", TILEGX_OPC_V2SHLSC, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000523c0000ULL,
+      0x28b4000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2shrs", TILEGX_OPC_V2SHRS, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052440000ULL,
+      0x28b8000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2shrsi", TILEGX_OPC_V2SHRSI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 29 }, { 6, 7, 30 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000602c0000ULL,
+      0x3016000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2shru", TILEGX_OPC_V2SHRU, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052480000ULL,
+      0x28ba000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2shrui", TILEGX_OPC_V2SHRUI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 29 }, { 6, 7, 30 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000060300000ULL,
+      0x3018000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2sub", TILEGX_OPC_V2SUB, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052500000ULL,
+      0x28be000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v2subsc", TILEGX_OPC_V2SUBSC, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000524c0000ULL,
+      0x28bc000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v4add", TILEGX_OPC_V4ADD, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052580000ULL,
+      0x28c2000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v4addsc", TILEGX_OPC_V4ADDSC, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052540000ULL,
+      0x28c0000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v4int_h", TILEGX_OPC_V4INT_H, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000525c0000ULL,
+      0x28c4000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v4int_l", TILEGX_OPC_V4INT_L, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052600000ULL,
+      0x28c6000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v4packsc", TILEGX_OPC_V4PACKSC, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052640000ULL,
+      0x28c8000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v4shl", TILEGX_OPC_V4SHL, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000526c0000ULL,
+      0x28cc000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v4shlsc", TILEGX_OPC_V4SHLSC, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052680000ULL,
+      0x28ca000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v4shrs", TILEGX_OPC_V4SHRS, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052700000ULL,
+      0x28ce000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v4shru", TILEGX_OPC_V4SHRU, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052740000ULL,
+      0x28d0000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v4sub", TILEGX_OPC_V4SUB, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x00000000527c0000ULL,
+      0x28d4000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "v4subsc", TILEGX_OPC_V4SUBSC, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000052780000ULL,
+      0x28d2000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "wh64", TILEGX_OPC_WH64, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 7 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0ULL,
+      0xfffff80000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      -1ULL,
+      0x286b300000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "xor", TILEGX_OPC_XOR, 0xf, 3, TREG_ZERO, 1,
+    { { 8, 9, 16 }, { 6, 7, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ffc0000ULL,
+      0xfffe000000000000ULL,
+      0x00000000780c0000ULL,
+      0x3c06000000000000ULL,
+      0ULL
+    },
+    {
+      0x0000000052800000ULL,
+      0x28d6000000000000ULL,
+      0x00000000500c0000ULL,
+      0x2c06000000000000ULL,
+      -1ULL
+    }
+#endif
+  },
+  { "xori", TILEGX_OPC_XORI, 0x3, 3, TREG_ZERO, 1,
+    { { 8, 9, 0 }, { 6, 7, 1 }, { 0, }, { 0, }, { 0, } },
+#ifndef DISASM_ONLY
+    {
+      0xc00000007ff00000ULL,
+      0xfff8000000000000ULL,
+      0ULL,
+      0ULL,
+      0ULL
+    },
+    {
+      0x0000000041400000ULL,
+      0x1968000000000000ULL,
+      -1ULL,
+      -1ULL,
+      -1ULL
+    }
+#endif
+  },
+  { NULL, TILEGX_OPC_NONE, 0, 0, TREG_ZERO, 0, { { 0, } },
+#ifndef DISASM_ONLY
+    { 0, }, { 0, }
+#endif
+  }
+};
+
+#define BITFIELD(start, size) ((start) | (((1 << (size)) - 1) << 6))
+#define CHILD(array_index) (TILEGX_OPC_NONE + (array_index))
+
+static const unsigned short decode_X0_fsm[936] =
+{
+  BITFIELD(22, 9) /* index 0 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_BFEXTS,
+  TILEGX_OPC_BFEXTS, TILEGX_OPC_BFEXTS, TILEGX_OPC_BFEXTS, TILEGX_OPC_BFEXTU,
+  TILEGX_OPC_BFEXTU, TILEGX_OPC_BFEXTU, TILEGX_OPC_BFEXTU, TILEGX_OPC_BFINS,
+  TILEGX_OPC_BFINS, TILEGX_OPC_BFINS, TILEGX_OPC_BFINS, TILEGX_OPC_MM,
+  TILEGX_OPC_MM, TILEGX_OPC_MM, TILEGX_OPC_MM, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, CHILD(528), CHILD(578),
+  CHILD(583), CHILD(588), CHILD(593), CHILD(598), TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, CHILD(603), CHILD(620), CHILD(637), CHILD(654), CHILD(671),
+  CHILD(703), CHILD(797), CHILD(814), CHILD(831), CHILD(848), CHILD(865),
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, CHILD(889), TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  BITFIELD(6, 2) /* index 513 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(518),
+  BITFIELD(8, 2) /* index 518 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(523),
+  BITFIELD(10, 2) /* index 523 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_MOVELI,
+  BITFIELD(20, 2) /* index 528 */,
+  TILEGX_OPC_NONE, CHILD(533), TILEGX_OPC_ADDXI, CHILD(548),
+  BITFIELD(6, 2) /* index 533 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(538),
+  BITFIELD(8, 2) /* index 538 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(543),
+  BITFIELD(10, 2) /* index 543 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI,
+  BITFIELD(0, 2) /* index 548 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(553),
+  BITFIELD(2, 2) /* index 553 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(558),
+  BITFIELD(4, 2) /* index 558 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(563),
+  BITFIELD(6, 2) /* index 563 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(568),
+  BITFIELD(8, 2) /* index 568 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(573),
+  BITFIELD(10, 2) /* index 573 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO,
+  BITFIELD(20, 2) /* index 578 */,
+  TILEGX_OPC_CMPEQI, TILEGX_OPC_CMPLTSI, TILEGX_OPC_CMPLTUI, TILEGX_OPC_ORI,
+  BITFIELD(20, 2) /* index 583 */,
+  TILEGX_OPC_V1ADDI, TILEGX_OPC_V1CMPEQI, TILEGX_OPC_V1CMPLTSI,
+  TILEGX_OPC_V1CMPLTUI,
+  BITFIELD(20, 2) /* index 588 */,
+  TILEGX_OPC_V1MAXUI, TILEGX_OPC_V1MINUI, TILEGX_OPC_V2ADDI,
+  TILEGX_OPC_V2CMPEQI,
+  BITFIELD(20, 2) /* index 593 */,
+  TILEGX_OPC_V2CMPLTSI, TILEGX_OPC_V2CMPLTUI, TILEGX_OPC_V2MAXSI,
+  TILEGX_OPC_V2MINSI,
+  BITFIELD(20, 2) /* index 598 */,
+  TILEGX_OPC_XORI, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(18, 4) /* index 603 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_ADDXSC, TILEGX_OPC_ADDX, TILEGX_OPC_ADD,
+  TILEGX_OPC_AND, TILEGX_OPC_CMOVEQZ, TILEGX_OPC_CMOVNEZ, TILEGX_OPC_CMPEQ,
+  TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU,
+  TILEGX_OPC_CMPNE, TILEGX_OPC_CMULAF, TILEGX_OPC_CMULA, TILEGX_OPC_CMULFR,
+  BITFIELD(18, 4) /* index 620 */,
+  TILEGX_OPC_CMULF, TILEGX_OPC_CMULHR, TILEGX_OPC_CMULH, TILEGX_OPC_CMUL,
+  TILEGX_OPC_CRC32_32, TILEGX_OPC_CRC32_8, TILEGX_OPC_DBLALIGN2,
+  TILEGX_OPC_DBLALIGN4, TILEGX_OPC_DBLALIGN6, TILEGX_OPC_DBLALIGN,
+  TILEGX_OPC_FDOUBLE_ADDSUB, TILEGX_OPC_FDOUBLE_ADD_FLAGS,
+  TILEGX_OPC_FDOUBLE_MUL_FLAGS, TILEGX_OPC_FDOUBLE_PACK1,
+  TILEGX_OPC_FDOUBLE_PACK2, TILEGX_OPC_FDOUBLE_SUB_FLAGS,
+  BITFIELD(18, 4) /* index 637 */,
+  TILEGX_OPC_FDOUBLE_UNPACK_MAX, TILEGX_OPC_FDOUBLE_UNPACK_MIN,
+  TILEGX_OPC_FSINGLE_ADD1, TILEGX_OPC_FSINGLE_ADDSUB2,
+  TILEGX_OPC_FSINGLE_MUL1, TILEGX_OPC_FSINGLE_MUL2, TILEGX_OPC_FSINGLE_PACK2,
+  TILEGX_OPC_FSINGLE_SUB1, TILEGX_OPC_MNZ, TILEGX_OPC_MULAX,
+  TILEGX_OPC_MULA_HS_HS, TILEGX_OPC_MULA_HS_HU, TILEGX_OPC_MULA_HS_LS,
+  TILEGX_OPC_MULA_HS_LU, TILEGX_OPC_MULA_HU_HU, TILEGX_OPC_MULA_HU_LS,
+  BITFIELD(18, 4) /* index 654 */,
+  TILEGX_OPC_MULA_HU_LU, TILEGX_OPC_MULA_LS_LS, TILEGX_OPC_MULA_LS_LU,
+  TILEGX_OPC_MULA_LU_LU, TILEGX_OPC_MULX, TILEGX_OPC_MUL_HS_HS,
+  TILEGX_OPC_MUL_HS_HU, TILEGX_OPC_MUL_HS_LS, TILEGX_OPC_MUL_HS_LU,
+  TILEGX_OPC_MUL_HU_HU, TILEGX_OPC_MUL_HU_LS, TILEGX_OPC_MUL_HU_LU,
+  TILEGX_OPC_MUL_LS_LS, TILEGX_OPC_MUL_LS_LU, TILEGX_OPC_MUL_LU_LU,
+  TILEGX_OPC_MZ,
+  BITFIELD(18, 4) /* index 671 */,
+  TILEGX_OPC_NOR, CHILD(688), TILEGX_OPC_ROTL, TILEGX_OPC_SHL1ADDX,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADDX, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL3ADDX, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHLX, TILEGX_OPC_SHL,
+  TILEGX_OPC_SHRS, TILEGX_OPC_SHRUX, TILEGX_OPC_SHRU, TILEGX_OPC_SHUFFLEBYTES,
+  TILEGX_OPC_SUBXSC,
+  BITFIELD(12, 2) /* index 688 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(693),
+  BITFIELD(14, 2) /* index 693 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(698),
+  BITFIELD(16, 2) /* index 698 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE,
+  BITFIELD(18, 4) /* index 703 */,
+  TILEGX_OPC_SUBX, TILEGX_OPC_SUB, CHILD(720), TILEGX_OPC_V1ADDUC,
+  TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADIFFU, TILEGX_OPC_V1AVGU,
+  TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLEU,
+  TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPNE,
+  TILEGX_OPC_V1DDOTPUSA, TILEGX_OPC_V1DDOTPUS, TILEGX_OPC_V1DOTPA,
+  BITFIELD(12, 4) /* index 720 */,
+  TILEGX_OPC_NONE, CHILD(737), CHILD(742), CHILD(747), CHILD(752), CHILD(757),
+  CHILD(762), CHILD(767), CHILD(772), CHILD(777), CHILD(782), CHILD(787),
+  CHILD(792), TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 737 */,
+  TILEGX_OPC_CLZ, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 742 */,
+  TILEGX_OPC_CTZ, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 747 */,
+  TILEGX_OPC_FNOP, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 752 */,
+  TILEGX_OPC_FSINGLE_PACK1, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 757 */,
+  TILEGX_OPC_NOP, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 762 */,
+  TILEGX_OPC_PCNT, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 767 */,
+  TILEGX_OPC_REVBITS, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 772 */,
+  TILEGX_OPC_REVBYTES, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 777 */,
+  TILEGX_OPC_TBLIDXB0, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 782 */,
+  TILEGX_OPC_TBLIDXB1, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 787 */,
+  TILEGX_OPC_TBLIDXB2, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 792 */,
+  TILEGX_OPC_TBLIDXB3, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(18, 4) /* index 797 */,
+  TILEGX_OPC_V1DOTPUSA, TILEGX_OPC_V1DOTPUS, TILEGX_OPC_V1DOTP,
+  TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_L, TILEGX_OPC_V1MAXU,
+  TILEGX_OPC_V1MINU, TILEGX_OPC_V1MNZ, TILEGX_OPC_V1MULTU, TILEGX_OPC_V1MULUS,
+  TILEGX_OPC_V1MULU, TILEGX_OPC_V1MZ, TILEGX_OPC_V1SADAU, TILEGX_OPC_V1SADU,
+  TILEGX_OPC_V1SHL, TILEGX_OPC_V1SHRS,
+  BITFIELD(18, 4) /* index 814 */,
+  TILEGX_OPC_V1SHRU, TILEGX_OPC_V1SUBUC, TILEGX_OPC_V1SUB, TILEGX_OPC_V2ADDSC,
+  TILEGX_OPC_V2ADD, TILEGX_OPC_V2ADIFFS, TILEGX_OPC_V2AVGS,
+  TILEGX_OPC_V2CMPEQ, TILEGX_OPC_V2CMPLES, TILEGX_OPC_V2CMPLEU,
+  TILEGX_OPC_V2CMPLTS, TILEGX_OPC_V2CMPLTU, TILEGX_OPC_V2CMPNE,
+  TILEGX_OPC_V2DOTPA, TILEGX_OPC_V2DOTP, TILEGX_OPC_V2INT_H,
+  BITFIELD(18, 4) /* index 831 */,
+  TILEGX_OPC_V2INT_L, TILEGX_OPC_V2MAXS, TILEGX_OPC_V2MINS, TILEGX_OPC_V2MNZ,
+  TILEGX_OPC_V2MULFSC, TILEGX_OPC_V2MULS, TILEGX_OPC_V2MULTS, TILEGX_OPC_V2MZ,
+  TILEGX_OPC_V2PACKH, TILEGX_OPC_V2PACKL, TILEGX_OPC_V2PACKUC,
+  TILEGX_OPC_V2SADAS, TILEGX_OPC_V2SADAU, TILEGX_OPC_V2SADS,
+  TILEGX_OPC_V2SADU, TILEGX_OPC_V2SHLSC,
+  BITFIELD(18, 4) /* index 848 */,
+  TILEGX_OPC_V2SHL, TILEGX_OPC_V2SHRS, TILEGX_OPC_V2SHRU, TILEGX_OPC_V2SUBSC,
+  TILEGX_OPC_V2SUB, TILEGX_OPC_V4ADDSC, TILEGX_OPC_V4ADD, TILEGX_OPC_V4INT_H,
+  TILEGX_OPC_V4INT_L, TILEGX_OPC_V4PACKSC, TILEGX_OPC_V4SHLSC,
+  TILEGX_OPC_V4SHL, TILEGX_OPC_V4SHRS, TILEGX_OPC_V4SHRU, TILEGX_OPC_V4SUBSC,
+  TILEGX_OPC_V4SUB,
+  BITFIELD(18, 3) /* index 865 */,
+  CHILD(874), CHILD(877), CHILD(880), CHILD(883), CHILD(886), TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(21, 1) /* index 874 */,
+  TILEGX_OPC_XOR, TILEGX_OPC_NONE,
+  BITFIELD(21, 1) /* index 877 */,
+  TILEGX_OPC_V1DDOTPUA, TILEGX_OPC_NONE,
+  BITFIELD(21, 1) /* index 880 */,
+  TILEGX_OPC_V1DDOTPU, TILEGX_OPC_NONE,
+  BITFIELD(21, 1) /* index 883 */,
+  TILEGX_OPC_V1DOTPUA, TILEGX_OPC_NONE,
+  BITFIELD(21, 1) /* index 886 */,
+  TILEGX_OPC_V1DOTPU, TILEGX_OPC_NONE,
+  BITFIELD(18, 4) /* index 889 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHLXI,
+  TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI, TILEGX_OPC_SHRUXI, TILEGX_OPC_V1SHLI,
+  TILEGX_OPC_V1SHRSI, TILEGX_OPC_V1SHRUI, TILEGX_OPC_V2SHLI,
+  TILEGX_OPC_V2SHRSI, TILEGX_OPC_V2SHRUI, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE,
+  BITFIELD(0, 2) /* index 906 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(911),
+  BITFIELD(2, 2) /* index 911 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(916),
+  BITFIELD(4, 2) /* index 916 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(921),
+  BITFIELD(6, 2) /* index 921 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(926),
+  BITFIELD(8, 2) /* index 926 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(931),
+  BITFIELD(10, 2) /* index 931 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  TILEGX_OPC_INFOL,
+};
+
+static const unsigned short decode_X1_fsm[1266] =
+{
+  BITFIELD(53, 9) /* index 0 */,
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_BEQZT,
+  TILEGX_OPC_BEQZT, TILEGX_OPC_BEQZ, TILEGX_OPC_BEQZ, TILEGX_OPC_BGEZT,
+  TILEGX_OPC_BGEZT, TILEGX_OPC_BGEZ, TILEGX_OPC_BGEZ, TILEGX_OPC_BGTZT,
+  TILEGX_OPC_BGTZT, TILEGX_OPC_BGTZ, TILEGX_OPC_BGTZ, TILEGX_OPC_BLBCT,
+  TILEGX_OPC_BLBCT, TILEGX_OPC_BLBC, TILEGX_OPC_BLBC, TILEGX_OPC_BLBST,
+  TILEGX_OPC_BLBST, TILEGX_OPC_BLBS, TILEGX_OPC_BLBS, TILEGX_OPC_BLEZT,
+  TILEGX_OPC_BLEZT, TILEGX_OPC_BLEZ, TILEGX_OPC_BLEZ, TILEGX_OPC_BLTZT,
+  TILEGX_OPC_BLTZT, TILEGX_OPC_BLTZ, TILEGX_OPC_BLTZ, TILEGX_OPC_BNEZT,
+  TILEGX_OPC_BNEZT, TILEGX_OPC_BNEZ, TILEGX_OPC_BNEZ, CHILD(528), CHILD(578),
+  CHILD(598), CHILD(703), CHILD(723), CHILD(728), CHILD(753), CHILD(758),
+  CHILD(763), CHILD(768), CHILD(773), CHILD(778), TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  CHILD(783), CHILD(800), CHILD(832), CHILD(849), CHILD(1168), CHILD(1185),
+  CHILD(1202), TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, CHILD(1219), TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, CHILD(1236), CHILD(1236), CHILD(1236),
+  CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236),
+  CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236),
+  CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236),
+  CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236),
+  CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236),
+  CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236),
+  CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236),
+  CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236),
+  CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236),
+  CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236),
+  CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236),
+  CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236), CHILD(1236),
+  CHILD(1236),
+  BITFIELD(37, 2) /* index 513 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(518),
+  BITFIELD(39, 2) /* index 518 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(523),
+  BITFIELD(41, 2) /* index 523 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_MOVELI,
+  BITFIELD(51, 2) /* index 528 */,
+  TILEGX_OPC_NONE, CHILD(533), TILEGX_OPC_ADDXI, CHILD(548),
+  BITFIELD(37, 2) /* index 533 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(538),
+  BITFIELD(39, 2) /* index 538 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(543),
+  BITFIELD(41, 2) /* index 543 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI,
+  BITFIELD(31, 2) /* index 548 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(553),
+  BITFIELD(33, 2) /* index 553 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(558),
+  BITFIELD(35, 2) /* index 558 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(563),
+  BITFIELD(37, 2) /* index 563 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(568),
+  BITFIELD(39, 2) /* index 568 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(573),
+  BITFIELD(41, 2) /* index 573 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO,
+  BITFIELD(51, 2) /* index 578 */,
+  TILEGX_OPC_CMPEQI, TILEGX_OPC_CMPLTSI, TILEGX_OPC_CMPLTUI, CHILD(583),
+  BITFIELD(31, 2) /* index 583 */,
+  TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, CHILD(588),
+  BITFIELD(33, 2) /* index 588 */,
+  TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, CHILD(593),
+  BITFIELD(35, 2) /* index 593 */,
+  TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD,
+  TILEGX_OPC_PREFETCH_ADD_L1_FAULT,
+  BITFIELD(51, 2) /* index 598 */,
+  CHILD(603), CHILD(618), CHILD(633), CHILD(648),
+  BITFIELD(31, 2) /* index 603 */,
+  TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, CHILD(608),
+  BITFIELD(33, 2) /* index 608 */,
+  TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, CHILD(613),
+  BITFIELD(35, 2) /* index 613 */,
+  TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD,
+  TILEGX_OPC_PREFETCH_ADD_L1,
+  BITFIELD(31, 2) /* index 618 */,
+  TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, CHILD(623),
+  BITFIELD(33, 2) /* index 623 */,
+  TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, CHILD(628),
+  BITFIELD(35, 2) /* index 628 */,
+  TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD,
+  TILEGX_OPC_PREFETCH_ADD_L2_FAULT,
+  BITFIELD(31, 2) /* index 633 */,
+  TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, CHILD(638),
+  BITFIELD(33, 2) /* index 638 */,
+  TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, CHILD(643),
+  BITFIELD(35, 2) /* index 643 */,
+  TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD,
+  TILEGX_OPC_PREFETCH_ADD_L2,
+  BITFIELD(31, 2) /* index 648 */,
+  CHILD(653), CHILD(653), CHILD(653), CHILD(673),
+  BITFIELD(43, 2) /* index 653 */,
+  CHILD(658), TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD,
+  BITFIELD(45, 2) /* index 658 */,
+  CHILD(663), TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD,
+  BITFIELD(47, 2) /* index 663 */,
+  CHILD(668), TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD,
+  BITFIELD(49, 2) /* index 668 */,
+  TILEGX_OPC_LD4S_TLS, TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD,
+  TILEGX_OPC_LD4S_ADD,
+  BITFIELD(33, 2) /* index 673 */,
+  CHILD(653), CHILD(653), CHILD(653), CHILD(678),
+  BITFIELD(35, 2) /* index 678 */,
+  CHILD(653), CHILD(653), CHILD(653), CHILD(683),
+  BITFIELD(43, 2) /* index 683 */,
+  CHILD(688), TILEGX_OPC_PREFETCH_ADD_L3_FAULT,
+  TILEGX_OPC_PREFETCH_ADD_L3_FAULT, TILEGX_OPC_PREFETCH_ADD_L3_FAULT,
+  BITFIELD(45, 2) /* index 688 */,
+  CHILD(693), TILEGX_OPC_PREFETCH_ADD_L3_FAULT,
+  TILEGX_OPC_PREFETCH_ADD_L3_FAULT, TILEGX_OPC_PREFETCH_ADD_L3_FAULT,
+  BITFIELD(47, 2) /* index 693 */,
+  CHILD(698), TILEGX_OPC_PREFETCH_ADD_L3_FAULT,
+  TILEGX_OPC_PREFETCH_ADD_L3_FAULT, TILEGX_OPC_PREFETCH_ADD_L3_FAULT,
+  BITFIELD(49, 2) /* index 698 */,
+  TILEGX_OPC_LD4S_TLS, TILEGX_OPC_PREFETCH_ADD_L3_FAULT,
+  TILEGX_OPC_PREFETCH_ADD_L3_FAULT, TILEGX_OPC_PREFETCH_ADD_L3_FAULT,
+  BITFIELD(51, 2) /* index 703 */,
+  CHILD(708), TILEGX_OPC_LDNT1S_ADD, TILEGX_OPC_LDNT1U_ADD,
+  TILEGX_OPC_LDNT2S_ADD,
+  BITFIELD(31, 2) /* index 708 */,
+  TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, CHILD(713),
+  BITFIELD(33, 2) /* index 713 */,
+  TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, CHILD(718),
+  BITFIELD(35, 2) /* index 718 */,
+  TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD,
+  TILEGX_OPC_PREFETCH_ADD_L3,
+  BITFIELD(51, 2) /* index 723 */,
+  TILEGX_OPC_LDNT2U_ADD, TILEGX_OPC_LDNT4S_ADD, TILEGX_OPC_LDNT4U_ADD,
+  TILEGX_OPC_LDNT_ADD,
+  BITFIELD(51, 2) /* index 728 */,
+  CHILD(733), TILEGX_OPC_LDNA_ADD, TILEGX_OPC_MFSPR, TILEGX_OPC_MTSPR,
+  BITFIELD(43, 2) /* index 733 */,
+  CHILD(738), TILEGX_OPC_LD_ADD, TILEGX_OPC_LD_ADD, TILEGX_OPC_LD_ADD,
+  BITFIELD(45, 2) /* index 738 */,
+  CHILD(743), TILEGX_OPC_LD_ADD, TILEGX_OPC_LD_ADD, TILEGX_OPC_LD_ADD,
+  BITFIELD(47, 2) /* index 743 */,
+  CHILD(748), TILEGX_OPC_LD_ADD, TILEGX_OPC_LD_ADD, TILEGX_OPC_LD_ADD,
+  BITFIELD(49, 2) /* index 748 */,
+  TILEGX_OPC_LD_TLS, TILEGX_OPC_LD_ADD, TILEGX_OPC_LD_ADD, TILEGX_OPC_LD_ADD,
+  BITFIELD(51, 2) /* index 753 */,
+  TILEGX_OPC_ORI, TILEGX_OPC_ST1_ADD, TILEGX_OPC_ST2_ADD, TILEGX_OPC_ST4_ADD,
+  BITFIELD(51, 2) /* index 758 */,
+  TILEGX_OPC_STNT1_ADD, TILEGX_OPC_STNT2_ADD, TILEGX_OPC_STNT4_ADD,
+  TILEGX_OPC_STNT_ADD,
+  BITFIELD(51, 2) /* index 763 */,
+  TILEGX_OPC_ST_ADD, TILEGX_OPC_V1ADDI, TILEGX_OPC_V1CMPEQI,
+  TILEGX_OPC_V1CMPLTSI,
+  BITFIELD(51, 2) /* index 768 */,
+  TILEGX_OPC_V1CMPLTUI, TILEGX_OPC_V1MAXUI, TILEGX_OPC_V1MINUI,
+  TILEGX_OPC_V2ADDI,
+  BITFIELD(51, 2) /* index 773 */,
+  TILEGX_OPC_V2CMPEQI, TILEGX_OPC_V2CMPLTSI, TILEGX_OPC_V2CMPLTUI,
+  TILEGX_OPC_V2MAXSI,
+  BITFIELD(51, 2) /* index 778 */,
+  TILEGX_OPC_V2MINSI, TILEGX_OPC_XORI, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(49, 4) /* index 783 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_ADDXSC, TILEGX_OPC_ADDX, TILEGX_OPC_ADD,
+  TILEGX_OPC_AND, TILEGX_OPC_CMPEQ, TILEGX_OPC_CMPEXCH4, TILEGX_OPC_CMPEXCH,
+  TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU,
+  TILEGX_OPC_CMPNE, TILEGX_OPC_DBLALIGN2, TILEGX_OPC_DBLALIGN4,
+  TILEGX_OPC_DBLALIGN6,
+  BITFIELD(49, 4) /* index 800 */,
+  TILEGX_OPC_EXCH4, TILEGX_OPC_EXCH, TILEGX_OPC_FETCHADD4,
+  TILEGX_OPC_FETCHADDGEZ4, TILEGX_OPC_FETCHADDGEZ, TILEGX_OPC_FETCHADD,
+  TILEGX_OPC_FETCHAND4, TILEGX_OPC_FETCHAND, TILEGX_OPC_FETCHOR4,
+  TILEGX_OPC_FETCHOR, TILEGX_OPC_MNZ, TILEGX_OPC_MZ, TILEGX_OPC_NOR,
+  CHILD(817), TILEGX_OPC_ROTL, TILEGX_OPC_SHL1ADDX,
+  BITFIELD(43, 2) /* index 817 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(822),
+  BITFIELD(45, 2) /* index 822 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(827),
+  BITFIELD(47, 2) /* index 827 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE,
+  BITFIELD(49, 4) /* index 832 */,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADDX, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL3ADDX, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHLX, TILEGX_OPC_SHL,
+  TILEGX_OPC_SHRS, TILEGX_OPC_SHRUX, TILEGX_OPC_SHRU, TILEGX_OPC_ST1,
+  TILEGX_OPC_ST2, TILEGX_OPC_ST4, TILEGX_OPC_STNT1, TILEGX_OPC_STNT2,
+  TILEGX_OPC_STNT4,
+  BITFIELD(46, 7) /* index 849 */,
+  TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT,
+  TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT,
+  TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST,
+  TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_SUBXSC,
+  TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC,
+  TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBX,
+  TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUBX,
+  TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUB,
+  TILEGX_OPC_SUB, TILEGX_OPC_SUB, TILEGX_OPC_SUB, TILEGX_OPC_SUB,
+  TILEGX_OPC_SUB, TILEGX_OPC_SUB, TILEGX_OPC_SUB, CHILD(978), CHILD(987),
+  CHILD(1066), CHILD(1150), CHILD(1159), TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC,
+  TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC,
+  TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD,
+  TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD,
+  TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD, TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ,
+  TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ,
+  TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ,
+  TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES,
+  TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES,
+  TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLEU,
+  TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU,
+  TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU,
+  TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS,
+  TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS,
+  TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS,
+  TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU,
+  TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU,
+  TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPNE,
+  TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE,
+  TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE,
+  TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H,
+  TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H,
+  TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H,
+  TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L,
+  TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L,
+  TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L,
+  BITFIELD(43, 3) /* index 978 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_DRAIN, TILEGX_OPC_DTLBPR, TILEGX_OPC_FINV,
+  TILEGX_OPC_FLUSHWB, TILEGX_OPC_FLUSH, TILEGX_OPC_FNOP, TILEGX_OPC_ICOH,
+  BITFIELD(43, 3) /* index 987 */,
+  CHILD(996), TILEGX_OPC_INV, TILEGX_OPC_IRET, TILEGX_OPC_JALRP,
+  TILEGX_OPC_JALR, TILEGX_OPC_JRP, TILEGX_OPC_JR, CHILD(1051),
+  BITFIELD(31, 2) /* index 996 */,
+  CHILD(1001), CHILD(1026), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(33, 2) /* index 1001 */,
+  TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_ILL, CHILD(1006),
+  BITFIELD(35, 2) /* index 1006 */,
+  TILEGX_OPC_ILL, CHILD(1011), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(37, 2) /* index 1011 */,
+  TILEGX_OPC_ILL, CHILD(1016), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(39, 2) /* index 1016 */,
+  TILEGX_OPC_ILL, CHILD(1021), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(41, 2) /* index 1021 */,
+  TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_BPT, TILEGX_OPC_ILL,
+  BITFIELD(33, 2) /* index 1026 */,
+  TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_ILL, CHILD(1031),
+  BITFIELD(35, 2) /* index 1031 */,
+  TILEGX_OPC_ILL, CHILD(1036), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(37, 2) /* index 1036 */,
+  TILEGX_OPC_ILL, CHILD(1041), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(39, 2) /* index 1041 */,
+  TILEGX_OPC_ILL, CHILD(1046), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(41, 2) /* index 1046 */,
+  TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_RAISE, TILEGX_OPC_ILL,
+  BITFIELD(31, 2) /* index 1051 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, CHILD(1056),
+  BITFIELD(33, 2) /* index 1056 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, CHILD(1061),
+  BITFIELD(35, 2) /* index 1061 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S,
+  TILEGX_OPC_PREFETCH_L1_FAULT,
+  BITFIELD(43, 3) /* index 1066 */,
+  CHILD(1075), CHILD(1090), CHILD(1105), CHILD(1120), CHILD(1135),
+  TILEGX_OPC_LDNA, TILEGX_OPC_LDNT1S, TILEGX_OPC_LDNT1U,
+  BITFIELD(31, 2) /* index 1075 */,
+  TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, CHILD(1080),
+  BITFIELD(33, 2) /* index 1080 */,
+  TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, CHILD(1085),
+  BITFIELD(35, 2) /* index 1085 */,
+  TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_PREFETCH,
+  BITFIELD(31, 2) /* index 1090 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, CHILD(1095),
+  BITFIELD(33, 2) /* index 1095 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, CHILD(1100),
+  BITFIELD(35, 2) /* index 1100 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S,
+  TILEGX_OPC_PREFETCH_L2_FAULT,
+  BITFIELD(31, 2) /* index 1105 */,
+  TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, CHILD(1110),
+  BITFIELD(33, 2) /* index 1110 */,
+  TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, CHILD(1115),
+  BITFIELD(35, 2) /* index 1115 */,
+  TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_PREFETCH_L2,
+  BITFIELD(31, 2) /* index 1120 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(1125),
+  BITFIELD(33, 2) /* index 1125 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(1130),
+  BITFIELD(35, 2) /* index 1130 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S,
+  TILEGX_OPC_PREFETCH_L3_FAULT,
+  BITFIELD(31, 2) /* index 1135 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(1140),
+  BITFIELD(33, 2) /* index 1140 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(1145),
+  BITFIELD(35, 2) /* index 1145 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_PREFETCH_L3,
+  BITFIELD(43, 3) /* index 1150 */,
+  TILEGX_OPC_LDNT2S, TILEGX_OPC_LDNT2U, TILEGX_OPC_LDNT4S, TILEGX_OPC_LDNT4U,
+  TILEGX_OPC_LDNT, TILEGX_OPC_LD, TILEGX_OPC_LNK, TILEGX_OPC_MF,
+  BITFIELD(43, 3) /* index 1159 */,
+  TILEGX_OPC_NAP, TILEGX_OPC_NOP, TILEGX_OPC_SWINT0, TILEGX_OPC_SWINT1,
+  TILEGX_OPC_SWINT2, TILEGX_OPC_SWINT3, TILEGX_OPC_WH64, TILEGX_OPC_NONE,
+  BITFIELD(49, 4) /* index 1168 */,
+  TILEGX_OPC_V1MAXU, TILEGX_OPC_V1MINU, TILEGX_OPC_V1MNZ, TILEGX_OPC_V1MZ,
+  TILEGX_OPC_V1SHL, TILEGX_OPC_V1SHRS, TILEGX_OPC_V1SHRU, TILEGX_OPC_V1SUBUC,
+  TILEGX_OPC_V1SUB, TILEGX_OPC_V2ADDSC, TILEGX_OPC_V2ADD, TILEGX_OPC_V2CMPEQ,
+  TILEGX_OPC_V2CMPLES, TILEGX_OPC_V2CMPLEU, TILEGX_OPC_V2CMPLTS,
+  TILEGX_OPC_V2CMPLTU,
+  BITFIELD(49, 4) /* index 1185 */,
+  TILEGX_OPC_V2CMPNE, TILEGX_OPC_V2INT_H, TILEGX_OPC_V2INT_L,
+  TILEGX_OPC_V2MAXS, TILEGX_OPC_V2MINS, TILEGX_OPC_V2MNZ, TILEGX_OPC_V2MZ,
+  TILEGX_OPC_V2PACKH, TILEGX_OPC_V2PACKL, TILEGX_OPC_V2PACKUC,
+  TILEGX_OPC_V2SHLSC, TILEGX_OPC_V2SHL, TILEGX_OPC_V2SHRS, TILEGX_OPC_V2SHRU,
+  TILEGX_OPC_V2SUBSC, TILEGX_OPC_V2SUB,
+  BITFIELD(49, 4) /* index 1202 */,
+  TILEGX_OPC_V4ADDSC, TILEGX_OPC_V4ADD, TILEGX_OPC_V4INT_H,
+  TILEGX_OPC_V4INT_L, TILEGX_OPC_V4PACKSC, TILEGX_OPC_V4SHLSC,
+  TILEGX_OPC_V4SHL, TILEGX_OPC_V4SHRS, TILEGX_OPC_V4SHRU, TILEGX_OPC_V4SUBSC,
+  TILEGX_OPC_V4SUB, TILEGX_OPC_XOR, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(49, 4) /* index 1219 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHLXI,
+  TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI, TILEGX_OPC_SHRUXI, TILEGX_OPC_V1SHLI,
+  TILEGX_OPC_V1SHRSI, TILEGX_OPC_V1SHRUI, TILEGX_OPC_V2SHLI,
+  TILEGX_OPC_V2SHRSI, TILEGX_OPC_V2SHRUI, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE,
+  BITFIELD(31, 2) /* index 1236 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(1241),
+  BITFIELD(33, 2) /* index 1241 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(1246),
+  BITFIELD(35, 2) /* index 1246 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(1251),
+  BITFIELD(37, 2) /* index 1251 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(1256),
+  BITFIELD(39, 2) /* index 1256 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(1261),
+  BITFIELD(41, 2) /* index 1261 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  TILEGX_OPC_INFOL,
+};
+
+static const unsigned short decode_Y0_fsm[178] =
+{
+  BITFIELD(27, 4) /* index 0 */,
+  CHILD(17), TILEGX_OPC_ADDXI, CHILD(32), TILEGX_OPC_CMPEQI,
+  TILEGX_OPC_CMPLTSI, CHILD(62), CHILD(67), CHILD(118), CHILD(123),
+  CHILD(128), CHILD(133), CHILD(153), CHILD(158), CHILD(163), CHILD(168),
+  CHILD(173),
+  BITFIELD(6, 2) /* index 17 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(22),
+  BITFIELD(8, 2) /* index 22 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(27),
+  BITFIELD(10, 2) /* index 27 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI,
+  BITFIELD(0, 2) /* index 32 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(37),
+  BITFIELD(2, 2) /* index 37 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(42),
+  BITFIELD(4, 2) /* index 42 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(47),
+  BITFIELD(6, 2) /* index 47 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(52),
+  BITFIELD(8, 2) /* index 52 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(57),
+  BITFIELD(10, 2) /* index 57 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO,
+  BITFIELD(18, 2) /* index 62 */,
+  TILEGX_OPC_ADDX, TILEGX_OPC_ADD, TILEGX_OPC_SUBX, TILEGX_OPC_SUB,
+  BITFIELD(15, 5) /* index 67 */,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD,
+  TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD,
+  TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, CHILD(100),
+  CHILD(109), TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(12, 3) /* index 100 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_CLZ, TILEGX_OPC_CTZ, TILEGX_OPC_FNOP,
+  TILEGX_OPC_FSINGLE_PACK1, TILEGX_OPC_NOP, TILEGX_OPC_PCNT,
+  TILEGX_OPC_REVBITS,
+  BITFIELD(12, 3) /* index 109 */,
+  TILEGX_OPC_REVBYTES, TILEGX_OPC_TBLIDXB0, TILEGX_OPC_TBLIDXB1,
+  TILEGX_OPC_TBLIDXB2, TILEGX_OPC_TBLIDXB3, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE,
+  BITFIELD(18, 2) /* index 118 */,
+  TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU,
+  BITFIELD(18, 2) /* index 123 */,
+  TILEGX_OPC_CMPEQ, TILEGX_OPC_CMPNE, TILEGX_OPC_MULAX, TILEGX_OPC_MULX,
+  BITFIELD(18, 2) /* index 128 */,
+  TILEGX_OPC_CMOVEQZ, TILEGX_OPC_CMOVNEZ, TILEGX_OPC_MNZ, TILEGX_OPC_MZ,
+  BITFIELD(18, 2) /* index 133 */,
+  TILEGX_OPC_AND, TILEGX_OPC_NOR, CHILD(138), TILEGX_OPC_XOR,
+  BITFIELD(12, 2) /* index 138 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(143),
+  BITFIELD(14, 2) /* index 143 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(148),
+  BITFIELD(16, 2) /* index 148 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE,
+  BITFIELD(18, 2) /* index 153 */,
+  TILEGX_OPC_ROTL, TILEGX_OPC_SHL, TILEGX_OPC_SHRS, TILEGX_OPC_SHRU,
+  BITFIELD(18, 2) /* index 158 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_SHL1ADDX, TILEGX_OPC_SHL2ADDX,
+  TILEGX_OPC_SHL3ADDX,
+  BITFIELD(18, 2) /* index 163 */,
+  TILEGX_OPC_MUL_HS_HS, TILEGX_OPC_MUL_HU_HU, TILEGX_OPC_MUL_LS_LS,
+  TILEGX_OPC_MUL_LU_LU,
+  BITFIELD(18, 2) /* index 168 */,
+  TILEGX_OPC_MULA_HS_HS, TILEGX_OPC_MULA_HU_HU, TILEGX_OPC_MULA_LS_LS,
+  TILEGX_OPC_MULA_LU_LU,
+  BITFIELD(18, 2) /* index 173 */,
+  TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI,
+};
+
+static const unsigned short decode_Y1_fsm[167] =
+{
+  BITFIELD(58, 4) /* index 0 */,
+  TILEGX_OPC_NONE, CHILD(17), TILEGX_OPC_ADDXI, CHILD(32), TILEGX_OPC_CMPEQI,
+  TILEGX_OPC_CMPLTSI, CHILD(62), CHILD(67), CHILD(117), CHILD(122),
+  CHILD(127), CHILD(132), CHILD(152), CHILD(157), CHILD(162), TILEGX_OPC_NONE,
+  BITFIELD(37, 2) /* index 17 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(22),
+  BITFIELD(39, 2) /* index 22 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(27),
+  BITFIELD(41, 2) /* index 27 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI,
+  BITFIELD(31, 2) /* index 32 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(37),
+  BITFIELD(33, 2) /* index 37 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(42),
+  BITFIELD(35, 2) /* index 42 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(47),
+  BITFIELD(37, 2) /* index 47 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(52),
+  BITFIELD(39, 2) /* index 52 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(57),
+  BITFIELD(41, 2) /* index 57 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO,
+  BITFIELD(49, 2) /* index 62 */,
+  TILEGX_OPC_ADDX, TILEGX_OPC_ADD, TILEGX_OPC_SUBX, TILEGX_OPC_SUB,
+  BITFIELD(47, 4) /* index 67 */,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL3ADD,
+  TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, CHILD(84),
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(43, 3) /* index 84 */,
+  CHILD(93), CHILD(96), CHILD(99), CHILD(102), CHILD(105), CHILD(108),
+  CHILD(111), CHILD(114),
+  BITFIELD(46, 1) /* index 93 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_FNOP,
+  BITFIELD(46, 1) /* index 96 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_ILL,
+  BITFIELD(46, 1) /* index 99 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_JALRP,
+  BITFIELD(46, 1) /* index 102 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_JALR,
+  BITFIELD(46, 1) /* index 105 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_JRP,
+  BITFIELD(46, 1) /* index 108 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_JR,
+  BITFIELD(46, 1) /* index 111 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_LNK,
+  BITFIELD(46, 1) /* index 114 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_NOP,
+  BITFIELD(49, 2) /* index 117 */,
+  TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU,
+  BITFIELD(49, 2) /* index 122 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_CMPEQ, TILEGX_OPC_CMPNE,
+  BITFIELD(49, 2) /* index 127 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_MNZ, TILEGX_OPC_MZ,
+  BITFIELD(49, 2) /* index 132 */,
+  TILEGX_OPC_AND, TILEGX_OPC_NOR, CHILD(137), TILEGX_OPC_XOR,
+  BITFIELD(43, 2) /* index 137 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(142),
+  BITFIELD(45, 2) /* index 142 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(147),
+  BITFIELD(47, 2) /* index 147 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE,
+  BITFIELD(49, 2) /* index 152 */,
+  TILEGX_OPC_ROTL, TILEGX_OPC_SHL, TILEGX_OPC_SHRS, TILEGX_OPC_SHRU,
+  BITFIELD(49, 2) /* index 157 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_SHL1ADDX, TILEGX_OPC_SHL2ADDX,
+  TILEGX_OPC_SHL3ADDX,
+  BITFIELD(49, 2) /* index 162 */,
+  TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI,
+};
+
+static const unsigned short decode_Y2_fsm[118] =
+{
+  BITFIELD(62, 2) /* index 0 */,
+  TILEGX_OPC_NONE, CHILD(5), CHILD(66), CHILD(109),
+  BITFIELD(55, 3) /* index 5 */,
+  CHILD(14), CHILD(14), CHILD(14), CHILD(17), CHILD(40), CHILD(40), CHILD(40),
+  CHILD(43),
+  BITFIELD(26, 1) /* index 14 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1U,
+  BITFIELD(26, 1) /* index 17 */,
+  CHILD(20), CHILD(30),
+  BITFIELD(51, 2) /* index 20 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, CHILD(25),
+  BITFIELD(53, 2) /* index 25 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S,
+  TILEGX_OPC_PREFETCH_L1_FAULT,
+  BITFIELD(51, 2) /* index 30 */,
+  TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, CHILD(35),
+  BITFIELD(53, 2) /* index 35 */,
+  TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_PREFETCH,
+  BITFIELD(26, 1) /* index 40 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2U,
+  BITFIELD(26, 1) /* index 43 */,
+  CHILD(46), CHILD(56),
+  BITFIELD(51, 2) /* index 46 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, CHILD(51),
+  BITFIELD(53, 2) /* index 51 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S,
+  TILEGX_OPC_PREFETCH_L2_FAULT,
+  BITFIELD(51, 2) /* index 56 */,
+  TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, CHILD(61),
+  BITFIELD(53, 2) /* index 61 */,
+  TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_PREFETCH_L2,
+  BITFIELD(56, 2) /* index 66 */,
+  CHILD(71), CHILD(74), CHILD(90), CHILD(93),
+  BITFIELD(26, 1) /* index 71 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_LD4S,
+  BITFIELD(26, 1) /* index 74 */,
+  TILEGX_OPC_NONE, CHILD(77),
+  BITFIELD(51, 2) /* index 77 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(82),
+  BITFIELD(53, 2) /* index 82 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(87),
+  BITFIELD(55, 1) /* index 87 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_PREFETCH_L3_FAULT,
+  BITFIELD(26, 1) /* index 90 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD,
+  BITFIELD(26, 1) /* index 93 */,
+  CHILD(96), TILEGX_OPC_LD,
+  BITFIELD(51, 2) /* index 96 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(101),
+  BITFIELD(53, 2) /* index 101 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(106),
+  BITFIELD(55, 1) /* index 106 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_PREFETCH_L3,
+  BITFIELD(26, 1) /* index 109 */,
+  CHILD(112), CHILD(115),
+  BITFIELD(57, 1) /* index 112 */,
+  TILEGX_OPC_ST1, TILEGX_OPC_ST4,
+  BITFIELD(57, 1) /* index 115 */,
+  TILEGX_OPC_ST2, TILEGX_OPC_ST,
+};
+
+#undef BITFIELD
+#undef CHILD
+
+const unsigned short * const
+tilegx_bundle_decoder_fsms[TILEGX_NUM_PIPELINE_ENCODINGS] =
+{
+  decode_X0_fsm,
+  decode_X1_fsm,
+  decode_Y0_fsm,
+  decode_Y1_fsm,
+  decode_Y2_fsm
+};
+
+const struct tilegx_operand tilegx_operands[35] =
+{
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_X0),
+    8, 1, 0, 0, 0, 0,
+    create_Imm8_X0, get_Imm8_X0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_X1),
+    8, 1, 0, 0, 0, 0,
+    create_Imm8_X1, get_Imm8_X1
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_Y0),
+    8, 1, 0, 0, 0, 0,
+    create_Imm8_Y0, get_Imm8_Y0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_Y1),
+    8, 1, 0, 0, 0, 0,
+    create_Imm8_Y1, get_Imm8_Y1
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM16_X0_HW0_LAST),
+    16, 1, 0, 0, 0, 0,
+    create_Imm16_X0, get_Imm16_X0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM16_X1_HW0_LAST),
+    16, 1, 0, 0, 0, 0,
+    create_Imm16_X1, get_Imm16_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 0, 1, 0, 0,
+    create_Dest_X1, get_Dest_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcA_X1, get_SrcA_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 0, 1, 0, 0,
+    create_Dest_X0, get_Dest_X0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcA_X0, get_SrcA_X0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 0, 1, 0, 0,
+    create_Dest_Y0, get_Dest_Y0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcA_Y0, get_SrcA_Y0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 0, 1, 0, 0,
+    create_Dest_Y1, get_Dest_Y1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcA_Y1, get_SrcA_Y1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcA_Y2, get_SrcA_Y2
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 1, 0, 0,
+    create_SrcA_X1, get_SrcA_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcB_X0, get_SrcB_X0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcB_X1, get_SrcB_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcB_Y0, get_SrcB_Y0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcB_Y1, get_SrcB_Y1
+  },
+  {
+    TILEGX_OP_TYPE_ADDRESS, BFD_RELOC(TILEGX_BROFF_X1),
+    17, 1, 0, 0, 1, TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES,
+    create_BrOff_X1, get_BrOff_X1
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_MMSTART_X0),
+    6, 0, 0, 0, 0, 0,
+    create_BFStart_X0, get_BFStart_X0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_MMEND_X0),
+    6, 0, 0, 0, 0, 0,
+    create_BFEnd_X0, get_BFEnd_X0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 1, 0, 0,
+    create_Dest_X0, get_Dest_X0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 1, 0, 0,
+    create_Dest_Y0, get_Dest_Y0
+  },
+  {
+    TILEGX_OP_TYPE_ADDRESS, BFD_RELOC(TILEGX_JUMPOFF_X1),
+    27, 1, 0, 0, 1, TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES,
+    create_JumpOff_X1, get_JumpOff_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 0, 1, 0, 0,
+    create_SrcBDest_Y2, get_SrcBDest_Y2
+  },
+  {
+    TILEGX_OP_TYPE_SPR, BFD_RELOC(TILEGX_MF_IMM14_X1),
+    14, 0, 0, 0, 0, 0,
+    create_MF_Imm14_X1, get_MF_Imm14_X1
+  },
+  {
+    TILEGX_OP_TYPE_SPR, BFD_RELOC(TILEGX_MT_IMM14_X1),
+    14, 0, 0, 0, 0, 0,
+    create_MT_Imm14_X1, get_MT_Imm14_X1
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_X0),
+    6, 0, 0, 0, 0, 0,
+    create_ShAmt_X0, get_ShAmt_X0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_X1),
+    6, 0, 0, 0, 0, 0,
+    create_ShAmt_X1, get_ShAmt_X1
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_Y0),
+    6, 0, 0, 0, 0, 0,
+    create_ShAmt_Y0, get_ShAmt_Y0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_Y1),
+    6, 0, 0, 0, 0, 0,
+    create_ShAmt_Y1, get_ShAmt_Y1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcBDest_Y2, get_SrcBDest_Y2
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_DEST_IMM8_X1),
+    8, 1, 0, 0, 0, 0,
+    create_Dest_Imm8_X1, get_Dest_Imm8_X1
+  }
+};
+
+/* Given a set of bundle bits and a specific pipe, returns which
+ * instruction the bundle contains in that pipe.
+ */
+const struct tilegx_opcode *
+find_opcode(tilegx_bundle_bits bits, tilegx_pipeline pipe)
+{
+  const unsigned short *table = tilegx_bundle_decoder_fsms[pipe];
+  int index = 0;
+
+  while (1)
+  {
+    unsigned short bitspec = table[index];
+    unsigned int bitfield =
+      ((unsigned int)(bits >> (bitspec & 63))) & (bitspec >> 6);
+
+    unsigned short next = table[index + 1 + bitfield];
+    if (next <= TILEGX_OPC_NONE)
+      return &tilegx_opcodes[next];
+
+    index = next - TILEGX_OPC_NONE;
+  }
+}
+
+int
+parse_insn_tilegx(tilegx_bundle_bits bits,
+                  unsigned long long pc,
+                  struct tilegx_decoded_instruction
+                  decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE])
+{
+  int num_instructions = 0;
+  int pipe;
+
+  int min_pipe, max_pipe;
+  if ((bits & TILEGX_BUNDLE_MODE_MASK) == 0)
+  {
+    min_pipe = TILEGX_PIPELINE_X0;
+    max_pipe = TILEGX_PIPELINE_X1;
+  }
+  else
+  {
+    min_pipe = TILEGX_PIPELINE_Y0;
+    max_pipe = TILEGX_PIPELINE_Y2;
+  }
+
+  /* For each pipe, find an instruction that fits. */
+  for (pipe = min_pipe; pipe <= max_pipe; pipe++)
+  {
+    const struct tilegx_opcode *opc;
+    struct tilegx_decoded_instruction *d;
+    int i;
+
+    d = &decoded[num_instructions++];
+    opc = find_opcode (bits, (tilegx_pipeline)pipe);
+    d->opcode = opc;
+
+    /* Decode each operand, sign extending, etc. as appropriate. */
+    for (i = 0; i < opc->num_operands; i++)
+    {
+      const struct tilegx_operand *op =
+        &tilegx_operands[opc->operands[pipe][i]];
+      int raw_opval = op->extract (bits);
+      long long opval;
+
+      if (op->is_signed)
+      {
+        /* Sign-extend the operand. */
+        int shift = (int)((sizeof(int) * 8) - op->num_bits);
+        raw_opval = (raw_opval << shift) >> shift;
+      }
+
+      /* Adjust PC-relative scaled branch offsets. */
+      if (op->type == TILEGX_OP_TYPE_ADDRESS)
+        opval = (raw_opval * TILEGX_BUNDLE_SIZE_IN_BYTES) + pc;
+      else
+        opval = raw_opval;
+
+      /* Record the final value. */
+      d->operands[i] = op;
+      d->operand_values[i] = opval;
+    }
+  }
+
+  return num_instructions;
+}
+
+struct tilegx_spr
+{
+  /* The number */
+  int number;
+
+  /* The name */
+  const char *name;
+};
+
+static int
+tilegx_spr_compare (const void *a_ptr, const void *b_ptr)
+{
+  const struct tilegx_spr *a = (const struct tilegx_spr *) a_ptr;
+  const struct tilegx_spr *b = (const struct tilegx_spr *) b_ptr;
+  return (a->number - b->number);
+}
+
+const struct tilegx_spr tilegx_sprs[] = {
+  { 0, "MPL_MEM_ERROR_SET_0" },
+  { 1, "MPL_MEM_ERROR_SET_1" },
+  { 2, "MPL_MEM_ERROR_SET_2" },
+  { 3, "MPL_MEM_ERROR_SET_3" },
+  { 4, "MPL_MEM_ERROR" },
+  { 5, "MEM_ERROR_CBOX_ADDR" },
+  { 6, "MEM_ERROR_CBOX_STATUS" },
+  { 7, "MEM_ERROR_ENABLE" },
+  { 8, "MEM_ERROR_MBOX_ADDR" },
+  { 9, "MEM_ERROR_MBOX_STATUS" },
+  { 10, "SBOX_ERROR" },
+  { 11, "XDN_DEMUX_ERROR" },
+  { 256, "MPL_SINGLE_STEP_3_SET_0" },
+  { 257, "MPL_SINGLE_STEP_3_SET_1" },
+  { 258, "MPL_SINGLE_STEP_3_SET_2" },
+  { 259, "MPL_SINGLE_STEP_3_SET_3" },
+  { 260, "MPL_SINGLE_STEP_3" },
+  { 261, "SINGLE_STEP_CONTROL_3" },
+  { 512, "MPL_SINGLE_STEP_2_SET_0" },
+  { 513, "MPL_SINGLE_STEP_2_SET_1" },
+  { 514, "MPL_SINGLE_STEP_2_SET_2" },
+  { 515, "MPL_SINGLE_STEP_2_SET_3" },
+  { 516, "MPL_SINGLE_STEP_2" },
+  { 517, "SINGLE_STEP_CONTROL_2" },
+  { 768, "MPL_SINGLE_STEP_1_SET_0" },
+  { 769, "MPL_SINGLE_STEP_1_SET_1" },
+  { 770, "MPL_SINGLE_STEP_1_SET_2" },
+  { 771, "MPL_SINGLE_STEP_1_SET_3" },
+  { 772, "MPL_SINGLE_STEP_1" },
+  { 773, "SINGLE_STEP_CONTROL_1" },
+  { 1024, "MPL_SINGLE_STEP_0_SET_0" },
+  { 1025, "MPL_SINGLE_STEP_0_SET_1" },
+  { 1026, "MPL_SINGLE_STEP_0_SET_2" },
+  { 1027, "MPL_SINGLE_STEP_0_SET_3" },
+  { 1028, "MPL_SINGLE_STEP_0" },
+  { 1029, "SINGLE_STEP_CONTROL_0" },
+  { 1280, "MPL_IDN_COMPLETE_SET_0" },
+  { 1281, "MPL_IDN_COMPLETE_SET_1" },
+  { 1282, "MPL_IDN_COMPLETE_SET_2" },
+  { 1283, "MPL_IDN_COMPLETE_SET_3" },
+  { 1284, "MPL_IDN_COMPLETE" },
+  { 1285, "IDN_COMPLETE_PENDING" },
+  { 1536, "MPL_UDN_COMPLETE_SET_0" },
+  { 1537, "MPL_UDN_COMPLETE_SET_1" },
+  { 1538, "MPL_UDN_COMPLETE_SET_2" },
+  { 1539, "MPL_UDN_COMPLETE_SET_3" },
+  { 1540, "MPL_UDN_COMPLETE" },
+  { 1541, "UDN_COMPLETE_PENDING" },
+  { 1792, "MPL_ITLB_MISS_SET_0" },
+  { 1793, "MPL_ITLB_MISS_SET_1" },
+  { 1794, "MPL_ITLB_MISS_SET_2" },
+  { 1795, "MPL_ITLB_MISS_SET_3" },
+  { 1796, "MPL_ITLB_MISS" },
+  { 1797, "ITLB_TSB_BASE_ADDR_0" },
+  { 1798, "ITLB_TSB_BASE_ADDR_1" },
+  { 1920, "ITLB_CURRENT_ATTR" },
+  { 1921, "ITLB_CURRENT_PA" },
+  { 1922, "ITLB_CURRENT_VA" },
+  { 1923, "ITLB_INDEX" },
+  { 1924, "ITLB_MATCH_0" },
+  { 1925, "ITLB_PERF" },
+  { 1926, "ITLB_PR" },
+  { 1927, "ITLB_TSB_ADDR_0" },
+  { 1928, "ITLB_TSB_ADDR_1" },
+  { 1929, "ITLB_TSB_FILL_CURRENT_ATTR" },
+  { 1930, "ITLB_TSB_FILL_MATCH" },
+  { 1931, "NUMBER_ITLB" },
+  { 1932, "REPLACEMENT_ITLB" },
+  { 1933, "WIRED_ITLB" },
+  { 2048, "MPL_ILL_SET_0" },
+  { 2049, "MPL_ILL_SET_1" },
+  { 2050, "MPL_ILL_SET_2" },
+  { 2051, "MPL_ILL_SET_3" },
+  { 2052, "MPL_ILL" },
+  { 2304, "MPL_GPV_SET_0" },
+  { 2305, "MPL_GPV_SET_1" },
+  { 2306, "MPL_GPV_SET_2" },
+  { 2307, "MPL_GPV_SET_3" },
+  { 2308, "MPL_GPV" },
+  { 2309, "GPV_REASON" },
+  { 2560, "MPL_IDN_ACCESS_SET_0" },
+  { 2561, "MPL_IDN_ACCESS_SET_1" },
+  { 2562, "MPL_IDN_ACCESS_SET_2" },
+  { 2563, "MPL_IDN_ACCESS_SET_3" },
+  { 2564, "MPL_IDN_ACCESS" },
+  { 2565, "IDN_DEMUX_COUNT_0" },
+  { 2566, "IDN_DEMUX_COUNT_1" },
+  { 2567, "IDN_FLUSH_EGRESS" },
+  { 2568, "IDN_PENDING" },
+  { 2569, "IDN_ROUTE_ORDER" },
+  { 2570, "IDN_SP_FIFO_CNT" },
+  { 2688, "IDN_DATA_AVAIL" },
+  { 2816, "MPL_UDN_ACCESS_SET_0" },
+  { 2817, "MPL_UDN_ACCESS_SET_1" },
+  { 2818, "MPL_UDN_ACCESS_SET_2" },
+  { 2819, "MPL_UDN_ACCESS_SET_3" },
+  { 2820, "MPL_UDN_ACCESS" },
+  { 2821, "UDN_DEMUX_COUNT_0" },
+  { 2822, "UDN_DEMUX_COUNT_1" },
+  { 2823, "UDN_DEMUX_COUNT_2" },
+  { 2824, "UDN_DEMUX_COUNT_3" },
+  { 2825, "UDN_FLUSH_EGRESS" },
+  { 2826, "UDN_PENDING" },
+  { 2827, "UDN_ROUTE_ORDER" },
+  { 2828, "UDN_SP_FIFO_CNT" },
+  { 2944, "UDN_DATA_AVAIL" },
+  { 3072, "MPL_SWINT_3_SET_0" },
+  { 3073, "MPL_SWINT_3_SET_1" },
+  { 3074, "MPL_SWINT_3_SET_2" },
+  { 3075, "MPL_SWINT_3_SET_3" },
+  { 3076, "MPL_SWINT_3" },
+  { 3328, "MPL_SWINT_2_SET_0" },
+  { 3329, "MPL_SWINT_2_SET_1" },
+  { 3330, "MPL_SWINT_2_SET_2" },
+  { 3331, "MPL_SWINT_2_SET_3" },
+  { 3332, "MPL_SWINT_2" },
+  { 3584, "MPL_SWINT_1_SET_0" },
+  { 3585, "MPL_SWINT_1_SET_1" },
+  { 3586, "MPL_SWINT_1_SET_2" },
+  { 3587, "MPL_SWINT_1_SET_3" },
+  { 3588, "MPL_SWINT_1" },
+  { 3840, "MPL_SWINT_0_SET_0" },
+  { 3841, "MPL_SWINT_0_SET_1" },
+  { 3842, "MPL_SWINT_0_SET_2" },
+  { 3843, "MPL_SWINT_0_SET_3" },
+  { 3844, "MPL_SWINT_0" },
+  { 4096, "MPL_ILL_TRANS_SET_0" },
+  { 4097, "MPL_ILL_TRANS_SET_1" },
+  { 4098, "MPL_ILL_TRANS_SET_2" },
+  { 4099, "MPL_ILL_TRANS_SET_3" },
+  { 4100, "MPL_ILL_TRANS" },
+  { 4101, "ILL_TRANS_REASON" },
+  { 4102, "ILL_VA_PC" },
+  { 4352, "MPL_UNALIGN_DATA_SET_0" },
+  { 4353, "MPL_UNALIGN_DATA_SET_1" },
+  { 4354, "MPL_UNALIGN_DATA_SET_2" },
+  { 4355, "MPL_UNALIGN_DATA_SET_3" },
+  { 4356, "MPL_UNALIGN_DATA" },
+  { 4608, "MPL_DTLB_MISS_SET_0" },
+  { 4609, "MPL_DTLB_MISS_SET_1" },
+  { 4610, "MPL_DTLB_MISS_SET_2" },
+  { 4611, "MPL_DTLB_MISS_SET_3" },
+  { 4612, "MPL_DTLB_MISS" },
+  { 4613, "DTLB_TSB_BASE_ADDR_0" },
+  { 4614, "DTLB_TSB_BASE_ADDR_1" },
+  { 4736, "AAR" },
+  { 4737, "CACHE_PINNED_WAYS" },
+  { 4738, "DTLB_BAD_ADDR" },
+  { 4739, "DTLB_BAD_ADDR_REASON" },
+  { 4740, "DTLB_CURRENT_ATTR" },
+  { 4741, "DTLB_CURRENT_PA" },
+  { 4742, "DTLB_CURRENT_VA" },
+  { 4743, "DTLB_INDEX" },
+  { 4744, "DTLB_MATCH_0" },
+  { 4745, "DTLB_PERF" },
+  { 4746, "DTLB_TSB_ADDR_0" },
+  { 4747, "DTLB_TSB_ADDR_1" },
+  { 4748, "DTLB_TSB_FILL_CURRENT_ATTR" },
+  { 4749, "DTLB_TSB_FILL_MATCH" },
+  { 4750, "NUMBER_DTLB" },
+  { 4751, "REPLACEMENT_DTLB" },
+  { 4752, "WIRED_DTLB" },
+  { 4864, "MPL_DTLB_ACCESS_SET_0" },
+  { 4865, "MPL_DTLB_ACCESS_SET_1" },
+  { 4866, "MPL_DTLB_ACCESS_SET_2" },
+  { 4867, "MPL_DTLB_ACCESS_SET_3" },
+  { 4868, "MPL_DTLB_ACCESS" },
+  { 5120, "MPL_IDN_FIREWALL_SET_0" },
+  { 5121, "MPL_IDN_FIREWALL_SET_1" },
+  { 5122, "MPL_IDN_FIREWALL_SET_2" },
+  { 5123, "MPL_IDN_FIREWALL_SET_3" },
+  { 5124, "MPL_IDN_FIREWALL" },
+  { 5125, "IDN_DIRECTION_PROTECT" },
+  { 5376, "MPL_UDN_FIREWALL_SET_0" },
+  { 5377, "MPL_UDN_FIREWALL_SET_1" },
+  { 5378, "MPL_UDN_FIREWALL_SET_2" },
+  { 5379, "MPL_UDN_FIREWALL_SET_3" },
+  { 5380, "MPL_UDN_FIREWALL" },
+  { 5381, "UDN_DIRECTION_PROTECT" },
+  { 5632, "MPL_TILE_TIMER_SET_0" },
+  { 5633, "MPL_TILE_TIMER_SET_1" },
+  { 5634, "MPL_TILE_TIMER_SET_2" },
+  { 5635, "MPL_TILE_TIMER_SET_3" },
+  { 5636, "MPL_TILE_TIMER" },
+  { 5637, "TILE_TIMER_CONTROL" },
+  { 5888, "MPL_AUX_TILE_TIMER_SET_0" },
+  { 5889, "MPL_AUX_TILE_TIMER_SET_1" },
+  { 5890, "MPL_AUX_TILE_TIMER_SET_2" },
+  { 5891, "MPL_AUX_TILE_TIMER_SET_3" },
+  { 5892, "MPL_AUX_TILE_TIMER" },
+  { 5893, "AUX_TILE_TIMER_CONTROL" },
+  { 6144, "MPL_IDN_TIMER_SET_0" },
+  { 6145, "MPL_IDN_TIMER_SET_1" },
+  { 6146, "MPL_IDN_TIMER_SET_2" },
+  { 6147, "MPL_IDN_TIMER_SET_3" },
+  { 6148, "MPL_IDN_TIMER" },
+  { 6149, "IDN_DEADLOCK_COUNT" },
+  { 6150, "IDN_DEADLOCK_TIMEOUT" },
+  { 6400, "MPL_UDN_TIMER_SET_0" },
+  { 6401, "MPL_UDN_TIMER_SET_1" },
+  { 6402, "MPL_UDN_TIMER_SET_2" },
+  { 6403, "MPL_UDN_TIMER_SET_3" },
+  { 6404, "MPL_UDN_TIMER" },
+  { 6405, "UDN_DEADLOCK_COUNT" },
+  { 6406, "UDN_DEADLOCK_TIMEOUT" },
+  { 6656, "MPL_IDN_AVAIL_SET_0" },
+  { 6657, "MPL_IDN_AVAIL_SET_1" },
+  { 6658, "MPL_IDN_AVAIL_SET_2" },
+  { 6659, "MPL_IDN_AVAIL_SET_3" },
+  { 6660, "MPL_IDN_AVAIL" },
+  { 6661, "IDN_AVAIL_EN" },
+  { 6912, "MPL_UDN_AVAIL_SET_0" },
+  { 6913, "MPL_UDN_AVAIL_SET_1" },
+  { 6914, "MPL_UDN_AVAIL_SET_2" },
+  { 6915, "MPL_UDN_AVAIL_SET_3" },
+  { 6916, "MPL_UDN_AVAIL" },
+  { 6917, "UDN_AVAIL_EN" },
+  { 7168, "MPL_IPI_3_SET_0" },
+  { 7169, "MPL_IPI_3_SET_1" },
+  { 7170, "MPL_IPI_3_SET_2" },
+  { 7171, "MPL_IPI_3_SET_3" },
+  { 7172, "MPL_IPI_3" },
+  { 7173, "IPI_EVENT_3" },
+  { 7174, "IPI_EVENT_RESET_3" },
+  { 7175, "IPI_EVENT_SET_3" },
+  { 7176, "IPI_MASK_3" },
+  { 7177, "IPI_MASK_RESET_3" },
+  { 7178, "IPI_MASK_SET_3" },
+  { 7424, "MPL_IPI_2_SET_0" },
+  { 7425, "MPL_IPI_2_SET_1" },
+  { 7426, "MPL_IPI_2_SET_2" },
+  { 7427, "MPL_IPI_2_SET_3" },
+  { 7428, "MPL_IPI_2" },
+  { 7429, "IPI_EVENT_2" },
+  { 7430, "IPI_EVENT_RESET_2" },
+  { 7431, "IPI_EVENT_SET_2" },
+  { 7432, "IPI_MASK_2" },
+  { 7433, "IPI_MASK_RESET_2" },
+  { 7434, "IPI_MASK_SET_2" },
+  { 7680, "MPL_IPI_1_SET_0" },
+  { 7681, "MPL_IPI_1_SET_1" },
+  { 7682, "MPL_IPI_1_SET_2" },
+  { 7683, "MPL_IPI_1_SET_3" },
+  { 7684, "MPL_IPI_1" },
+  { 7685, "IPI_EVENT_1" },
+  { 7686, "IPI_EVENT_RESET_1" },
+  { 7687, "IPI_EVENT_SET_1" },
+  { 7688, "IPI_MASK_1" },
+  { 7689, "IPI_MASK_RESET_1" },
+  { 7690, "IPI_MASK_SET_1" },
+  { 7936, "MPL_IPI_0_SET_0" },
+  { 7937, "MPL_IPI_0_SET_1" },
+  { 7938, "MPL_IPI_0_SET_2" },
+  { 7939, "MPL_IPI_0_SET_3" },
+  { 7940, "MPL_IPI_0" },
+  { 7941, "IPI_EVENT_0" },
+  { 7942, "IPI_EVENT_RESET_0" },
+  { 7943, "IPI_EVENT_SET_0" },
+  { 7944, "IPI_MASK_0" },
+  { 7945, "IPI_MASK_RESET_0" },
+  { 7946, "IPI_MASK_SET_0" },
+  { 8192, "MPL_PERF_COUNT_SET_0" },
+  { 8193, "MPL_PERF_COUNT_SET_1" },
+  { 8194, "MPL_PERF_COUNT_SET_2" },
+  { 8195, "MPL_PERF_COUNT_SET_3" },
+  { 8196, "MPL_PERF_COUNT" },
+  { 8197, "PERF_COUNT_0" },
+  { 8198, "PERF_COUNT_1" },
+  { 8199, "PERF_COUNT_CTL" },
+  { 8200, "PERF_COUNT_DN_CTL" },
+  { 8201, "PERF_COUNT_STS" },
+  { 8202, "WATCH_MASK" },
+  { 8203, "WATCH_VAL" },
+  { 8448, "MPL_AUX_PERF_COUNT_SET_0" },
+  { 8449, "MPL_AUX_PERF_COUNT_SET_1" },
+  { 8450, "MPL_AUX_PERF_COUNT_SET_2" },
+  { 8451, "MPL_AUX_PERF_COUNT_SET_3" },
+  { 8452, "MPL_AUX_PERF_COUNT" },
+  { 8453, "AUX_PERF_COUNT_0" },
+  { 8454, "AUX_PERF_COUNT_1" },
+  { 8455, "AUX_PERF_COUNT_CTL" },
+  { 8456, "AUX_PERF_COUNT_STS" },
+  { 8704, "MPL_INTCTRL_3_SET_0" },
+  { 8705, "MPL_INTCTRL_3_SET_1" },
+  { 8706, "MPL_INTCTRL_3_SET_2" },
+  { 8707, "MPL_INTCTRL_3_SET_3" },
+  { 8708, "MPL_INTCTRL_3" },
+  { 8709, "INTCTRL_3_STATUS" },
+  { 8710, "INTERRUPT_MASK_3" },
+  { 8711, "INTERRUPT_MASK_RESET_3" },
+  { 8712, "INTERRUPT_MASK_SET_3" },
+  { 8713, "INTERRUPT_VECTOR_BASE_3" },
+  { 8714, "SINGLE_STEP_EN_0_3" },
+  { 8715, "SINGLE_STEP_EN_1_3" },
+  { 8716, "SINGLE_STEP_EN_2_3" },
+  { 8717, "SINGLE_STEP_EN_3_3" },
+  { 8832, "EX_CONTEXT_3_0" },
+  { 8833, "EX_CONTEXT_3_1" },
+  { 8834, "SYSTEM_SAVE_3_0" },
+  { 8835, "SYSTEM_SAVE_3_1" },
+  { 8836, "SYSTEM_SAVE_3_2" },
+  { 8837, "SYSTEM_SAVE_3_3" },
+  { 8960, "MPL_INTCTRL_2_SET_0" },
+  { 8961, "MPL_INTCTRL_2_SET_1" },
+  { 8962, "MPL_INTCTRL_2_SET_2" },
+  { 8963, "MPL_INTCTRL_2_SET_3" },
+  { 8964, "MPL_INTCTRL_2" },
+  { 8965, "INTCTRL_2_STATUS" },
+  { 8966, "INTERRUPT_MASK_2" },
+  { 8967, "INTERRUPT_MASK_RESET_2" },
+  { 8968, "INTERRUPT_MASK_SET_2" },
+  { 8969, "INTERRUPT_VECTOR_BASE_2" },
+  { 8970, "SINGLE_STEP_EN_0_2" },
+  { 8971, "SINGLE_STEP_EN_1_2" },
+  { 8972, "SINGLE_STEP_EN_2_2" },
+  { 8973, "SINGLE_STEP_EN_3_2" },
+  { 9088, "EX_CONTEXT_2_0" },
+  { 9089, "EX_CONTEXT_2_1" },
+  { 9090, "SYSTEM_SAVE_2_0" },
+  { 9091, "SYSTEM_SAVE_2_1" },
+  { 9092, "SYSTEM_SAVE_2_2" },
+  { 9093, "SYSTEM_SAVE_2_3" },
+  { 9216, "MPL_INTCTRL_1_SET_0" },
+  { 9217, "MPL_INTCTRL_1_SET_1" },
+  { 9218, "MPL_INTCTRL_1_SET_2" },
+  { 9219, "MPL_INTCTRL_1_SET_3" },
+  { 9220, "MPL_INTCTRL_1" },
+  { 9221, "INTCTRL_1_STATUS" },
+  { 9222, "INTERRUPT_MASK_1" },
+  { 9223, "INTERRUPT_MASK_RESET_1" },
+  { 9224, "INTERRUPT_MASK_SET_1" },
+  { 9225, "INTERRUPT_VECTOR_BASE_1" },
+  { 9226, "SINGLE_STEP_EN_0_1" },
+  { 9227, "SINGLE_STEP_EN_1_1" },
+  { 9228, "SINGLE_STEP_EN_2_1" },
+  { 9229, "SINGLE_STEP_EN_3_1" },
+  { 9344, "EX_CONTEXT_1_0" },
+  { 9345, "EX_CONTEXT_1_1" },
+  { 9346, "SYSTEM_SAVE_1_0" },
+  { 9347, "SYSTEM_SAVE_1_1" },
+  { 9348, "SYSTEM_SAVE_1_2" },
+  { 9349, "SYSTEM_SAVE_1_3" },
+  { 9472, "MPL_INTCTRL_0_SET_0" },
+  { 9473, "MPL_INTCTRL_0_SET_1" },
+  { 9474, "MPL_INTCTRL_0_SET_2" },
+  { 9475, "MPL_INTCTRL_0_SET_3" },
+  { 9476, "MPL_INTCTRL_0" },
+  { 9477, "INTCTRL_0_STATUS" },
+  { 9478, "INTERRUPT_MASK_0" },
+  { 9479, "INTERRUPT_MASK_RESET_0" },
+  { 9480, "INTERRUPT_MASK_SET_0" },
+  { 9481, "INTERRUPT_VECTOR_BASE_0" },
+  { 9482, "SINGLE_STEP_EN_0_0" },
+  { 9483, "SINGLE_STEP_EN_1_0" },
+  { 9484, "SINGLE_STEP_EN_2_0" },
+  { 9485, "SINGLE_STEP_EN_3_0" },
+  { 9600, "EX_CONTEXT_0_0" },
+  { 9601, "EX_CONTEXT_0_1" },
+  { 9602, "SYSTEM_SAVE_0_0" },
+  { 9603, "SYSTEM_SAVE_0_1" },
+  { 9604, "SYSTEM_SAVE_0_2" },
+  { 9605, "SYSTEM_SAVE_0_3" },
+  { 9728, "MPL_BOOT_ACCESS_SET_0" },
+  { 9729, "MPL_BOOT_ACCESS_SET_1" },
+  { 9730, "MPL_BOOT_ACCESS_SET_2" },
+  { 9731, "MPL_BOOT_ACCESS_SET_3" },
+  { 9732, "MPL_BOOT_ACCESS" },
+  { 9733, "BIG_ENDIAN_CONFIG" },
+  { 9734, "CACHE_INVALIDATION_COMPRESSION_MODE" },
+  { 9735, "CACHE_INVALIDATION_MASK_0" },
+  { 9736, "CACHE_INVALIDATION_MASK_1" },
+  { 9737, "CACHE_INVALIDATION_MASK_2" },
+  { 9738, "CBOX_CACHEASRAM_CONFIG" },
+  { 9739, "CBOX_CACHE_CONFIG" },
+  { 9740, "CBOX_HOME_MAP_ADDR" },
+  { 9741, "CBOX_HOME_MAP_DATA" },
+  { 9742, "CBOX_MMAP_0" },
+  { 9743, "CBOX_MMAP_1" },
+  { 9744, "CBOX_MMAP_2" },
+  { 9745, "CBOX_MMAP_3" },
+  { 9746, "CBOX_MSR" },
+  { 9747, "DIAG_BCST_CTL" },
+  { 9748, "DIAG_BCST_MASK" },
+  { 9749, "DIAG_BCST_TRIGGER" },
+  { 9750, "DIAG_MUX_CTL" },
+  { 9751, "DIAG_TRACE_CTL" },
+  { 9752, "DIAG_TRACE_DATA" },
+  { 9753, "DIAG_TRACE_STS" },
+  { 9754, "IDN_DEMUX_BUF_THRESH" },
+  { 9755, "L1_I_PIN_WAY_0" },
+  { 9756, "MEM_ROUTE_ORDER" },
+  { 9757, "MEM_STRIPE_CONFIG" },
+  { 9758, "PERF_COUNT_PLS" },
+  { 9759, "PSEUDO_RANDOM_NUMBER_MODIFY" },
+  { 9760, "QUIESCE_CTL" },
+  { 9761, "RSHIM_COORD" },
+  { 9762, "SBOX_CONFIG" },
+  { 9763, "UDN_DEMUX_BUF_THRESH" },
+  { 9764, "XDN_CORE_STARVATION_COUNT" },
+  { 9765, "XDN_ROUND_ROBIN_ARB_CTL" },
+  { 9856, "CYCLE_MODIFY" },
+  { 9857, "I_AAR" },
+  { 9984, "MPL_WORLD_ACCESS_SET_0" },
+  { 9985, "MPL_WORLD_ACCESS_SET_1" },
+  { 9986, "MPL_WORLD_ACCESS_SET_2" },
+  { 9987, "MPL_WORLD_ACCESS_SET_3" },
+  { 9988, "MPL_WORLD_ACCESS" },
+  { 9989, "DONE" },
+  { 9990, "DSTREAM_PF" },
+  { 9991, "FAIL" },
+  { 9992, "INTERRUPT_CRITICAL_SECTION" },
+  { 9993, "PASS" },
+  { 9994, "PSEUDO_RANDOM_NUMBER" },
+  { 9995, "TILE_COORD" },
+  { 9996, "TILE_RTF_HWM" },
+  { 10112, "CMPEXCH_VALUE" },
+  { 10113, "CYCLE" },
+  { 10114, "EVENT_BEGIN" },
+  { 10115, "EVENT_END" },
+  { 10116, "PROC_STATUS" },
+  { 10117, "SIM_CONTROL" },
+  { 10118, "SIM_SOCKET" },
+  { 10119, "STATUS_SATURATE" },
+  { 10240, "MPL_I_ASID_SET_0" },
+  { 10241, "MPL_I_ASID_SET_1" },
+  { 10242, "MPL_I_ASID_SET_2" },
+  { 10243, "MPL_I_ASID_SET_3" },
+  { 10244, "MPL_I_ASID" },
+  { 10245, "I_ASID" },
+  { 10496, "MPL_D_ASID_SET_0" },
+  { 10497, "MPL_D_ASID_SET_1" },
+  { 10498, "MPL_D_ASID_SET_2" },
+  { 10499, "MPL_D_ASID_SET_3" },
+  { 10500, "MPL_D_ASID" },
+  { 10501, "D_ASID" },
+  { 10752, "MPL_DOUBLE_FAULT_SET_0" },
+  { 10753, "MPL_DOUBLE_FAULT_SET_1" },
+  { 10754, "MPL_DOUBLE_FAULT_SET_2" },
+  { 10755, "MPL_DOUBLE_FAULT_SET_3" },
+  { 10756, "MPL_DOUBLE_FAULT" },
+  { 10757, "LAST_INTERRUPT_REASON" },
+};
+
+const int tilegx_num_sprs = 441;
+
+const char *
+get_tilegx_spr_name (int num)
+{
+  void *result;
+  struct tilegx_spr key;
+
+  key.number = num;
+  result = bsearch((const void *) &key, (const void *) tilegx_sprs,
+                   tilegx_num_sprs, sizeof (struct tilegx_spr),
+                   tilegx_spr_compare);
+
+  if (result == NULL)
+  {
+    return (NULL);
+  }
+  else
+  {
+    struct tilegx_spr *result_ptr = (struct tilegx_spr *) result;
+    return (result_ptr->name);
+  }
+}
+
+int
+print_insn_tilegx (unsigned char * memaddr)
+{
+  struct tilegx_decoded_instruction
+    decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+  unsigned char opbuf[TILEGX_BUNDLE_SIZE_IN_BYTES];
+  int i, num_instructions, num_printed;
+  tilegx_mnemonic padding_mnemonic;
+
+  memcpy((void *)opbuf, (void *)memaddr, TILEGX_BUNDLE_SIZE_IN_BYTES);
+
+  /* Parse the instructions in the bundle. */
+  num_instructions =
+    parse_insn_tilegx (*(unsigned long long *)opbuf, (unsigned long long)memaddr, decoded);
+
+  /* Print the instructions in the bundle. */
+  printf("{ ");
+  num_printed = 0;
+
+  /* Determine which nop opcode is used for padding and should be skipped. */
+  padding_mnemonic = TILEGX_OPC_FNOP;
+  for (i = 0; i < num_instructions; i++)
+  {
+    if (!decoded[i].opcode->can_bundle)
+    {
+      /* Instructions that cannot be bundled are padded out with nops,
+         rather than fnops. Displaying them is always clutter. */
+      padding_mnemonic = TILEGX_OPC_NOP;
+      break;
+    }
+  }
+
+  for (i = 0; i < num_instructions; i++)
+  {
+    const struct tilegx_opcode *opcode = decoded[i].opcode;
+    const char *name;
+    int j;
+
+    /* Do not print out fnops, unless everything is an fnop, in
+       which case we will print out just the last one. */
+    if (opcode->mnemonic == padding_mnemonic
+        && (num_printed > 0 || i + 1 < num_instructions))
+      continue;
+
+    if (num_printed > 0)
+      printf(" ; ");
+    ++num_printed;
+
+    name = opcode->name;
+    if (name == NULL)
+      name = "<invalid>";
+    printf("%s", name);
+
+    for (j = 0; j < opcode->num_operands; j++)
+    {
+      unsigned long long num;
+      const struct tilegx_operand *op;
+      const char *spr_name;
+
+      if (j > 0)
+        printf (",");
+      printf (" ");
+
+      num = decoded[i].operand_values[j];
+
+      op = decoded[i].operands[j];
+      switch (op->type)
+      {
+      case TILEGX_OP_TYPE_REGISTER:
+        printf ("%s", tilegx_register_names[(int)num]);
+        break;
+      case TILEGX_OP_TYPE_SPR:
+        spr_name = get_tilegx_spr_name(num);
+        if (spr_name != NULL)
+          printf ("%s", spr_name);
+        else
+          printf ("%d", (int)num);
+        break;
+      case TILEGX_OP_TYPE_IMMEDIATE:
+        printf ("%d", (int)num);
+        break;
+      case TILEGX_OP_TYPE_ADDRESS:
+        printf ("0x%016llx", num);
+        break;
+      default:
+        abort ();
+      }
+    }
+  }
+  printf (" }\n");
+
+  return TILEGX_BUNDLE_SIZE_IN_BYTES;
+}
diff --git a/src/c/pcre2/src/sljit/sljitNativeTILEGX_64.c b/src/c/pcre2/src/sljit/sljitNativeTILEGX_64.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitNativeTILEGX_64.c
@@ -0,0 +1,2565 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright 2013-2013 Tilera Corporation(jiwang@tilera.com). All rights reserved.
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* TileGX architecture. */
+/* Contributed by Tilera Corporation. */
+#include "sljitNativeTILEGX-encoder.c"
+
+#define SIMM_8BIT_MAX (0x7f)
+#define SIMM_8BIT_MIN (-0x80)
+#define SIMM_16BIT_MAX (0x7fff)
+#define SIMM_16BIT_MIN (-0x8000)
+#define SIMM_17BIT_MAX (0xffff)
+#define SIMM_17BIT_MIN (-0x10000)
+#define SIMM_32BIT_MAX (0x7fffffff)
+#define SIMM_32BIT_MIN (-0x7fffffff - 1)
+#define SIMM_48BIT_MAX (0x7fffffff0000L)
+#define SIMM_48BIT_MIN (-0x800000000000L)
+#define IMM16(imm) ((imm) & 0xffff)
+
+#define UIMM_16BIT_MAX (0xffff)
+
+#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
+#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)
+#define TMP_REG3 (SLJIT_NUMBER_OF_REGISTERS + 4)
+#define ADDR_TMP (SLJIT_NUMBER_OF_REGISTERS + 5)
+#define PIC_ADDR_REG TMP_REG2
+
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 6] = {
+	63, 0, 1, 2, 3, 4, 30, 31, 32, 33, 34, 54, 5, 16, 6, 7
+};
+
+#define SLJIT_LOCALS_REG_mapped 54
+#define TMP_REG1_mapped 5
+#define TMP_REG2_mapped 16
+#define TMP_REG3_mapped 6
+#define ADDR_TMP_mapped 7
+
+/* Flags are keept in volatile registers. */
+#define EQUAL_FLAG 8
+/* And carry flag as well. */
+#define ULESS_FLAG 9
+#define UGREATER_FLAG 10
+#define LESS_FLAG 11
+#define GREATER_FLAG 12
+#define OVERFLOW_FLAG 13
+
+#define ZERO 63
+#define RA 55
+#define TMP_EREG1 14
+#define TMP_EREG2 15
+
+#define LOAD_DATA 0x01
+#define WORD_DATA 0x00
+#define BYTE_DATA 0x02
+#define HALF_DATA 0x04
+#define INT_DATA 0x06
+#define SIGNED_DATA 0x08
+#define DOUBLE_DATA 0x10
+
+/* Separates integer and floating point registers */
+#define GPR_REG 0xf
+
+#define MEM_MASK 0x1f
+
+#define WRITE_BACK 0x00020
+#define ARG_TEST 0x00040
+#define ALT_KEEP_CACHE 0x00080
+#define CUMULATIVE_OP 0x00100
+#define LOGICAL_OP 0x00200
+#define IMM_OP 0x00400
+#define SRC2_IMM 0x00800
+
+#define UNUSED_DEST 0x01000
+#define REG_DEST 0x02000
+#define REG1_SOURCE 0x04000
+#define REG2_SOURCE 0x08000
+#define SLOW_SRC1 0x10000
+#define SLOW_SRC2 0x20000
+#define SLOW_DEST 0x40000
+
+/* Only these flags are set. UNUSED_DEST is not set when no flags should be set.
+ */
+#define CHECK_FLAGS(list) (!(flags & UNUSED_DEST) || (op & GET_FLAGS(~(list))))
+
+SLJIT_API_FUNC_ATTRIBUTE const char *sljit_get_platform_name(void)
+{
+	return "TileGX" SLJIT_CPUINFO;
+}
+
+/* Length of an instruction word */
+typedef sljit_uw sljit_ins;
+
+struct jit_instr {
+	const struct tilegx_opcode* opcode; 
+	tilegx_pipeline pipe;
+	unsigned long input_registers;
+	unsigned long output_registers;
+	int operand_value[4];
+	int line;
+};
+
+/* Opcode Helper Macros */
+#define TILEGX_X_MODE 0
+
+#define X_MODE create_Mode(TILEGX_X_MODE)
+
+#define FNOP_X0 \
+	create_Opcode_X0(RRR_0_OPCODE_X0) | \
+	create_RRROpcodeExtension_X0(UNARY_RRR_0_OPCODE_X0) | \
+	create_UnaryOpcodeExtension_X0(FNOP_UNARY_OPCODE_X0)
+
+#define FNOP_X1 \
+	create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(UNARY_RRR_0_OPCODE_X1) | \
+	create_UnaryOpcodeExtension_X1(FNOP_UNARY_OPCODE_X1)
+
+#define NOP \
+	create_Mode(TILEGX_X_MODE) | FNOP_X0 | FNOP_X1
+
+#define ANOP_X0 \
+	create_Opcode_X0(RRR_0_OPCODE_X0) | \
+	create_RRROpcodeExtension_X0(UNARY_RRR_0_OPCODE_X0) | \
+	create_UnaryOpcodeExtension_X0(NOP_UNARY_OPCODE_X0)
+
+#define BPT create_Mode(TILEGX_X_MODE) | create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(UNARY_RRR_0_OPCODE_X1) | \
+	create_UnaryOpcodeExtension_X1(ILL_UNARY_OPCODE_X1) | \
+	create_Dest_X1(0x1C) | create_SrcA_X1(0x25) | ANOP_X0
+
+#define ADD_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(ADD_RRR_0_OPCODE_X1) | FNOP_X0
+
+#define ADDI_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(IMM8_OPCODE_X1) | \
+	create_Imm8OpcodeExtension_X1(ADDI_IMM8_OPCODE_X1) | FNOP_X0
+
+#define SUB_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(SUB_RRR_0_OPCODE_X1) | FNOP_X0
+
+#define NOR_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(NOR_RRR_0_OPCODE_X1) | FNOP_X0
+
+#define OR_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(OR_RRR_0_OPCODE_X1) | FNOP_X0
+
+#define AND_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(AND_RRR_0_OPCODE_X1) | FNOP_X0
+
+#define XOR_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(XOR_RRR_0_OPCODE_X1) | FNOP_X0
+
+#define CMOVNEZ_X0 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X0(RRR_0_OPCODE_X0) | \
+	create_RRROpcodeExtension_X0(CMOVNEZ_RRR_0_OPCODE_X0) | FNOP_X1
+
+#define CMOVEQZ_X0 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X0(RRR_0_OPCODE_X0) | \
+	create_RRROpcodeExtension_X0(CMOVEQZ_RRR_0_OPCODE_X0) | FNOP_X1
+
+#define ADDLI_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(ADDLI_OPCODE_X1) | FNOP_X0
+
+#define V4INT_L_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(V4INT_L_RRR_0_OPCODE_X1) | FNOP_X0
+
+#define BFEXTU_X0 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X0(BF_OPCODE_X0) | \
+	create_BFOpcodeExtension_X0(BFEXTU_BF_OPCODE_X0) | FNOP_X1
+
+#define BFEXTS_X0 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X0(BF_OPCODE_X0) | \
+	create_BFOpcodeExtension_X0(BFEXTS_BF_OPCODE_X0) | FNOP_X1
+
+#define SHL16INSLI_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(SHL16INSLI_OPCODE_X1) | FNOP_X0
+
+#define ST_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(ST_RRR_0_OPCODE_X1) | create_Dest_X1(0x0) | FNOP_X0
+
+#define LD_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(UNARY_RRR_0_OPCODE_X1) | \
+	create_UnaryOpcodeExtension_X1(LD_UNARY_OPCODE_X1) | FNOP_X0
+
+#define JR_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(UNARY_RRR_0_OPCODE_X1) | \
+	create_UnaryOpcodeExtension_X1(JR_UNARY_OPCODE_X1) | FNOP_X0
+
+#define JALR_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(UNARY_RRR_0_OPCODE_X1) | \
+	create_UnaryOpcodeExtension_X1(JALR_UNARY_OPCODE_X1) | FNOP_X0
+
+#define CLZ_X0 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X0(RRR_0_OPCODE_X0) | \
+	create_RRROpcodeExtension_X0(UNARY_RRR_0_OPCODE_X0) | \
+	create_UnaryOpcodeExtension_X0(CNTLZ_UNARY_OPCODE_X0) | FNOP_X1
+
+#define CMPLTUI_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(IMM8_OPCODE_X1) | \
+	create_Imm8OpcodeExtension_X1(CMPLTUI_IMM8_OPCODE_X1) | FNOP_X0
+
+#define CMPLTU_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(CMPLTU_RRR_0_OPCODE_X1) | FNOP_X0
+
+#define CMPLTS_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(CMPLTS_RRR_0_OPCODE_X1) | FNOP_X0
+
+#define XORI_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(IMM8_OPCODE_X1) | \
+	create_Imm8OpcodeExtension_X1(XORI_IMM8_OPCODE_X1) | FNOP_X0
+
+#define ORI_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(IMM8_OPCODE_X1) | \
+	create_Imm8OpcodeExtension_X1(ORI_IMM8_OPCODE_X1) | FNOP_X0
+
+#define ANDI_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(IMM8_OPCODE_X1) | \
+	create_Imm8OpcodeExtension_X1(ANDI_IMM8_OPCODE_X1) | FNOP_X0
+
+#define SHLI_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(SHIFT_OPCODE_X1) | \
+	create_ShiftOpcodeExtension_X1(SHLI_SHIFT_OPCODE_X1) | FNOP_X0
+
+#define SHL_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(SHL_RRR_0_OPCODE_X1) | FNOP_X0
+
+#define SHRSI_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(SHIFT_OPCODE_X1) | \
+	create_ShiftOpcodeExtension_X1(SHRSI_SHIFT_OPCODE_X1) | FNOP_X0
+
+#define SHRS_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(SHRS_RRR_0_OPCODE_X1) | FNOP_X0
+
+#define SHRUI_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(SHIFT_OPCODE_X1) | \
+	create_ShiftOpcodeExtension_X1(SHRUI_SHIFT_OPCODE_X1) | FNOP_X0
+
+#define SHRU_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(RRR_0_OPCODE_X1) | \
+	create_RRROpcodeExtension_X1(SHRU_RRR_0_OPCODE_X1) | FNOP_X0
+
+#define BEQZ_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(BRANCH_OPCODE_X1) | \
+	create_BrType_X1(BEQZ_BRANCH_OPCODE_X1) | FNOP_X0
+
+#define BNEZ_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(BRANCH_OPCODE_X1) | \
+	create_BrType_X1(BNEZ_BRANCH_OPCODE_X1) | FNOP_X0
+
+#define J_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(JUMP_OPCODE_X1) | \
+	create_JumpOpcodeExtension_X1(J_JUMP_OPCODE_X1) | FNOP_X0
+
+#define JAL_X1 \
+	create_Mode(TILEGX_X_MODE) | create_Opcode_X1(JUMP_OPCODE_X1) | \
+	create_JumpOpcodeExtension_X1(JAL_JUMP_OPCODE_X1) | FNOP_X0
+
+#define DEST_X0(x) create_Dest_X0(x)
+#define SRCA_X0(x) create_SrcA_X0(x)
+#define SRCB_X0(x) create_SrcB_X0(x)
+#define DEST_X1(x) create_Dest_X1(x)
+#define SRCA_X1(x) create_SrcA_X1(x)
+#define SRCB_X1(x) create_SrcB_X1(x)
+#define IMM16_X1(x) create_Imm16_X1(x)
+#define IMM8_X1(x) create_Imm8_X1(x)
+#define BFSTART_X0(x) create_BFStart_X0(x)
+#define BFEND_X0(x) create_BFEnd_X0(x)
+#define SHIFTIMM_X1(x) create_ShAmt_X1(x)
+#define JOFF_X1(x) create_JumpOff_X1(x)
+#define BOFF_X1(x) create_BrOff_X1(x)
+
+static const tilegx_mnemonic data_transfer_insts[16] = {
+	/* u w s */ TILEGX_OPC_ST   /* st */,
+	/* u w l */ TILEGX_OPC_LD   /* ld */,
+	/* u b s */ TILEGX_OPC_ST1  /* st1 */,
+	/* u b l */ TILEGX_OPC_LD1U /* ld1u */,
+	/* u h s */ TILEGX_OPC_ST2  /* st2 */,
+	/* u h l */ TILEGX_OPC_LD2U /* ld2u */,
+	/* u i s */ TILEGX_OPC_ST4  /* st4 */,
+	/* u i l */ TILEGX_OPC_LD4U /* ld4u */,
+	/* s w s */ TILEGX_OPC_ST   /* st */,
+	/* s w l */ TILEGX_OPC_LD   /* ld */,
+	/* s b s */ TILEGX_OPC_ST1  /* st1 */,
+	/* s b l */ TILEGX_OPC_LD1S /* ld1s */,
+	/* s h s */ TILEGX_OPC_ST2  /* st2 */,
+	/* s h l */ TILEGX_OPC_LD2S /* ld2s */,
+	/* s i s */ TILEGX_OPC_ST4  /* st4 */,
+	/* s i l */ TILEGX_OPC_LD4S /* ld4s */,
+};
+
+#ifdef TILEGX_JIT_DEBUG
+static sljit_s32 push_inst_debug(struct sljit_compiler *compiler, sljit_ins ins, int line)
+{
+	sljit_ins *ptr = (sljit_ins *)ensure_buf(compiler, sizeof(sljit_ins));
+	FAIL_IF(!ptr);
+	*ptr = ins;
+	compiler->size++;
+	printf("|%04d|S0|:\t\t", line);
+	print_insn_tilegx(ptr);
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 push_inst_nodebug(struct sljit_compiler *compiler, sljit_ins ins)
+{
+	sljit_ins *ptr = (sljit_ins *)ensure_buf(compiler, sizeof(sljit_ins));
+	FAIL_IF(!ptr);
+	*ptr = ins;
+	compiler->size++;
+	return SLJIT_SUCCESS;
+}
+
+#define push_inst(a, b) push_inst_debug(a, b, __LINE__)
+#else
+static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins)
+{
+	sljit_ins *ptr = (sljit_ins *)ensure_buf(compiler, sizeof(sljit_ins));
+	FAIL_IF(!ptr);
+	*ptr = ins;
+	compiler->size++;
+	return SLJIT_SUCCESS;
+}
+#endif
+
+#define BUNDLE_FORMAT_MASK(p0, p1, p2) \
+	((p0) | ((p1) << 8) | ((p2) << 16))
+
+#define BUNDLE_FORMAT(p0, p1, p2) \
+	{ \
+		{ \
+			(tilegx_pipeline)(p0), \
+			(tilegx_pipeline)(p1), \
+			(tilegx_pipeline)(p2) \
+		}, \
+		BUNDLE_FORMAT_MASK(1 << (p0), 1 << (p1), (1 << (p2))) \
+	}
+
+#define NO_PIPELINE TILEGX_NUM_PIPELINE_ENCODINGS
+
+#define tilegx_is_x_pipeline(p) ((int)(p) <= (int)TILEGX_PIPELINE_X1)
+
+#define PI(encoding) \
+	push_inst(compiler, encoding)
+
+#define PB3(opcode, dst, srca, srcb) \
+	push_3_buffer(compiler, opcode, dst, srca, srcb, __LINE__)
+
+#define PB2(opcode, dst, src) \
+	push_2_buffer(compiler, opcode, dst, src, __LINE__)
+
+#define JR(reg) \
+	push_jr_buffer(compiler, TILEGX_OPC_JR, reg, __LINE__)
+
+#define ADD(dst, srca, srcb) \
+	push_3_buffer(compiler, TILEGX_OPC_ADD, dst, srca, srcb, __LINE__)
+
+#define SUB(dst, srca, srcb) \
+	push_3_buffer(compiler, TILEGX_OPC_SUB, dst, srca, srcb, __LINE__)
+
+#define MUL(dst, srca, srcb) \
+	push_3_buffer(compiler, TILEGX_OPC_MULX, dst, srca, srcb, __LINE__)
+
+#define NOR(dst, srca, srcb) \
+	push_3_buffer(compiler, TILEGX_OPC_NOR, dst, srca, srcb, __LINE__)
+
+#define OR(dst, srca, srcb) \
+	push_3_buffer(compiler, TILEGX_OPC_OR, dst, srca, srcb, __LINE__)
+
+#define XOR(dst, srca, srcb) \
+	push_3_buffer(compiler, TILEGX_OPC_XOR, dst, srca, srcb, __LINE__)
+
+#define AND(dst, srca, srcb) \
+	push_3_buffer(compiler, TILEGX_OPC_AND, dst, srca, srcb, __LINE__)
+
+#define CLZ(dst, src) \
+	push_2_buffer(compiler, TILEGX_OPC_CLZ, dst, src, __LINE__)
+
+#define SHLI(dst, srca, srcb) \
+	push_3_buffer(compiler, TILEGX_OPC_SHLI, dst, srca, srcb, __LINE__)
+
+#define SHRUI(dst, srca, imm) \
+	push_3_buffer(compiler, TILEGX_OPC_SHRUI, dst, srca, imm, __LINE__)
+
+#define XORI(dst, srca, imm) \
+	push_3_buffer(compiler, TILEGX_OPC_XORI, dst, srca, imm, __LINE__)
+
+#define ORI(dst, srca, imm) \
+	push_3_buffer(compiler, TILEGX_OPC_ORI, dst, srca, imm, __LINE__)
+
+#define CMPLTU(dst, srca, srcb) \
+	push_3_buffer(compiler, TILEGX_OPC_CMPLTU, dst, srca, srcb, __LINE__)
+
+#define CMPLTS(dst, srca, srcb) \
+	push_3_buffer(compiler, TILEGX_OPC_CMPLTS, dst, srca, srcb, __LINE__)
+
+#define CMPLTUI(dst, srca, imm) \
+	push_3_buffer(compiler, TILEGX_OPC_CMPLTUI, dst, srca, imm, __LINE__)
+
+#define CMOVNEZ(dst, srca, srcb) \
+	push_3_buffer(compiler, TILEGX_OPC_CMOVNEZ, dst, srca, srcb, __LINE__)
+
+#define CMOVEQZ(dst, srca, srcb) \
+	push_3_buffer(compiler, TILEGX_OPC_CMOVEQZ, dst, srca, srcb, __LINE__)
+
+#define ADDLI(dst, srca, srcb) \
+	push_3_buffer(compiler, TILEGX_OPC_ADDLI, dst, srca, srcb, __LINE__)
+
+#define SHL16INSLI(dst, srca, srcb) \
+	push_3_buffer(compiler, TILEGX_OPC_SHL16INSLI, dst, srca, srcb, __LINE__)
+
+#define LD_ADD(dst, addr, adjust) \
+	push_3_buffer(compiler, TILEGX_OPC_LD_ADD, dst, addr, adjust, __LINE__)
+
+#define ST_ADD(src, addr, adjust) \
+	push_3_buffer(compiler, TILEGX_OPC_ST_ADD, src, addr, adjust, __LINE__)
+
+#define LD(dst, addr) \
+	push_2_buffer(compiler, TILEGX_OPC_LD, dst, addr, __LINE__)
+
+#define BFEXTU(dst, src, start, end) \
+	push_4_buffer(compiler, TILEGX_OPC_BFEXTU, dst, src, start, end, __LINE__)
+
+#define BFEXTS(dst, src, start, end) \
+	push_4_buffer(compiler, TILEGX_OPC_BFEXTS, dst, src, start, end, __LINE__)
+
+#define ADD_SOLO(dest, srca, srcb) \
+	push_inst(compiler, ADD_X1 | DEST_X1(dest) | SRCA_X1(srca) | SRCB_X1(srcb))
+
+#define ADDI_SOLO(dest, srca, imm) \
+	push_inst(compiler, ADDI_X1 | DEST_X1(dest) | SRCA_X1(srca) | IMM8_X1(imm))
+
+#define ADDLI_SOLO(dest, srca, imm) \
+	push_inst(compiler, ADDLI_X1 | DEST_X1(dest) | SRCA_X1(srca) | IMM16_X1(imm))
+
+#define SHL16INSLI_SOLO(dest, srca, imm) \
+	push_inst(compiler, SHL16INSLI_X1 | DEST_X1(dest) | SRCA_X1(srca) | IMM16_X1(imm))
+
+#define JALR_SOLO(reg) \
+	push_inst(compiler, JALR_X1 | SRCA_X1(reg))
+
+#define JR_SOLO(reg) \
+	push_inst(compiler, JR_X1 | SRCA_X1(reg))
+
+struct Format {
+	/* Mapping of bundle issue slot to assigned pipe. */
+	tilegx_pipeline pipe[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+
+	/* Mask of pipes used by this bundle. */
+	unsigned int pipe_mask;
+};
+
+const struct Format formats[] =
+{
+	/* In Y format we must always have something in Y2, since it has
+	* no fnop, so this conveys that Y2 must always be used. */
+	BUNDLE_FORMAT(TILEGX_PIPELINE_Y0, TILEGX_PIPELINE_Y2, NO_PIPELINE),
+	BUNDLE_FORMAT(TILEGX_PIPELINE_Y1, TILEGX_PIPELINE_Y2, NO_PIPELINE),
+	BUNDLE_FORMAT(TILEGX_PIPELINE_Y2, TILEGX_PIPELINE_Y0, NO_PIPELINE),
+	BUNDLE_FORMAT(TILEGX_PIPELINE_Y2, TILEGX_PIPELINE_Y1, NO_PIPELINE),
+
+	/* Y format has three instructions. */
+	BUNDLE_FORMAT(TILEGX_PIPELINE_Y0, TILEGX_PIPELINE_Y1, TILEGX_PIPELINE_Y2),
+	BUNDLE_FORMAT(TILEGX_PIPELINE_Y0, TILEGX_PIPELINE_Y2, TILEGX_PIPELINE_Y1),
+	BUNDLE_FORMAT(TILEGX_PIPELINE_Y1, TILEGX_PIPELINE_Y0, TILEGX_PIPELINE_Y2),
+	BUNDLE_FORMAT(TILEGX_PIPELINE_Y1, TILEGX_PIPELINE_Y2, TILEGX_PIPELINE_Y0),
+	BUNDLE_FORMAT(TILEGX_PIPELINE_Y2, TILEGX_PIPELINE_Y0, TILEGX_PIPELINE_Y1),
+	BUNDLE_FORMAT(TILEGX_PIPELINE_Y2, TILEGX_PIPELINE_Y1, TILEGX_PIPELINE_Y0),
+
+	/* X format has only two instructions. */
+	BUNDLE_FORMAT(TILEGX_PIPELINE_X0, TILEGX_PIPELINE_X1, NO_PIPELINE),
+	BUNDLE_FORMAT(TILEGX_PIPELINE_X1, TILEGX_PIPELINE_X0, NO_PIPELINE)
+};
+
+
+struct jit_instr inst_buf[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+unsigned long inst_buf_index;
+
+tilegx_pipeline get_any_valid_pipe(const struct tilegx_opcode* opcode)
+{
+	/* FIXME: tile: we could pregenerate this. */
+	int pipe;
+	for (pipe = 0; ((opcode->pipes & (1 << pipe)) == 0 && pipe < TILEGX_NUM_PIPELINE_ENCODINGS); pipe++)
+		;
+	return (tilegx_pipeline)(pipe);
+}
+
+void insert_nop(tilegx_mnemonic opc, int line)
+{
+	const struct tilegx_opcode* opcode = NULL;
+
+	memmove(&inst_buf[1], &inst_buf[0], inst_buf_index * sizeof inst_buf[0]);
+
+	opcode = &tilegx_opcodes[opc];
+	inst_buf[0].opcode = opcode;
+	inst_buf[0].pipe = get_any_valid_pipe(opcode);
+	inst_buf[0].input_registers = 0;
+	inst_buf[0].output_registers = 0;
+	inst_buf[0].line = line;
+	++inst_buf_index;
+}
+
+const struct Format* compute_format()
+{
+	unsigned int compatible_pipes = BUNDLE_FORMAT_MASK(
+		inst_buf[0].opcode->pipes,
+		inst_buf[1].opcode->pipes,
+		(inst_buf_index == 3 ? inst_buf[2].opcode->pipes : (1 << NO_PIPELINE)));
+
+	const struct Format* match = NULL;
+	const struct Format *b = NULL;
+	unsigned int i;
+	for (i = 0; i < sizeof formats / sizeof formats[0]; i++) {
+		b = &formats[i];
+		if ((b->pipe_mask & compatible_pipes) == b->pipe_mask) {
+			match = b;
+			break;
+		}
+	}
+
+	return match;
+}
+
+sljit_s32 assign_pipes()
+{
+	unsigned long output_registers = 0;
+	unsigned int i = 0;
+
+	if (inst_buf_index == 1) {
+		tilegx_mnemonic opc = inst_buf[0].opcode->can_bundle
+					? TILEGX_OPC_FNOP : TILEGX_OPC_NOP;
+		insert_nop(opc, __LINE__);
+	}
+
+	const struct Format* match = compute_format();
+
+	if (match == NULL)
+		return -1;
+
+	for (i = 0; i < inst_buf_index; i++) {
+
+		if ((i > 0) && ((inst_buf[i].input_registers & output_registers) != 0))
+			return -1;
+
+		if ((i > 0) && ((inst_buf[i].output_registers & output_registers) != 0))
+			return -1;
+
+		/* Don't include Rzero in the match set, to avoid triggering
+		   needlessly on 'prefetch' instrs. */
+
+		output_registers |= inst_buf[i].output_registers & 0xFFFFFFFFFFFFFFL;
+
+		inst_buf[i].pipe = match->pipe[i];
+	}
+
+	/* If only 2 instrs, and in Y-mode, insert a nop. */
+	if (inst_buf_index == 2 && !tilegx_is_x_pipeline(match->pipe[0])) {
+		insert_nop(TILEGX_OPC_FNOP, __LINE__);
+
+		/* Select the yet unassigned pipe. */
+		tilegx_pipeline pipe = (tilegx_pipeline)(((TILEGX_PIPELINE_Y0
+					+ TILEGX_PIPELINE_Y1 + TILEGX_PIPELINE_Y2)
+					- (inst_buf[1].pipe + inst_buf[2].pipe)));
+
+		inst_buf[0].pipe = pipe;
+	}
+
+	return 0;
+}
+
+tilegx_bundle_bits get_bundle_bit(struct jit_instr *inst)
+{
+	int i, val;
+	const struct tilegx_opcode* opcode = inst->opcode;
+	tilegx_bundle_bits bits = opcode->fixed_bit_values[inst->pipe];
+
+	const struct tilegx_operand* operand = NULL;
+	for (i = 0; i < opcode->num_operands; i++) {
+		operand = &tilegx_operands[opcode->operands[inst->pipe][i]];
+		val = inst->operand_value[i];
+
+		bits |= operand->insert(val);
+	}
+
+	return bits;
+}
+
+static sljit_s32 update_buffer(struct sljit_compiler *compiler)
+{
+	int i;
+	int orig_index = inst_buf_index;
+	struct jit_instr inst0 = inst_buf[0];
+	struct jit_instr inst1 = inst_buf[1];
+	struct jit_instr inst2 = inst_buf[2];
+	tilegx_bundle_bits bits = 0;
+
+	/* If the bundle is valid as is, perform the encoding and return 1. */
+	if (assign_pipes() == 0) {
+		for (i = 0; i < inst_buf_index; i++) {
+			bits |= get_bundle_bit(inst_buf + i);
+#ifdef TILEGX_JIT_DEBUG
+			printf("|%04d", inst_buf[i].line);
+#endif
+		}
+#ifdef TILEGX_JIT_DEBUG
+		if (inst_buf_index == 3)
+			printf("|M0|:\t");
+		else
+			printf("|M0|:\t\t");
+		print_insn_tilegx(&bits);
+#endif
+
+		inst_buf_index = 0;
+
+#ifdef TILEGX_JIT_DEBUG
+		return push_inst_nodebug(compiler, bits);
+#else
+		return push_inst(compiler, bits);
+#endif
+	}
+
+	/* If the bundle is invalid, split it in two. First encode the first two
+	   (or possibly 1) instructions, and then the last, separately. Note that
+	   assign_pipes may have re-ordered the instrs (by inserting no-ops in
+	   lower slots) so we need to reset them. */
+
+	inst_buf_index = orig_index - 1;
+	inst_buf[0] = inst0;
+	inst_buf[1] = inst1;
+	inst_buf[2] = inst2;
+	if (assign_pipes() == 0) {
+		for (i = 0; i < inst_buf_index; i++) {
+			bits |= get_bundle_bit(inst_buf + i);
+#ifdef TILEGX_JIT_DEBUG
+			printf("|%04d", inst_buf[i].line);
+#endif
+		}
+
+#ifdef TILEGX_JIT_DEBUG
+		if (inst_buf_index == 3)
+			printf("|M1|:\t");
+		else
+			printf("|M1|:\t\t");
+		print_insn_tilegx(&bits);
+#endif
+
+		if ((orig_index - 1) == 2) {
+			inst_buf[0] = inst2;
+			inst_buf_index = 1;
+		} else if ((orig_index - 1) == 1) {
+			inst_buf[0] = inst1;
+			inst_buf_index = 1;
+		} else
+			SLJIT_UNREACHABLE();
+
+#ifdef TILEGX_JIT_DEBUG
+		return push_inst_nodebug(compiler, bits);
+#else
+		return push_inst(compiler, bits);
+#endif
+	} else {
+		/* We had 3 instrs of which the first 2 can't live in the same bundle.
+		   Split those two. Note that we don't try to then combine the second
+		   and third instr into a single bundle.  First instruction: */
+		inst_buf_index = 1;
+		inst_buf[0] = inst0;
+		inst_buf[1] = inst1;
+		inst_buf[2] = inst2;
+		if (assign_pipes() == 0) {
+			for (i = 0; i < inst_buf_index; i++) {
+				bits |= get_bundle_bit(inst_buf + i);
+#ifdef TILEGX_JIT_DEBUG
+				printf("|%04d", inst_buf[i].line);
+#endif
+			}
+
+#ifdef TILEGX_JIT_DEBUG
+			if (inst_buf_index == 3)
+				printf("|M2|:\t");
+			else
+				printf("|M2|:\t\t");
+			print_insn_tilegx(&bits);
+#endif
+
+			inst_buf[0] = inst1;
+			inst_buf[1] = inst2;
+			inst_buf_index = orig_index - 1;
+#ifdef TILEGX_JIT_DEBUG
+			return push_inst_nodebug(compiler, bits);
+#else
+			return push_inst(compiler, bits);
+#endif
+		} else
+			SLJIT_UNREACHABLE();
+	}
+
+	SLJIT_UNREACHABLE();
+}
+
+static sljit_s32 flush_buffer(struct sljit_compiler *compiler)
+{
+	while (inst_buf_index != 0) {
+		FAIL_IF(update_buffer(compiler));
+	}
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 push_4_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int op0, int op1, int op2, int op3, int line)
+{
+	if (inst_buf_index == TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE)
+		FAIL_IF(update_buffer(compiler));
+
+	const struct tilegx_opcode* opcode = &tilegx_opcodes[opc];
+	inst_buf[inst_buf_index].opcode = opcode;
+	inst_buf[inst_buf_index].pipe = get_any_valid_pipe(opcode);
+	inst_buf[inst_buf_index].operand_value[0] = op0;
+	inst_buf[inst_buf_index].operand_value[1] = op1;
+	inst_buf[inst_buf_index].operand_value[2] = op2;
+	inst_buf[inst_buf_index].operand_value[3] = op3;
+	inst_buf[inst_buf_index].input_registers = 1L << op1;
+	inst_buf[inst_buf_index].output_registers = 1L << op0;
+	inst_buf[inst_buf_index].line = line;
+	inst_buf_index++;
+
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 push_3_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int op0, int op1, int op2, int line)
+{
+	if (inst_buf_index == TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE)
+		FAIL_IF(update_buffer(compiler));
+
+	const struct tilegx_opcode* opcode = &tilegx_opcodes[opc];
+	inst_buf[inst_buf_index].opcode = opcode;
+	inst_buf[inst_buf_index].pipe = get_any_valid_pipe(opcode);
+	inst_buf[inst_buf_index].operand_value[0] = op0;
+	inst_buf[inst_buf_index].operand_value[1] = op1;
+	inst_buf[inst_buf_index].operand_value[2] = op2;
+	inst_buf[inst_buf_index].line = line;
+
+	switch (opc) {
+	case TILEGX_OPC_ST_ADD:
+		inst_buf[inst_buf_index].input_registers = (1L << op0) | (1L << op1);
+		inst_buf[inst_buf_index].output_registers = 1L << op0;
+		break;
+	case TILEGX_OPC_LD_ADD:
+		inst_buf[inst_buf_index].input_registers = 1L << op1;
+		inst_buf[inst_buf_index].output_registers = (1L << op0) | (1L << op1);
+		break;
+	case TILEGX_OPC_ADD:
+	case TILEGX_OPC_AND:
+	case TILEGX_OPC_SUB:
+	case TILEGX_OPC_MULX:
+	case TILEGX_OPC_OR:
+	case TILEGX_OPC_XOR:
+	case TILEGX_OPC_NOR:
+	case TILEGX_OPC_SHL:
+	case TILEGX_OPC_SHRU:
+	case TILEGX_OPC_SHRS:
+	case TILEGX_OPC_CMPLTU:
+	case TILEGX_OPC_CMPLTS:
+	case TILEGX_OPC_CMOVEQZ:
+	case TILEGX_OPC_CMOVNEZ:
+		inst_buf[inst_buf_index].input_registers = (1L << op1) | (1L << op2);
+		inst_buf[inst_buf_index].output_registers = 1L << op0;
+		break;
+	case TILEGX_OPC_ADDLI:
+	case TILEGX_OPC_XORI:
+	case TILEGX_OPC_ORI:
+	case TILEGX_OPC_SHLI:
+	case TILEGX_OPC_SHRUI:
+	case TILEGX_OPC_SHRSI:
+	case TILEGX_OPC_SHL16INSLI:
+	case TILEGX_OPC_CMPLTUI:
+	case TILEGX_OPC_CMPLTSI:
+		inst_buf[inst_buf_index].input_registers = 1L << op1;
+		inst_buf[inst_buf_index].output_registers = 1L << op0;
+		break;
+	default:
+		printf("unrecoginzed opc: %s\n", opcode->name);
+		SLJIT_UNREACHABLE();
+	}
+
+	inst_buf_index++;
+
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 push_2_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int op0, int op1, int line)
+{
+	if (inst_buf_index == TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE)
+		FAIL_IF(update_buffer(compiler));
+
+	const struct tilegx_opcode* opcode = &tilegx_opcodes[opc];
+	inst_buf[inst_buf_index].opcode = opcode;
+	inst_buf[inst_buf_index].pipe = get_any_valid_pipe(opcode);
+	inst_buf[inst_buf_index].operand_value[0] = op0;
+	inst_buf[inst_buf_index].operand_value[1] = op1;
+	inst_buf[inst_buf_index].line = line;
+
+	switch (opc) {
+	case TILEGX_OPC_BEQZ:
+	case TILEGX_OPC_BNEZ:
+		inst_buf[inst_buf_index].input_registers = 1L << op0;
+		break;
+	case TILEGX_OPC_ST:
+	case TILEGX_OPC_ST1:
+	case TILEGX_OPC_ST2:
+	case TILEGX_OPC_ST4:
+		inst_buf[inst_buf_index].input_registers = (1L << op0) | (1L << op1);
+		inst_buf[inst_buf_index].output_registers = 0;
+		break;
+	case TILEGX_OPC_CLZ:
+	case TILEGX_OPC_LD:
+	case TILEGX_OPC_LD1U:
+	case TILEGX_OPC_LD1S:
+	case TILEGX_OPC_LD2U:
+	case TILEGX_OPC_LD2S:
+	case TILEGX_OPC_LD4U:
+	case TILEGX_OPC_LD4S:
+		inst_buf[inst_buf_index].input_registers = 1L << op1;
+		inst_buf[inst_buf_index].output_registers = 1L << op0;
+		break;
+	default:
+		printf("unrecoginzed opc: %s\n", opcode->name);
+		SLJIT_UNREACHABLE();
+	}
+
+	inst_buf_index++;
+
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 push_0_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int line)
+{
+	if (inst_buf_index == TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE)
+		FAIL_IF(update_buffer(compiler));
+
+	const struct tilegx_opcode* opcode = &tilegx_opcodes[opc];
+	inst_buf[inst_buf_index].opcode = opcode;
+	inst_buf[inst_buf_index].pipe = get_any_valid_pipe(opcode);
+	inst_buf[inst_buf_index].input_registers = 0;
+	inst_buf[inst_buf_index].output_registers = 0;
+	inst_buf[inst_buf_index].line = line;
+	inst_buf_index++;
+
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 push_jr_buffer(struct sljit_compiler *compiler, tilegx_mnemonic opc, int op0, int line)
+{
+	if (inst_buf_index == TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE)
+		FAIL_IF(update_buffer(compiler));
+
+	const struct tilegx_opcode* opcode = &tilegx_opcodes[opc];
+	inst_buf[inst_buf_index].opcode = opcode;
+	inst_buf[inst_buf_index].pipe = get_any_valid_pipe(opcode);
+	inst_buf[inst_buf_index].operand_value[0] = op0;
+	inst_buf[inst_buf_index].input_registers = 1L << op0;
+	inst_buf[inst_buf_index].output_registers = 0;
+	inst_buf[inst_buf_index].line = line;
+	inst_buf_index++;
+ 
+	return flush_buffer(compiler);
+}
+
+static SLJIT_INLINE sljit_ins * detect_jump_type(struct sljit_jump *jump, sljit_ins *code_ptr, sljit_ins *code)
+{
+	sljit_sw diff;
+	sljit_uw target_addr;
+	sljit_ins *inst;
+
+	if (jump->flags & SLJIT_REWRITABLE_JUMP)
+		return code_ptr;
+
+	if (jump->flags & JUMP_ADDR)
+		target_addr = jump->u.target;
+	else {
+		SLJIT_ASSERT(jump->flags & JUMP_LABEL);
+		target_addr = (sljit_uw)(code + jump->u.label->size);
+	}
+
+	inst = (sljit_ins *)jump->addr;
+	if (jump->flags & IS_COND)
+		inst--;
+
+	diff = ((sljit_sw) target_addr - (sljit_sw) inst) >> 3;
+	if (diff <= SIMM_17BIT_MAX && diff >= SIMM_17BIT_MIN) {
+		jump->flags |= PATCH_B;
+
+		if (!(jump->flags & IS_COND)) {
+			if (jump->flags & IS_JAL) {
+				jump->flags &= ~(PATCH_B);
+				jump->flags |= PATCH_J;
+				inst[0] = JAL_X1;
+
+#ifdef TILEGX_JIT_DEBUG
+				printf("[runtime relocate]%04d:\t", __LINE__);
+				print_insn_tilegx(inst);
+#endif
+			} else {
+				inst[0] = BEQZ_X1 | SRCA_X1(ZERO);
+
+#ifdef TILEGX_JIT_DEBUG
+				printf("[runtime relocate]%04d:\t", __LINE__);
+				print_insn_tilegx(inst);
+#endif
+			}
+
+			return inst;
+		}
+
+		inst[0] = inst[0] ^ (0x7L << 55);
+
+#ifdef TILEGX_JIT_DEBUG
+		printf("[runtime relocate]%04d:\t", __LINE__);
+		print_insn_tilegx(inst);
+#endif
+		jump->addr -= sizeof(sljit_ins);
+		return inst;
+	}
+
+	if (jump->flags & IS_COND) {
+		if ((target_addr & ~0x3FFFFFFFL) == ((jump->addr + sizeof(sljit_ins)) & ~0x3FFFFFFFL)) {
+			jump->flags |= PATCH_J;
+			inst[0] = (inst[0] & ~(BOFF_X1(-1))) | BOFF_X1(2);
+			inst[1] = J_X1;
+			return inst + 1;
+		}
+
+		return code_ptr;
+	}
+
+	if ((target_addr & ~0x3FFFFFFFL) == ((jump->addr + sizeof(sljit_ins)) & ~0x3FFFFFFFL)) {
+		jump->flags |= PATCH_J;
+
+		if (jump->flags & IS_JAL) {
+			inst[0] = JAL_X1;
+
+#ifdef TILEGX_JIT_DEBUG
+			printf("[runtime relocate]%04d:\t", __LINE__);
+			print_insn_tilegx(inst);
+#endif
+
+		} else {
+			inst[0] = J_X1;
+
+#ifdef TILEGX_JIT_DEBUG
+			printf("[runtime relocate]%04d:\t", __LINE__);
+			print_insn_tilegx(inst);
+#endif
+		}
+
+		return inst;
+	}
+
+	return code_ptr;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void * sljit_generate_code(struct sljit_compiler *compiler)
+{
+	struct sljit_memory_fragment *buf;
+	sljit_ins *code;
+	sljit_ins *code_ptr;
+	sljit_ins *buf_ptr;
+	sljit_ins *buf_end;
+	sljit_uw word_count;
+	sljit_uw addr;
+
+	struct sljit_label *label;
+	struct sljit_jump *jump;
+	struct sljit_const *const_;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_generate_code(compiler));
+	reverse_buf(compiler);
+
+	code = (sljit_ins *)SLJIT_MALLOC_EXEC(compiler->size * sizeof(sljit_ins), compiler->exec_allocator_data);
+	PTR_FAIL_WITH_EXEC_IF(code);
+	buf = compiler->buf;
+
+	code_ptr = code;
+	word_count = 0;
+	label = compiler->labels;
+	jump = compiler->jumps;
+	const_ = compiler->consts;
+	do {
+		buf_ptr = (sljit_ins *)buf->memory;
+		buf_end = buf_ptr + (buf->used_size >> 3);
+		do {
+			*code_ptr = *buf_ptr++;
+			SLJIT_ASSERT(!label || label->size >= word_count);
+			SLJIT_ASSERT(!jump || jump->addr >= word_count);
+			SLJIT_ASSERT(!const_ || const_->addr >= word_count);
+			/* These structures are ordered by their address. */
+			if (label && label->size == word_count) {
+				/* Just recording the address. */
+				label->addr = (sljit_uw) code_ptr;
+				label->size = code_ptr - code;
+				label = label->next;
+			}
+
+			if (jump && jump->addr == word_count) {
+				if (jump->flags & IS_JAL)
+					jump->addr = (sljit_uw)(code_ptr - 4);
+				else
+					jump->addr = (sljit_uw)(code_ptr - 3);
+
+				code_ptr = detect_jump_type(jump, code_ptr, code);
+				jump = jump->next;
+			}
+
+			if (const_ && const_->addr == word_count) {
+				/* Just recording the address. */
+				const_->addr = (sljit_uw) code_ptr;
+				const_ = const_->next;
+			}
+
+			code_ptr++;
+			word_count++;
+		} while (buf_ptr < buf_end);
+
+		buf = buf->next;
+	} while (buf);
+
+	if (label && label->size == word_count) {
+		label->addr = (sljit_uw) code_ptr;
+		label->size = code_ptr - code;
+		label = label->next;
+	}
+
+	SLJIT_ASSERT(!label);
+	SLJIT_ASSERT(!jump);
+	SLJIT_ASSERT(!const_);
+	SLJIT_ASSERT(code_ptr - code <= (sljit_sw)compiler->size);
+
+	jump = compiler->jumps;
+	while (jump) {
+		do {
+			addr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
+			buf_ptr = (sljit_ins *)jump->addr;
+
+			if (jump->flags & PATCH_B) {
+				addr = (sljit_sw)(addr - (jump->addr)) >> 3;
+				SLJIT_ASSERT((sljit_sw) addr <= SIMM_17BIT_MAX && (sljit_sw) addr >= SIMM_17BIT_MIN);
+				buf_ptr[0] = (buf_ptr[0] & ~(BOFF_X1(-1))) | BOFF_X1(addr);
+
+#ifdef TILEGX_JIT_DEBUG
+				printf("[runtime relocate]%04d:\t", __LINE__);
+				print_insn_tilegx(buf_ptr);
+#endif
+				break;
+			}
+
+			if (jump->flags & PATCH_J) {
+				SLJIT_ASSERT((addr & ~0x3FFFFFFFL) == ((jump->addr + sizeof(sljit_ins)) & ~0x3FFFFFFFL));
+				addr = (sljit_sw)(addr - (jump->addr)) >> 3;
+				buf_ptr[0] = (buf_ptr[0] & ~(JOFF_X1(-1))) | JOFF_X1(addr);
+
+#ifdef TILEGX_JIT_DEBUG
+				printf("[runtime relocate]%04d:\t", __LINE__);
+				print_insn_tilegx(buf_ptr);
+#endif
+				break;
+			}
+
+			SLJIT_ASSERT(!(jump->flags & IS_JAL));
+
+			/* Set the fields of immediate loads. */
+			buf_ptr[0] = (buf_ptr[0] & ~(0xFFFFL << 43)) | (((addr >> 32) & 0xFFFFL) << 43);
+			buf_ptr[1] = (buf_ptr[1] & ~(0xFFFFL << 43)) | (((addr >> 16) & 0xFFFFL) << 43);
+			buf_ptr[2] = (buf_ptr[2] & ~(0xFFFFL << 43)) | ((addr & 0xFFFFL) << 43);
+		} while (0);
+
+		jump = jump->next;
+	}
+
+	compiler->error = SLJIT_ERR_COMPILED;
+	compiler->executable_size = (code_ptr - code) * sizeof(sljit_ins);
+
+	SLJIT_CACHE_FLUSH(code, code_ptr);
+	SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);
+	return code;
+}
+
+static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
+{
+
+	if (imm <= SIMM_16BIT_MAX && imm >= SIMM_16BIT_MIN)
+		return ADDLI(dst_ar, ZERO, imm);
+
+	if (imm <= SIMM_32BIT_MAX && imm >= SIMM_32BIT_MIN) {
+		FAIL_IF(ADDLI(dst_ar, ZERO, imm >> 16));
+		return SHL16INSLI(dst_ar, dst_ar, imm);
+	}
+
+	if (imm <= SIMM_48BIT_MAX && imm >= SIMM_48BIT_MIN) {
+		FAIL_IF(ADDLI(dst_ar, ZERO, imm >> 32));
+		FAIL_IF(SHL16INSLI(dst_ar, dst_ar, imm >> 16));
+		return SHL16INSLI(dst_ar, dst_ar, imm);
+	}
+
+	FAIL_IF(ADDLI(dst_ar, ZERO, imm >> 48));
+	FAIL_IF(SHL16INSLI(dst_ar, dst_ar, imm >> 32));
+	FAIL_IF(SHL16INSLI(dst_ar, dst_ar, imm >> 16));
+	return SHL16INSLI(dst_ar, dst_ar, imm);
+}
+
+static sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm, int flush)
+{
+	/* Should *not* be optimized as load_immediate, as pcre relocation
+	   mechanism will match this fixed 4-instruction pattern. */
+	if (flush) {
+		FAIL_IF(ADDLI_SOLO(dst_ar, ZERO, imm >> 32));
+		FAIL_IF(SHL16INSLI_SOLO(dst_ar, dst_ar, imm >> 16));
+		return SHL16INSLI_SOLO(dst_ar, dst_ar, imm);
+	}
+
+	FAIL_IF(ADDLI(dst_ar, ZERO, imm >> 32));
+	FAIL_IF(SHL16INSLI(dst_ar, dst_ar, imm >> 16));
+	return SHL16INSLI(dst_ar, dst_ar, imm);
+}
+
+static sljit_s32 emit_const_64(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm, int flush)
+{
+	/* Should *not* be optimized as load_immediate, as pcre relocation
+	   mechanism will match this fixed 4-instruction pattern. */
+	if (flush) {
+		FAIL_IF(ADDLI_SOLO(reg_map[dst_ar], ZERO, imm >> 48));
+		FAIL_IF(SHL16INSLI_SOLO(reg_map[dst_ar], reg_map[dst_ar], imm >> 32));
+		FAIL_IF(SHL16INSLI_SOLO(reg_map[dst_ar], reg_map[dst_ar], imm >> 16));
+		return SHL16INSLI_SOLO(reg_map[dst_ar], reg_map[dst_ar], imm);
+	}
+
+	FAIL_IF(ADDLI(reg_map[dst_ar], ZERO, imm >> 48));
+	FAIL_IF(SHL16INSLI(reg_map[dst_ar], reg_map[dst_ar], imm >> 32));
+	FAIL_IF(SHL16INSLI(reg_map[dst_ar], reg_map[dst_ar], imm >> 16));
+	return SHL16INSLI(reg_map[dst_ar], reg_map[dst_ar], imm);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	sljit_ins base;
+	sljit_s32 i, tmp;
+ 
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
+	set_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
+
+	local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
+	local_size = (local_size + 7) & ~7;
+	compiler->local_size = local_size;
+
+	if (local_size <= SIMM_16BIT_MAX) {
+		/* Frequent case. */
+		FAIL_IF(ADDLI(SLJIT_LOCALS_REG_mapped, SLJIT_LOCALS_REG_mapped, -local_size));
+		base = SLJIT_LOCALS_REG_mapped;
+	} else {
+		FAIL_IF(load_immediate(compiler, TMP_REG1_mapped, local_size));
+		FAIL_IF(ADD(TMP_REG2_mapped, SLJIT_LOCALS_REG_mapped, ZERO));
+		FAIL_IF(SUB(SLJIT_LOCALS_REG_mapped, SLJIT_LOCALS_REG_mapped, TMP_REG1_mapped));
+		base = TMP_REG2_mapped;
+		local_size = 0;
+	}
+
+	/* Save the return address. */
+	FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 8));
+	FAIL_IF(ST_ADD(ADDR_TMP_mapped, RA, -8));
+
+	/* Save the S registers. */
+	tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
+	for (i = SLJIT_S0; i >= tmp; i--) {
+		FAIL_IF(ST_ADD(ADDR_TMP_mapped, reg_map[i], -8));
+	}
+
+	/* Save the R registers that need to be reserved. */
+	for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
+		FAIL_IF(ST_ADD(ADDR_TMP_mapped, reg_map[i], -8));
+	}
+
+	/* Move the arguments to S registers. */
+	for (i = 0; i < args; i++) {
+		FAIL_IF(ADD(reg_map[SLJIT_S0 - i], i, ZERO));
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 args, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
+	set_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
+
+	local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
+	compiler->local_size = (local_size + 7) & ~7;
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 local_size;
+	sljit_ins base;
+	sljit_s32 i, tmp;
+	sljit_s32 saveds;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_return(compiler, op, src, srcw));
+
+	FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
+
+	local_size = compiler->local_size;
+	if (local_size <= SIMM_16BIT_MAX)
+		base = SLJIT_LOCALS_REG_mapped;
+	else {
+		FAIL_IF(load_immediate(compiler, TMP_REG1_mapped, local_size));
+		FAIL_IF(ADD(TMP_REG1_mapped, SLJIT_LOCALS_REG_mapped, TMP_REG1_mapped));
+		base = TMP_REG1_mapped;
+		local_size = 0;
+	}
+
+	/* Restore the return address. */
+	FAIL_IF(ADDLI(ADDR_TMP_mapped, base, local_size - 8));
+	FAIL_IF(LD_ADD(RA, ADDR_TMP_mapped, -8));
+
+	/* Restore the S registers. */
+	saveds = compiler->saveds;
+	tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
+	for (i = SLJIT_S0; i >= tmp; i--) {
+		FAIL_IF(LD_ADD(reg_map[i], ADDR_TMP_mapped, -8));
+	}
+
+	/* Restore the R registers that need to be reserved. */
+	for (i = compiler->scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
+		FAIL_IF(LD_ADD(reg_map[i], ADDR_TMP_mapped, -8));
+	}
+
+	if (compiler->local_size <= SIMM_16BIT_MAX)
+		FAIL_IF(ADDLI(SLJIT_LOCALS_REG_mapped, SLJIT_LOCALS_REG_mapped, compiler->local_size));
+	else
+		FAIL_IF(ADD(SLJIT_LOCALS_REG_mapped, TMP_REG1_mapped, ZERO));
+
+	return JR(RA);
+}
+
+/* reg_ar is an absoulute register! */
+
+/* Can perform an operation using at most 1 instruction. */
+static sljit_s32 getput_arg_fast(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg, sljit_sw argw)
+{
+	SLJIT_ASSERT(arg & SLJIT_MEM);
+
+	if ((!(flags & WRITE_BACK) || !(arg & REG_MASK))
+			&& !(arg & OFFS_REG_MASK) && argw <= SIMM_16BIT_MAX && argw >= SIMM_16BIT_MIN) {
+		/* Works for both absoulte and relative addresses. */
+		if (SLJIT_UNLIKELY(flags & ARG_TEST))
+			return 1;
+
+		FAIL_IF(ADDLI(ADDR_TMP_mapped, reg_map[arg & REG_MASK], argw));
+
+		if (flags & LOAD_DATA)
+			FAIL_IF(PB2(data_transfer_insts[flags & MEM_MASK], reg_ar, ADDR_TMP_mapped));
+		else
+			FAIL_IF(PB2(data_transfer_insts[flags & MEM_MASK], ADDR_TMP_mapped, reg_ar));
+
+		return -1;
+	}
+
+	return 0;
+}
+
+/* See getput_arg below.
+   Note: can_cache is called only for binary operators. Those
+   operators always uses word arguments without write back. */
+static sljit_s32 can_cache(sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
+{
+	SLJIT_ASSERT((arg & SLJIT_MEM) && (next_arg & SLJIT_MEM));
+
+	/* Simple operation except for updates. */
+	if (arg & OFFS_REG_MASK) {
+		argw &= 0x3;
+		next_argw &= 0x3;
+		if (argw && argw == next_argw
+				&& (arg == next_arg || (arg & OFFS_REG_MASK) == (next_arg & OFFS_REG_MASK)))
+			return 1;
+		return 0;
+	}
+
+	if (arg == next_arg) {
+		if (((next_argw - argw) <= SIMM_16BIT_MAX
+				&& (next_argw - argw) >= SIMM_16BIT_MIN))
+			return 1;
+
+		return 0;
+	}
+
+	return 0;
+}
+
+/* Emit the necessary instructions. See can_cache above. */
+static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
+{
+	sljit_s32 tmp_ar, base;
+
+	SLJIT_ASSERT(arg & SLJIT_MEM);
+	if (!(next_arg & SLJIT_MEM)) {
+		next_arg = 0;
+		next_argw = 0;
+	}
+
+	if ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA))
+		tmp_ar = reg_ar;
+	else
+		tmp_ar = TMP_REG1_mapped;
+
+	base = arg & REG_MASK;
+
+	if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
+		argw &= 0x3;
+
+		if ((flags & WRITE_BACK) && reg_ar == reg_map[base]) {
+			SLJIT_ASSERT(!(flags & LOAD_DATA) && reg_map[TMP_REG1] != reg_ar);
+			FAIL_IF(ADD(TMP_REG1_mapped, reg_ar, ZERO));
+			reg_ar = TMP_REG1_mapped;
+		}
+
+		/* Using the cache. */
+		if (argw == compiler->cache_argw) {
+			if (!(flags & WRITE_BACK)) {
+				if (arg == compiler->cache_arg) {
+					if (flags & LOAD_DATA)
+						return PB2(data_transfer_insts[flags & MEM_MASK], reg_ar, TMP_REG3_mapped);
+					else
+						return PB2(data_transfer_insts[flags & MEM_MASK], TMP_REG3_mapped, reg_ar);
+				}
+
+				if ((SLJIT_MEM | (arg & OFFS_REG_MASK)) == compiler->cache_arg) {
+					if (arg == next_arg && argw == (next_argw & 0x3)) {
+						compiler->cache_arg = arg;
+						compiler->cache_argw = argw;
+						FAIL_IF(ADD(TMP_REG3_mapped, reg_map[base], TMP_REG3_mapped));
+						if (flags & LOAD_DATA)
+							return PB2(data_transfer_insts[flags & MEM_MASK], reg_ar, TMP_REG3_mapped);
+						else
+							return PB2(data_transfer_insts[flags & MEM_MASK], TMP_REG3_mapped, reg_ar);
+					}
+
+					FAIL_IF(ADD(tmp_ar, reg_map[base], TMP_REG3_mapped));
+					if (flags & LOAD_DATA)
+						return PB2(data_transfer_insts[flags & MEM_MASK], reg_ar, tmp_ar);
+					else
+						return PB2(data_transfer_insts[flags & MEM_MASK], tmp_ar, reg_ar);
+				}
+			} else {
+				if ((SLJIT_MEM | (arg & OFFS_REG_MASK)) == compiler->cache_arg) {
+					FAIL_IF(ADD(reg_map[base], reg_map[base], TMP_REG3_mapped));
+					if (flags & LOAD_DATA)
+						return PB2(data_transfer_insts[flags & MEM_MASK], reg_ar, reg_map[base]);
+					else
+						return PB2(data_transfer_insts[flags & MEM_MASK], reg_map[base], reg_ar);
+				}
+			}
+		}
+
+		if (SLJIT_UNLIKELY(argw)) {
+			compiler->cache_arg = SLJIT_MEM | (arg & OFFS_REG_MASK);
+			compiler->cache_argw = argw;
+			FAIL_IF(SHLI(TMP_REG3_mapped, reg_map[OFFS_REG(arg)], argw));
+		}
+
+		if (!(flags & WRITE_BACK)) {
+			if (arg == next_arg && argw == (next_argw & 0x3)) {
+				compiler->cache_arg = arg;
+				compiler->cache_argw = argw;
+				FAIL_IF(ADD(TMP_REG3_mapped, reg_map[base], reg_map[!argw ? OFFS_REG(arg) : TMP_REG3]));
+				tmp_ar = TMP_REG3_mapped;
+			} else
+				FAIL_IF(ADD(tmp_ar, reg_map[base], reg_map[!argw ? OFFS_REG(arg) : TMP_REG3]));
+
+			if (flags & LOAD_DATA)
+				return PB2(data_transfer_insts[flags & MEM_MASK], reg_ar, tmp_ar);
+			else
+				return PB2(data_transfer_insts[flags & MEM_MASK], tmp_ar, reg_ar);
+		}
+
+		FAIL_IF(ADD(reg_map[base], reg_map[base], reg_map[!argw ? OFFS_REG(arg) : TMP_REG3]));
+
+		if (flags & LOAD_DATA)
+			return PB2(data_transfer_insts[flags & MEM_MASK], reg_ar, reg_map[base]);
+		else
+			return PB2(data_transfer_insts[flags & MEM_MASK], reg_map[base], reg_ar);
+	}
+
+	if (SLJIT_UNLIKELY(flags & WRITE_BACK) && base) {
+		/* Update only applies if a base register exists. */
+		if (reg_ar == reg_map[base]) {
+			SLJIT_ASSERT(!(flags & LOAD_DATA) && TMP_REG1_mapped != reg_ar);
+			if (argw <= SIMM_16BIT_MAX && argw >= SIMM_16BIT_MIN) {
+				FAIL_IF(ADDLI(ADDR_TMP_mapped, reg_map[base], argw));
+				if (flags & LOAD_DATA)
+					FAIL_IF(PB2(data_transfer_insts[flags & MEM_MASK], reg_ar, ADDR_TMP_mapped));
+				else
+					FAIL_IF(PB2(data_transfer_insts[flags & MEM_MASK], ADDR_TMP_mapped, reg_ar));
+
+				if (argw)
+					return ADDLI(reg_map[base], reg_map[base], argw);
+
+				return SLJIT_SUCCESS;
+			}
+
+			FAIL_IF(ADD(TMP_REG1_mapped, reg_ar, ZERO));
+			reg_ar = TMP_REG1_mapped;
+		}
+
+		if (argw <= SIMM_16BIT_MAX && argw >= SIMM_16BIT_MIN) {
+			if (argw)
+				FAIL_IF(ADDLI(reg_map[base], reg_map[base], argw));
+		} else {
+			if (compiler->cache_arg == SLJIT_MEM
+					&& argw - compiler->cache_argw <= SIMM_16BIT_MAX
+					&& argw - compiler->cache_argw >= SIMM_16BIT_MIN) {
+				if (argw != compiler->cache_argw) {
+					FAIL_IF(ADD(TMP_REG3_mapped, TMP_REG3_mapped, argw - compiler->cache_argw));
+					compiler->cache_argw = argw;
+				}
+
+				FAIL_IF(ADD(reg_map[base], reg_map[base], TMP_REG3_mapped));
+			} else {
+				compiler->cache_arg = SLJIT_MEM;
+				compiler->cache_argw = argw;
+				FAIL_IF(load_immediate(compiler, TMP_REG3_mapped, argw));
+				FAIL_IF(ADD(reg_map[base], reg_map[base], TMP_REG3_mapped));
+			}
+		}
+
+		if (flags & LOAD_DATA)
+			return PB2(data_transfer_insts[flags & MEM_MASK], reg_ar, reg_map[base]);
+		else
+			return PB2(data_transfer_insts[flags & MEM_MASK], reg_map[base], reg_ar);
+	}
+
+	if (compiler->cache_arg == arg
+			&& argw - compiler->cache_argw <= SIMM_16BIT_MAX
+			&& argw - compiler->cache_argw >= SIMM_16BIT_MIN) {
+		if (argw != compiler->cache_argw) {
+			FAIL_IF(ADDLI(TMP_REG3_mapped, TMP_REG3_mapped, argw - compiler->cache_argw));
+			compiler->cache_argw = argw;
+		}
+
+		if (flags & LOAD_DATA)
+			return PB2(data_transfer_insts[flags & MEM_MASK], reg_ar, TMP_REG3_mapped);
+		else
+			return PB2(data_transfer_insts[flags & MEM_MASK], TMP_REG3_mapped, reg_ar);
+	}
+
+	if (compiler->cache_arg == SLJIT_MEM
+			&& argw - compiler->cache_argw <= SIMM_16BIT_MAX
+			&& argw - compiler->cache_argw >= SIMM_16BIT_MIN) {
+		if (argw != compiler->cache_argw)
+			FAIL_IF(ADDLI(TMP_REG3_mapped, TMP_REG3_mapped, argw - compiler->cache_argw));
+	} else {
+		compiler->cache_arg = SLJIT_MEM;
+		FAIL_IF(load_immediate(compiler, TMP_REG3_mapped, argw));
+	}
+
+	compiler->cache_argw = argw;
+
+	if (!base) {
+		if (flags & LOAD_DATA)
+			return PB2(data_transfer_insts[flags & MEM_MASK], reg_ar, TMP_REG3_mapped);
+		else
+			return PB2(data_transfer_insts[flags & MEM_MASK], TMP_REG3_mapped, reg_ar);
+	}
+
+	if (arg == next_arg
+			&& next_argw - argw <= SIMM_16BIT_MAX
+			&& next_argw - argw >= SIMM_16BIT_MIN) {
+		compiler->cache_arg = arg;
+		FAIL_IF(ADD(TMP_REG3_mapped, TMP_REG3_mapped, reg_map[base]));
+		if (flags & LOAD_DATA)
+			return PB2(data_transfer_insts[flags & MEM_MASK], reg_ar, TMP_REG3_mapped);
+		else
+			return PB2(data_transfer_insts[flags & MEM_MASK], TMP_REG3_mapped, reg_ar);
+	}
+
+	FAIL_IF(ADD(tmp_ar, TMP_REG3_mapped, reg_map[base]));
+
+	if (flags & LOAD_DATA)
+		return PB2(data_transfer_insts[flags & MEM_MASK], reg_ar, tmp_ar);
+	else
+		return PB2(data_transfer_insts[flags & MEM_MASK], tmp_ar, reg_ar);
+}
+
+static SLJIT_INLINE sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg_ar, sljit_s32 arg, sljit_sw argw)
+{
+	if (getput_arg_fast(compiler, flags, reg_ar, arg, argw))
+		return compiler->error;
+
+	compiler->cache_arg = 0;
+	compiler->cache_argw = 0;
+	return getput_arg(compiler, flags, reg_ar, arg, argw, 0, 0);
+}
+
+static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg1, sljit_sw arg1w, sljit_s32 arg2, sljit_sw arg2w)
+{
+	if (getput_arg_fast(compiler, flags, reg, arg1, arg1w))
+		return compiler->error;
+	return getput_arg(compiler, flags, reg, arg1, arg1w, arg2, arg2w);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	/* For UNUSED dst. Uncommon, but possible. */
+	if (dst == SLJIT_UNUSED)
+		return SLJIT_SUCCESS;
+
+	if (FAST_IS_REG(dst))
+		return ADD(reg_map[dst], RA, ZERO);
+
+	/* Memory. */
+	return emit_op_mem(compiler, WORD_DATA, RA, dst, dstw);
+}
+
+static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags, sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
+{
+	sljit_s32 overflow_ra = 0;
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_P:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if (dst != src2)
+			return ADD(reg_map[dst], reg_map[src2], ZERO);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U32:
+	case SLJIT_MOV_S32:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
+			if (op == SLJIT_MOV_S32)
+				return BFEXTS(reg_map[dst], reg_map[src2], 0, 31);
+
+			return BFEXTU(reg_map[dst], reg_map[src2], 0, 31);
+		} else if (dst != src2) {
+			SLJIT_ASSERT(src2 == 0);
+			return ADD(reg_map[dst], reg_map[src2], ZERO);
+		}
+
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U8:
+	case SLJIT_MOV_S8:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
+			if (op == SLJIT_MOV_S8)
+				return BFEXTS(reg_map[dst], reg_map[src2], 0, 7);
+
+			return BFEXTU(reg_map[dst], reg_map[src2], 0, 7);
+		} else if (dst != src2) {
+			SLJIT_ASSERT(src2 == 0);
+			return ADD(reg_map[dst], reg_map[src2], ZERO);
+		}
+
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MOV_U16:
+	case SLJIT_MOV_S16:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
+			if (op == SLJIT_MOV_S16)
+				return BFEXTS(reg_map[dst], reg_map[src2], 0, 15);
+
+			return BFEXTU(reg_map[dst], reg_map[src2], 0, 15);
+		} else if (dst != src2) {
+			SLJIT_ASSERT(src2 == 0);
+			return ADD(reg_map[dst], reg_map[src2], ZERO);
+		}
+
+		return SLJIT_SUCCESS;
+
+	case SLJIT_NOT:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if (op & SLJIT_SET_E)
+			FAIL_IF(NOR(EQUAL_FLAG, reg_map[src2], reg_map[src2]));
+		if (CHECK_FLAGS(SLJIT_SET_E))
+			FAIL_IF(NOR(reg_map[dst], reg_map[src2], reg_map[src2]));
+
+		return SLJIT_SUCCESS;
+
+	case SLJIT_CLZ:
+		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+		if (op & SLJIT_SET_E)
+			FAIL_IF(CLZ(EQUAL_FLAG, reg_map[src2]));
+		if (CHECK_FLAGS(SLJIT_SET_E))
+			FAIL_IF(CLZ(reg_map[dst], reg_map[src2]));
+
+		return SLJIT_SUCCESS;
+
+	case SLJIT_ADD:
+		if (flags & SRC2_IMM) {
+			if (op & SLJIT_SET_O) {
+				FAIL_IF(SHRUI(TMP_EREG1, reg_map[src1], 63));
+				if (src2 < 0)
+					FAIL_IF(XORI(TMP_EREG1, TMP_EREG1, 1));
+			}
+
+			if (op & SLJIT_SET_E)
+				FAIL_IF(ADDLI(EQUAL_FLAG, reg_map[src1], src2));
+
+			if (op & SLJIT_SET_C) {
+				if (src2 >= 0)
+					FAIL_IF(ORI(ULESS_FLAG ,reg_map[src1], src2));
+				else {
+					FAIL_IF(ADDLI(ULESS_FLAG ,ZERO, src2));
+					FAIL_IF(OR(ULESS_FLAG,reg_map[src1],ULESS_FLAG));
+				}
+			}
+
+			/* dst may be the same as src1 or src2. */
+			if (CHECK_FLAGS(SLJIT_SET_E))
+				FAIL_IF(ADDLI(reg_map[dst], reg_map[src1], src2));
+
+			if (op & SLJIT_SET_O) {
+				FAIL_IF(SHRUI(OVERFLOW_FLAG, reg_map[dst], 63));
+
+				if (src2 < 0)
+					FAIL_IF(XORI(OVERFLOW_FLAG, OVERFLOW_FLAG, 1));
+			}
+		} else {
+			if (op & SLJIT_SET_O) {
+				FAIL_IF(XOR(TMP_EREG1, reg_map[src1], reg_map[src2]));
+				FAIL_IF(SHRUI(TMP_EREG1, TMP_EREG1, 63));
+
+				if (src1 != dst)
+					overflow_ra = reg_map[src1];
+				else if (src2 != dst)
+					overflow_ra = reg_map[src2];
+				else {
+					/* Rare ocasion. */
+					FAIL_IF(ADD(TMP_EREG2, reg_map[src1], ZERO));
+					overflow_ra = TMP_EREG2;
+				}
+			}
+
+			if (op & SLJIT_SET_E)
+				FAIL_IF(ADD(EQUAL_FLAG ,reg_map[src1], reg_map[src2]));
+
+			if (op & SLJIT_SET_C)
+				FAIL_IF(OR(ULESS_FLAG,reg_map[src1], reg_map[src2]));
+
+			/* dst may be the same as src1 or src2. */
+			if (CHECK_FLAGS(SLJIT_SET_E))
+				FAIL_IF(ADD(reg_map[dst],reg_map[src1], reg_map[src2]));
+
+			if (op & SLJIT_SET_O) {
+				FAIL_IF(XOR(OVERFLOW_FLAG,reg_map[dst], overflow_ra));
+				FAIL_IF(SHRUI(OVERFLOW_FLAG, OVERFLOW_FLAG, 63));
+			}
+		}
+
+		/* a + b >= a | b (otherwise, the carry should be set to 1). */
+		if (op & SLJIT_SET_C)
+			FAIL_IF(CMPLTU(ULESS_FLAG ,reg_map[dst] ,ULESS_FLAG));
+
+		if (op & SLJIT_SET_O)
+			return CMOVNEZ(OVERFLOW_FLAG, TMP_EREG1, ZERO);
+
+		return SLJIT_SUCCESS;
+
+	case SLJIT_ADDC:
+		if (flags & SRC2_IMM) {
+			if (op & SLJIT_SET_C) {
+				if (src2 >= 0)
+					FAIL_IF(ORI(TMP_EREG1, reg_map[src1], src2));
+				else {
+					FAIL_IF(ADDLI(TMP_EREG1, ZERO, src2));
+					FAIL_IF(OR(TMP_EREG1, reg_map[src1], TMP_EREG1));
+				}
+			}
+
+			FAIL_IF(ADDLI(reg_map[dst], reg_map[src1], src2));
+
+		} else {
+			if (op & SLJIT_SET_C)
+				FAIL_IF(OR(TMP_EREG1, reg_map[src1], reg_map[src2]));
+
+			/* dst may be the same as src1 or src2. */
+			FAIL_IF(ADD(reg_map[dst], reg_map[src1], reg_map[src2]));
+		}
+
+		if (op & SLJIT_SET_C)
+			FAIL_IF(CMPLTU(TMP_EREG1, reg_map[dst], TMP_EREG1));
+
+		FAIL_IF(ADD(reg_map[dst], reg_map[dst], ULESS_FLAG));
+
+		if (!(op & SLJIT_SET_C))
+			return SLJIT_SUCCESS;
+
+		/* Set TMP_EREG2 (dst == 0) && (ULESS_FLAG == 1). */
+		FAIL_IF(CMPLTUI(TMP_EREG2, reg_map[dst], 1));
+		FAIL_IF(AND(TMP_EREG2, TMP_EREG2, ULESS_FLAG));
+		/* Set carry flag. */
+		return OR(ULESS_FLAG, TMP_EREG2, TMP_EREG1);
+
+	case SLJIT_SUB:
+		if ((flags & SRC2_IMM) && ((op & (SLJIT_SET_U | SLJIT_SET_S)) || src2 == SIMM_16BIT_MIN)) {
+			FAIL_IF(ADDLI(TMP_REG2_mapped, ZERO, src2));
+			src2 = TMP_REG2;
+			flags &= ~SRC2_IMM;
+		}
+
+		if (flags & SRC2_IMM) {
+			if (op & SLJIT_SET_O) {
+				FAIL_IF(SHRUI(TMP_EREG1,reg_map[src1], 63));
+
+				if (src2 < 0)
+					FAIL_IF(XORI(TMP_EREG1, TMP_EREG1, 1));
+
+				if (src1 != dst)
+					overflow_ra = reg_map[src1];
+				else {
+					/* Rare ocasion. */
+					FAIL_IF(ADD(TMP_EREG2, reg_map[src1], ZERO));
+					overflow_ra = TMP_EREG2;
+				}
+			}
+
+			if (op & SLJIT_SET_E)
+				FAIL_IF(ADDLI(EQUAL_FLAG, reg_map[src1], -src2));
+
+			if (op & SLJIT_SET_C) {
+				FAIL_IF(load_immediate(compiler, ADDR_TMP_mapped, src2));
+				FAIL_IF(CMPLTU(ULESS_FLAG, reg_map[src1], ADDR_TMP_mapped));
+			}
+
+			/* dst may be the same as src1 or src2. */
+			if (CHECK_FLAGS(SLJIT_SET_E))
+				FAIL_IF(ADDLI(reg_map[dst], reg_map[src1], -src2));
+
+		} else {
+
+			if (op & SLJIT_SET_O) {
+				FAIL_IF(XOR(TMP_EREG1, reg_map[src1], reg_map[src2]));
+				FAIL_IF(SHRUI(TMP_EREG1, TMP_EREG1, 63));
+
+				if (src1 != dst)
+					overflow_ra = reg_map[src1];
+				else {
+					/* Rare ocasion. */
+					FAIL_IF(ADD(TMP_EREG2, reg_map[src1], ZERO));
+					overflow_ra = TMP_EREG2;
+				}
+			}
+
+			if (op & SLJIT_SET_E)
+				FAIL_IF(SUB(EQUAL_FLAG, reg_map[src1], reg_map[src2]));
+
+			if (op & (SLJIT_SET_U | SLJIT_SET_C))
+				FAIL_IF(CMPLTU(ULESS_FLAG, reg_map[src1], reg_map[src2]));
+
+			if (op & SLJIT_SET_U)
+				FAIL_IF(CMPLTU(UGREATER_FLAG, reg_map[src2], reg_map[src1]));
+
+			if (op & SLJIT_SET_S) {
+				FAIL_IF(CMPLTS(LESS_FLAG ,reg_map[src1] ,reg_map[src2]));
+				FAIL_IF(CMPLTS(GREATER_FLAG ,reg_map[src2] ,reg_map[src1]));
+			}
+
+			/* dst may be the same as src1 or src2. */
+			if (CHECK_FLAGS(SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_C))
+				FAIL_IF(SUB(reg_map[dst], reg_map[src1], reg_map[src2]));
+		}
+
+		if (op & SLJIT_SET_O) {
+			FAIL_IF(XOR(OVERFLOW_FLAG, reg_map[dst], overflow_ra));
+			FAIL_IF(SHRUI(OVERFLOW_FLAG, OVERFLOW_FLAG, 63));
+			return CMOVEQZ(OVERFLOW_FLAG, TMP_EREG1, ZERO);
+		}
+
+		return SLJIT_SUCCESS;
+
+	case SLJIT_SUBC:
+		if ((flags & SRC2_IMM) && src2 == SIMM_16BIT_MIN) {
+			FAIL_IF(ADDLI(TMP_REG2_mapped, ZERO, src2));
+			src2 = TMP_REG2;
+			flags &= ~SRC2_IMM;
+		}
+
+		if (flags & SRC2_IMM) {
+			if (op & SLJIT_SET_C) {
+				FAIL_IF(load_immediate(compiler, ADDR_TMP_mapped, -src2));
+				FAIL_IF(CMPLTU(TMP_EREG1, reg_map[src1], ADDR_TMP_mapped));
+			}
+
+			/* dst may be the same as src1 or src2. */
+			FAIL_IF(ADDLI(reg_map[dst], reg_map[src1], -src2));
+
+		} else {
+			if (op & SLJIT_SET_C)
+				FAIL_IF(CMPLTU(TMP_EREG1, reg_map[src1], reg_map[src2]));
+				/* dst may be the same as src1 or src2. */
+			FAIL_IF(SUB(reg_map[dst], reg_map[src1], reg_map[src2]));
+		}
+
+		if (op & SLJIT_SET_C)
+			FAIL_IF(CMOVEQZ(TMP_EREG1, reg_map[dst], ULESS_FLAG));
+
+		FAIL_IF(SUB(reg_map[dst], reg_map[dst], ULESS_FLAG));
+
+		if (op & SLJIT_SET_C)
+			FAIL_IF(ADD(ULESS_FLAG, TMP_EREG1, ZERO));
+
+		return SLJIT_SUCCESS;
+
+	case SLJIT_MUL:
+		if (flags & SRC2_IMM) {
+			FAIL_IF(load_immediate(compiler, TMP_REG2_mapped, src2));
+			src2 = TMP_REG2;
+			flags &= ~SRC2_IMM;
+		}
+
+		FAIL_IF(MUL(reg_map[dst], reg_map[src1], reg_map[src2]));
+
+		return SLJIT_SUCCESS;
+
+#define EMIT_LOGICAL(op_imm, op_norm) \
+	if (flags & SRC2_IMM) { \
+		FAIL_IF(load_immediate(compiler, ADDR_TMP_mapped, src2)); \
+		if (op & SLJIT_SET_E) \
+			FAIL_IF(push_3_buffer( \
+				compiler, op_norm, EQUAL_FLAG, reg_map[src1], \
+				ADDR_TMP_mapped, __LINE__)); \
+		if (CHECK_FLAGS(SLJIT_SET_E)) \
+			FAIL_IF(push_3_buffer( \
+				compiler, op_norm, reg_map[dst], reg_map[src1], \
+				ADDR_TMP_mapped, __LINE__)); \
+	} else { \
+		if (op & SLJIT_SET_E) \
+			FAIL_IF(push_3_buffer( \
+				compiler, op_norm, EQUAL_FLAG, reg_map[src1], \
+				reg_map[src2], __LINE__)); \
+		if (CHECK_FLAGS(SLJIT_SET_E)) \
+			FAIL_IF(push_3_buffer( \
+				compiler, op_norm, reg_map[dst], reg_map[src1], \
+				reg_map[src2], __LINE__)); \
+	}
+
+	case SLJIT_AND:
+		EMIT_LOGICAL(TILEGX_OPC_ANDI, TILEGX_OPC_AND);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_OR:
+		EMIT_LOGICAL(TILEGX_OPC_ORI, TILEGX_OPC_OR);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_XOR:
+		EMIT_LOGICAL(TILEGX_OPC_XORI, TILEGX_OPC_XOR);
+		return SLJIT_SUCCESS;
+
+#define EMIT_SHIFT(op_imm, op_norm) \
+	if (flags & SRC2_IMM) { \
+		if (op & SLJIT_SET_E) \
+			FAIL_IF(push_3_buffer( \
+				compiler, op_imm, EQUAL_FLAG, reg_map[src1], \
+				src2 & 0x3F, __LINE__)); \
+		if (CHECK_FLAGS(SLJIT_SET_E)) \
+			FAIL_IF(push_3_buffer( \
+				compiler, op_imm, reg_map[dst], reg_map[src1], \
+				src2 & 0x3F, __LINE__)); \
+	} else { \
+		if (op & SLJIT_SET_E) \
+			FAIL_IF(push_3_buffer( \
+				compiler, op_norm, EQUAL_FLAG, reg_map[src1], \
+				reg_map[src2], __LINE__)); \
+		if (CHECK_FLAGS(SLJIT_SET_E)) \
+			FAIL_IF(push_3_buffer( \
+				compiler, op_norm, reg_map[dst], reg_map[src1], \
+				reg_map[src2], __LINE__)); \
+	}
+
+	case SLJIT_SHL:
+		EMIT_SHIFT(TILEGX_OPC_SHLI, TILEGX_OPC_SHL);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_LSHR:
+		EMIT_SHIFT(TILEGX_OPC_SHRUI, TILEGX_OPC_SHRU);
+		return SLJIT_SUCCESS;
+
+	case SLJIT_ASHR:
+		EMIT_SHIFT(TILEGX_OPC_SHRSI, TILEGX_OPC_SHRS);
+		return SLJIT_SUCCESS;
+	}
+
+	SLJIT_UNREACHABLE();
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags, sljit_s32 dst, sljit_sw dstw, sljit_s32 src1, sljit_sw src1w, sljit_s32 src2, sljit_sw src2w)
+{
+	/* arg1 goes to TMP_REG1 or src reg.
+	   arg2 goes to TMP_REG2, imm or src reg.
+	   TMP_REG3 can be used for caching.
+	   result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */
+	sljit_s32 dst_r = TMP_REG2;
+	sljit_s32 src1_r;
+	sljit_sw src2_r = 0;
+	sljit_s32 sugg_src2_r = TMP_REG2;
+
+	if (!(flags & ALT_KEEP_CACHE)) {
+		compiler->cache_arg = 0;
+		compiler->cache_argw = 0;
+	}
+
+	if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) {
+		if (op >= SLJIT_MOV && op <= SLJIT_MOVU_S32 && !(src2 & SLJIT_MEM))
+			return SLJIT_SUCCESS;
+		if (GET_FLAGS(op))
+			flags |= UNUSED_DEST;
+	} else if (FAST_IS_REG(dst)) {
+		dst_r = dst;
+		flags |= REG_DEST;
+		if (op >= SLJIT_MOV && op <= SLJIT_MOVU_S32)
+			sugg_src2_r = dst_r;
+	} else if ((dst & SLJIT_MEM) && !getput_arg_fast(compiler, flags | ARG_TEST, TMP_REG1_mapped, dst, dstw))
+		flags |= SLOW_DEST;
+
+	if (flags & IMM_OP) {
+		if ((src2 & SLJIT_IMM) && src2w) {
+			if ((!(flags & LOGICAL_OP)
+					&& (src2w <= SIMM_16BIT_MAX && src2w >= SIMM_16BIT_MIN))
+					|| ((flags & LOGICAL_OP) && !(src2w & ~UIMM_16BIT_MAX))) {
+				flags |= SRC2_IMM;
+				src2_r = src2w;
+			}
+		}
+
+		if (!(flags & SRC2_IMM) && (flags & CUMULATIVE_OP) && (src1 & SLJIT_IMM) && src1w) {
+			if ((!(flags & LOGICAL_OP)
+					&& (src1w <= SIMM_16BIT_MAX && src1w >= SIMM_16BIT_MIN))
+					|| ((flags & LOGICAL_OP) && !(src1w & ~UIMM_16BIT_MAX))) {
+				flags |= SRC2_IMM;
+				src2_r = src1w;
+
+				/* And swap arguments. */
+				src1 = src2;
+				src1w = src2w;
+				src2 = SLJIT_IMM;
+				/* src2w = src2_r unneeded. */
+			}
+		}
+	}
+
+	/* Source 1. */
+	if (FAST_IS_REG(src1)) {
+		src1_r = src1;
+		flags |= REG1_SOURCE;
+	} else if (src1 & SLJIT_IMM) {
+		if (src1w) {
+			FAIL_IF(load_immediate(compiler, TMP_REG1_mapped, src1w));
+			src1_r = TMP_REG1;
+		} else
+			src1_r = 0;
+	} else {
+		if (getput_arg_fast(compiler, flags | LOAD_DATA, TMP_REG1_mapped, src1, src1w))
+			FAIL_IF(compiler->error);
+		else
+			flags |= SLOW_SRC1;
+		src1_r = TMP_REG1;
+	}
+
+	/* Source 2. */
+	if (FAST_IS_REG(src2)) {
+		src2_r = src2;
+		flags |= REG2_SOURCE;
+		if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOVU_S32)
+			dst_r = src2_r;
+	} else if (src2 & SLJIT_IMM) {
+		if (!(flags & SRC2_IMM)) {
+			if (src2w) {
+				FAIL_IF(load_immediate(compiler, reg_map[sugg_src2_r], src2w));
+				src2_r = sugg_src2_r;
+			} else {
+				src2_r = 0;
+				if ((op >= SLJIT_MOV && op <= SLJIT_MOVU_S32) && (dst & SLJIT_MEM))
+					dst_r = 0;
+			}
+		}
+	} else {
+		if (getput_arg_fast(compiler, flags | LOAD_DATA, reg_map[sugg_src2_r], src2, src2w))
+			FAIL_IF(compiler->error);
+		else
+			flags |= SLOW_SRC2;
+		src2_r = sugg_src2_r;
+	}
+
+	if ((flags & (SLOW_SRC1 | SLOW_SRC2)) == (SLOW_SRC1 | SLOW_SRC2)) {
+		SLJIT_ASSERT(src2_r == TMP_REG2);
+		if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
+			FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG2_mapped, src2, src2w, src1, src1w));
+			FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1_mapped, src1, src1w, dst, dstw));
+		} else {
+			FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1_mapped, src1, src1w, src2, src2w));
+			FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG2_mapped, src2, src2w, dst, dstw));
+		}
+	} else if (flags & SLOW_SRC1)
+		FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, TMP_REG1_mapped, src1, src1w, dst, dstw));
+	else if (flags & SLOW_SRC2)
+		FAIL_IF(getput_arg(compiler, flags | LOAD_DATA, reg_map[sugg_src2_r], src2, src2w, dst, dstw));
+
+	FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r));
+
+	if (dst & SLJIT_MEM) {
+		if (!(flags & SLOW_DEST)) {
+			getput_arg_fast(compiler, flags, reg_map[dst_r], dst, dstw);
+			return compiler->error;
+		}
+
+		return getput_arg(compiler, flags, reg_map[dst_r], dst, dstw, 0, 0);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst, sljit_sw dstw, sljit_s32 src, sljit_sw srcw, sljit_s32 type)
+{
+	sljit_s32 sugg_dst_ar, dst_ar;
+	sljit_s32 flags = GET_ALL_FLAGS(op);
+	sljit_s32 mem_type = (op & SLJIT_I32_OP) ? (INT_DATA | SIGNED_DATA) : WORD_DATA;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	op = GET_OPCODE(op);
+	if (op == SLJIT_MOV_S32 || op == SLJIT_MOV_U32)
+		mem_type = INT_DATA | SIGNED_DATA;
+	sugg_dst_ar = reg_map[(op < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG2];
+
+	compiler->cache_arg = 0;
+	compiler->cache_argw = 0;
+	if (op >= SLJIT_ADD && (src & SLJIT_MEM)) {
+		ADJUST_LOCAL_OFFSET(src, srcw);
+		FAIL_IF(emit_op_mem2(compiler, mem_type | LOAD_DATA, TMP_REG1_mapped, src, srcw, dst, dstw));
+		src = TMP_REG1;
+		srcw = 0;
+	}
+
+	switch (type & 0xff) {
+	case SLJIT_EQUAL:
+	case SLJIT_NOT_EQUAL:
+		FAIL_IF(CMPLTUI(sugg_dst_ar, EQUAL_FLAG, 1));
+		dst_ar = sugg_dst_ar;
+		break;
+	case SLJIT_LESS:
+	case SLJIT_GREATER_EQUAL:
+		dst_ar = ULESS_FLAG;
+		break;
+	case SLJIT_GREATER:
+	case SLJIT_LESS_EQUAL:
+		dst_ar = UGREATER_FLAG;
+		break;
+	case SLJIT_SIG_LESS:
+	case SLJIT_SIG_GREATER_EQUAL:
+		dst_ar = LESS_FLAG;
+		break;
+	case SLJIT_SIG_GREATER:
+	case SLJIT_SIG_LESS_EQUAL:
+		dst_ar = GREATER_FLAG;
+		break;
+	case SLJIT_OVERFLOW:
+	case SLJIT_NOT_OVERFLOW:
+		dst_ar = OVERFLOW_FLAG;
+		break;
+	case SLJIT_MUL_OVERFLOW:
+	case SLJIT_MUL_NOT_OVERFLOW:
+		FAIL_IF(CMPLTUI(sugg_dst_ar, OVERFLOW_FLAG, 1));
+		dst_ar = sugg_dst_ar;
+		type ^= 0x1; /* Flip type bit for the XORI below. */
+		break;
+
+	default:
+		SLJIT_UNREACHABLE();
+		dst_ar = sugg_dst_ar;
+		break;
+	}
+
+	if (type & 0x1) {
+		FAIL_IF(XORI(sugg_dst_ar, dst_ar, 1));
+		dst_ar = sugg_dst_ar;
+	}
+
+	if (op >= SLJIT_ADD) {
+		if (TMP_REG2_mapped != dst_ar)
+			FAIL_IF(ADD(TMP_REG2_mapped, dst_ar, ZERO));
+		return emit_op(compiler, op | flags, mem_type | CUMULATIVE_OP | LOGICAL_OP | IMM_OP | ALT_KEEP_CACHE, dst, dstw, src, srcw, TMP_REG2, 0);
+	}
+
+	if (dst & SLJIT_MEM)
+		return emit_op_mem(compiler, mem_type, dst_ar, dst, dstw);
+
+	if (sugg_dst_ar != dst_ar)
+		return ADD(sugg_dst_ar, dst_ar, ZERO);
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op) {
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op0(compiler, op));
+
+	op = GET_OPCODE(op);
+	switch (op) {
+	case SLJIT_NOP:
+		return push_0_buffer(compiler, TILEGX_OPC_FNOP, __LINE__);
+
+	case SLJIT_BREAKPOINT:
+		return PI(BPT);
+
+	case SLJIT_LMUL_UW:
+	case SLJIT_LMUL_SW:
+	case SLJIT_DIVMOD_UW:
+	case SLJIT_DIVMOD_SW:
+	case SLJIT_DIV_UW:
+	case SLJIT_DIV_SW:
+		SLJIT_UNREACHABLE();
+	case SLJIT_ENDBR:
+	case SLJIT_SKIP_FRAMES_BEFORE_RETURN:
+		return SLJIT_SUCCESS;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst, sljit_sw dstw, sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_MOV:
+	case SLJIT_MOV_P:
+		return emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_MOV_U32:
+		return emit_op(compiler, SLJIT_MOV_U32, INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_MOV_S32:
+		return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_MOV_U8:
+		return emit_op(compiler, SLJIT_MOV_U8, BYTE_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8) srcw : srcw);
+
+	case SLJIT_MOV_S8:
+		return emit_op(compiler, SLJIT_MOV_S8, BYTE_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8) srcw : srcw);
+
+	case SLJIT_MOV_U16:
+		return emit_op(compiler, SLJIT_MOV_U16, HALF_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16) srcw : srcw);
+
+	case SLJIT_MOV_S16:
+		return emit_op(compiler, SLJIT_MOV_S16, HALF_DATA | SIGNED_DATA, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16) srcw : srcw);
+
+	case SLJIT_MOVU:
+	case SLJIT_MOVU_P:
+		return emit_op(compiler, SLJIT_MOV, WORD_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_MOVU_U32:
+		return emit_op(compiler, SLJIT_MOV_U32, INT_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_MOVU_S32:
+		return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_MOVU_U8:
+		return emit_op(compiler, SLJIT_MOV_U8, BYTE_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8) srcw : srcw);
+
+	case SLJIT_MOVU_S8:
+		return emit_op(compiler, SLJIT_MOV_S8, BYTE_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8) srcw : srcw);
+
+	case SLJIT_MOVU_U16:
+		return emit_op(compiler, SLJIT_MOV_U16, HALF_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16) srcw : srcw);
+
+	case SLJIT_MOVU_S16:
+		return emit_op(compiler, SLJIT_MOV_S16, HALF_DATA | SIGNED_DATA | WRITE_BACK, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16) srcw : srcw);
+
+	case SLJIT_NOT:
+		return emit_op(compiler, op, 0, dst, dstw, TMP_REG1, 0, src, srcw);
+
+	case SLJIT_NEG:
+		return emit_op(compiler, SLJIT_SUB | GET_ALL_FLAGS(op), IMM_OP, dst, dstw, SLJIT_IMM, 0, src, srcw);
+
+	case SLJIT_CLZ:
+		return emit_op(compiler, op, (op & SLJIT_I32_OP) ? INT_DATA : WORD_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst, sljit_sw dstw, sljit_s32 src1, sljit_sw src1w, sljit_s32 src2, sljit_sw src2w)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_ADD:
+	case SLJIT_ADDC:
+		return emit_op(compiler, op, CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_SUB:
+	case SLJIT_SUBC:
+		return emit_op(compiler, op, IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_MUL:
+		return emit_op(compiler, op, CUMULATIVE_OP, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_AND:
+	case SLJIT_OR:
+	case SLJIT_XOR:
+		return emit_op(compiler, op, CUMULATIVE_OP | LOGICAL_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+
+	case SLJIT_SHL:
+	case SLJIT_LSHR:
+	case SLJIT_ASHR:
+		if (src2 & SLJIT_IMM)
+			src2w &= 0x3f;
+		if (op & SLJIT_I32_OP)
+			src2w &= 0x1f;
+
+		return emit_op(compiler, op, IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_src(compiler, op, src, srcw));
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	switch (op) {
+	case SLJIT_FAST_RETURN:
+		if (FAST_IS_REG(src))
+			FAIL_IF(ADD(RA, reg_map[src], ZERO));
+
+		else
+			FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, RA, src, srcw));
+
+		return JR(RA);
+	case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN:
+		return SLJIT_SUCCESS;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_label * sljit_emit_label(struct sljit_compiler *compiler)
+{
+	struct sljit_label *label;
+
+	flush_buffer(compiler);
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_label(compiler));
+
+	if (compiler->last_label && compiler->last_label->size == compiler->size)
+		return compiler->last_label;
+
+	label = (struct sljit_label *)ensure_abuf(compiler, sizeof(struct sljit_label));
+	PTR_FAIL_IF(!label);
+	set_label(label, compiler);
+	return label;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 src_r = TMP_REG2;
+	struct sljit_jump *jump = NULL;
+
+	flush_buffer(compiler);
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	if (FAST_IS_REG(src)) {
+		if (reg_map[src] != 0)
+			src_r = src;
+		else
+			FAIL_IF(ADD_SOLO(TMP_REG2_mapped, reg_map[src], ZERO));
+	}
+
+	if (type >= SLJIT_CALL0) {
+		SLJIT_ASSERT(reg_map[PIC_ADDR_REG] == 16 && PIC_ADDR_REG == TMP_REG2);
+		if (src & (SLJIT_IMM | SLJIT_MEM)) {
+			if (src & SLJIT_IMM)
+				FAIL_IF(emit_const(compiler, reg_map[PIC_ADDR_REG], srcw, 1));
+			else {
+				SLJIT_ASSERT(src_r == TMP_REG2 && (src & SLJIT_MEM));
+				FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, TMP_REG2, 0, TMP_REG1, 0, src, srcw));
+			}
+
+			FAIL_IF(ADD_SOLO(0, reg_map[SLJIT_R0], ZERO));
+
+			FAIL_IF(ADDI_SOLO(54, 54, -16));
+
+			FAIL_IF(JALR_SOLO(reg_map[PIC_ADDR_REG]));
+
+			return ADDI_SOLO(54, 54, 16);
+		}
+
+		/* Register input. */
+		if (type >= SLJIT_CALL1)
+			FAIL_IF(ADD_SOLO(0, reg_map[SLJIT_R0], ZERO));
+
+		FAIL_IF(ADD_SOLO(reg_map[PIC_ADDR_REG], reg_map[src_r], ZERO));
+
+		FAIL_IF(ADDI_SOLO(54, 54, -16));
+
+		FAIL_IF(JALR_SOLO(reg_map[src_r]));
+
+		return ADDI_SOLO(54, 54, 16);
+	}
+
+	if (src & SLJIT_IMM) {
+		jump = (struct sljit_jump *)ensure_abuf(compiler, sizeof(struct sljit_jump));
+		FAIL_IF(!jump);
+		set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_JAL : 0));
+		jump->u.target = srcw;
+		FAIL_IF(emit_const(compiler, TMP_REG2_mapped, 0, 1));
+
+		if (type >= SLJIT_FAST_CALL) {
+			FAIL_IF(ADD_SOLO(ZERO, ZERO, ZERO));
+			jump->addr = compiler->size;
+			FAIL_IF(JR_SOLO(reg_map[src_r]));
+		} else {
+			jump->addr = compiler->size;
+			FAIL_IF(JR_SOLO(reg_map[src_r]));
+		}
+
+		return SLJIT_SUCCESS;
+
+	} else if (src & SLJIT_MEM) {
+		FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, TMP_REG2, 0, TMP_REG1, 0, src, srcw));
+		flush_buffer(compiler);
+	}
+
+	FAIL_IF(JR_SOLO(reg_map[src_r]));
+
+	if (jump)
+		jump->addr = compiler->size;
+
+	return SLJIT_SUCCESS;
+}
+
+#define BR_Z(src) \
+	inst = BEQZ_X1 | SRCA_X1(src); \
+	flags = IS_COND;
+
+#define BR_NZ(src) \
+	inst = BNEZ_X1 | SRCA_X1(src); \
+	flags = IS_COND;
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump * sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
+{
+	struct sljit_jump *jump;
+	sljit_ins inst;
+	sljit_s32 flags = 0;
+
+	flush_buffer(compiler);
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_jump(compiler, type));
+
+	jump = (struct sljit_jump *)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	PTR_FAIL_IF(!jump);
+	set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
+	type &= 0xff;
+
+	switch (type) {
+	case SLJIT_EQUAL:
+		BR_NZ(EQUAL_FLAG);
+		break;
+	case SLJIT_NOT_EQUAL:
+		BR_Z(EQUAL_FLAG);
+		break;
+	case SLJIT_LESS:
+		BR_Z(ULESS_FLAG);
+		break;
+	case SLJIT_GREATER_EQUAL:
+		BR_NZ(ULESS_FLAG);
+		break;
+	case SLJIT_GREATER:
+		BR_Z(UGREATER_FLAG);
+		break;
+	case SLJIT_LESS_EQUAL:
+		BR_NZ(UGREATER_FLAG);
+		break;
+	case SLJIT_SIG_LESS:
+		BR_Z(LESS_FLAG);
+		break;
+	case SLJIT_SIG_GREATER_EQUAL:
+		BR_NZ(LESS_FLAG);
+		break;
+	case SLJIT_SIG_GREATER:
+		BR_Z(GREATER_FLAG);
+		break;
+	case SLJIT_SIG_LESS_EQUAL:
+		BR_NZ(GREATER_FLAG);
+		break;
+	case SLJIT_OVERFLOW:
+	case SLJIT_MUL_OVERFLOW:
+		BR_Z(OVERFLOW_FLAG);
+		break;
+	case SLJIT_NOT_OVERFLOW:
+	case SLJIT_MUL_NOT_OVERFLOW:
+		BR_NZ(OVERFLOW_FLAG);
+		break;
+	default:
+		/* Not conditional branch. */
+		inst = 0;
+		break;
+	}
+
+	jump->flags |= flags;
+
+	if (inst) {
+		inst = inst | ((type <= SLJIT_JUMP) ? BOFF_X1(5) : BOFF_X1(6));
+		PTR_FAIL_IF(PI(inst));
+	}
+
+	PTR_FAIL_IF(emit_const(compiler, TMP_REG2_mapped, 0, 1));
+	if (type <= SLJIT_JUMP) {
+		jump->addr = compiler->size;
+		PTR_FAIL_IF(JR_SOLO(TMP_REG2_mapped));
+	} else {
+		SLJIT_ASSERT(reg_map[PIC_ADDR_REG] == 16 && PIC_ADDR_REG == TMP_REG2);
+		/* Cannot be optimized out if type is >= CALL0. */
+		jump->flags |= IS_JAL | (type >= SLJIT_CALL0 ? SLJIT_REWRITABLE_JUMP : 0);
+		PTR_FAIL_IF(ADD_SOLO(0, reg_map[SLJIT_R0], ZERO));
+		jump->addr = compiler->size;
+		PTR_FAIL_IF(JALR_SOLO(TMP_REG2_mapped));
+	}
+
+	return jump;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst, sljit_sw dstw, sljit_s32 src, sljit_sw srcw)
+{
+	SLJIT_UNREACHABLE();
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst, sljit_sw dstw, sljit_s32 src1, sljit_sw src1w, sljit_s32 src2, sljit_sw src2w)
+{
+	SLJIT_UNREACHABLE();
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const * sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
+{
+	struct sljit_const *const_;
+	sljit_s32 reg;
+
+	flush_buffer(compiler);
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	const_ = (struct sljit_const *)ensure_abuf(compiler, sizeof(struct sljit_const));
+	PTR_FAIL_IF(!const_);
+	set_const(const_, compiler);
+
+	reg = FAST_IS_REG(dst) ? dst : TMP_REG2;
+
+	PTR_FAIL_IF(emit_const_64(compiler, reg, init_value, 1));
+
+	if (dst & SLJIT_MEM)
+		PTR_FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0));
+	return const_;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target)
+{
+	sljit_ins *inst = (sljit_ins *)addr;
+
+	inst[0] = (inst[0] & ~(0xFFFFL << 43)) | (((new_target >> 32) & 0xffff) << 43);
+	inst[1] = (inst[1] & ~(0xFFFFL << 43)) | (((new_target >> 16) & 0xffff) << 43);
+	inst[2] = (inst[2] & ~(0xFFFFL << 43)) | ((new_target & 0xffff) << 43);
+	SLJIT_CACHE_FLUSH(inst, inst + 3);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
+{
+	sljit_ins *inst = (sljit_ins *)addr;
+
+	inst[0] = (inst[0] & ~(0xFFFFL << 43)) | (((new_constant >> 48) & 0xFFFFL) << 43);
+	inst[1] = (inst[1] & ~(0xFFFFL << 43)) | (((new_constant >> 32) & 0xFFFFL) << 43);
+	inst[2] = (inst[2] & ~(0xFFFFL << 43)) | (((new_constant >> 16) & 0xFFFFL) << 43);
+	inst[3] = (inst[3] & ~(0xFFFFL << 43)) | ((new_constant & 0xFFFFL) << 43);
+	SLJIT_CACHE_FLUSH(inst, inst + 4);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+{
+	CHECK_REG_INDEX(check_sljit_get_register_index(reg));
+	return reg_map[reg];
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+	void *instruction, sljit_s32 size)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
diff --git a/src/c/pcre2/src/sljit/sljitNativeX86_32.c b/src/c/pcre2/src/sljit/sljitNativeX86_32.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitNativeX86_32.c
@@ -0,0 +1,928 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* x86 32-bit arch dependent functions. */
+
+static sljit_s32 emit_do_imm(struct sljit_compiler *compiler, sljit_u8 opcode, sljit_sw imm)
+{
+	sljit_u8 *inst;
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + sizeof(sljit_sw));
+	FAIL_IF(!inst);
+	INC_SIZE(1 + sizeof(sljit_sw));
+	*inst++ = opcode;
+	sljit_unaligned_store_sw(inst, imm);
+	return SLJIT_SUCCESS;
+}
+
+static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_sw executable_offset)
+{
+	sljit_s32 type = jump->flags >> TYPE_SHIFT;
+
+	if (type == SLJIT_JUMP) {
+		*code_ptr++ = JMP_i32;
+		jump->addr++;
+	}
+	else if (type >= SLJIT_FAST_CALL) {
+		*code_ptr++ = CALL_i32;
+		jump->addr++;
+	}
+	else {
+		*code_ptr++ = GROUP_0F;
+		*code_ptr++ = get_jump_code(type);
+		jump->addr += 2;
+	}
+
+	if (jump->flags & JUMP_LABEL)
+		jump->flags |= PATCH_MW;
+	else
+		sljit_unaligned_store_sw(code_ptr, jump->u.target - (jump->addr + 4) - (sljit_uw)executable_offset);
+	code_ptr += 4;
+
+	return code_ptr;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	sljit_s32 args, size;
+	sljit_u8 *inst;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+	/* Emit ENDBR32 at function entry if needed.  */
+	FAIL_IF(emit_endbranch(compiler));
+
+	args = get_arg_count(arg_types);
+	compiler->args = args;
+
+	/* [esp+0] for saving temporaries and function calls. */
+	compiler->stack_tmp_size = 2 * sizeof(sljit_sw);
+
+#if !(defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
+	if (scratches > 3)
+		compiler->stack_tmp_size = 3 * sizeof(sljit_sw);
+#endif
+
+	compiler->saveds_offset = compiler->stack_tmp_size;
+	if (scratches > 3)
+		compiler->saveds_offset += ((scratches > (3 + 6)) ? 6 : (scratches - 3)) * sizeof(sljit_sw);
+
+	compiler->locals_offset = compiler->saveds_offset;
+
+	if (saveds > 3)
+		compiler->locals_offset += (saveds - 3) * sizeof(sljit_sw);
+
+	if (options & SLJIT_F64_ALIGNMENT)
+		compiler->locals_offset = (compiler->locals_offset + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1);
+
+	size = 1 + (scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3);
+#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
+	size += (args > 0 ? (args * 2) : 0) + (args > 2 ? 2 : 0);
+#else
+	size += (args > 0 ? (2 + args * 3) : 0);
+#endif
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
+	FAIL_IF(!inst);
+
+	INC_SIZE(size);
+	PUSH_REG(reg_map[TMP_REG1]);
+#if !(defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
+	if (args > 0) {
+		*inst++ = MOV_r_rm;
+		*inst++ = MOD_REG | (reg_map[TMP_REG1] << 3) | 0x4 /* esp */;
+	}
+#endif
+	if (saveds > 2 || scratches > 9)
+		PUSH_REG(reg_map[SLJIT_S2]);
+	if (saveds > 1 || scratches > 10)
+		PUSH_REG(reg_map[SLJIT_S1]);
+	if (saveds > 0 || scratches > 11)
+		PUSH_REG(reg_map[SLJIT_S0]);
+
+#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
+	if (args > 0) {
+		inst[0] = MOV_r_rm;
+		inst[1] = MOD_REG | (reg_map[SLJIT_S0] << 3) | reg_map[SLJIT_R2];
+		inst += 2;
+	}
+	if (args > 1) {
+		inst[0] = MOV_r_rm;
+		inst[1] = MOD_REG | (reg_map[SLJIT_S1] << 3) | reg_map[SLJIT_R1];
+		inst += 2;
+	}
+	if (args > 2) {
+		inst[0] = MOV_r_rm;
+		inst[1] = MOD_DISP8 | (reg_map[SLJIT_S2] << 3) | 0x4 /* esp */;
+		inst[2] = 0x24;
+		inst[3] = sizeof(sljit_sw) * (3 + 2); /* saveds >= 3 as well. */
+	}
+#else
+	if (args > 0) {
+		inst[0] = MOV_r_rm;
+		inst[1] = MOD_DISP8 | (reg_map[SLJIT_S0] << 3) | reg_map[TMP_REG1];
+		inst[2] = sizeof(sljit_sw) * 2;
+		inst += 3;
+	}
+	if (args > 1) {
+		inst[0] = MOV_r_rm;
+		inst[1] = MOD_DISP8 | (reg_map[SLJIT_S1] << 3) | reg_map[TMP_REG1];
+		inst[2] = sizeof(sljit_sw) * 3;
+		inst += 3;
+	}
+	if (args > 2) {
+		inst[0] = MOV_r_rm;
+		inst[1] = MOD_DISP8 | (reg_map[SLJIT_S2] << 3) | reg_map[TMP_REG1];
+		inst[2] = sizeof(sljit_sw) * 4;
+	}
+#endif
+
+	SLJIT_ASSERT(SLJIT_LOCALS_OFFSET > 0);
+
+#if defined(__APPLE__)
+	/* Ignore pushed registers and SLJIT_LOCALS_OFFSET when computing the aligned local size. */
+	saveds = (2 + (scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3)) * sizeof(sljit_uw);
+	local_size = ((SLJIT_LOCALS_OFFSET + saveds + local_size + 15) & ~15) - saveds;
+#else
+	if (options & SLJIT_F64_ALIGNMENT)
+		local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1));
+	else
+		local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_sw) - 1) & ~(sizeof(sljit_sw) - 1));
+#endif
+
+	compiler->local_size = local_size;
+
+#ifdef _WIN32
+	if (local_size > 0) {
+		if (local_size <= 4 * 4096) {
+			if (local_size > 4096)
+				EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -4096);
+			if (local_size > 2 * 4096)
+				EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -4096 * 2);
+			if (local_size > 3 * 4096)
+				EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -4096 * 3);
+		}
+		else {
+			EMIT_MOV(compiler, SLJIT_R0, 0, SLJIT_SP, 0);
+			EMIT_MOV(compiler, SLJIT_R1, 0, SLJIT_IMM, (local_size - 1) >> 12);
+
+			SLJIT_ASSERT (reg_map[SLJIT_R0] == 0);
+
+			EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_R0), -4096);
+			FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
+				SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_IMM, 4096));
+			FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
+				SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1));
+
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+			FAIL_IF(!inst);
+
+			INC_SIZE(2);
+			inst[0] = JNE_i8;
+			inst[1] = (sljit_s8) -16;
+		}
+
+		EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -local_size);
+	}
+#endif
+
+	SLJIT_ASSERT(local_size > 0);
+
+#if !defined(__APPLE__)
+	if (options & SLJIT_F64_ALIGNMENT) {
+		EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_SP, 0);
+
+		/* Some space might allocated during sljit_grow_stack() above on WIN32. */
+		FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
+			SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size + sizeof(sljit_sw)));
+
+#if defined _WIN32 && !(defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
+		if (compiler->local_size > 1024)
+			FAIL_IF(emit_cum_binary(compiler, BINARY_OPCODE(ADD),
+				TMP_REG1, 0, TMP_REG1, 0, SLJIT_IMM, sizeof(sljit_sw)));
+#endif
+
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 6);
+		FAIL_IF(!inst);
+
+		INC_SIZE(6);
+		inst[0] = GROUP_BINARY_81;
+		inst[1] = MOD_REG | AND | reg_map[SLJIT_SP];
+		sljit_unaligned_store_sw(inst + 2, ~(sizeof(sljit_f64) - 1));
+
+		/* The real local size must be used. */
+		return emit_mov(compiler, SLJIT_MEM1(SLJIT_SP), compiler->local_size, TMP_REG1, 0);
+	}
+#endif
+	return emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
+		SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+	compiler->args = get_arg_count(arg_types);
+
+	/* [esp+0] for saving temporaries and function calls. */
+	compiler->stack_tmp_size = 2 * sizeof(sljit_sw);
+
+#if !(defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
+	if (scratches > 3)
+		compiler->stack_tmp_size = 3 * sizeof(sljit_sw);
+#endif
+
+	compiler->saveds_offset = compiler->stack_tmp_size;
+	if (scratches > 3)
+		compiler->saveds_offset += ((scratches > (3 + 6)) ? 6 : (scratches - 3)) * sizeof(sljit_sw);
+
+	compiler->locals_offset = compiler->saveds_offset;
+
+	if (saveds > 3)
+		compiler->locals_offset += (saveds - 3) * sizeof(sljit_sw);
+
+	if (options & SLJIT_F64_ALIGNMENT)
+		compiler->locals_offset = (compiler->locals_offset + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1);
+
+#if defined(__APPLE__)
+	saveds = (2 + (scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3)) * sizeof(sljit_uw);
+	compiler->local_size = ((SLJIT_LOCALS_OFFSET + saveds + local_size + 15) & ~15) - saveds;
+#else
+	if (options & SLJIT_F64_ALIGNMENT)
+		compiler->local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_f64) - 1) & ~(sizeof(sljit_f64) - 1));
+	else
+		compiler->local_size = SLJIT_LOCALS_OFFSET + ((local_size + sizeof(sljit_sw) - 1) & ~(sizeof(sljit_sw) - 1));
+#endif
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 size;
+	sljit_u8 *inst;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_return(compiler, op, src, srcw));
+	SLJIT_ASSERT(compiler->args >= 0);
+
+	FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
+
+	SLJIT_ASSERT(compiler->local_size > 0);
+
+#if !defined(__APPLE__)
+	if (compiler->options & SLJIT_F64_ALIGNMENT)
+		EMIT_MOV(compiler, SLJIT_SP, 0, SLJIT_MEM1(SLJIT_SP), compiler->local_size)
+	else
+		FAIL_IF(emit_cum_binary(compiler, BINARY_OPCODE(ADD),
+			SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, compiler->local_size));
+#else
+	FAIL_IF(emit_cum_binary(compiler, BINARY_OPCODE(ADD),
+		SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, compiler->local_size));
+#endif
+
+	size = 2 + (compiler->scratches > 9 ? (compiler->scratches - 9) : 0) +
+		(compiler->saveds <= 3 ? compiler->saveds : 3);
+#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
+	if (compiler->args > 2)
+		size += 2;
+#endif
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
+	FAIL_IF(!inst);
+
+	INC_SIZE(size);
+
+	if (compiler->saveds > 0 || compiler->scratches > 11)
+		POP_REG(reg_map[SLJIT_S0]);
+	if (compiler->saveds > 1 || compiler->scratches > 10)
+		POP_REG(reg_map[SLJIT_S1]);
+	if (compiler->saveds > 2 || compiler->scratches > 9)
+		POP_REG(reg_map[SLJIT_S2]);
+	POP_REG(reg_map[TMP_REG1]);
+#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
+	if (compiler->args > 2)
+		RET_I16(sizeof(sljit_sw));
+	else
+		RET();
+#else
+	RET();
+#endif
+
+	return SLJIT_SUCCESS;
+}
+
+/* --------------------------------------------------------------------- */
+/*  Operators                                                            */
+/* --------------------------------------------------------------------- */
+
+/* Size contains the flags as well. */
+static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32 size,
+	/* The register or immediate operand. */
+	sljit_s32 a, sljit_sw imma,
+	/* The general operand (not immediate). */
+	sljit_s32 b, sljit_sw immb)
+{
+	sljit_u8 *inst;
+	sljit_u8 *buf_ptr;
+	sljit_s32 flags = size & ~0xf;
+	sljit_s32 inst_size;
+
+	/* Both cannot be switched on. */
+	SLJIT_ASSERT((flags & (EX86_BIN_INS | EX86_SHIFT_INS)) != (EX86_BIN_INS | EX86_SHIFT_INS));
+	/* Size flags not allowed for typed instructions. */
+	SLJIT_ASSERT(!(flags & (EX86_BIN_INS | EX86_SHIFT_INS)) || (flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) == 0);
+	/* Both size flags cannot be switched on. */
+	SLJIT_ASSERT((flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) != (EX86_BYTE_ARG | EX86_HALF_ARG));
+	/* SSE2 and immediate is not possible. */
+	SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2));
+	SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3)
+		&& (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66)
+		&& (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66));
+	/* We don't support (%ebp). */
+	SLJIT_ASSERT(!(b & SLJIT_MEM) || immb || reg_map[b & REG_MASK] != 5);
+
+	size &= 0xf;
+	inst_size = size;
+
+	if (flags & (EX86_PREF_F2 | EX86_PREF_F3))
+		inst_size++;
+	if (flags & EX86_PREF_66)
+		inst_size++;
+
+	/* Calculate size of b. */
+	inst_size += 1; /* mod r/m byte. */
+	if (b & SLJIT_MEM) {
+		if ((b & REG_MASK) == SLJIT_UNUSED)
+			inst_size += sizeof(sljit_sw);
+		else if (immb != 0 && !(b & OFFS_REG_MASK)) {
+			/* Immediate operand. */
+			if (immb <= 127 && immb >= -128)
+				inst_size += sizeof(sljit_s8);
+			else
+				inst_size += sizeof(sljit_sw);
+		}
+
+		if ((b & REG_MASK) == SLJIT_SP && !(b & OFFS_REG_MASK))
+			b |= TO_OFFS_REG(SLJIT_SP);
+
+		if ((b & OFFS_REG_MASK) != SLJIT_UNUSED)
+			inst_size += 1; /* SIB byte. */
+	}
+
+	/* Calculate size of a. */
+	if (a & SLJIT_IMM) {
+		if (flags & EX86_BIN_INS) {
+			if (imma <= 127 && imma >= -128) {
+				inst_size += 1;
+				flags |= EX86_BYTE_ARG;
+			} else
+				inst_size += 4;
+		}
+		else if (flags & EX86_SHIFT_INS) {
+			imma &= 0x1f;
+			if (imma != 1) {
+				inst_size ++;
+				flags |= EX86_BYTE_ARG;
+			}
+		} else if (flags & EX86_BYTE_ARG)
+			inst_size++;
+		else if (flags & EX86_HALF_ARG)
+			inst_size += sizeof(short);
+		else
+			inst_size += sizeof(sljit_sw);
+	}
+	else
+		SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG);
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + inst_size);
+	PTR_FAIL_IF(!inst);
+
+	/* Encoding the byte. */
+	INC_SIZE(inst_size);
+	if (flags & EX86_PREF_F2)
+		*inst++ = 0xf2;
+	if (flags & EX86_PREF_F3)
+		*inst++ = 0xf3;
+	if (flags & EX86_PREF_66)
+		*inst++ = 0x66;
+
+	buf_ptr = inst + size;
+
+	/* Encode mod/rm byte. */
+	if (!(flags & EX86_SHIFT_INS)) {
+		if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM))
+			*inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81;
+
+		if (a & SLJIT_IMM)
+			*buf_ptr = 0;
+		else if (!(flags & EX86_SSE2_OP1))
+			*buf_ptr = reg_map[a] << 3;
+		else
+			*buf_ptr = a << 3;
+	}
+	else {
+		if (a & SLJIT_IMM) {
+			if (imma == 1)
+				*inst = GROUP_SHIFT_1;
+			else
+				*inst = GROUP_SHIFT_N;
+		} else
+			*inst = GROUP_SHIFT_CL;
+		*buf_ptr = 0;
+	}
+
+	if (!(b & SLJIT_MEM))
+		*buf_ptr++ |= MOD_REG + ((!(flags & EX86_SSE2_OP2)) ? reg_map[b] : b);
+	else if ((b & REG_MASK) != SLJIT_UNUSED) {
+		if ((b & OFFS_REG_MASK) == SLJIT_UNUSED || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP)) {
+			if (immb != 0) {
+				if (immb <= 127 && immb >= -128)
+					*buf_ptr |= 0x40;
+				else
+					*buf_ptr |= 0x80;
+			}
+
+			if ((b & OFFS_REG_MASK) == SLJIT_UNUSED)
+				*buf_ptr++ |= reg_map[b & REG_MASK];
+			else {
+				*buf_ptr++ |= 0x04;
+				*buf_ptr++ = reg_map[b & REG_MASK] | (reg_map[OFFS_REG(b)] << 3);
+			}
+
+			if (immb != 0) {
+				if (immb <= 127 && immb >= -128)
+					*buf_ptr++ = immb; /* 8 bit displacement. */
+				else {
+					sljit_unaligned_store_sw(buf_ptr, immb); /* 32 bit displacement. */
+					buf_ptr += sizeof(sljit_sw);
+				}
+			}
+		}
+		else {
+			*buf_ptr++ |= 0x04;
+			*buf_ptr++ = reg_map[b & REG_MASK] | (reg_map[OFFS_REG(b)] << 3) | (immb << 6);
+		}
+	}
+	else {
+		*buf_ptr++ |= 0x05;
+		sljit_unaligned_store_sw(buf_ptr, immb); /* 32 bit displacement. */
+		buf_ptr += sizeof(sljit_sw);
+	}
+
+	if (a & SLJIT_IMM) {
+		if (flags & EX86_BYTE_ARG)
+			*buf_ptr = imma;
+		else if (flags & EX86_HALF_ARG)
+			sljit_unaligned_store_s16(buf_ptr, imma);
+		else if (!(flags & EX86_SHIFT_INS))
+			sljit_unaligned_store_sw(buf_ptr, imma);
+	}
+
+	return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Call / return instructions                                           */
+/* --------------------------------------------------------------------- */
+
+#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
+
+static sljit_s32 c_fast_call_get_stack_size(sljit_s32 arg_types, sljit_s32 *word_arg_count_ptr)
+{
+	sljit_s32 stack_size = 0;
+	sljit_s32 word_arg_count = 0;
+
+	arg_types >>= SLJIT_DEF_SHIFT;
+
+	while (arg_types) {
+		switch (arg_types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			stack_size += sizeof(sljit_f32);
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			stack_size += sizeof(sljit_f64);
+			break;
+		default:
+			word_arg_count++;
+			if (word_arg_count > 2)
+				stack_size += sizeof(sljit_sw);
+			break;
+		}
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	if (word_arg_count_ptr)
+		*word_arg_count_ptr = word_arg_count;
+
+	return stack_size;
+}
+
+static sljit_s32 c_fast_call_with_args(struct sljit_compiler *compiler,
+	sljit_s32 arg_types, sljit_s32 stack_size, sljit_s32 word_arg_count, sljit_s32 swap_args)
+{
+	sljit_u8 *inst;
+	sljit_s32 float_arg_count;
+
+	if (stack_size == sizeof(sljit_sw) && word_arg_count == 3) {
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
+		FAIL_IF(!inst);
+		INC_SIZE(1);
+		PUSH_REG(reg_map[SLJIT_R2]);
+	}
+	else if (stack_size > 0) {
+		if (word_arg_count >= 4)
+			EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), compiler->saveds_offset - sizeof(sljit_sw));
+
+		FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
+			SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, stack_size));
+
+		stack_size = 0;
+		arg_types >>= SLJIT_DEF_SHIFT;
+		word_arg_count = 0;
+		float_arg_count = 0;
+		while (arg_types) {
+			switch (arg_types & SLJIT_DEF_MASK) {
+			case SLJIT_ARG_TYPE_F32:
+				float_arg_count++;
+				FAIL_IF(emit_sse2_store(compiler, 1, SLJIT_MEM1(SLJIT_SP), stack_size, float_arg_count));
+				stack_size += sizeof(sljit_f32);
+				break;
+			case SLJIT_ARG_TYPE_F64:
+				float_arg_count++;
+				FAIL_IF(emit_sse2_store(compiler, 0, SLJIT_MEM1(SLJIT_SP), stack_size, float_arg_count));
+				stack_size += sizeof(sljit_f64);
+				break;
+			default:
+				word_arg_count++;
+				if (word_arg_count == 3) {
+					EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), stack_size, SLJIT_R2, 0);
+					stack_size += sizeof(sljit_sw);
+				}
+				else if (word_arg_count == 4) {
+					EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), stack_size, TMP_REG1, 0);
+					stack_size += sizeof(sljit_sw);
+				}
+				break;
+			}
+
+			arg_types >>= SLJIT_DEF_SHIFT;
+		}
+	}
+
+	if (word_arg_count > 0) {
+		if (swap_args) {
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
+			FAIL_IF(!inst);
+			INC_SIZE(1);
+
+			*inst++ = XCHG_EAX_r | reg_map[SLJIT_R2];
+		}
+		else {
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+			FAIL_IF(!inst);
+			INC_SIZE(2);
+
+			*inst++ = MOV_r_rm;
+			*inst++ = MOD_REG | (reg_map[SLJIT_R2] << 3) | reg_map[SLJIT_R0];
+		}
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+#endif
+
+static sljit_s32 cdecl_call_get_stack_size(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *word_arg_count_ptr)
+{
+	sljit_s32 stack_size = 0;
+	sljit_s32 word_arg_count = 0;
+
+	arg_types >>= SLJIT_DEF_SHIFT;
+
+	while (arg_types) {
+		switch (arg_types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			stack_size += sizeof(sljit_f32);
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			stack_size += sizeof(sljit_f64);
+			break;
+		default:
+			word_arg_count++;
+			stack_size += sizeof(sljit_sw);
+			break;
+		}
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	if (word_arg_count_ptr)
+		*word_arg_count_ptr = word_arg_count;
+
+	if (stack_size <= compiler->stack_tmp_size)
+		return 0;
+
+#if defined(__APPLE__)
+	return ((stack_size - compiler->stack_tmp_size + 15) & ~15);
+#else
+	return stack_size - compiler->stack_tmp_size;
+#endif
+}
+
+static sljit_s32 cdecl_call_with_args(struct sljit_compiler *compiler,
+	sljit_s32 arg_types, sljit_s32 stack_size, sljit_s32 word_arg_count)
+{
+	sljit_s32 float_arg_count = 0;
+
+	if (word_arg_count >= 4)
+		EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), compiler->saveds_offset - sizeof(sljit_sw));
+
+	if (stack_size > 0)
+		FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
+			SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, stack_size));
+
+	stack_size = 0;
+	word_arg_count = 0;
+	arg_types >>= SLJIT_DEF_SHIFT;
+
+	while (arg_types) {
+		switch (arg_types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			float_arg_count++;
+			FAIL_IF(emit_sse2_store(compiler, 1, SLJIT_MEM1(SLJIT_SP), stack_size, float_arg_count));
+			stack_size += sizeof(sljit_f32);
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			float_arg_count++;
+			FAIL_IF(emit_sse2_store(compiler, 0, SLJIT_MEM1(SLJIT_SP), stack_size, float_arg_count));
+			stack_size += sizeof(sljit_f64);
+			break;
+		default:
+			word_arg_count++;
+			EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), stack_size, (word_arg_count >= 4) ? TMP_REG1 : word_arg_count, 0);
+			stack_size += sizeof(sljit_sw);
+			break;
+		}
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 post_call_with_args(struct sljit_compiler *compiler,
+	sljit_s32 arg_types, sljit_s32 stack_size)
+{
+	sljit_u8 *inst;
+	sljit_s32 single;
+
+	if (stack_size > 0)
+		FAIL_IF(emit_cum_binary(compiler, BINARY_OPCODE(ADD),
+			SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, stack_size));
+
+	if ((arg_types & SLJIT_DEF_MASK) < SLJIT_ARG_TYPE_F32)
+		return SLJIT_SUCCESS;
+
+	single = ((arg_types & SLJIT_DEF_MASK) == SLJIT_ARG_TYPE_F32);
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + 3);
+	FAIL_IF(!inst);
+	INC_SIZE(3);
+	inst[0] = single ? FSTPS : FSTPD;
+	inst[1] = (0x03 << 3) | 0x04;
+	inst[2] = (0x04 << 3) | reg_map[SLJIT_SP];
+
+	return emit_sse2_load(compiler, single, SLJIT_FR0, SLJIT_MEM1(SLJIT_SP), 0);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types)
+{
+	struct sljit_jump *jump;
+	sljit_s32 stack_size = 0;
+	sljit_s32 word_arg_count;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
+
+#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
+	if ((type & 0xff) == SLJIT_CALL) {
+		stack_size = c_fast_call_get_stack_size(arg_types, &word_arg_count);
+		PTR_FAIL_IF(c_fast_call_with_args(compiler, arg_types, stack_size, word_arg_count, 0));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+		compiler->skip_checks = 1;
+#endif
+
+		jump = sljit_emit_jump(compiler, type);
+		PTR_FAIL_IF(jump == NULL);
+
+		PTR_FAIL_IF(post_call_with_args(compiler, arg_types, 0));
+		return jump;
+	}
+#endif
+
+	stack_size = cdecl_call_get_stack_size(compiler, arg_types, &word_arg_count);
+	PTR_FAIL_IF(cdecl_call_with_args(compiler, arg_types, stack_size, word_arg_count));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+
+	jump = sljit_emit_jump(compiler, type);
+	PTR_FAIL_IF(jump == NULL);
+
+	PTR_FAIL_IF(post_call_with_args(compiler, arg_types, stack_size));
+	return jump;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 stack_size = 0;
+	sljit_s32 word_arg_count;
+#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
+	sljit_s32 swap_args;
+#endif
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
+
+#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
+	SLJIT_ASSERT(reg_map[SLJIT_R0] == 0 && reg_map[SLJIT_R2] == 1 && SLJIT_R0 == 1 && SLJIT_R2 == 3);
+
+	if ((type & 0xff) == SLJIT_CALL) {
+		stack_size = c_fast_call_get_stack_size(arg_types, &word_arg_count);
+		swap_args = 0;
+
+		if (word_arg_count > 0) {
+			if ((src & REG_MASK) == SLJIT_R2 || OFFS_REG(src) == SLJIT_R2) {
+				swap_args = 1;
+				if (((src & REG_MASK) | 0x2) == SLJIT_R2)
+					src ^= 0x2;
+				if ((OFFS_REG(src) | 0x2) == SLJIT_R2)
+					src ^= TO_OFFS_REG(0x2);
+			}
+		}
+
+		FAIL_IF(c_fast_call_with_args(compiler, arg_types, stack_size, word_arg_count, swap_args));
+
+		compiler->saveds_offset += stack_size;
+		compiler->locals_offset += stack_size;
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+		compiler->skip_checks = 1;
+#endif
+		FAIL_IF(sljit_emit_ijump(compiler, type, src, srcw));
+
+		compiler->saveds_offset -= stack_size;
+		compiler->locals_offset -= stack_size;
+
+		return post_call_with_args(compiler, arg_types, 0);
+	}
+#endif
+
+	stack_size = cdecl_call_get_stack_size(compiler, arg_types, &word_arg_count);
+	FAIL_IF(cdecl_call_with_args(compiler, arg_types, stack_size, word_arg_count));
+
+	compiler->saveds_offset += stack_size;
+	compiler->locals_offset += stack_size;
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+	FAIL_IF(sljit_emit_ijump(compiler, type, src, srcw));
+
+	compiler->saveds_offset -= stack_size;
+	compiler->locals_offset -= stack_size;
+
+	return post_call_with_args(compiler, arg_types, stack_size);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	sljit_u8 *inst;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	CHECK_EXTRA_REGS(dst, dstw, (void)0);
+
+	/* For UNUSED dst. Uncommon, but possible. */
+	if (dst == SLJIT_UNUSED)
+		dst = TMP_REG1;
+
+	if (FAST_IS_REG(dst)) {
+		/* Unused dest is possible here. */
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
+		FAIL_IF(!inst);
+
+		INC_SIZE(1);
+		POP_REG(reg_map[dst]);
+		return SLJIT_SUCCESS;
+	}
+
+	/* Memory. */
+	inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
+	FAIL_IF(!inst);
+	*inst++ = POP_rm;
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
+{
+	sljit_u8 *inst;
+
+	CHECK_EXTRA_REGS(src, srcw, (void)0);
+
+	if (FAST_IS_REG(src)) {
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 1);
+		FAIL_IF(!inst);
+
+		INC_SIZE(1 + 1);
+		PUSH_REG(reg_map[src]);
+	}
+	else {
+		inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
+		FAIL_IF(!inst);
+		*inst++ = GROUP_FF;
+		*inst |= PUSH_rm;
+
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
+		FAIL_IF(!inst);
+		INC_SIZE(1);
+	}
+
+	RET();
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 skip_frames_before_return(struct sljit_compiler *compiler)
+{
+	sljit_s32 size, saved_size;
+	sljit_s32 has_f64_aligment;
+
+	/* Don't adjust shadow stack if it isn't enabled.  */
+	if (!cpu_has_shadow_stack ())
+		return SLJIT_SUCCESS;
+
+	SLJIT_ASSERT(compiler->args >= 0);
+	SLJIT_ASSERT(compiler->local_size > 0);
+
+#if !defined(__APPLE__)
+	has_f64_aligment = compiler->options & SLJIT_F64_ALIGNMENT;
+#else
+	has_f64_aligment = 0;
+#endif
+
+	size = compiler->local_size;
+	saved_size = (1 + (compiler->scratches > 9 ? (compiler->scratches - 9) : 0) + (compiler->saveds <= 3 ? compiler->saveds : 3)) * sizeof(sljit_uw);
+	if (has_f64_aligment) {
+		/* mov TMP_REG1, [esp + local_size].  */
+		EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), size);
+		/* mov TMP_REG1, [TMP_REG1+ saved_size].  */
+		EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(TMP_REG1), saved_size);
+		/* Move return address to [esp]. */
+		EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), 0, TMP_REG1, 0);
+		size = 0;
+	} else
+		size += saved_size;
+
+	return adjust_shadow_stack(compiler, SLJIT_UNUSED, 0, SLJIT_SP, size);
+}
diff --git a/src/c/pcre2/src/sljit/sljitNativeX86_64.c b/src/c/pcre2/src/sljit/sljitNativeX86_64.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitNativeX86_64.c
@@ -0,0 +1,918 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* x86 64-bit arch dependent functions. */
+
+static sljit_s32 emit_load_imm64(struct sljit_compiler *compiler, sljit_s32 reg, sljit_sw imm)
+{
+	sljit_u8 *inst;
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + sizeof(sljit_sw));
+	FAIL_IF(!inst);
+	INC_SIZE(2 + sizeof(sljit_sw));
+	*inst++ = REX_W | ((reg_map[reg] <= 7) ? 0 : REX_B);
+	*inst++ = MOV_r_i32 + (reg_map[reg] & 0x7);
+	sljit_unaligned_store_sw(inst, imm);
+	return SLJIT_SUCCESS;
+}
+
+static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr)
+{
+	sljit_s32 type = jump->flags >> TYPE_SHIFT;
+
+	int short_addr = !(jump->flags & SLJIT_REWRITABLE_JUMP) && !(jump->flags & JUMP_LABEL) && (jump->u.target <= 0xffffffff);
+
+	/* The relative jump below specialized for this case. */
+	SLJIT_ASSERT(reg_map[TMP_REG2] >= 8);
+
+	if (type < SLJIT_JUMP) {
+		/* Invert type. */
+		*code_ptr++ = get_jump_code(type ^ 0x1) - 0x10;
+		*code_ptr++ = short_addr ? (6 + 3) : (10 + 3);
+	}
+
+	*code_ptr++ = short_addr ? REX_B : (REX_W | REX_B);
+	*code_ptr++ = MOV_r_i32 | reg_lmap[TMP_REG2];
+	jump->addr = (sljit_uw)code_ptr;
+
+	if (jump->flags & JUMP_LABEL)
+		jump->flags |= PATCH_MD;
+	else if (short_addr)
+		sljit_unaligned_store_s32(code_ptr, (sljit_s32)jump->u.target);
+	else
+		sljit_unaligned_store_sw(code_ptr, jump->u.target);
+
+	code_ptr += short_addr ? sizeof(sljit_s32) : sizeof(sljit_sw);
+
+	*code_ptr++ = REX_B;
+	*code_ptr++ = GROUP_FF;
+	*code_ptr++ = MOD_REG | (type >= SLJIT_FAST_CALL ? CALL_rm : JMP_rm) | reg_lmap[TMP_REG2];
+
+	return code_ptr;
+}
+
+static sljit_u8* generate_put_label_code(struct sljit_put_label *put_label, sljit_u8 *code_ptr, sljit_uw max_label)
+{
+	if (max_label > HALFWORD_MAX) {
+		put_label->addr -= put_label->flags;
+		put_label->flags = PATCH_MD;
+		return code_ptr;
+	}
+
+	if (put_label->flags == 0) {
+		/* Destination is register. */
+		code_ptr = (sljit_u8*)put_label->addr - 2 - sizeof(sljit_uw);
+
+		SLJIT_ASSERT((code_ptr[0] & 0xf8) == REX_W);
+		SLJIT_ASSERT((code_ptr[1] & 0xf8) == MOV_r_i32);
+
+		if ((code_ptr[0] & 0x07) != 0) {
+			code_ptr[0] = (sljit_u8)(code_ptr[0] & ~0x08);
+			code_ptr += 2 + sizeof(sljit_s32);
+		}
+		else {
+			code_ptr[0] = code_ptr[1];
+			code_ptr += 1 + sizeof(sljit_s32);
+		}
+
+		put_label->addr = (sljit_uw)code_ptr;
+		return code_ptr;
+	}
+
+	code_ptr -= put_label->flags + (2 + sizeof(sljit_uw));
+	SLJIT_MEMMOVE(code_ptr, code_ptr + (2 + sizeof(sljit_uw)), put_label->flags);
+
+	SLJIT_ASSERT((code_ptr[0] & 0xf8) == REX_W);
+
+	if ((code_ptr[1] & 0xf8) == MOV_r_i32) {
+		code_ptr += 2 + sizeof(sljit_uw);
+		SLJIT_ASSERT((code_ptr[0] & 0xf8) == REX_W);
+	}
+
+	SLJIT_ASSERT(code_ptr[1] == MOV_rm_r);
+
+	code_ptr[0] = (sljit_u8)(code_ptr[0] & ~0x4);
+	code_ptr[1] = MOV_rm_i32;
+	code_ptr[2] = (sljit_u8)(code_ptr[2] & ~(0x7 << 3));
+
+	code_ptr = (sljit_u8*)(put_label->addr - (2 + sizeof(sljit_uw)) + sizeof(sljit_s32));
+	put_label->addr = (sljit_uw)code_ptr;
+	put_label->flags = 0;
+	return code_ptr;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	sljit_s32 args, i, tmp, size, saved_register_size;
+	sljit_u8 *inst;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+	/* Emit ENDBR64 at function entry if needed.  */
+	FAIL_IF(emit_endbranch(compiler));
+
+	compiler->mode32 = 0;
+
+#ifdef _WIN64
+	/* Two/four register slots for parameters plus space for xmm6 register if needed. */
+	if (fscratches >= 6 || fsaveds >= 1)
+		compiler->locals_offset = 6 * sizeof(sljit_sw);
+	else
+		compiler->locals_offset = ((scratches > 2) ? 4 : 2) * sizeof(sljit_sw);
+#endif
+
+	/* Including the return address saved by the call instruction. */
+	saved_register_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
+
+	tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
+	for (i = SLJIT_S0; i >= tmp; i--) {
+		size = reg_map[i] >= 8 ? 2 : 1;
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
+		FAIL_IF(!inst);
+		INC_SIZE(size);
+		if (reg_map[i] >= 8)
+			*inst++ = REX_B;
+		PUSH_REG(reg_lmap[i]);
+	}
+
+	for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
+		size = reg_map[i] >= 8 ? 2 : 1;
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
+		FAIL_IF(!inst);
+		INC_SIZE(size);
+		if (reg_map[i] >= 8)
+			*inst++ = REX_B;
+		PUSH_REG(reg_lmap[i]);
+	}
+
+	args = get_arg_count(arg_types);
+
+	if (args > 0) {
+		size = args * 3;
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
+		FAIL_IF(!inst);
+
+		INC_SIZE(size);
+
+#ifndef _WIN64
+		if (args > 0) {
+			inst[0] = REX_W;
+			inst[1] = MOV_r_rm;
+			inst[2] = MOD_REG | (reg_map[SLJIT_S0] << 3) | 0x7 /* rdi */;
+			inst += 3;
+		}
+		if (args > 1) {
+			inst[0] = REX_W | REX_R;
+			inst[1] = MOV_r_rm;
+			inst[2] = MOD_REG | (reg_lmap[SLJIT_S1] << 3) | 0x6 /* rsi */;
+			inst += 3;
+		}
+		if (args > 2) {
+			inst[0] = REX_W | REX_R;
+			inst[1] = MOV_r_rm;
+			inst[2] = MOD_REG | (reg_lmap[SLJIT_S2] << 3) | 0x2 /* rdx */;
+		}
+#else
+		if (args > 0) {
+			inst[0] = REX_W;
+			inst[1] = MOV_r_rm;
+			inst[2] = MOD_REG | (reg_map[SLJIT_S0] << 3) | 0x1 /* rcx */;
+			inst += 3;
+		}
+		if (args > 1) {
+			inst[0] = REX_W;
+			inst[1] = MOV_r_rm;
+			inst[2] = MOD_REG | (reg_map[SLJIT_S1] << 3) | 0x2 /* rdx */;
+			inst += 3;
+		}
+		if (args > 2) {
+			inst[0] = REX_W | REX_B;
+			inst[1] = MOV_r_rm;
+			inst[2] = MOD_REG | (reg_map[SLJIT_S2] << 3) | 0x0 /* r8 */;
+		}
+#endif
+	}
+
+	local_size = ((local_size + SLJIT_LOCALS_OFFSET + saved_register_size + 15) & ~15) - saved_register_size;
+	compiler->local_size = local_size;
+
+#ifdef _WIN64
+	if (local_size > 0) {
+		if (local_size <= 4 * 4096) {
+			if (local_size > 4096)
+				EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -4096);
+			if (local_size > 2 * 4096)
+				EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -4096 * 2);
+			if (local_size > 3 * 4096)
+				EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -4096 * 3);
+		}
+		else {
+			EMIT_MOV(compiler, SLJIT_R0, 0, SLJIT_SP, 0);
+			EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, (local_size - 1) >> 12);
+
+			SLJIT_ASSERT (reg_map[SLJIT_R0] == 0);
+
+			EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_MEM1(SLJIT_R0), -4096);
+			FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
+				SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_IMM, 4096));
+			FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
+				TMP_REG1, 0, TMP_REG1, 0, SLJIT_IMM, 1));
+
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+			FAIL_IF(!inst);
+
+			INC_SIZE(2);
+			inst[0] = JNE_i8;
+			inst[1] = (sljit_s8) -19;
+		}
+
+		EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(SLJIT_SP), -local_size);
+	}
+#endif
+
+	if (local_size > 0) {
+		FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
+			SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size));
+	}
+
+#ifdef _WIN64
+	/* Save xmm6 register: movaps [rsp + 0x20], xmm6 */
+	if (fscratches >= 6 || fsaveds >= 1) {
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 5);
+		FAIL_IF(!inst);
+		INC_SIZE(5);
+		*inst++ = GROUP_0F;
+		sljit_unaligned_store_s32(inst, 0x20247429);
+	}
+#endif
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
+	sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
+	sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
+{
+	sljit_s32 saved_register_size;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size));
+	set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
+
+#ifdef _WIN64
+	/* Two/four register slots for parameters plus space for xmm6 register if needed. */
+	if (fscratches >= 6 || fsaveds >= 1)
+		compiler->locals_offset = 6 * sizeof(sljit_sw);
+	else
+		compiler->locals_offset = ((scratches > 2) ? 4 : 2) * sizeof(sljit_sw);
+#endif
+
+	/* Including the return address saved by the call instruction. */
+	saved_register_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
+	compiler->local_size = ((local_size + SLJIT_LOCALS_OFFSET + saved_register_size + 15) & ~15) - saved_register_size;
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 i, tmp, size;
+	sljit_u8 *inst;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_return(compiler, op, src, srcw));
+
+	FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
+
+#ifdef _WIN64
+	/* Restore xmm6 register: movaps xmm6, [rsp + 0x20] */
+	if (compiler->fscratches >= 6 || compiler->fsaveds >= 1) {
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 5);
+		FAIL_IF(!inst);
+		INC_SIZE(5);
+		*inst++ = GROUP_0F;
+		sljit_unaligned_store_s32(inst, 0x20247428);
+	}
+#endif
+
+	if (compiler->local_size > 0) {
+		if (compiler->local_size <= 127) {
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
+			FAIL_IF(!inst);
+			INC_SIZE(4);
+			*inst++ = REX_W;
+			*inst++ = GROUP_BINARY_83;
+			*inst++ = MOD_REG | ADD | 4;
+			*inst = compiler->local_size;
+		}
+		else {
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 7);
+			FAIL_IF(!inst);
+			INC_SIZE(7);
+			*inst++ = REX_W;
+			*inst++ = GROUP_BINARY_81;
+			*inst++ = MOD_REG | ADD | 4;
+			sljit_unaligned_store_s32(inst, compiler->local_size);
+		}
+	}
+
+	tmp = compiler->scratches;
+	for (i = SLJIT_FIRST_SAVED_REG; i <= tmp; i++) {
+		size = reg_map[i] >= 8 ? 2 : 1;
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
+		FAIL_IF(!inst);
+		INC_SIZE(size);
+		if (reg_map[i] >= 8)
+			*inst++ = REX_B;
+		POP_REG(reg_lmap[i]);
+	}
+
+	tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG;
+	for (i = tmp; i <= SLJIT_S0; i++) {
+		size = reg_map[i] >= 8 ? 2 : 1;
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
+		FAIL_IF(!inst);
+		INC_SIZE(size);
+		if (reg_map[i] >= 8)
+			*inst++ = REX_B;
+		POP_REG(reg_lmap[i]);
+	}
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
+	FAIL_IF(!inst);
+	INC_SIZE(1);
+	RET();
+	return SLJIT_SUCCESS;
+}
+
+/* --------------------------------------------------------------------- */
+/*  Operators                                                            */
+/* --------------------------------------------------------------------- */
+
+static sljit_s32 emit_do_imm32(struct sljit_compiler *compiler, sljit_u8 rex, sljit_u8 opcode, sljit_sw imm)
+{
+	sljit_u8 *inst;
+	sljit_s32 length = 1 + (rex ? 1 : 0) + sizeof(sljit_s32);
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + length);
+	FAIL_IF(!inst);
+	INC_SIZE(length);
+	if (rex)
+		*inst++ = rex;
+	*inst++ = opcode;
+	sljit_unaligned_store_s32(inst, imm);
+	return SLJIT_SUCCESS;
+}
+
+static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32 size,
+	/* The register or immediate operand. */
+	sljit_s32 a, sljit_sw imma,
+	/* The general operand (not immediate). */
+	sljit_s32 b, sljit_sw immb)
+{
+	sljit_u8 *inst;
+	sljit_u8 *buf_ptr;
+	sljit_u8 rex = 0;
+	sljit_s32 flags = size & ~0xf;
+	sljit_s32 inst_size;
+
+	/* The immediate operand must be 32 bit. */
+	SLJIT_ASSERT(!(a & SLJIT_IMM) || compiler->mode32 || IS_HALFWORD(imma));
+	/* Both cannot be switched on. */
+	SLJIT_ASSERT((flags & (EX86_BIN_INS | EX86_SHIFT_INS)) != (EX86_BIN_INS | EX86_SHIFT_INS));
+	/* Size flags not allowed for typed instructions. */
+	SLJIT_ASSERT(!(flags & (EX86_BIN_INS | EX86_SHIFT_INS)) || (flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) == 0);
+	/* Both size flags cannot be switched on. */
+	SLJIT_ASSERT((flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) != (EX86_BYTE_ARG | EX86_HALF_ARG));
+	/* SSE2 and immediate is not possible. */
+	SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2));
+	SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3)
+		&& (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66)
+		&& (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66));
+
+	size &= 0xf;
+	inst_size = size;
+
+	if (!compiler->mode32 && !(flags & EX86_NO_REXW))
+		rex |= REX_W;
+	else if (flags & EX86_REX)
+		rex |= REX;
+
+	if (flags & (EX86_PREF_F2 | EX86_PREF_F3))
+		inst_size++;
+	if (flags & EX86_PREF_66)
+		inst_size++;
+
+	/* Calculate size of b. */
+	inst_size += 1; /* mod r/m byte. */
+	if (b & SLJIT_MEM) {
+		if (!(b & OFFS_REG_MASK)) {
+			if (NOT_HALFWORD(immb)) {
+				PTR_FAIL_IF(emit_load_imm64(compiler, TMP_REG2, immb));
+				immb = 0;
+				if (b & REG_MASK)
+					b |= TO_OFFS_REG(TMP_REG2);
+				else
+					b |= TMP_REG2;
+			}
+			else if (reg_lmap[b & REG_MASK] == 4)
+				b |= TO_OFFS_REG(SLJIT_SP);
+		}
+
+		if ((b & REG_MASK) == SLJIT_UNUSED)
+			inst_size += 1 + sizeof(sljit_s32); /* SIB byte required to avoid RIP based addressing. */
+		else {
+			if (reg_map[b & REG_MASK] >= 8)
+				rex |= REX_B;
+
+			if (immb != 0 && (!(b & OFFS_REG_MASK) || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP))) {
+				/* Immediate operand. */
+				if (immb <= 127 && immb >= -128)
+					inst_size += sizeof(sljit_s8);
+				else
+					inst_size += sizeof(sljit_s32);
+			}
+			else if (reg_lmap[b & REG_MASK] == 5)
+				inst_size += sizeof(sljit_s8);
+
+			if ((b & OFFS_REG_MASK) != SLJIT_UNUSED) {
+				inst_size += 1; /* SIB byte. */
+				if (reg_map[OFFS_REG(b)] >= 8)
+					rex |= REX_X;
+			}
+		}
+	}
+	else if (!(flags & EX86_SSE2_OP2)) {
+		if (reg_map[b] >= 8)
+			rex |= REX_B;
+	}
+	else if (freg_map[b] >= 8)
+		rex |= REX_B;
+
+	if (a & SLJIT_IMM) {
+		if (flags & EX86_BIN_INS) {
+			if (imma <= 127 && imma >= -128) {
+				inst_size += 1;
+				flags |= EX86_BYTE_ARG;
+			} else
+				inst_size += 4;
+		}
+		else if (flags & EX86_SHIFT_INS) {
+			imma &= compiler->mode32 ? 0x1f : 0x3f;
+			if (imma != 1) {
+				inst_size ++;
+				flags |= EX86_BYTE_ARG;
+			}
+		} else if (flags & EX86_BYTE_ARG)
+			inst_size++;
+		else if (flags & EX86_HALF_ARG)
+			inst_size += sizeof(short);
+		else
+			inst_size += sizeof(sljit_s32);
+	}
+	else {
+		SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG);
+		/* reg_map[SLJIT_PREF_SHIFT_REG] is less than 8. */
+		if (!(flags & EX86_SSE2_OP1)) {
+			if (reg_map[a] >= 8)
+				rex |= REX_R;
+		}
+		else if (freg_map[a] >= 8)
+			rex |= REX_R;
+	}
+
+	if (rex)
+		inst_size++;
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + inst_size);
+	PTR_FAIL_IF(!inst);
+
+	/* Encoding the byte. */
+	INC_SIZE(inst_size);
+	if (flags & EX86_PREF_F2)
+		*inst++ = 0xf2;
+	if (flags & EX86_PREF_F3)
+		*inst++ = 0xf3;
+	if (flags & EX86_PREF_66)
+		*inst++ = 0x66;
+	if (rex)
+		*inst++ = rex;
+	buf_ptr = inst + size;
+
+	/* Encode mod/rm byte. */
+	if (!(flags & EX86_SHIFT_INS)) {
+		if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM))
+			*inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81;
+
+		if (a & SLJIT_IMM)
+			*buf_ptr = 0;
+		else if (!(flags & EX86_SSE2_OP1))
+			*buf_ptr = reg_lmap[a] << 3;
+		else
+			*buf_ptr = freg_lmap[a] << 3;
+	}
+	else {
+		if (a & SLJIT_IMM) {
+			if (imma == 1)
+				*inst = GROUP_SHIFT_1;
+			else
+				*inst = GROUP_SHIFT_N;
+		} else
+			*inst = GROUP_SHIFT_CL;
+		*buf_ptr = 0;
+	}
+
+	if (!(b & SLJIT_MEM))
+		*buf_ptr++ |= MOD_REG + ((!(flags & EX86_SSE2_OP2)) ? reg_lmap[b] : freg_lmap[b]);
+	else if ((b & REG_MASK) != SLJIT_UNUSED) {
+		if ((b & OFFS_REG_MASK) == SLJIT_UNUSED || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP)) {
+			if (immb != 0 || reg_lmap[b & REG_MASK] == 5) {
+				if (immb <= 127 && immb >= -128)
+					*buf_ptr |= 0x40;
+				else
+					*buf_ptr |= 0x80;
+			}
+
+			if ((b & OFFS_REG_MASK) == SLJIT_UNUSED)
+				*buf_ptr++ |= reg_lmap[b & REG_MASK];
+			else {
+				*buf_ptr++ |= 0x04;
+				*buf_ptr++ = reg_lmap[b & REG_MASK] | (reg_lmap[OFFS_REG(b)] << 3);
+			}
+
+			if (immb != 0 || reg_lmap[b & REG_MASK] == 5) {
+				if (immb <= 127 && immb >= -128)
+					*buf_ptr++ = immb; /* 8 bit displacement. */
+				else {
+					sljit_unaligned_store_s32(buf_ptr, immb); /* 32 bit displacement. */
+					buf_ptr += sizeof(sljit_s32);
+				}
+			}
+		}
+		else {
+			if (reg_lmap[b & REG_MASK] == 5)
+				*buf_ptr |= 0x40;
+			*buf_ptr++ |= 0x04;
+			*buf_ptr++ = reg_lmap[b & REG_MASK] | (reg_lmap[OFFS_REG(b)] << 3) | (immb << 6);
+			if (reg_lmap[b & REG_MASK] == 5)
+				*buf_ptr++ = 0;
+		}
+	}
+	else {
+		*buf_ptr++ |= 0x04;
+		*buf_ptr++ = 0x25;
+		sljit_unaligned_store_s32(buf_ptr, immb); /* 32 bit displacement. */
+		buf_ptr += sizeof(sljit_s32);
+	}
+
+	if (a & SLJIT_IMM) {
+		if (flags & EX86_BYTE_ARG)
+			*buf_ptr = imma;
+		else if (flags & EX86_HALF_ARG)
+			sljit_unaligned_store_s16(buf_ptr, imma);
+		else if (!(flags & EX86_SHIFT_INS))
+			sljit_unaligned_store_s32(buf_ptr, imma);
+	}
+
+	return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Call / return instructions                                           */
+/* --------------------------------------------------------------------- */
+
+#ifndef _WIN64
+
+static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *src_ptr, sljit_sw srcw)
+{
+	sljit_s32 src = src_ptr ? (*src_ptr) : 0;
+	sljit_s32 word_arg_count = 0;
+
+	SLJIT_ASSERT(reg_map[SLJIT_R1] == 6 && reg_map[SLJIT_R3] == 1 && reg_map[TMP_REG1] == 2);
+
+	compiler->mode32 = 0;
+
+	/* Remove return value. */
+	arg_types >>= SLJIT_DEF_SHIFT;
+
+	while (arg_types) {
+		if ((arg_types & SLJIT_DEF_MASK) < SLJIT_ARG_TYPE_F32)
+			word_arg_count++;
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	if (word_arg_count == 0)
+		return SLJIT_SUCCESS;
+
+	if (src & SLJIT_MEM) {
+		ADJUST_LOCAL_OFFSET(src, srcw);
+		EMIT_MOV(compiler, TMP_REG2, 0, src, srcw);
+		*src_ptr = TMP_REG2;
+	}
+	else if (src == SLJIT_R2 && word_arg_count >= SLJIT_R2)
+		*src_ptr = TMP_REG1;
+
+	if (word_arg_count >= 3)
+		EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R2, 0);
+	return emit_mov(compiler, SLJIT_R2, 0, SLJIT_R0, 0);
+}
+
+#else
+
+static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types, sljit_s32 *src_ptr, sljit_sw srcw)
+{
+	sljit_s32 src = src_ptr ? (*src_ptr) : 0;
+	sljit_s32 arg_count = 0;
+	sljit_s32 word_arg_count = 0;
+	sljit_s32 float_arg_count = 0;
+	sljit_s32 types = 0;
+	sljit_s32 data_trandfer = 0;
+	static sljit_u8 word_arg_regs[5] = { 0, SLJIT_R3, SLJIT_R1, SLJIT_R2, TMP_REG1 };
+
+	SLJIT_ASSERT(reg_map[SLJIT_R3] == 1 && reg_map[SLJIT_R1] == 2 && reg_map[SLJIT_R2] == 8 && reg_map[TMP_REG1] == 9);
+
+	compiler->mode32 = 0;
+	arg_types >>= SLJIT_DEF_SHIFT;
+
+	while (arg_types) {
+		types = (types << SLJIT_DEF_SHIFT) | (arg_types & SLJIT_DEF_MASK);
+
+		switch (arg_types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+		case SLJIT_ARG_TYPE_F64:
+			arg_count++;
+			float_arg_count++;
+
+			if (arg_count != float_arg_count)
+				data_trandfer = 1;
+			break;
+		default:
+			arg_count++;
+			word_arg_count++;
+
+			if (arg_count != word_arg_count || arg_count != word_arg_regs[arg_count]) {
+				data_trandfer = 1;
+
+				if (src == word_arg_regs[arg_count]) {
+					EMIT_MOV(compiler, TMP_REG2, 0, src, 0);
+					*src_ptr = TMP_REG2;
+				}
+			}
+			break;
+		}
+
+		arg_types >>= SLJIT_DEF_SHIFT;
+	}
+
+	if (!data_trandfer)
+		return SLJIT_SUCCESS;
+
+	if (src & SLJIT_MEM) {
+		ADJUST_LOCAL_OFFSET(src, srcw);
+		EMIT_MOV(compiler, TMP_REG2, 0, src, srcw);
+		*src_ptr = TMP_REG2;
+	}
+
+	while (types) {
+		switch (types & SLJIT_DEF_MASK) {
+		case SLJIT_ARG_TYPE_F32:
+			if (arg_count != float_arg_count)
+				FAIL_IF(emit_sse2_load(compiler, 1, arg_count, float_arg_count, 0));
+			arg_count--;
+			float_arg_count--;
+			break;
+		case SLJIT_ARG_TYPE_F64:
+			if (arg_count != float_arg_count)
+				FAIL_IF(emit_sse2_load(compiler, 0, arg_count, float_arg_count, 0));
+			arg_count--;
+			float_arg_count--;
+			break;
+		default:
+			if (arg_count != word_arg_count || arg_count != word_arg_regs[arg_count])
+				EMIT_MOV(compiler, word_arg_regs[arg_count], 0, word_arg_count, 0);
+			arg_count--;
+			word_arg_count--;
+			break;
+		}
+
+		types >>= SLJIT_DEF_SHIFT;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+#endif
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types)
+{
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
+
+	PTR_FAIL_IF(call_with_args(compiler, arg_types, NULL, 0));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+
+	return sljit_emit_jump(compiler, type);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 arg_types,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
+
+	FAIL_IF(call_with_args(compiler, arg_types, &src, srcw));
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+
+	return sljit_emit_ijump(compiler, type, src, srcw);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	sljit_u8 *inst;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	/* For UNUSED dst. Uncommon, but possible. */
+	if (dst == SLJIT_UNUSED)
+		dst = TMP_REG1;
+
+	if (FAST_IS_REG(dst)) {
+		if (reg_map[dst] < 8) {
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
+			FAIL_IF(!inst);
+			INC_SIZE(1);
+			POP_REG(reg_lmap[dst]);
+			return SLJIT_SUCCESS;
+		}
+
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+		FAIL_IF(!inst);
+		INC_SIZE(2);
+		*inst++ = REX_B;
+		POP_REG(reg_lmap[dst]);
+		return SLJIT_SUCCESS;
+	}
+
+	/* REX_W is not necessary (src is not immediate). */
+	compiler->mode32 = 1;
+	inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
+	FAIL_IF(!inst);
+	*inst++ = POP_rm;
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
+{
+	sljit_u8 *inst;
+
+	if (FAST_IS_REG(src)) {
+		if (reg_map[src] < 8) {
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 1);
+			FAIL_IF(!inst);
+
+			INC_SIZE(1 + 1);
+			PUSH_REG(reg_lmap[src]);
+		}
+		else {
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + 1);
+			FAIL_IF(!inst);
+
+			INC_SIZE(2 + 1);
+			*inst++ = REX_B;
+			PUSH_REG(reg_lmap[src]);
+		}
+	}
+	else {
+		/* REX_W is not necessary (src is not immediate). */
+		compiler->mode32 = 1;
+		inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
+		FAIL_IF(!inst);
+		*inst++ = GROUP_FF;
+		*inst |= PUSH_rm;
+
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
+		FAIL_IF(!inst);
+		INC_SIZE(1);
+	}
+
+	RET();
+	return SLJIT_SUCCESS;
+}
+
+/* --------------------------------------------------------------------- */
+/*  Extend input                                                         */
+/* --------------------------------------------------------------------- */
+
+static sljit_s32 emit_mov_int(struct sljit_compiler *compiler, sljit_s32 sign,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_u8* inst;
+	sljit_s32 dst_r;
+
+	compiler->mode32 = 0;
+
+	if (dst == SLJIT_UNUSED && !(src & SLJIT_MEM))
+		return SLJIT_SUCCESS; /* Empty instruction. */
+
+	if (src & SLJIT_IMM) {
+		if (FAST_IS_REG(dst)) {
+			if (sign || ((sljit_uw)srcw <= 0x7fffffff)) {
+				inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw);
+				FAIL_IF(!inst);
+				*inst = MOV_rm_i32;
+				return SLJIT_SUCCESS;
+			}
+			return emit_load_imm64(compiler, dst, srcw);
+		}
+		compiler->mode32 = 1;
+		inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw);
+		FAIL_IF(!inst);
+		*inst = MOV_rm_i32;
+		compiler->mode32 = 0;
+		return SLJIT_SUCCESS;
+	}
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+
+	if ((dst & SLJIT_MEM) && FAST_IS_REG(src))
+		dst_r = src;
+	else {
+		if (sign) {
+			inst = emit_x86_instruction(compiler, 1, dst_r, 0, src, srcw);
+			FAIL_IF(!inst);
+			*inst++ = MOVSXD_r_rm;
+		} else {
+			compiler->mode32 = 1;
+			FAIL_IF(emit_mov(compiler, dst_r, 0, src, srcw));
+			compiler->mode32 = 0;
+		}
+	}
+
+	if (dst & SLJIT_MEM) {
+		compiler->mode32 = 1;
+		inst = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw);
+		FAIL_IF(!inst);
+		*inst = MOV_rm_r;
+		compiler->mode32 = 0;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 skip_frames_before_return(struct sljit_compiler *compiler)
+{
+	sljit_s32 tmp, size;
+
+	/* Don't adjust shadow stack if it isn't enabled.  */
+	if (!cpu_has_shadow_stack ())
+		return SLJIT_SUCCESS;
+
+	size = compiler->local_size;
+	tmp = compiler->scratches;
+	if (tmp >= SLJIT_FIRST_SAVED_REG)
+		size += (tmp - SLJIT_FIRST_SAVED_REG + 1) * sizeof(sljit_uw);
+	tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG;
+	if (SLJIT_S0 >= tmp)
+		size += (SLJIT_S0 - tmp + 1) * sizeof(sljit_uw);
+
+	return adjust_shadow_stack(compiler, SLJIT_UNUSED, 0, SLJIT_SP, size);
+}
diff --git a/src/c/pcre2/src/sljit/sljitNativeX86_common.c b/src/c/pcre2/src/sljit/sljitNativeX86_common.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitNativeX86_common.c
@@ -0,0 +1,3142 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
+{
+#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
+	return "x86" SLJIT_CPUINFO " ABI:fastcall";
+#else
+	return "x86" SLJIT_CPUINFO;
+#endif
+}
+
+/*
+   32b register indexes:
+     0 - EAX
+     1 - ECX
+     2 - EDX
+     3 - EBX
+     4 - ESP
+     5 - EBP
+     6 - ESI
+     7 - EDI
+*/
+
+/*
+   64b register indexes:
+     0 - RAX
+     1 - RCX
+     2 - RDX
+     3 - RBX
+     4 - RSP
+     5 - RBP
+     6 - RSI
+     7 - RDI
+     8 - R8   - From now on REX prefix is required
+     9 - R9
+    10 - R10
+    11 - R11
+    12 - R12
+    13 - R13
+    14 - R14
+    15 - R15
+*/
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+
+/* Last register + 1. */
+#define TMP_REG1	(SLJIT_NUMBER_OF_REGISTERS + 2)
+
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 3] = {
+	0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 7, 6, 3, 4, 5
+};
+
+#define CHECK_EXTRA_REGS(p, w, do) \
+	if (p >= SLJIT_R3 && p <= SLJIT_S3) { \
+		if (p <= compiler->scratches) \
+			w = compiler->saveds_offset - ((p) - SLJIT_R2) * (sljit_sw)sizeof(sljit_sw); \
+		else \
+			w = compiler->locals_offset + ((p) - SLJIT_S2) * (sljit_sw)sizeof(sljit_sw); \
+		p = SLJIT_MEM1(SLJIT_SP); \
+		do; \
+	}
+
+#else /* SLJIT_CONFIG_X86_32 */
+
+/* Last register + 1. */
+#define TMP_REG1	(SLJIT_NUMBER_OF_REGISTERS + 2)
+#define TMP_REG2	(SLJIT_NUMBER_OF_REGISTERS + 3)
+
+/* Note: r12 & 0x7 == 0b100, which decoded as SIB byte present
+   Note: avoid to use r12 and r13 for memory addessing
+   therefore r12 is better to be a higher saved register. */
+#ifndef _WIN64
+/* Args: rdi(=7), rsi(=6), rdx(=2), rcx(=1), r8, r9. Scratches: rax(=0), r10, r11 */
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 4] = {
+	0, 0, 6, 7, 1, 8, 11, 10, 12, 5, 13, 14, 15, 3, 4, 2, 9
+};
+/* low-map. reg_map & 0x7. */
+static const sljit_u8 reg_lmap[SLJIT_NUMBER_OF_REGISTERS + 4] = {
+	0, 0, 6, 7, 1, 0, 3,  2,  4,  5,  5,  6,  7, 3, 4, 2, 1
+};
+#else
+/* Args: rcx(=1), rdx(=2), r8, r9. Scratches: rax(=0), r10, r11 */
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 4] = {
+	0, 0, 2, 8, 1, 11, 12, 5, 13, 14, 15, 7, 6, 3, 4, 9, 10
+};
+/* low-map. reg_map & 0x7. */
+static const sljit_u8 reg_lmap[SLJIT_NUMBER_OF_REGISTERS + 4] = {
+	0, 0, 2, 0, 1,  3,  4, 5,  5,  6,  7, 7, 6, 3, 4, 1,  2
+};
+#endif
+
+/* Args: xmm0-xmm3 */
+static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = {
+	4, 0, 1, 2, 3, 5, 6
+};
+/* low-map. freg_map & 0x7. */
+static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = {
+	4, 0, 1, 2, 3, 5, 6
+};
+
+#define REX_W		0x48
+#define REX_R		0x44
+#define REX_X		0x42
+#define REX_B		0x41
+#define REX		0x40
+
+#ifndef _WIN64
+#define HALFWORD_MAX 0x7fffffffl
+#define HALFWORD_MIN -0x80000000l
+#else
+#define HALFWORD_MAX 0x7fffffffll
+#define HALFWORD_MIN -0x80000000ll
+#endif
+
+#define IS_HALFWORD(x)		((x) <= HALFWORD_MAX && (x) >= HALFWORD_MIN)
+#define NOT_HALFWORD(x)		((x) > HALFWORD_MAX || (x) < HALFWORD_MIN)
+
+#define CHECK_EXTRA_REGS(p, w, do)
+
+#endif /* SLJIT_CONFIG_X86_32 */
+
+#define TMP_FREG	(0)
+
+/* Size flags for emit_x86_instruction: */
+#define EX86_BIN_INS		0x0010
+#define EX86_SHIFT_INS		0x0020
+#define EX86_REX		0x0040
+#define EX86_NO_REXW		0x0080
+#define EX86_BYTE_ARG		0x0100
+#define EX86_HALF_ARG		0x0200
+#define EX86_PREF_66		0x0400
+#define EX86_PREF_F2		0x0800
+#define EX86_PREF_F3		0x1000
+#define EX86_SSE2_OP1		0x2000
+#define EX86_SSE2_OP2		0x4000
+#define EX86_SSE2		(EX86_SSE2_OP1 | EX86_SSE2_OP2)
+
+/* --------------------------------------------------------------------- */
+/*  Instrucion forms                                                     */
+/* --------------------------------------------------------------------- */
+
+#define ADD		(/* BINARY */ 0 << 3)
+#define ADD_EAX_i32	0x05
+#define ADD_r_rm	0x03
+#define ADD_rm_r	0x01
+#define ADDSD_x_xm	0x58
+#define ADC		(/* BINARY */ 2 << 3)
+#define ADC_EAX_i32	0x15
+#define ADC_r_rm	0x13
+#define ADC_rm_r	0x11
+#define AND		(/* BINARY */ 4 << 3)
+#define AND_EAX_i32	0x25
+#define AND_r_rm	0x23
+#define AND_rm_r	0x21
+#define ANDPD_x_xm	0x54
+#define BSR_r_rm	(/* GROUP_0F */ 0xbd)
+#define CALL_i32	0xe8
+#define CALL_rm		(/* GROUP_FF */ 2 << 3)
+#define CDQ		0x99
+#define CMOVE_r_rm	(/* GROUP_0F */ 0x44)
+#define CMP		(/* BINARY */ 7 << 3)
+#define CMP_EAX_i32	0x3d
+#define CMP_r_rm	0x3b
+#define CMP_rm_r	0x39
+#define CVTPD2PS_x_xm	0x5a
+#define CVTSI2SD_x_rm	0x2a
+#define CVTTSD2SI_r_xm	0x2c
+#define DIV		(/* GROUP_F7 */ 6 << 3)
+#define DIVSD_x_xm	0x5e
+#define FSTPS		0xd9
+#define FSTPD		0xdd
+#define INT3		0xcc
+#define IDIV		(/* GROUP_F7 */ 7 << 3)
+#define IMUL		(/* GROUP_F7 */ 5 << 3)
+#define IMUL_r_rm	(/* GROUP_0F */ 0xaf)
+#define IMUL_r_rm_i8	0x6b
+#define IMUL_r_rm_i32	0x69
+#define JE_i8		0x74
+#define JNE_i8		0x75
+#define JMP_i8		0xeb
+#define JMP_i32		0xe9
+#define JMP_rm		(/* GROUP_FF */ 4 << 3)
+#define LEA_r_m		0x8d
+#define MOV_r_rm	0x8b
+#define MOV_r_i32	0xb8
+#define MOV_rm_r	0x89
+#define MOV_rm_i32	0xc7
+#define MOV_rm8_i8	0xc6
+#define MOV_rm8_r8	0x88
+#define MOVSD_x_xm	0x10
+#define MOVSD_xm_x	0x11
+#define MOVSXD_r_rm	0x63
+#define MOVSX_r_rm8	(/* GROUP_0F */ 0xbe)
+#define MOVSX_r_rm16	(/* GROUP_0F */ 0xbf)
+#define MOVZX_r_rm8	(/* GROUP_0F */ 0xb6)
+#define MOVZX_r_rm16	(/* GROUP_0F */ 0xb7)
+#define MUL		(/* GROUP_F7 */ 4 << 3)
+#define MULSD_x_xm	0x59
+#define NEG_rm		(/* GROUP_F7 */ 3 << 3)
+#define NOP		0x90
+#define NOT_rm		(/* GROUP_F7 */ 2 << 3)
+#define OR		(/* BINARY */ 1 << 3)
+#define OR_r_rm		0x0b
+#define OR_EAX_i32	0x0d
+#define OR_rm_r		0x09
+#define OR_rm8_r8	0x08
+#define POP_r		0x58
+#define POP_rm		0x8f
+#define POPF		0x9d
+#define PREFETCH	0x18
+#define PUSH_i32	0x68
+#define PUSH_r		0x50
+#define PUSH_rm		(/* GROUP_FF */ 6 << 3)
+#define PUSHF		0x9c
+#define RET_near	0xc3
+#define RET_i16		0xc2
+#define SBB		(/* BINARY */ 3 << 3)
+#define SBB_EAX_i32	0x1d
+#define SBB_r_rm	0x1b
+#define SBB_rm_r	0x19
+#define SAR		(/* SHIFT */ 7 << 3)
+#define SHL		(/* SHIFT */ 4 << 3)
+#define SHR		(/* SHIFT */ 5 << 3)
+#define SUB		(/* BINARY */ 5 << 3)
+#define SUB_EAX_i32	0x2d
+#define SUB_r_rm	0x2b
+#define SUB_rm_r	0x29
+#define SUBSD_x_xm	0x5c
+#define TEST_EAX_i32	0xa9
+#define TEST_rm_r	0x85
+#define UCOMISD_x_xm	0x2e
+#define UNPCKLPD_x_xm	0x14
+#define XCHG_EAX_r	0x90
+#define XCHG_r_rm	0x87
+#define XOR		(/* BINARY */ 6 << 3)
+#define XOR_EAX_i32	0x35
+#define XOR_r_rm	0x33
+#define XOR_rm_r	0x31
+#define XORPD_x_xm	0x57
+
+#define GROUP_0F	0x0f
+#define GROUP_F7	0xf7
+#define GROUP_FF	0xff
+#define GROUP_BINARY_81	0x81
+#define GROUP_BINARY_83	0x83
+#define GROUP_SHIFT_1	0xd1
+#define GROUP_SHIFT_N	0xc1
+#define GROUP_SHIFT_CL	0xd3
+
+#define MOD_REG		0xc0
+#define MOD_DISP8	0x40
+
+#define INC_SIZE(s)			(*inst++ = (s), compiler->size += (s))
+
+#define PUSH_REG(r)			(*inst++ = (PUSH_r + (r)))
+#define POP_REG(r)			(*inst++ = (POP_r + (r)))
+#define RET()				(*inst++ = (RET_near))
+#define RET_I16(n)			(*inst++ = (RET_i16), *inst++ = n, *inst++ = 0)
+/* r32, r/m32 */
+#define MOV_RM(mod, reg, rm)		(*inst++ = (MOV_r_rm), *inst++ = (mod) << 6 | (reg) << 3 | (rm))
+
+/* Multithreading does not affect these static variables, since they store
+   built-in CPU features. Therefore they can be overwritten by different threads
+   if they detect the CPU features in the same time. */
+#if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2)
+static sljit_s32 cpu_has_sse2 = -1;
+#endif
+static sljit_s32 cpu_has_cmov = -1;
+
+#ifdef _WIN32_WCE
+#include <cmnintrin.h>
+#elif defined(_MSC_VER) && _MSC_VER >= 1400
+#include <intrin.h>
+#endif
+
+/******************************************************/
+/*    Unaligned-store functions                       */
+/******************************************************/
+
+static SLJIT_INLINE void sljit_unaligned_store_s16(void *addr, sljit_s16 value)
+{
+	SLJIT_MEMCPY(addr, &value, sizeof(value));
+}
+
+static SLJIT_INLINE void sljit_unaligned_store_s32(void *addr, sljit_s32 value)
+{
+	SLJIT_MEMCPY(addr, &value, sizeof(value));
+}
+
+static SLJIT_INLINE void sljit_unaligned_store_sw(void *addr, sljit_sw value)
+{
+	SLJIT_MEMCPY(addr, &value, sizeof(value));
+}
+
+/******************************************************/
+/*    Utility functions                               */
+/******************************************************/
+
+static void get_cpu_features(void)
+{
+	sljit_u32 features;
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+
+	int CPUInfo[4];
+	__cpuid(CPUInfo, 1);
+	features = (sljit_u32)CPUInfo[3];
+
+#elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_C)
+
+	/* AT&T syntax. */
+	__asm__ (
+		"movl $0x1, %%eax\n"
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+		/* On x86-32, there is no red zone, so this
+		   should work (no need for a local variable). */
+		"push %%ebx\n"
+#endif
+		"cpuid\n"
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+		"pop %%ebx\n"
+#endif
+		"movl %%edx, %0\n"
+		: "=g" (features)
+		:
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+		: "%eax", "%ecx", "%edx"
+#else
+		: "%rax", "%rbx", "%rcx", "%rdx"
+#endif
+	);
+
+#else /* _MSC_VER && _MSC_VER >= 1400 */
+
+	/* Intel syntax. */
+	__asm {
+		mov eax, 1
+		cpuid
+		mov features, edx
+	}
+
+#endif /* _MSC_VER && _MSC_VER >= 1400 */
+
+#if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2)
+	cpu_has_sse2 = (features >> 26) & 0x1;
+#endif
+	cpu_has_cmov = (features >> 15) & 0x1;
+}
+
+static sljit_u8 get_jump_code(sljit_s32 type)
+{
+	switch (type) {
+	case SLJIT_EQUAL:
+	case SLJIT_EQUAL_F64:
+		return 0x84 /* je */;
+
+	case SLJIT_NOT_EQUAL:
+	case SLJIT_NOT_EQUAL_F64:
+		return 0x85 /* jne */;
+
+	case SLJIT_LESS:
+	case SLJIT_LESS_F64:
+		return 0x82 /* jc */;
+
+	case SLJIT_GREATER_EQUAL:
+	case SLJIT_GREATER_EQUAL_F64:
+		return 0x83 /* jae */;
+
+	case SLJIT_GREATER:
+	case SLJIT_GREATER_F64:
+		return 0x87 /* jnbe */;
+
+	case SLJIT_LESS_EQUAL:
+	case SLJIT_LESS_EQUAL_F64:
+		return 0x86 /* jbe */;
+
+	case SLJIT_SIG_LESS:
+		return 0x8c /* jl */;
+
+	case SLJIT_SIG_GREATER_EQUAL:
+		return 0x8d /* jnl */;
+
+	case SLJIT_SIG_GREATER:
+		return 0x8f /* jnle */;
+
+	case SLJIT_SIG_LESS_EQUAL:
+		return 0x8e /* jle */;
+
+	case SLJIT_OVERFLOW:
+	case SLJIT_MUL_OVERFLOW:
+		return 0x80 /* jo */;
+
+	case SLJIT_NOT_OVERFLOW:
+	case SLJIT_MUL_NOT_OVERFLOW:
+		return 0x81 /* jno */;
+
+	case SLJIT_UNORDERED_F64:
+		return 0x8a /* jp */;
+
+	case SLJIT_ORDERED_F64:
+		return 0x8b /* jpo */;
+	}
+	return 0;
+}
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_sw executable_offset);
+#else
+static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr);
+static sljit_u8* generate_put_label_code(struct sljit_put_label *put_label, sljit_u8 *code_ptr, sljit_uw max_label);
+#endif
+
+static sljit_u8* generate_near_jump_code(struct sljit_jump *jump, sljit_u8 *code_ptr, sljit_u8 *code, sljit_sw executable_offset)
+{
+	sljit_s32 type = jump->flags >> TYPE_SHIFT;
+	sljit_s32 short_jump;
+	sljit_uw label_addr;
+
+	if (jump->flags & JUMP_LABEL)
+		label_addr = (sljit_uw)(code + jump->u.label->size);
+	else
+		label_addr = jump->u.target - executable_offset;
+
+	short_jump = (sljit_sw)(label_addr - (jump->addr + 2)) >= -128 && (sljit_sw)(label_addr - (jump->addr + 2)) <= 127;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	if ((sljit_sw)(label_addr - (jump->addr + 1)) > HALFWORD_MAX || (sljit_sw)(label_addr - (jump->addr + 1)) < HALFWORD_MIN)
+		return generate_far_jump_code(jump, code_ptr);
+#endif
+
+	if (type == SLJIT_JUMP) {
+		if (short_jump)
+			*code_ptr++ = JMP_i8;
+		else
+			*code_ptr++ = JMP_i32;
+		jump->addr++;
+	}
+	else if (type >= SLJIT_FAST_CALL) {
+		short_jump = 0;
+		*code_ptr++ = CALL_i32;
+		jump->addr++;
+	}
+	else if (short_jump) {
+		*code_ptr++ = get_jump_code(type) - 0x10;
+		jump->addr++;
+	}
+	else {
+		*code_ptr++ = GROUP_0F;
+		*code_ptr++ = get_jump_code(type);
+		jump->addr += 2;
+	}
+
+	if (short_jump) {
+		jump->flags |= PATCH_MB;
+		code_ptr += sizeof(sljit_s8);
+	} else {
+		jump->flags |= PATCH_MW;
+		code_ptr += sizeof(sljit_s32);
+	}
+
+	return code_ptr;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
+{
+	struct sljit_memory_fragment *buf;
+	sljit_u8 *code;
+	sljit_u8 *code_ptr;
+	sljit_u8 *buf_ptr;
+	sljit_u8 *buf_end;
+	sljit_u8 len;
+	sljit_sw executable_offset;
+	sljit_sw jump_addr;
+
+	struct sljit_label *label;
+	struct sljit_jump *jump;
+	struct sljit_const *const_;
+	struct sljit_put_label *put_label;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_generate_code(compiler));
+	reverse_buf(compiler);
+
+	/* Second code generation pass. */
+	code = (sljit_u8*)SLJIT_MALLOC_EXEC(compiler->size, compiler->exec_allocator_data);
+	PTR_FAIL_WITH_EXEC_IF(code);
+	buf = compiler->buf;
+
+	code_ptr = code;
+	label = compiler->labels;
+	jump = compiler->jumps;
+	const_ = compiler->consts;
+	put_label = compiler->put_labels;
+	executable_offset = SLJIT_EXEC_OFFSET(code);
+
+	do {
+		buf_ptr = buf->memory;
+		buf_end = buf_ptr + buf->used_size;
+		do {
+			len = *buf_ptr++;
+			if (len > 0) {
+				/* The code is already generated. */
+				SLJIT_MEMCPY(code_ptr, buf_ptr, len);
+				code_ptr += len;
+				buf_ptr += len;
+			}
+			else {
+				switch (*buf_ptr) {
+				case 0:
+					label->addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+					label->size = code_ptr - code;
+					label = label->next;
+					break;
+				case 1:
+					jump->addr = (sljit_uw)code_ptr;
+					if (!(jump->flags & SLJIT_REWRITABLE_JUMP))
+						code_ptr = generate_near_jump_code(jump, code_ptr, code, executable_offset);
+					else {
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+						code_ptr = generate_far_jump_code(jump, code_ptr, executable_offset);
+#else
+						code_ptr = generate_far_jump_code(jump, code_ptr);
+#endif
+					}
+					jump = jump->next;
+					break;
+				case 2:
+					const_->addr = ((sljit_uw)code_ptr) - sizeof(sljit_sw);
+					const_ = const_->next;
+					break;
+				default:
+					SLJIT_ASSERT(*buf_ptr == 3);
+					SLJIT_ASSERT(put_label->label);
+					put_label->addr = (sljit_uw)code_ptr;
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+					code_ptr = generate_put_label_code(put_label, code_ptr, (sljit_uw)SLJIT_ADD_EXEC_OFFSET(code, executable_offset) + put_label->label->size);
+#endif
+					put_label = put_label->next;
+					break;
+				}
+				buf_ptr++;
+			}
+		} while (buf_ptr < buf_end);
+		SLJIT_ASSERT(buf_ptr == buf_end);
+		buf = buf->next;
+	} while (buf);
+
+	SLJIT_ASSERT(!label);
+	SLJIT_ASSERT(!jump);
+	SLJIT_ASSERT(!const_);
+	SLJIT_ASSERT(!put_label);
+	SLJIT_ASSERT(code_ptr <= code + compiler->size);
+
+	jump = compiler->jumps;
+	while (jump) {
+		jump_addr = jump->addr + executable_offset;
+
+		if (jump->flags & PATCH_MB) {
+			SLJIT_ASSERT((sljit_sw)(jump->u.label->addr - (jump_addr + sizeof(sljit_s8))) >= -128 && (sljit_sw)(jump->u.label->addr - (jump_addr + sizeof(sljit_s8))) <= 127);
+			*(sljit_u8*)jump->addr = (sljit_u8)(jump->u.label->addr - (jump_addr + sizeof(sljit_s8)));
+		} else if (jump->flags & PATCH_MW) {
+			if (jump->flags & JUMP_LABEL) {
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+				sljit_unaligned_store_sw((void*)jump->addr, (sljit_sw)(jump->u.label->addr - (jump_addr + sizeof(sljit_sw))));
+#else
+				SLJIT_ASSERT((sljit_sw)(jump->u.label->addr - (jump_addr + sizeof(sljit_s32))) >= HALFWORD_MIN && (sljit_sw)(jump->u.label->addr - (jump_addr + sizeof(sljit_s32))) <= HALFWORD_MAX);
+				sljit_unaligned_store_s32((void*)jump->addr, (sljit_s32)(jump->u.label->addr - (jump_addr + sizeof(sljit_s32))));
+#endif
+			}
+			else {
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+				sljit_unaligned_store_sw((void*)jump->addr, (sljit_sw)(jump->u.target - (jump_addr + sizeof(sljit_sw))));
+#else
+				SLJIT_ASSERT((sljit_sw)(jump->u.target - (jump_addr + sizeof(sljit_s32))) >= HALFWORD_MIN && (sljit_sw)(jump->u.target - (jump_addr + sizeof(sljit_s32))) <= HALFWORD_MAX);
+				sljit_unaligned_store_s32((void*)jump->addr, (sljit_s32)(jump->u.target - (jump_addr + sizeof(sljit_s32))));
+#endif
+			}
+		}
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+		else if (jump->flags & PATCH_MD)
+			sljit_unaligned_store_sw((void*)jump->addr, jump->u.label->addr);
+#endif
+
+		jump = jump->next;
+	}
+
+	put_label = compiler->put_labels;
+	while (put_label) {
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+		sljit_unaligned_store_sw((void*)(put_label->addr - sizeof(sljit_sw)), (sljit_sw)put_label->label->addr);
+#else
+		if (put_label->flags & PATCH_MD) {
+			SLJIT_ASSERT(put_label->label->addr > HALFWORD_MAX);
+			sljit_unaligned_store_sw((void*)(put_label->addr - sizeof(sljit_sw)), (sljit_sw)put_label->label->addr);
+		}
+		else {
+			SLJIT_ASSERT(put_label->label->addr <= HALFWORD_MAX);
+			sljit_unaligned_store_s32((void*)(put_label->addr - sizeof(sljit_s32)), (sljit_s32)put_label->label->addr);
+		}
+#endif
+
+		put_label = put_label->next;
+	}
+
+	compiler->error = SLJIT_ERR_COMPILED;
+	compiler->executable_offset = executable_offset;
+	compiler->executable_size = code_ptr - code;
+
+	code = (sljit_u8*)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
+
+	SLJIT_UPDATE_WX_FLAGS(code, (sljit_u8*)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset), 1);
+	return (void*)code;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
+{
+	switch (feature_type) {
+	case SLJIT_HAS_FPU:
+#ifdef SLJIT_IS_FPU_AVAILABLE
+		return SLJIT_IS_FPU_AVAILABLE;
+#elif (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2)
+		if (cpu_has_sse2 == -1)
+			get_cpu_features();
+		return cpu_has_sse2;
+#else /* SLJIT_DETECT_SSE2 */
+		return 1;
+#endif /* SLJIT_DETECT_SSE2 */
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+	case SLJIT_HAS_VIRTUAL_REGISTERS:
+		return 1;
+#endif
+
+	case SLJIT_HAS_CLZ:
+	case SLJIT_HAS_CMOV:
+		if (cpu_has_cmov == -1)
+			get_cpu_features();
+		return cpu_has_cmov;
+
+	case SLJIT_HAS_PREFETCH:
+		return 1;
+
+	case SLJIT_HAS_SSE2:
+#if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2)
+		if (cpu_has_sse2 == -1)
+			get_cpu_features();
+		return cpu_has_sse2;
+#else
+		return 1;
+#endif
+
+	default:
+		return 0;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+/*  Operators                                                            */
+/* --------------------------------------------------------------------- */
+
+#define BINARY_OPCODE(opcode) (((opcode ## _EAX_i32) << 24) | ((opcode ## _r_rm) << 16) | ((opcode ## _rm_r) << 8) | (opcode))
+
+static sljit_s32 emit_cum_binary(struct sljit_compiler *compiler,
+	sljit_u32 op_types,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w);
+
+static sljit_s32 emit_non_cum_binary(struct sljit_compiler *compiler,
+	sljit_u32 op_types,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w);
+
+static sljit_s32 emit_mov(struct sljit_compiler *compiler,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw);
+
+#define EMIT_MOV(compiler, dst, dstw, src, srcw) \
+	FAIL_IF(emit_mov(compiler, dst, dstw, src, srcw));
+
+static SLJIT_INLINE sljit_s32 emit_sse2_store(struct sljit_compiler *compiler,
+	sljit_s32 single, sljit_s32 dst, sljit_sw dstw, sljit_s32 src);
+
+static SLJIT_INLINE sljit_s32 emit_sse2_load(struct sljit_compiler *compiler,
+	sljit_s32 single, sljit_s32 dst, sljit_s32 src, sljit_sw srcw);
+
+static sljit_s32 emit_cmp_binary(struct sljit_compiler *compiler,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w);
+
+static SLJIT_INLINE sljit_s32 emit_endbranch(struct sljit_compiler *compiler)
+{
+#if (defined SLJIT_CONFIG_X86_CET && SLJIT_CONFIG_X86_CET)
+	/* Emit endbr32/endbr64 when CET is enabled.  */
+	sljit_u8 *inst;
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
+	FAIL_IF(!inst);
+	INC_SIZE(4);
+	*inst++ = 0xf3;
+	*inst++ = 0x0f;
+	*inst++ = 0x1e;
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+	*inst = 0xfb;
+#else
+	*inst = 0xfa;
+#endif
+#else /* !SLJIT_CONFIG_X86_CET */
+	SLJIT_UNUSED_ARG(compiler);
+#endif /* SLJIT_CONFIG_X86_CET */
+	return SLJIT_SUCCESS;
+}
+
+#if (defined SLJIT_CONFIG_X86_CET && SLJIT_CONFIG_X86_CET) && defined (__SHSTK__)
+
+static SLJIT_INLINE sljit_s32 emit_rdssp(struct sljit_compiler *compiler, sljit_s32 reg)
+{
+	sljit_u8 *inst;
+	sljit_s32 size;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	size = 5;
+#else
+	size = 4;
+#endif
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
+	FAIL_IF(!inst);
+	INC_SIZE(size);
+	*inst++ = 0xf3;
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	*inst++ = REX_W | (reg_map[reg] <= 7 ? 0 : REX_B);
+#endif
+	*inst++ = 0x0f;
+	*inst++ = 0x1e;
+	*inst = (0x3 << 6) | (0x1 << 3) | (reg_map[reg] & 0x7);
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 emit_incssp(struct sljit_compiler *compiler, sljit_s32 reg)
+{
+	sljit_u8 *inst;
+	sljit_s32 size;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	size = 5;
+#else
+	size = 4;
+#endif
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
+	FAIL_IF(!inst);
+	INC_SIZE(size);
+	*inst++ = 0xf3;
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	*inst++ = REX_W | (reg_map[reg] <= 7 ? 0 : REX_B);
+#endif
+	*inst++ = 0x0f;
+	*inst++ = 0xae;
+	*inst = (0x3 << 6) | (0x5 << 3) | (reg_map[reg] & 0x7);
+	return SLJIT_SUCCESS;
+}
+
+#endif /* SLJIT_CONFIG_X86_CET && __SHSTK__ */
+
+static SLJIT_INLINE sljit_s32 cpu_has_shadow_stack(void)
+{
+#if (defined SLJIT_CONFIG_X86_CET && SLJIT_CONFIG_X86_CET) && defined (__SHSTK__)
+	return _get_ssp() != 0;
+#else /* !SLJIT_CONFIG_X86_CET || !__SHSTK__ */
+	return 0;
+#endif /* SLJIT_CONFIG_X86_CET && __SHSTK__ */
+}
+
+static SLJIT_INLINE sljit_s32 adjust_shadow_stack(struct sljit_compiler *compiler,
+	sljit_s32 src, sljit_sw srcw, sljit_s32 base, sljit_sw disp)
+{
+#if (defined SLJIT_CONFIG_X86_CET && SLJIT_CONFIG_X86_CET) && defined (__SHSTK__)
+	sljit_u8 *inst, *jz_after_cmp_inst;
+	sljit_uw size_jz_after_cmp_inst;
+
+	sljit_uw size_before_rdssp_inst = compiler->size;
+
+	/* Generate "RDSSP TMP_REG1". */
+	FAIL_IF(emit_rdssp(compiler, TMP_REG1));
+
+	/* Load return address on shadow stack into TMP_REG1. */
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+	SLJIT_ASSERT(reg_map[TMP_REG1] == 5);
+
+	/* Hand code unsupported "mov 0x0(%ebp),%ebp". */
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + 3);
+	FAIL_IF(!inst);
+	INC_SIZE(3);
+	*inst++ = 0x8b;
+	*inst++ = 0x6d;
+	*inst = 0;
+#else /* !SLJIT_CONFIG_X86_32 */
+	EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(TMP_REG1), 0);
+#endif /* SLJIT_CONFIG_X86_32 */
+
+	if (src == SLJIT_UNUSED) {
+		/* Return address is on stack.  */
+		src = SLJIT_MEM1(base);
+		srcw = disp;
+	}
+
+	/* Compare return address against TMP_REG1. */
+	FAIL_IF(emit_cmp_binary (compiler, TMP_REG1, 0, src, srcw));
+
+	/* Generate JZ to skip shadow stack ajdustment when shadow
+	   stack matches normal stack. */
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+	FAIL_IF(!inst);
+	INC_SIZE(2);
+	*inst++ = get_jump_code(SLJIT_EQUAL) - 0x10;
+	size_jz_after_cmp_inst = compiler->size;
+	jz_after_cmp_inst = inst;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	/* REX_W is not necessary. */
+	compiler->mode32 = 1;
+#endif
+	/* Load 1 into TMP_REG1. */
+	EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, 1);
+
+	/* Generate "INCSSP TMP_REG1". */
+	FAIL_IF(emit_incssp(compiler, TMP_REG1));
+
+	/* Jump back to "RDSSP TMP_REG1" to check shadow stack again. */
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+	FAIL_IF(!inst);
+	INC_SIZE(2);
+	*inst++ = JMP_i8;
+	*inst = size_before_rdssp_inst - compiler->size;
+
+	*jz_after_cmp_inst = compiler->size - size_jz_after_cmp_inst;
+#else /* !SLJIT_CONFIG_X86_CET || !__SHSTK__ */
+	SLJIT_UNUSED_ARG(compiler);
+	SLJIT_UNUSED_ARG(src);
+	SLJIT_UNUSED_ARG(srcw);
+	SLJIT_UNUSED_ARG(base);
+	SLJIT_UNUSED_ARG(disp);
+#endif /* SLJIT_CONFIG_X86_CET && __SHSTK__ */
+	return SLJIT_SUCCESS;
+}
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+#include "sljitNativeX86_32.c"
+#else
+#include "sljitNativeX86_64.c"
+#endif
+
+static sljit_s32 emit_mov(struct sljit_compiler *compiler,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_u8* inst;
+
+	SLJIT_ASSERT(dst != SLJIT_UNUSED);
+
+	if (FAST_IS_REG(src)) {
+		inst = emit_x86_instruction(compiler, 1, src, 0, dst, dstw);
+		FAIL_IF(!inst);
+		*inst = MOV_rm_r;
+		return SLJIT_SUCCESS;
+	}
+	if (src & SLJIT_IMM) {
+		if (FAST_IS_REG(dst)) {
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+			return emit_do_imm(compiler, MOV_r_i32 + reg_map[dst], srcw);
+#else
+			if (!compiler->mode32) {
+				if (NOT_HALFWORD(srcw))
+					return emit_load_imm64(compiler, dst, srcw);
+			}
+			else
+				return emit_do_imm32(compiler, (reg_map[dst] >= 8) ? REX_B : 0, MOV_r_i32 + reg_lmap[dst], srcw);
+#endif
+		}
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+		if (!compiler->mode32 && NOT_HALFWORD(srcw)) {
+			/* Immediate to memory move. Only SLJIT_MOV operation copies
+			   an immediate directly into memory so TMP_REG1 can be used. */
+			FAIL_IF(emit_load_imm64(compiler, TMP_REG1, srcw));
+			inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, dst, dstw);
+			FAIL_IF(!inst);
+			*inst = MOV_rm_r;
+			return SLJIT_SUCCESS;
+		}
+#endif
+		inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, srcw, dst, dstw);
+		FAIL_IF(!inst);
+		*inst = MOV_rm_i32;
+		return SLJIT_SUCCESS;
+	}
+	if (FAST_IS_REG(dst)) {
+		inst = emit_x86_instruction(compiler, 1, dst, 0, src, srcw);
+		FAIL_IF(!inst);
+		*inst = MOV_r_rm;
+		return SLJIT_SUCCESS;
+	}
+
+	/* Memory to memory move. Only SLJIT_MOV operation copies
+	   data from memory to memory so TMP_REG1 can be used. */
+	inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src, srcw);
+	FAIL_IF(!inst);
+	*inst = MOV_r_rm;
+	inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, dst, dstw);
+	FAIL_IF(!inst);
+	*inst = MOV_rm_r;
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
+{
+	sljit_u8 *inst;
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	sljit_s32 size;
+#endif
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op0(compiler, op));
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_BREAKPOINT:
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
+		FAIL_IF(!inst);
+		INC_SIZE(1);
+		*inst = INT3;
+		break;
+	case SLJIT_NOP:
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
+		FAIL_IF(!inst);
+		INC_SIZE(1);
+		*inst = NOP;
+		break;
+	case SLJIT_LMUL_UW:
+	case SLJIT_LMUL_SW:
+	case SLJIT_DIVMOD_UW:
+	case SLJIT_DIVMOD_SW:
+	case SLJIT_DIV_UW:
+	case SLJIT_DIV_SW:
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+#ifdef _WIN64
+		SLJIT_ASSERT(
+			reg_map[SLJIT_R0] == 0
+			&& reg_map[SLJIT_R1] == 2
+			&& reg_map[TMP_REG1] > 7);
+#else
+		SLJIT_ASSERT(
+			reg_map[SLJIT_R0] == 0
+			&& reg_map[SLJIT_R1] < 7
+			&& reg_map[TMP_REG1] == 2);
+#endif
+		compiler->mode32 = op & SLJIT_I32_OP;
+#endif
+		SLJIT_COMPILE_ASSERT((SLJIT_DIVMOD_UW & 0x2) == 0 && SLJIT_DIV_UW - 0x2 == SLJIT_DIVMOD_UW, bad_div_opcode_assignments);
+
+		op = GET_OPCODE(op);
+		if ((op | 0x2) == SLJIT_DIV_UW) {
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64)
+			EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R1, 0);
+			inst = emit_x86_instruction(compiler, 1, SLJIT_R1, 0, SLJIT_R1, 0);
+#else
+			inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, TMP_REG1, 0);
+#endif
+			FAIL_IF(!inst);
+			*inst = XOR_r_rm;
+		}
+
+		if ((op | 0x2) == SLJIT_DIV_SW) {
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64)
+			EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_R1, 0);
+#endif
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
+			FAIL_IF(!inst);
+			INC_SIZE(1);
+			*inst = CDQ;
+#else
+			if (compiler->mode32) {
+				inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
+				FAIL_IF(!inst);
+				INC_SIZE(1);
+				*inst = CDQ;
+			} else {
+				inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+				FAIL_IF(!inst);
+				INC_SIZE(2);
+				*inst++ = REX_W;
+				*inst = CDQ;
+			}
+#endif
+		}
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+		FAIL_IF(!inst);
+		INC_SIZE(2);
+		*inst++ = GROUP_F7;
+		*inst = MOD_REG | ((op >= SLJIT_DIVMOD_UW) ? reg_map[TMP_REG1] : reg_map[SLJIT_R1]);
+#else
+#ifdef _WIN64
+		size = (!compiler->mode32 || op >= SLJIT_DIVMOD_UW) ? 3 : 2;
+#else
+		size = (!compiler->mode32) ? 3 : 2;
+#endif
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
+		FAIL_IF(!inst);
+		INC_SIZE(size);
+#ifdef _WIN64
+		if (!compiler->mode32)
+			*inst++ = REX_W | ((op >= SLJIT_DIVMOD_UW) ? REX_B : 0);
+		else if (op >= SLJIT_DIVMOD_UW)
+			*inst++ = REX_B;
+		*inst++ = GROUP_F7;
+		*inst = MOD_REG | ((op >= SLJIT_DIVMOD_UW) ? reg_lmap[TMP_REG1] : reg_lmap[SLJIT_R1]);
+#else
+		if (!compiler->mode32)
+			*inst++ = REX_W;
+		*inst++ = GROUP_F7;
+		*inst = MOD_REG | reg_map[SLJIT_R1];
+#endif
+#endif
+		switch (op) {
+		case SLJIT_LMUL_UW:
+			*inst |= MUL;
+			break;
+		case SLJIT_LMUL_SW:
+			*inst |= IMUL;
+			break;
+		case SLJIT_DIVMOD_UW:
+		case SLJIT_DIV_UW:
+			*inst |= DIV;
+			break;
+		case SLJIT_DIVMOD_SW:
+		case SLJIT_DIV_SW:
+			*inst |= IDIV;
+			break;
+		}
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && !defined(_WIN64)
+		if (op <= SLJIT_DIVMOD_SW)
+			EMIT_MOV(compiler, SLJIT_R1, 0, TMP_REG1, 0);
+#else
+		if (op >= SLJIT_DIV_UW)
+			EMIT_MOV(compiler, SLJIT_R1, 0, TMP_REG1, 0);
+#endif
+		break;
+	case SLJIT_ENDBR:
+		return emit_endbranch(compiler);
+	case SLJIT_SKIP_FRAMES_BEFORE_RETURN:
+		return skip_frames_before_return(compiler);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+#define ENCODE_PREFIX(prefix) \
+	do { \
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); \
+		FAIL_IF(!inst); \
+		INC_SIZE(1); \
+		*inst = (prefix); \
+	} while (0)
+
+static sljit_s32 emit_mov_byte(struct sljit_compiler *compiler, sljit_s32 sign,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_u8* inst;
+	sljit_s32 dst_r;
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+	sljit_s32 work_r;
+#endif
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	compiler->mode32 = 0;
+#endif
+
+	if (src & SLJIT_IMM) {
+		if (FAST_IS_REG(dst)) {
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+			return emit_do_imm(compiler, MOV_r_i32 + reg_map[dst], srcw);
+#else
+			inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, srcw, dst, 0);
+			FAIL_IF(!inst);
+			*inst = MOV_rm_i32;
+			return SLJIT_SUCCESS;
+#endif
+		}
+		inst = emit_x86_instruction(compiler, 1 | EX86_BYTE_ARG | EX86_NO_REXW, SLJIT_IMM, srcw, dst, dstw);
+		FAIL_IF(!inst);
+		*inst = MOV_rm8_i8;
+		return SLJIT_SUCCESS;
+	}
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+
+	if ((dst & SLJIT_MEM) && FAST_IS_REG(src)) {
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+		if (reg_map[src] >= 4) {
+			SLJIT_ASSERT(dst_r == TMP_REG1);
+			EMIT_MOV(compiler, TMP_REG1, 0, src, 0);
+		} else
+			dst_r = src;
+#else
+		dst_r = src;
+#endif
+	}
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+	else if (FAST_IS_REG(src) && reg_map[src] >= 4) {
+		/* src, dst are registers. */
+		SLJIT_ASSERT(SLOW_IS_REG(dst));
+		if (reg_map[dst] < 4) {
+			if (dst != src)
+				EMIT_MOV(compiler, dst, 0, src, 0);
+			inst = emit_x86_instruction(compiler, 2, dst, 0, dst, 0);
+			FAIL_IF(!inst);
+			*inst++ = GROUP_0F;
+			*inst = sign ? MOVSX_r_rm8 : MOVZX_r_rm8;
+		}
+		else {
+			if (dst != src)
+				EMIT_MOV(compiler, dst, 0, src, 0);
+			if (sign) {
+				/* shl reg, 24 */
+				inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 24, dst, 0);
+				FAIL_IF(!inst);
+				*inst |= SHL;
+				/* sar reg, 24 */
+				inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 24, dst, 0);
+				FAIL_IF(!inst);
+				*inst |= SAR;
+			}
+			else {
+				inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, 0xff, dst, 0);
+				FAIL_IF(!inst);
+				*(inst + 1) |= AND;
+			}
+		}
+		return SLJIT_SUCCESS;
+	}
+#endif
+	else {
+		/* src can be memory addr or reg_map[src] < 4 on x86_32 architectures. */
+		inst = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw);
+		FAIL_IF(!inst);
+		*inst++ = GROUP_0F;
+		*inst = sign ? MOVSX_r_rm8 : MOVZX_r_rm8;
+	}
+
+	if (dst & SLJIT_MEM) {
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+		if (dst_r == TMP_REG1) {
+			/* Find a non-used register, whose reg_map[src] < 4. */
+			if ((dst & REG_MASK) == SLJIT_R0) {
+				if ((dst & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_R1))
+					work_r = SLJIT_R2;
+				else
+					work_r = SLJIT_R1;
+			}
+			else {
+				if ((dst & OFFS_REG_MASK) != TO_OFFS_REG(SLJIT_R0))
+					work_r = SLJIT_R0;
+				else if ((dst & REG_MASK) == SLJIT_R1)
+					work_r = SLJIT_R2;
+				else
+					work_r = SLJIT_R1;
+			}
+
+			if (work_r == SLJIT_R0) {
+				ENCODE_PREFIX(XCHG_EAX_r + reg_map[TMP_REG1]);
+			}
+			else {
+				inst = emit_x86_instruction(compiler, 1, work_r, 0, dst_r, 0);
+				FAIL_IF(!inst);
+				*inst = XCHG_r_rm;
+			}
+
+			inst = emit_x86_instruction(compiler, 1, work_r, 0, dst, dstw);
+			FAIL_IF(!inst);
+			*inst = MOV_rm8_r8;
+
+			if (work_r == SLJIT_R0) {
+				ENCODE_PREFIX(XCHG_EAX_r + reg_map[TMP_REG1]);
+			}
+			else {
+				inst = emit_x86_instruction(compiler, 1, work_r, 0, dst_r, 0);
+				FAIL_IF(!inst);
+				*inst = XCHG_r_rm;
+			}
+		}
+		else {
+			inst = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw);
+			FAIL_IF(!inst);
+			*inst = MOV_rm8_r8;
+		}
+#else
+		inst = emit_x86_instruction(compiler, 1 | EX86_REX | EX86_NO_REXW, dst_r, 0, dst, dstw);
+		FAIL_IF(!inst);
+		*inst = MOV_rm8_r8;
+#endif
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_prefetch(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_u8* inst;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	compiler->mode32 = 1;
+#endif
+
+	inst = emit_x86_instruction(compiler, 2, 0, 0, src, srcw);
+	FAIL_IF(!inst);
+	*inst++ = GROUP_0F;
+	*inst++ = PREFETCH;
+
+	if (op == SLJIT_PREFETCH_L1)
+		*inst |= (1 << 3);
+	else if (op == SLJIT_PREFETCH_L2)
+		*inst |= (2 << 3);
+	else if (op == SLJIT_PREFETCH_L3)
+		*inst |= (3 << 3);
+
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_mov_half(struct sljit_compiler *compiler, sljit_s32 sign,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_u8* inst;
+	sljit_s32 dst_r;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	compiler->mode32 = 0;
+#endif
+
+	if (src & SLJIT_IMM) {
+		if (FAST_IS_REG(dst)) {
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+			return emit_do_imm(compiler, MOV_r_i32 + reg_map[dst], srcw);
+#else
+			inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, srcw, dst, 0);
+			FAIL_IF(!inst);
+			*inst = MOV_rm_i32;
+			return SLJIT_SUCCESS;
+#endif
+		}
+		inst = emit_x86_instruction(compiler, 1 | EX86_HALF_ARG | EX86_NO_REXW | EX86_PREF_66, SLJIT_IMM, srcw, dst, dstw);
+		FAIL_IF(!inst);
+		*inst = MOV_rm_i32;
+		return SLJIT_SUCCESS;
+	}
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+
+	if ((dst & SLJIT_MEM) && FAST_IS_REG(src))
+		dst_r = src;
+	else {
+		inst = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw);
+		FAIL_IF(!inst);
+		*inst++ = GROUP_0F;
+		*inst = sign ? MOVSX_r_rm16 : MOVZX_r_rm16;
+	}
+
+	if (dst & SLJIT_MEM) {
+		inst = emit_x86_instruction(compiler, 1 | EX86_NO_REXW | EX86_PREF_66, dst_r, 0, dst, dstw);
+		FAIL_IF(!inst);
+		*inst = MOV_rm_r;
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_unary(struct sljit_compiler *compiler, sljit_u8 opcode,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_u8* inst;
+
+	if (dst == src && dstw == srcw) {
+		/* Same input and output */
+		inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
+		FAIL_IF(!inst);
+		*inst++ = GROUP_F7;
+		*inst |= opcode;
+		return SLJIT_SUCCESS;
+	}
+
+	if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED))
+		dst = TMP_REG1;
+
+	if (FAST_IS_REG(dst)) {
+		EMIT_MOV(compiler, dst, 0, src, srcw);
+		inst = emit_x86_instruction(compiler, 1, 0, 0, dst, 0);
+		FAIL_IF(!inst);
+		*inst++ = GROUP_F7;
+		*inst |= opcode;
+		return SLJIT_SUCCESS;
+	}
+
+	EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
+	inst = emit_x86_instruction(compiler, 1, 0, 0, TMP_REG1, 0);
+	FAIL_IF(!inst);
+	*inst++ = GROUP_F7;
+	*inst |= opcode;
+	EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0);
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_not_with_flags(struct sljit_compiler *compiler,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_u8* inst;
+
+	if (dst == SLJIT_UNUSED)
+		dst = TMP_REG1;
+
+	if (FAST_IS_REG(dst)) {
+		EMIT_MOV(compiler, dst, 0, src, srcw);
+		inst = emit_x86_instruction(compiler, 1, 0, 0, dst, 0);
+		FAIL_IF(!inst);
+		*inst++ = GROUP_F7;
+		*inst |= NOT_rm;
+		inst = emit_x86_instruction(compiler, 1, dst, 0, dst, 0);
+		FAIL_IF(!inst);
+		*inst = OR_r_rm;
+		return SLJIT_SUCCESS;
+	}
+
+	EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
+	inst = emit_x86_instruction(compiler, 1, 0, 0, TMP_REG1, 0);
+	FAIL_IF(!inst);
+	*inst++ = GROUP_F7;
+	*inst |= NOT_rm;
+	inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, TMP_REG1, 0);
+	FAIL_IF(!inst);
+	*inst = OR_r_rm;
+	EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0);
+	return SLJIT_SUCCESS;
+}
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+static const sljit_sw emit_clz_arg = 32 + 31;
+#endif
+
+static sljit_s32 emit_clz(struct sljit_compiler *compiler, sljit_s32 op_flags,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_u8* inst;
+	sljit_s32 dst_r;
+
+	SLJIT_UNUSED_ARG(op_flags);
+
+	if (cpu_has_cmov == -1)
+		get_cpu_features();
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+
+	inst = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw);
+	FAIL_IF(!inst);
+	*inst++ = GROUP_0F;
+	*inst = BSR_r_rm;
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+	if (cpu_has_cmov) {
+		if (dst_r != TMP_REG1) {
+			EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, 32 + 31);
+			inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG1, 0);
+		}
+		else
+			inst = emit_x86_instruction(compiler, 2, dst_r, 0, SLJIT_MEM0(), (sljit_sw)&emit_clz_arg);
+
+		FAIL_IF(!inst);
+		*inst++ = GROUP_0F;
+		*inst = CMOVE_r_rm;
+	}
+	else
+		FAIL_IF(sljit_emit_cmov_generic(compiler, SLJIT_EQUAL, dst_r, SLJIT_IMM, 32 + 31));
+
+	inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, 31, dst_r, 0);
+#else
+	if (cpu_has_cmov) {
+		EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_IMM, !(op_flags & SLJIT_I32_OP) ? (64 + 63) : (32 + 31));
+
+		inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG2, 0);
+		FAIL_IF(!inst);
+		*inst++ = GROUP_0F;
+		*inst = CMOVE_r_rm;
+	}
+	else
+		FAIL_IF(sljit_emit_cmov_generic(compiler, SLJIT_EQUAL, dst_r, SLJIT_IMM, !(op_flags & SLJIT_I32_OP) ? (64 + 63) : (32 + 31)));
+
+	inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, !(op_flags & SLJIT_I32_OP) ? 63 : 31, dst_r, 0);
+#endif
+
+	FAIL_IF(!inst);
+	*(inst + 1) |= XOR;
+
+	if (dst & SLJIT_MEM)
+		EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 op_flags = GET_ALL_FLAGS(op);
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+	sljit_s32 dst_is_ereg = 0;
+#endif
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	CHECK_EXTRA_REGS(dst, dstw, dst_is_ereg = 1);
+	CHECK_EXTRA_REGS(src, srcw, (void)0);
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	compiler->mode32 = op_flags & SLJIT_I32_OP;
+#endif
+
+	op = GET_OPCODE(op);
+
+	if (op >= SLJIT_MOV && op <= SLJIT_MOV_P) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+		compiler->mode32 = 0;
+#endif
+
+		if (FAST_IS_REG(src) && src == dst) {
+			if (!TYPE_CAST_NEEDED(op))
+				return SLJIT_SUCCESS;
+		}
+
+		if (op_flags & SLJIT_I32_OP) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+			if (src & SLJIT_MEM) {
+				if (op == SLJIT_MOV_S32)
+					op = SLJIT_MOV_U32;
+			}
+			else if (src & SLJIT_IMM) {
+				if (op == SLJIT_MOV_U32)
+					op = SLJIT_MOV_S32;
+			}
+#endif
+		}
+
+		if (src & SLJIT_IMM) {
+			switch (op) {
+			case SLJIT_MOV_U8:
+				srcw = (sljit_u8)srcw;
+				break;
+			case SLJIT_MOV_S8:
+				srcw = (sljit_s8)srcw;
+				break;
+			case SLJIT_MOV_U16:
+				srcw = (sljit_u16)srcw;
+				break;
+			case SLJIT_MOV_S16:
+				srcw = (sljit_s16)srcw;
+				break;
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+			case SLJIT_MOV_U32:
+				srcw = (sljit_u32)srcw;
+				break;
+			case SLJIT_MOV_S32:
+				srcw = (sljit_s32)srcw;
+				break;
+#endif
+			}
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+			if (SLJIT_UNLIKELY(dst_is_ereg))
+				return emit_mov(compiler, dst, dstw, src, srcw);
+#endif
+		}
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+		if (SLJIT_UNLIKELY(dst_is_ereg) && (!(op == SLJIT_MOV || op == SLJIT_MOV_U32 || op == SLJIT_MOV_S32 || op == SLJIT_MOV_P) || (src & SLJIT_MEM))) {
+			SLJIT_ASSERT(dst == SLJIT_MEM1(SLJIT_SP));
+			dst = TMP_REG1;
+		}
+#endif
+
+		switch (op) {
+		case SLJIT_MOV:
+		case SLJIT_MOV_P:
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+		case SLJIT_MOV_U32:
+		case SLJIT_MOV_S32:
+#endif
+			FAIL_IF(emit_mov(compiler, dst, dstw, src, srcw));
+			break;
+		case SLJIT_MOV_U8:
+			FAIL_IF(emit_mov_byte(compiler, 0, dst, dstw, src, srcw));
+			break;
+		case SLJIT_MOV_S8:
+			FAIL_IF(emit_mov_byte(compiler, 1, dst, dstw, src, srcw));
+			break;
+		case SLJIT_MOV_U16:
+			FAIL_IF(emit_mov_half(compiler, 0, dst, dstw, src, srcw));
+			break;
+		case SLJIT_MOV_S16:
+			FAIL_IF(emit_mov_half(compiler, 1, dst, dstw, src, srcw));
+			break;
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+		case SLJIT_MOV_U32:
+			FAIL_IF(emit_mov_int(compiler, 0, dst, dstw, src, srcw));
+			break;
+		case SLJIT_MOV_S32:
+			FAIL_IF(emit_mov_int(compiler, 1, dst, dstw, src, srcw));
+			break;
+#endif
+		}
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+		if (SLJIT_UNLIKELY(dst_is_ereg) && dst == TMP_REG1)
+			return emit_mov(compiler, SLJIT_MEM1(SLJIT_SP), dstw, TMP_REG1, 0);
+#endif
+		return SLJIT_SUCCESS;
+	}
+
+	switch (op) {
+	case SLJIT_NOT:
+		if (SLJIT_UNLIKELY(op_flags & SLJIT_SET_Z))
+			return emit_not_with_flags(compiler, dst, dstw, src, srcw);
+		return emit_unary(compiler, NOT_rm, dst, dstw, src, srcw);
+
+	case SLJIT_NEG:
+		return emit_unary(compiler, NEG_rm, dst, dstw, src, srcw);
+
+	case SLJIT_CLZ:
+		return emit_clz(compiler, op_flags, dst, dstw, src, srcw);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+
+#define BINARY_IMM(op_imm, op_mr, immw, arg, argw) \
+	if (IS_HALFWORD(immw) || compiler->mode32) { \
+		inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, immw, arg, argw); \
+		FAIL_IF(!inst); \
+		*(inst + 1) |= (op_imm); \
+	} \
+	else { \
+		FAIL_IF(emit_load_imm64(compiler, (arg == TMP_REG1) ? TMP_REG2 : TMP_REG1, immw)); \
+		inst = emit_x86_instruction(compiler, 1, (arg == TMP_REG1) ? TMP_REG2 : TMP_REG1, 0, arg, argw); \
+		FAIL_IF(!inst); \
+		*inst = (op_mr); \
+	}
+
+#define BINARY_EAX_IMM(op_eax_imm, immw) \
+	FAIL_IF(emit_do_imm32(compiler, (!compiler->mode32) ? REX_W : 0, (op_eax_imm), immw))
+
+#else
+
+#define BINARY_IMM(op_imm, op_mr, immw, arg, argw) \
+	inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, immw, arg, argw); \
+	FAIL_IF(!inst); \
+	*(inst + 1) |= (op_imm);
+
+#define BINARY_EAX_IMM(op_eax_imm, immw) \
+	FAIL_IF(emit_do_imm(compiler, (op_eax_imm), immw))
+
+#endif
+
+static sljit_s32 emit_cum_binary(struct sljit_compiler *compiler,
+	sljit_u32 op_types,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_u8* inst;
+	sljit_u8 op_eax_imm = (op_types >> 24);
+	sljit_u8 op_rm = (op_types >> 16) & 0xff;
+	sljit_u8 op_mr = (op_types >> 8) & 0xff;
+	sljit_u8 op_imm = op_types & 0xff;
+
+	if (dst == SLJIT_UNUSED) {
+		EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+		if (src2 & SLJIT_IMM) {
+			BINARY_IMM(op_imm, op_mr, src2w, TMP_REG1, 0);
+		}
+		else {
+			inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src2, src2w);
+			FAIL_IF(!inst);
+			*inst = op_rm;
+		}
+		return SLJIT_SUCCESS;
+	}
+
+	if (dst == src1 && dstw == src1w) {
+		if (src2 & SLJIT_IMM) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+			if ((dst == SLJIT_R0) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) {
+#else
+			if ((dst == SLJIT_R0) && (src2w > 127 || src2w < -128)) {
+#endif
+				BINARY_EAX_IMM(op_eax_imm, src2w);
+			}
+			else {
+				BINARY_IMM(op_imm, op_mr, src2w, dst, dstw);
+			}
+		}
+		else if (FAST_IS_REG(dst)) {
+			inst = emit_x86_instruction(compiler, 1, dst, dstw, src2, src2w);
+			FAIL_IF(!inst);
+			*inst = op_rm;
+		}
+		else if (FAST_IS_REG(src2)) {
+			/* Special exception for sljit_emit_op_flags. */
+			inst = emit_x86_instruction(compiler, 1, src2, src2w, dst, dstw);
+			FAIL_IF(!inst);
+			*inst = op_mr;
+		}
+		else {
+			EMIT_MOV(compiler, TMP_REG1, 0, src2, src2w);
+			inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, dst, dstw);
+			FAIL_IF(!inst);
+			*inst = op_mr;
+		}
+		return SLJIT_SUCCESS;
+	}
+
+	/* Only for cumulative operations. */
+	if (dst == src2 && dstw == src2w) {
+		if (src1 & SLJIT_IMM) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+			if ((dst == SLJIT_R0) && (src1w > 127 || src1w < -128) && (compiler->mode32 || IS_HALFWORD(src1w))) {
+#else
+			if ((dst == SLJIT_R0) && (src1w > 127 || src1w < -128)) {
+#endif
+				BINARY_EAX_IMM(op_eax_imm, src1w);
+			}
+			else {
+				BINARY_IMM(op_imm, op_mr, src1w, dst, dstw);
+			}
+		}
+		else if (FAST_IS_REG(dst)) {
+			inst = emit_x86_instruction(compiler, 1, dst, dstw, src1, src1w);
+			FAIL_IF(!inst);
+			*inst = op_rm;
+		}
+		else if (FAST_IS_REG(src1)) {
+			inst = emit_x86_instruction(compiler, 1, src1, src1w, dst, dstw);
+			FAIL_IF(!inst);
+			*inst = op_mr;
+		}
+		else {
+			EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+			inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, dst, dstw);
+			FAIL_IF(!inst);
+			*inst = op_mr;
+		}
+		return SLJIT_SUCCESS;
+	}
+
+	/* General version. */
+	if (FAST_IS_REG(dst)) {
+		EMIT_MOV(compiler, dst, 0, src1, src1w);
+		if (src2 & SLJIT_IMM) {
+			BINARY_IMM(op_imm, op_mr, src2w, dst, 0);
+		}
+		else {
+			inst = emit_x86_instruction(compiler, 1, dst, 0, src2, src2w);
+			FAIL_IF(!inst);
+			*inst = op_rm;
+		}
+	}
+	else {
+		/* This version requires less memory writing. */
+		EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+		if (src2 & SLJIT_IMM) {
+			BINARY_IMM(op_imm, op_mr, src2w, TMP_REG1, 0);
+		}
+		else {
+			inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src2, src2w);
+			FAIL_IF(!inst);
+			*inst = op_rm;
+		}
+		EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_non_cum_binary(struct sljit_compiler *compiler,
+	sljit_u32 op_types,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_u8* inst;
+	sljit_u8 op_eax_imm = (op_types >> 24);
+	sljit_u8 op_rm = (op_types >> 16) & 0xff;
+	sljit_u8 op_mr = (op_types >> 8) & 0xff;
+	sljit_u8 op_imm = op_types & 0xff;
+
+	if (dst == SLJIT_UNUSED) {
+		EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+		if (src2 & SLJIT_IMM) {
+			BINARY_IMM(op_imm, op_mr, src2w, TMP_REG1, 0);
+		}
+		else {
+			inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src2, src2w);
+			FAIL_IF(!inst);
+			*inst = op_rm;
+		}
+		return SLJIT_SUCCESS;
+	}
+
+	if (dst == src1 && dstw == src1w) {
+		if (src2 & SLJIT_IMM) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+			if ((dst == SLJIT_R0) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) {
+#else
+			if ((dst == SLJIT_R0) && (src2w > 127 || src2w < -128)) {
+#endif
+				BINARY_EAX_IMM(op_eax_imm, src2w);
+			}
+			else {
+				BINARY_IMM(op_imm, op_mr, src2w, dst, dstw);
+			}
+		}
+		else if (FAST_IS_REG(dst)) {
+			inst = emit_x86_instruction(compiler, 1, dst, dstw, src2, src2w);
+			FAIL_IF(!inst);
+			*inst = op_rm;
+		}
+		else if (FAST_IS_REG(src2)) {
+			inst = emit_x86_instruction(compiler, 1, src2, src2w, dst, dstw);
+			FAIL_IF(!inst);
+			*inst = op_mr;
+		}
+		else {
+			EMIT_MOV(compiler, TMP_REG1, 0, src2, src2w);
+			inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, dst, dstw);
+			FAIL_IF(!inst);
+			*inst = op_mr;
+		}
+		return SLJIT_SUCCESS;
+	}
+
+	/* General version. */
+	if (FAST_IS_REG(dst) && dst != src2) {
+		EMIT_MOV(compiler, dst, 0, src1, src1w);
+		if (src2 & SLJIT_IMM) {
+			BINARY_IMM(op_imm, op_mr, src2w, dst, 0);
+		}
+		else {
+			inst = emit_x86_instruction(compiler, 1, dst, 0, src2, src2w);
+			FAIL_IF(!inst);
+			*inst = op_rm;
+		}
+	}
+	else {
+		/* This version requires less memory writing. */
+		EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+		if (src2 & SLJIT_IMM) {
+			BINARY_IMM(op_imm, op_mr, src2w, TMP_REG1, 0);
+		}
+		else {
+			inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src2, src2w);
+			FAIL_IF(!inst);
+			*inst = op_rm;
+		}
+		EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_mul(struct sljit_compiler *compiler,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_u8* inst;
+	sljit_s32 dst_r;
+
+	dst_r = SLOW_IS_REG(dst) ? dst : TMP_REG1;
+
+	/* Register destination. */
+	if (dst_r == src1 && !(src2 & SLJIT_IMM)) {
+		inst = emit_x86_instruction(compiler, 2, dst_r, 0, src2, src2w);
+		FAIL_IF(!inst);
+		*inst++ = GROUP_0F;
+		*inst = IMUL_r_rm;
+	}
+	else if (dst_r == src2 && !(src1 & SLJIT_IMM)) {
+		inst = emit_x86_instruction(compiler, 2, dst_r, 0, src1, src1w);
+		FAIL_IF(!inst);
+		*inst++ = GROUP_0F;
+		*inst = IMUL_r_rm;
+	}
+	else if (src1 & SLJIT_IMM) {
+		if (src2 & SLJIT_IMM) {
+			EMIT_MOV(compiler, dst_r, 0, SLJIT_IMM, src2w);
+			src2 = dst_r;
+			src2w = 0;
+		}
+
+		if (src1w <= 127 && src1w >= -128) {
+			inst = emit_x86_instruction(compiler, 1, dst_r, 0, src2, src2w);
+			FAIL_IF(!inst);
+			*inst = IMUL_r_rm_i8;
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
+			FAIL_IF(!inst);
+			INC_SIZE(1);
+			*inst = (sljit_s8)src1w;
+		}
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+		else {
+			inst = emit_x86_instruction(compiler, 1, dst_r, 0, src2, src2w);
+			FAIL_IF(!inst);
+			*inst = IMUL_r_rm_i32;
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
+			FAIL_IF(!inst);
+			INC_SIZE(4);
+			sljit_unaligned_store_sw(inst, src1w);
+		}
+#else
+		else if (IS_HALFWORD(src1w)) {
+			inst = emit_x86_instruction(compiler, 1, dst_r, 0, src2, src2w);
+			FAIL_IF(!inst);
+			*inst = IMUL_r_rm_i32;
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
+			FAIL_IF(!inst);
+			INC_SIZE(4);
+			sljit_unaligned_store_s32(inst, (sljit_s32)src1w);
+		}
+		else {
+			if (dst_r != src2)
+				EMIT_MOV(compiler, dst_r, 0, src2, src2w);
+			FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src1w));
+			inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG2, 0);
+			FAIL_IF(!inst);
+			*inst++ = GROUP_0F;
+			*inst = IMUL_r_rm;
+		}
+#endif
+	}
+	else if (src2 & SLJIT_IMM) {
+		/* Note: src1 is NOT immediate. */
+
+		if (src2w <= 127 && src2w >= -128) {
+			inst = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w);
+			FAIL_IF(!inst);
+			*inst = IMUL_r_rm_i8;
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
+			FAIL_IF(!inst);
+			INC_SIZE(1);
+			*inst = (sljit_s8)src2w;
+		}
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+		else {
+			inst = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w);
+			FAIL_IF(!inst);
+			*inst = IMUL_r_rm_i32;
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
+			FAIL_IF(!inst);
+			INC_SIZE(4);
+			sljit_unaligned_store_sw(inst, src2w);
+		}
+#else
+		else if (IS_HALFWORD(src2w)) {
+			inst = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w);
+			FAIL_IF(!inst);
+			*inst = IMUL_r_rm_i32;
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
+			FAIL_IF(!inst);
+			INC_SIZE(4);
+			sljit_unaligned_store_s32(inst, (sljit_s32)src2w);
+		}
+		else {
+			if (dst_r != src1)
+				EMIT_MOV(compiler, dst_r, 0, src1, src1w);
+			FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src2w));
+			inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG2, 0);
+			FAIL_IF(!inst);
+			*inst++ = GROUP_0F;
+			*inst = IMUL_r_rm;
+		}
+#endif
+	}
+	else {
+		/* Neither argument is immediate. */
+		if (ADDRESSING_DEPENDS_ON(src2, dst_r))
+			dst_r = TMP_REG1;
+		EMIT_MOV(compiler, dst_r, 0, src1, src1w);
+		inst = emit_x86_instruction(compiler, 2, dst_r, 0, src2, src2w);
+		FAIL_IF(!inst);
+		*inst++ = GROUP_0F;
+		*inst = IMUL_r_rm;
+	}
+
+	if (dst & SLJIT_MEM)
+		EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0);
+
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_lea_binary(struct sljit_compiler *compiler,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_u8* inst;
+	sljit_s32 dst_r, done = 0;
+
+	/* These cases better be left to handled by normal way. */
+	if (dst == src1 && dstw == src1w)
+		return SLJIT_ERR_UNSUPPORTED;
+	if (dst == src2 && dstw == src2w)
+		return SLJIT_ERR_UNSUPPORTED;
+
+	dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+
+	if (FAST_IS_REG(src1)) {
+		if (FAST_IS_REG(src2)) {
+			inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM2(src1, src2), 0);
+			FAIL_IF(!inst);
+			*inst = LEA_r_m;
+			done = 1;
+		}
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+		if ((src2 & SLJIT_IMM) && (compiler->mode32 || IS_HALFWORD(src2w))) {
+			inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src1), (sljit_s32)src2w);
+#else
+		if (src2 & SLJIT_IMM) {
+			inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src1), src2w);
+#endif
+			FAIL_IF(!inst);
+			*inst = LEA_r_m;
+			done = 1;
+		}
+	}
+	else if (FAST_IS_REG(src2)) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+		if ((src1 & SLJIT_IMM) && (compiler->mode32 || IS_HALFWORD(src1w))) {
+			inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src2), (sljit_s32)src1w);
+#else
+		if (src1 & SLJIT_IMM) {
+			inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src2), src1w);
+#endif
+			FAIL_IF(!inst);
+			*inst = LEA_r_m;
+			done = 1;
+		}
+	}
+
+	if (done) {
+		if (dst_r == TMP_REG1)
+			return emit_mov(compiler, dst, dstw, TMP_REG1, 0);
+		return SLJIT_SUCCESS;
+	}
+	return SLJIT_ERR_UNSUPPORTED;
+}
+
+static sljit_s32 emit_cmp_binary(struct sljit_compiler *compiler,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_u8* inst;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	if (src1 == SLJIT_R0 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) {
+#else
+	if (src1 == SLJIT_R0 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128)) {
+#endif
+		BINARY_EAX_IMM(CMP_EAX_i32, src2w);
+		return SLJIT_SUCCESS;
+	}
+
+	if (FAST_IS_REG(src1)) {
+		if (src2 & SLJIT_IMM) {
+			BINARY_IMM(CMP, CMP_rm_r, src2w, src1, 0);
+		}
+		else {
+			inst = emit_x86_instruction(compiler, 1, src1, 0, src2, src2w);
+			FAIL_IF(!inst);
+			*inst = CMP_r_rm;
+		}
+		return SLJIT_SUCCESS;
+	}
+
+	if (FAST_IS_REG(src2) && !(src1 & SLJIT_IMM)) {
+		inst = emit_x86_instruction(compiler, 1, src2, 0, src1, src1w);
+		FAIL_IF(!inst);
+		*inst = CMP_rm_r;
+		return SLJIT_SUCCESS;
+	}
+
+	if (src2 & SLJIT_IMM) {
+		if (src1 & SLJIT_IMM) {
+			EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+			src1 = TMP_REG1;
+			src1w = 0;
+		}
+		BINARY_IMM(CMP, CMP_rm_r, src2w, src1, src1w);
+	}
+	else {
+		EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+		inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src2, src2w);
+		FAIL_IF(!inst);
+		*inst = CMP_r_rm;
+	}
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_test_binary(struct sljit_compiler *compiler,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_u8* inst;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	if (src1 == SLJIT_R0 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) {
+#else
+	if (src1 == SLJIT_R0 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128)) {
+#endif
+		BINARY_EAX_IMM(TEST_EAX_i32, src2w);
+		return SLJIT_SUCCESS;
+	}
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	if (src2 == SLJIT_R0 && (src1 & SLJIT_IMM) && (src1w > 127 || src1w < -128) && (compiler->mode32 || IS_HALFWORD(src1w))) {
+#else
+	if (src2 == SLJIT_R0 && (src1 & SLJIT_IMM) && (src1w > 127 || src1w < -128)) {
+#endif
+		BINARY_EAX_IMM(TEST_EAX_i32, src1w);
+		return SLJIT_SUCCESS;
+	}
+
+	if (!(src1 & SLJIT_IMM)) {
+		if (src2 & SLJIT_IMM) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+			if (IS_HALFWORD(src2w) || compiler->mode32) {
+				inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, src1w);
+				FAIL_IF(!inst);
+				*inst = GROUP_F7;
+			}
+			else {
+				FAIL_IF(emit_load_imm64(compiler, TMP_REG1, src2w));
+				inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src1, src1w);
+				FAIL_IF(!inst);
+				*inst = TEST_rm_r;
+			}
+#else
+			inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, src1w);
+			FAIL_IF(!inst);
+			*inst = GROUP_F7;
+#endif
+			return SLJIT_SUCCESS;
+		}
+		else if (FAST_IS_REG(src1)) {
+			inst = emit_x86_instruction(compiler, 1, src1, 0, src2, src2w);
+			FAIL_IF(!inst);
+			*inst = TEST_rm_r;
+			return SLJIT_SUCCESS;
+		}
+	}
+
+	if (!(src2 & SLJIT_IMM)) {
+		if (src1 & SLJIT_IMM) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+			if (IS_HALFWORD(src1w) || compiler->mode32) {
+				inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src1w, src2, src2w);
+				FAIL_IF(!inst);
+				*inst = GROUP_F7;
+			}
+			else {
+				FAIL_IF(emit_load_imm64(compiler, TMP_REG1, src1w));
+				inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src2, src2w);
+				FAIL_IF(!inst);
+				*inst = TEST_rm_r;
+			}
+#else
+			inst = emit_x86_instruction(compiler, 1, src1, src1w, src2, src2w);
+			FAIL_IF(!inst);
+			*inst = GROUP_F7;
+#endif
+			return SLJIT_SUCCESS;
+		}
+		else if (FAST_IS_REG(src2)) {
+			inst = emit_x86_instruction(compiler, 1, src2, 0, src1, src1w);
+			FAIL_IF(!inst);
+			*inst = TEST_rm_r;
+			return SLJIT_SUCCESS;
+		}
+	}
+
+	EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+	if (src2 & SLJIT_IMM) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+		if (IS_HALFWORD(src2w) || compiler->mode32) {
+			inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, TMP_REG1, 0);
+			FAIL_IF(!inst);
+			*inst = GROUP_F7;
+		}
+		else {
+			FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src2w));
+			inst = emit_x86_instruction(compiler, 1, TMP_REG2, 0, TMP_REG1, 0);
+			FAIL_IF(!inst);
+			*inst = TEST_rm_r;
+		}
+#else
+		inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, TMP_REG1, 0);
+		FAIL_IF(!inst);
+		*inst = GROUP_F7;
+#endif
+	}
+	else {
+		inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, src2, src2w);
+		FAIL_IF(!inst);
+		*inst = TEST_rm_r;
+	}
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_shift(struct sljit_compiler *compiler,
+	sljit_u8 mode,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_u8* inst;
+
+	if ((src2 & SLJIT_IMM) || (src2 == SLJIT_PREF_SHIFT_REG)) {
+		if (dst == src1 && dstw == src1w) {
+			inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, dst, dstw);
+			FAIL_IF(!inst);
+			*inst |= mode;
+			return SLJIT_SUCCESS;
+		}
+		if (dst == SLJIT_UNUSED) {
+			EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+			inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, TMP_REG1, 0);
+			FAIL_IF(!inst);
+			*inst |= mode;
+			return SLJIT_SUCCESS;
+		}
+		if (dst == SLJIT_PREF_SHIFT_REG && src2 == SLJIT_PREF_SHIFT_REG) {
+			EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+			inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0);
+			FAIL_IF(!inst);
+			*inst |= mode;
+			EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0);
+			return SLJIT_SUCCESS;
+		}
+		if (FAST_IS_REG(dst)) {
+			EMIT_MOV(compiler, dst, 0, src1, src1w);
+			inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, dst, 0);
+			FAIL_IF(!inst);
+			*inst |= mode;
+			return SLJIT_SUCCESS;
+		}
+
+		EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+		inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, TMP_REG1, 0);
+		FAIL_IF(!inst);
+		*inst |= mode;
+		EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0);
+		return SLJIT_SUCCESS;
+	}
+
+	if (dst == SLJIT_PREF_SHIFT_REG) {
+		EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+		EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w);
+		inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0);
+		FAIL_IF(!inst);
+		*inst |= mode;
+		EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0);
+	}
+	else if (SLOW_IS_REG(dst) && dst != src2 && !ADDRESSING_DEPENDS_ON(src2, dst)) {
+		if (src1 != dst)
+			EMIT_MOV(compiler, dst, 0, src1, src1w);
+		EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_PREF_SHIFT_REG, 0);
+		EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w);
+		inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, dst, 0);
+		FAIL_IF(!inst);
+		*inst |= mode;
+		EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0);
+	}
+	else {
+		/* This case is complex since ecx itself may be used for
+		   addressing, and this case must be supported as well. */
+		EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+		EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_PREF_SHIFT_REG, 0);
+		EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w);
+		inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0);
+		FAIL_IF(!inst);
+		*inst |= mode;
+		EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, SLJIT_MEM1(SLJIT_SP), 0);
+#else
+		EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_PREF_SHIFT_REG, 0);
+		EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w);
+		inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0);
+		FAIL_IF(!inst);
+		*inst |= mode;
+		EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG2, 0);
+#endif
+		if (dst != SLJIT_UNUSED)
+			return emit_mov(compiler, dst, dstw, TMP_REG1, 0);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_shift_with_flags(struct sljit_compiler *compiler,
+	sljit_u8 mode, sljit_s32 set_flags,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	/* The CPU does not set flags if the shift count is 0. */
+	if (src2 & SLJIT_IMM) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+		if ((src2w & 0x3f) != 0 || (compiler->mode32 && (src2w & 0x1f) != 0))
+			return emit_shift(compiler, mode, dst, dstw, src1, src1w, src2, src2w);
+#else
+		if ((src2w & 0x1f) != 0)
+			return emit_shift(compiler, mode, dst, dstw, src1, src1w, src2, src2w);
+#endif
+		if (!set_flags)
+			return emit_mov(compiler, dst, dstw, src1, src1w);
+		/* OR dst, src, 0 */
+		return emit_cum_binary(compiler, BINARY_OPCODE(OR),
+			dst, dstw, src1, src1w, SLJIT_IMM, 0);
+	}
+
+	if (!set_flags)
+		return emit_shift(compiler, mode, dst, dstw, src1, src1w, src2, src2w);
+
+	if (!FAST_IS_REG(dst))
+		FAIL_IF(emit_cmp_binary(compiler, src1, src1w, SLJIT_IMM, 0));
+
+	FAIL_IF(emit_shift(compiler, mode, dst, dstw, src1, src1w, src2, src2w));
+
+	if (FAST_IS_REG(dst))
+		return emit_cmp_binary(compiler, (dst == SLJIT_UNUSED) ? TMP_REG1 : dst, dstw, SLJIT_IMM, 0);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+	CHECK_EXTRA_REGS(dst, dstw, (void)0);
+	CHECK_EXTRA_REGS(src1, src1w, (void)0);
+	CHECK_EXTRA_REGS(src2, src2w, (void)0);
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	compiler->mode32 = op & SLJIT_I32_OP;
+#endif
+
+	if (dst == SLJIT_UNUSED && !HAS_FLAGS(op))
+		return SLJIT_SUCCESS;
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_ADD:
+		if (!HAS_FLAGS(op)) {
+			if (emit_lea_binary(compiler, dst, dstw, src1, src1w, src2, src2w) != SLJIT_ERR_UNSUPPORTED)
+				return compiler->error;
+		}
+		return emit_cum_binary(compiler, BINARY_OPCODE(ADD),
+			dst, dstw, src1, src1w, src2, src2w);
+	case SLJIT_ADDC:
+		return emit_cum_binary(compiler, BINARY_OPCODE(ADC),
+			dst, dstw, src1, src1w, src2, src2w);
+	case SLJIT_SUB:
+		if (!HAS_FLAGS(op)) {
+			if ((src2 & SLJIT_IMM) && emit_lea_binary(compiler, dst, dstw, src1, src1w, SLJIT_IMM, -src2w) != SLJIT_ERR_UNSUPPORTED)
+				return compiler->error;
+			if (SLOW_IS_REG(dst) && src2 == dst) {
+				FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB), dst, 0, dst, 0, src1, src1w));
+				return emit_unary(compiler, NEG_rm, dst, 0, dst, 0);
+			}
+		}
+
+		if (dst == SLJIT_UNUSED)
+			return emit_cmp_binary(compiler, src1, src1w, src2, src2w);
+		return emit_non_cum_binary(compiler, BINARY_OPCODE(SUB),
+			dst, dstw, src1, src1w, src2, src2w);
+	case SLJIT_SUBC:
+		return emit_non_cum_binary(compiler, BINARY_OPCODE(SBB),
+			dst, dstw, src1, src1w, src2, src2w);
+	case SLJIT_MUL:
+		return emit_mul(compiler, dst, dstw, src1, src1w, src2, src2w);
+	case SLJIT_AND:
+		if (dst == SLJIT_UNUSED)
+			return emit_test_binary(compiler, src1, src1w, src2, src2w);
+		return emit_cum_binary(compiler, BINARY_OPCODE(AND),
+			dst, dstw, src1, src1w, src2, src2w);
+	case SLJIT_OR:
+		return emit_cum_binary(compiler, BINARY_OPCODE(OR),
+			dst, dstw, src1, src1w, src2, src2w);
+	case SLJIT_XOR:
+		return emit_cum_binary(compiler, BINARY_OPCODE(XOR),
+			dst, dstw, src1, src1w, src2, src2w);
+	case SLJIT_SHL:
+		return emit_shift_with_flags(compiler, SHL, HAS_FLAGS(op),
+			dst, dstw, src1, src1w, src2, src2w);
+	case SLJIT_LSHR:
+		return emit_shift_with_flags(compiler, SHR, HAS_FLAGS(op),
+			dst, dstw, src1, src1w, src2, src2w);
+	case SLJIT_ASHR:
+		return emit_shift_with_flags(compiler, SAR, HAS_FLAGS(op),
+			dst, dstw, src1, src1w, src2, src2w);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src, sljit_sw srcw)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_src(compiler, op, src, srcw));
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	CHECK_EXTRA_REGS(src, srcw, (void)0);
+
+	switch (op) {
+	case SLJIT_FAST_RETURN:
+		return emit_fast_return(compiler, src, srcw);
+	case SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN:
+		/* Don't adjust shadow stack if it isn't enabled.  */
+		if (!cpu_has_shadow_stack ())
+			return SLJIT_SUCCESS;
+		return adjust_shadow_stack(compiler, src, srcw, SLJIT_UNUSED, 0);
+	case SLJIT_PREFETCH_L1:
+	case SLJIT_PREFETCH_L2:
+	case SLJIT_PREFETCH_L3:
+	case SLJIT_PREFETCH_ONCE:
+		return emit_prefetch(compiler, op, src, srcw);
+	}
+
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+{
+	CHECK_REG_INDEX(check_sljit_get_register_index(reg));
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+	if (reg >= SLJIT_R3 && reg <= SLJIT_R8)
+		return -1;
+#endif
+	return reg_map[reg];
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
+{
+	CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+	return reg;
+#else
+	return freg_map[reg];
+#endif
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
+	void *instruction, sljit_s32 size)
+{
+	sljit_u8 *inst;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
+	FAIL_IF(!inst);
+	INC_SIZE(size);
+	SLJIT_MEMCPY(inst, instruction, size);
+	return SLJIT_SUCCESS;
+}
+
+/* --------------------------------------------------------------------- */
+/*  Floating point operators                                             */
+/* --------------------------------------------------------------------- */
+
+/* Alignment(3) + 4 * 16 bytes. */
+static sljit_s32 sse2_data[3 + (4 * 4)];
+static sljit_s32 *sse2_buffer;
+
+static void init_compiler(void)
+{
+	/* Align to 16 bytes. */
+	sse2_buffer = (sljit_s32*)(((sljit_uw)sse2_data + 15) & ~0xf);
+
+	/* Single precision constants (each constant is 16 byte long). */
+	sse2_buffer[0] = 0x80000000;
+	sse2_buffer[4] = 0x7fffffff;
+	/* Double precision constants (each constant is 16 byte long). */
+	sse2_buffer[8] = 0;
+	sse2_buffer[9] = 0x80000000;
+	sse2_buffer[12] = 0xffffffff;
+	sse2_buffer[13] = 0x7fffffff;
+}
+
+static sljit_s32 emit_sse2(struct sljit_compiler *compiler, sljit_u8 opcode,
+	sljit_s32 single, sljit_s32 xmm1, sljit_s32 xmm2, sljit_sw xmm2w)
+{
+	sljit_u8 *inst;
+
+	inst = emit_x86_instruction(compiler, 2 | (single ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2, xmm1, 0, xmm2, xmm2w);
+	FAIL_IF(!inst);
+	*inst++ = GROUP_0F;
+	*inst = opcode;
+	return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_sse2_logic(struct sljit_compiler *compiler, sljit_u8 opcode,
+	sljit_s32 pref66, sljit_s32 xmm1, sljit_s32 xmm2, sljit_sw xmm2w)
+{
+	sljit_u8 *inst;
+
+	inst = emit_x86_instruction(compiler, 2 | (pref66 ? EX86_PREF_66 : 0) | EX86_SSE2, xmm1, 0, xmm2, xmm2w);
+	FAIL_IF(!inst);
+	*inst++ = GROUP_0F;
+	*inst = opcode;
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 emit_sse2_load(struct sljit_compiler *compiler,
+	sljit_s32 single, sljit_s32 dst, sljit_s32 src, sljit_sw srcw)
+{
+	return emit_sse2(compiler, MOVSD_x_xm, single, dst, src, srcw);
+}
+
+static SLJIT_INLINE sljit_s32 emit_sse2_store(struct sljit_compiler *compiler,
+	sljit_s32 single, sljit_s32 dst, sljit_sw dstw, sljit_s32 src)
+{
+	return emit_sse2(compiler, MOVSD_xm_x, single, src, dst, dstw);
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+	sljit_u8 *inst;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	if (GET_OPCODE(op) == SLJIT_CONV_SW_FROM_F64)
+		compiler->mode32 = 0;
+#endif
+
+	inst = emit_x86_instruction(compiler, 2 | ((op & SLJIT_F32_OP) ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2_OP2, dst_r, 0, src, srcw);
+	FAIL_IF(!inst);
+	*inst++ = GROUP_0F;
+	*inst = CVTTSD2SI_r_xm;
+
+	if (dst & SLJIT_MEM)
+		return emit_mov(compiler, dst, dstw, TMP_REG1, 0);
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG;
+	sljit_u8 *inst;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_SW)
+		compiler->mode32 = 0;
+#endif
+
+	if (src & SLJIT_IMM) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+		if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
+			srcw = (sljit_s32)srcw;
+#endif
+		EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
+		src = TMP_REG1;
+		srcw = 0;
+	}
+
+	inst = emit_x86_instruction(compiler, 2 | ((op & SLJIT_F32_OP) ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2_OP1, dst_r, 0, src, srcw);
+	FAIL_IF(!inst);
+	*inst++ = GROUP_0F;
+	*inst = CVTSI2SD_x_rm;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	compiler->mode32 = 1;
+#endif
+	if (dst_r == TMP_FREG)
+		return emit_sse2_store(compiler, op & SLJIT_F32_OP, dst, dstw, TMP_FREG);
+	return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	if (!FAST_IS_REG(src1)) {
+		FAIL_IF(emit_sse2_load(compiler, op & SLJIT_F32_OP, TMP_FREG, src1, src1w));
+		src1 = TMP_FREG;
+	}
+
+	return emit_sse2_logic(compiler, UCOMISD_x_xm, !(op & SLJIT_F32_OP), src1, src2, src2w);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_s32 dst_r;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	compiler->mode32 = 1;
+#endif
+
+	CHECK_ERROR();
+	SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw);
+
+	if (GET_OPCODE(op) == SLJIT_MOV_F64) {
+		if (FAST_IS_REG(dst))
+			return emit_sse2_load(compiler, op & SLJIT_F32_OP, dst, src, srcw);
+		if (FAST_IS_REG(src))
+			return emit_sse2_store(compiler, op & SLJIT_F32_OP, dst, dstw, src);
+		FAIL_IF(emit_sse2_load(compiler, op & SLJIT_F32_OP, TMP_FREG, src, srcw));
+		return emit_sse2_store(compiler, op & SLJIT_F32_OP, dst, dstw, TMP_FREG);
+	}
+
+	if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32) {
+		dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG;
+		if (FAST_IS_REG(src)) {
+			/* We overwrite the high bits of source. From SLJIT point of view,
+			   this is not an issue.
+			   Note: In SSE3, we could also use MOVDDUP and MOVSLDUP. */
+			FAIL_IF(emit_sse2_logic(compiler, UNPCKLPD_x_xm, op & SLJIT_F32_OP, src, src, 0));
+		}
+		else {
+			FAIL_IF(emit_sse2_load(compiler, !(op & SLJIT_F32_OP), TMP_FREG, src, srcw));
+			src = TMP_FREG;
+		}
+
+		FAIL_IF(emit_sse2_logic(compiler, CVTPD2PS_x_xm, op & SLJIT_F32_OP, dst_r, src, 0));
+		if (dst_r == TMP_FREG)
+			return emit_sse2_store(compiler, op & SLJIT_F32_OP, dst, dstw, TMP_FREG);
+		return SLJIT_SUCCESS;
+	}
+
+	if (FAST_IS_REG(dst)) {
+		dst_r = dst;
+		if (dst != src)
+			FAIL_IF(emit_sse2_load(compiler, op & SLJIT_F32_OP, dst_r, src, srcw));
+	}
+	else {
+		dst_r = TMP_FREG;
+		FAIL_IF(emit_sse2_load(compiler, op & SLJIT_F32_OP, dst_r, src, srcw));
+	}
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_NEG_F64:
+		FAIL_IF(emit_sse2_logic(compiler, XORPD_x_xm, 1, dst_r, SLJIT_MEM0(), (sljit_sw)(op & SLJIT_F32_OP ? sse2_buffer : sse2_buffer + 8)));
+		break;
+
+	case SLJIT_ABS_F64:
+		FAIL_IF(emit_sse2_logic(compiler, ANDPD_x_xm, 1, dst_r, SLJIT_MEM0(), (sljit_sw)(op & SLJIT_F32_OP ? sse2_buffer + 4 : sse2_buffer + 12)));
+		break;
+	}
+
+	if (dst_r == TMP_FREG)
+		return emit_sse2_store(compiler, op & SLJIT_F32_OP, dst, dstw, TMP_FREG);
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 src1, sljit_sw src1w,
+	sljit_s32 src2, sljit_sw src2w)
+{
+	sljit_s32 dst_r;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_fop2(compiler, op, dst, dstw, src1, src1w, src2, src2w));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	ADJUST_LOCAL_OFFSET(src1, src1w);
+	ADJUST_LOCAL_OFFSET(src2, src2w);
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	compiler->mode32 = 1;
+#endif
+
+	if (FAST_IS_REG(dst)) {
+		dst_r = dst;
+		if (dst == src1)
+			; /* Do nothing here. */
+		else if (dst == src2 && (op == SLJIT_ADD_F64 || op == SLJIT_MUL_F64)) {
+			/* Swap arguments. */
+			src2 = src1;
+			src2w = src1w;
+		}
+		else if (dst != src2)
+			FAIL_IF(emit_sse2_load(compiler, op & SLJIT_F32_OP, dst_r, src1, src1w));
+		else {
+			dst_r = TMP_FREG;
+			FAIL_IF(emit_sse2_load(compiler, op & SLJIT_F32_OP, TMP_FREG, src1, src1w));
+		}
+	}
+	else {
+		dst_r = TMP_FREG;
+		FAIL_IF(emit_sse2_load(compiler, op & SLJIT_F32_OP, TMP_FREG, src1, src1w));
+	}
+
+	switch (GET_OPCODE(op)) {
+	case SLJIT_ADD_F64:
+		FAIL_IF(emit_sse2(compiler, ADDSD_x_xm, op & SLJIT_F32_OP, dst_r, src2, src2w));
+		break;
+
+	case SLJIT_SUB_F64:
+		FAIL_IF(emit_sse2(compiler, SUBSD_x_xm, op & SLJIT_F32_OP, dst_r, src2, src2w));
+		break;
+
+	case SLJIT_MUL_F64:
+		FAIL_IF(emit_sse2(compiler, MULSD_x_xm, op & SLJIT_F32_OP, dst_r, src2, src2w));
+		break;
+
+	case SLJIT_DIV_F64:
+		FAIL_IF(emit_sse2(compiler, DIVSD_x_xm, op & SLJIT_F32_OP, dst_r, src2, src2w));
+		break;
+	}
+
+	if (dst_r == TMP_FREG)
+		return emit_sse2_store(compiler, op & SLJIT_F32_OP, dst, dstw, TMP_FREG);
+	return SLJIT_SUCCESS;
+}
+
+/* --------------------------------------------------------------------- */
+/*  Conditional instructions                                             */
+/* --------------------------------------------------------------------- */
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
+{
+	sljit_u8 *inst;
+	struct sljit_label *label;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_label(compiler));
+
+	if (compiler->last_label && compiler->last_label->size == compiler->size)
+		return compiler->last_label;
+
+	label = (struct sljit_label*)ensure_abuf(compiler, sizeof(struct sljit_label));
+	PTR_FAIL_IF(!label);
+	set_label(label, compiler);
+
+	inst = (sljit_u8*)ensure_buf(compiler, 2);
+	PTR_FAIL_IF(!inst);
+
+	*inst++ = 0;
+	*inst++ = 0;
+
+	return label;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
+{
+	sljit_u8 *inst;
+	struct sljit_jump *jump;
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_jump(compiler, type));
+
+	jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+	PTR_FAIL_IF_NULL(jump);
+	set_jump(jump, compiler, (type & SLJIT_REWRITABLE_JUMP) | ((type & 0xff) << TYPE_SHIFT));
+	type &= 0xff;
+
+	/* Worst case size. */
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+	compiler->size += (type >= SLJIT_JUMP) ? 5 : 6;
+#else
+	compiler->size += (type >= SLJIT_JUMP) ? (10 + 3) : (2 + 10 + 3);
+#endif
+
+	inst = (sljit_u8*)ensure_buf(compiler, 2);
+	PTR_FAIL_IF_NULL(inst);
+
+	*inst++ = 0;
+	*inst++ = 1;
+	return jump;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
+{
+	sljit_u8 *inst;
+	struct sljit_jump *jump;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
+	ADJUST_LOCAL_OFFSET(src, srcw);
+
+	CHECK_EXTRA_REGS(src, srcw, (void)0);
+
+	if (src == SLJIT_IMM) {
+		jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+		FAIL_IF_NULL(jump);
+		set_jump(jump, compiler, JUMP_ADDR | (type << TYPE_SHIFT));
+		jump->u.target = srcw;
+
+		/* Worst case size. */
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+		compiler->size += 5;
+#else
+		compiler->size += 10 + 3;
+#endif
+
+		inst = (sljit_u8*)ensure_buf(compiler, 2);
+		FAIL_IF_NULL(inst);
+
+		*inst++ = 0;
+		*inst++ = 1;
+	}
+	else {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+		/* REX_W is not necessary (src is not immediate). */
+		compiler->mode32 = 1;
+#endif
+		inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
+		FAIL_IF(!inst);
+		*inst++ = GROUP_FF;
+		*inst |= (type >= SLJIT_FAST_CALL) ? CALL_rm : JMP_rm;
+	}
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
+	sljit_s32 dst, sljit_sw dstw,
+	sljit_s32 type)
+{
+	sljit_u8 *inst;
+	sljit_u8 cond_set = 0;
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	sljit_s32 reg;
+#endif
+	/* ADJUST_LOCAL_OFFSET and CHECK_EXTRA_REGS might overwrite these values. */
+	sljit_s32 dst_save = dst;
+	sljit_sw dstw_save = dstw;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
+
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+	CHECK_EXTRA_REGS(dst, dstw, (void)0);
+
+	type &= 0xff;
+	/* setcc = jcc + 0x10. */
+	cond_set = get_jump_code(type) + 0x10;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	if (GET_OPCODE(op) == SLJIT_OR && !GET_ALL_FLAGS(op) && FAST_IS_REG(dst)) {
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 4 + 3);
+		FAIL_IF(!inst);
+		INC_SIZE(4 + 3);
+		/* Set low register to conditional flag. */
+		*inst++ = (reg_map[TMP_REG1] <= 7) ? REX : REX_B;
+		*inst++ = GROUP_0F;
+		*inst++ = cond_set;
+		*inst++ = MOD_REG | reg_lmap[TMP_REG1];
+		*inst++ = REX | (reg_map[TMP_REG1] <= 7 ? 0 : REX_R) | (reg_map[dst] <= 7 ? 0 : REX_B);
+		*inst++ = OR_rm8_r8;
+		*inst++ = MOD_REG | (reg_lmap[TMP_REG1] << 3) | reg_lmap[dst];
+		return SLJIT_SUCCESS;
+	}
+
+	reg = (GET_OPCODE(op) < SLJIT_ADD && FAST_IS_REG(dst)) ? dst : TMP_REG1;
+
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + 4 + 4);
+	FAIL_IF(!inst);
+	INC_SIZE(4 + 4);
+	/* Set low register to conditional flag. */
+	*inst++ = (reg_map[reg] <= 7) ? REX : REX_B;
+	*inst++ = GROUP_0F;
+	*inst++ = cond_set;
+	*inst++ = MOD_REG | reg_lmap[reg];
+	*inst++ = REX_W | (reg_map[reg] <= 7 ? 0 : (REX_B | REX_R));
+	/* The movzx instruction does not affect flags. */
+	*inst++ = GROUP_0F;
+	*inst++ = MOVZX_r_rm8;
+	*inst = MOD_REG | (reg_lmap[reg] << 3) | reg_lmap[reg];
+
+	if (reg != TMP_REG1)
+		return SLJIT_SUCCESS;
+
+	if (GET_OPCODE(op) < SLJIT_ADD) {
+		compiler->mode32 = GET_OPCODE(op) != SLJIT_MOV;
+		return emit_mov(compiler, dst, dstw, TMP_REG1, 0);
+	}
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+	return sljit_emit_op2(compiler, op, dst_save, dstw_save, dst_save, dstw_save, TMP_REG1, 0);
+
+#else
+	/* The SLJIT_CONFIG_X86_32 code path starts here. */
+	if (GET_OPCODE(op) < SLJIT_ADD && FAST_IS_REG(dst)) {
+		if (reg_map[dst] <= 4) {
+			/* Low byte is accessible. */
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 3 + 3);
+			FAIL_IF(!inst);
+			INC_SIZE(3 + 3);
+			/* Set low byte to conditional flag. */
+			*inst++ = GROUP_0F;
+			*inst++ = cond_set;
+			*inst++ = MOD_REG | reg_map[dst];
+
+			*inst++ = GROUP_0F;
+			*inst++ = MOVZX_r_rm8;
+			*inst = MOD_REG | (reg_map[dst] << 3) | reg_map[dst];
+			return SLJIT_SUCCESS;
+		}
+
+		/* Low byte is not accessible. */
+		if (cpu_has_cmov == -1)
+			get_cpu_features();
+
+		if (cpu_has_cmov) {
+			EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, 1);
+			/* a xor reg, reg operation would overwrite the flags. */
+			EMIT_MOV(compiler, dst, 0, SLJIT_IMM, 0);
+
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 3);
+			FAIL_IF(!inst);
+			INC_SIZE(3);
+
+			*inst++ = GROUP_0F;
+			/* cmovcc = setcc - 0x50. */
+			*inst++ = cond_set - 0x50;
+			*inst++ = MOD_REG | (reg_map[dst] << 3) | reg_map[TMP_REG1];
+			return SLJIT_SUCCESS;
+		}
+
+		inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 3 + 3 + 1);
+		FAIL_IF(!inst);
+		INC_SIZE(1 + 3 + 3 + 1);
+		*inst++ = XCHG_EAX_r + reg_map[TMP_REG1];
+		/* Set al to conditional flag. */
+		*inst++ = GROUP_0F;
+		*inst++ = cond_set;
+		*inst++ = MOD_REG | 0 /* eax */;
+
+		*inst++ = GROUP_0F;
+		*inst++ = MOVZX_r_rm8;
+		*inst++ = MOD_REG | (reg_map[dst] << 3) | 0 /* eax */;
+		*inst++ = XCHG_EAX_r + reg_map[TMP_REG1];
+		return SLJIT_SUCCESS;
+	}
+
+	if (GET_OPCODE(op) == SLJIT_OR && !GET_ALL_FLAGS(op) && FAST_IS_REG(dst) && reg_map[dst] <= 4) {
+		SLJIT_ASSERT(reg_map[SLJIT_R0] == 0);
+
+		if (dst != SLJIT_R0) {
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 3 + 2 + 1);
+			FAIL_IF(!inst);
+			INC_SIZE(1 + 3 + 2 + 1);
+			/* Set low register to conditional flag. */
+			*inst++ = XCHG_EAX_r + reg_map[TMP_REG1];
+			*inst++ = GROUP_0F;
+			*inst++ = cond_set;
+			*inst++ = MOD_REG | 0 /* eax */;
+			*inst++ = OR_rm8_r8;
+			*inst++ = MOD_REG | (0 /* eax */ << 3) | reg_map[dst];
+			*inst++ = XCHG_EAX_r + reg_map[TMP_REG1];
+		}
+		else {
+			inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + 3 + 2 + 2);
+			FAIL_IF(!inst);
+			INC_SIZE(2 + 3 + 2 + 2);
+			/* Set low register to conditional flag. */
+			*inst++ = XCHG_r_rm;
+			*inst++ = MOD_REG | (1 /* ecx */ << 3) | reg_map[TMP_REG1];
+			*inst++ = GROUP_0F;
+			*inst++ = cond_set;
+			*inst++ = MOD_REG | 1 /* ecx */;
+			*inst++ = OR_rm8_r8;
+			*inst++ = MOD_REG | (1 /* ecx */ << 3) | 0 /* eax */;
+			*inst++ = XCHG_r_rm;
+			*inst++ = MOD_REG | (1 /* ecx */ << 3) | reg_map[TMP_REG1];
+		}
+		return SLJIT_SUCCESS;
+	}
+
+	/* Set TMP_REG1 to the bit. */
+	inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 3 + 3 + 1);
+	FAIL_IF(!inst);
+	INC_SIZE(1 + 3 + 3 + 1);
+	*inst++ = XCHG_EAX_r + reg_map[TMP_REG1];
+	/* Set al to conditional flag. */
+	*inst++ = GROUP_0F;
+	*inst++ = cond_set;
+	*inst++ = MOD_REG | 0 /* eax */;
+
+	*inst++ = GROUP_0F;
+	*inst++ = MOVZX_r_rm8;
+	*inst++ = MOD_REG | (0 << 3) /* eax */ | 0 /* eax */;
+
+	*inst++ = XCHG_EAX_r + reg_map[TMP_REG1];
+
+	if (GET_OPCODE(op) < SLJIT_ADD)
+		return emit_mov(compiler, dst, dstw, TMP_REG1, 0);
+
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
+		|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+	compiler->skip_checks = 1;
+#endif
+	return sljit_emit_op2(compiler, op, dst_save, dstw_save, dst_save, dstw_save, TMP_REG1, 0);
+#endif /* SLJIT_CONFIG_X86_64 */
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+	sljit_s32 dst_reg,
+	sljit_s32 src, sljit_sw srcw)
+{
+	sljit_u8* inst;
+
+	CHECK_ERROR();
+	CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+	dst_reg &= ~SLJIT_I32_OP;
+
+	if (!sljit_has_cpu_feature(SLJIT_HAS_CMOV) || (dst_reg >= SLJIT_R3 && dst_reg <= SLJIT_S3))
+		return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);
+#else
+	if (!sljit_has_cpu_feature(SLJIT_HAS_CMOV))
+		return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);
+#endif
+
+	/* ADJUST_LOCAL_OFFSET is not needed. */
+	CHECK_EXTRA_REGS(src, srcw, (void)0);
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	compiler->mode32 = dst_reg & SLJIT_I32_OP;
+	dst_reg &= ~SLJIT_I32_OP;
+#endif
+
+	if (SLJIT_UNLIKELY(src & SLJIT_IMM)) {
+		EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, srcw);
+		src = TMP_REG1;
+		srcw = 0;
+	}
+
+	inst = emit_x86_instruction(compiler, 2, dst_reg, 0, src, srcw);
+	FAIL_IF(!inst);
+	*inst++ = GROUP_0F;
+	*inst = get_jump_code(type & 0xff) - 0x40;
+	return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset)
+{
+	CHECK_ERROR();
+	CHECK(check_sljit_get_local_base(compiler, dst, dstw, offset));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	CHECK_EXTRA_REGS(dst, dstw, (void)0);
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	compiler->mode32 = 0;
+#endif
+
+	ADJUST_LOCAL_OFFSET(SLJIT_MEM1(SLJIT_SP), offset);
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	if (NOT_HALFWORD(offset)) {
+		FAIL_IF(emit_load_imm64(compiler, TMP_REG1, offset));
+#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
+		SLJIT_ASSERT(emit_lea_binary(compiler, dst, dstw, SLJIT_SP, 0, TMP_REG1, 0) != SLJIT_ERR_UNSUPPORTED);
+		return compiler->error;
+#else
+		return emit_lea_binary(compiler, dst, dstw, SLJIT_SP, 0, TMP_REG1, 0);
+#endif
+	}
+#endif
+
+	if (offset != 0)
+		return emit_lea_binary(compiler, dst, dstw, SLJIT_SP, 0, SLJIT_IMM, offset);
+	return emit_mov(compiler, dst, dstw, SLJIT_SP, 0);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
+{
+	sljit_u8 *inst;
+	struct sljit_const *const_;
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	sljit_s32 reg;
+#endif
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_const(compiler, dst, dstw, init_value));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	CHECK_EXTRA_REGS(dst, dstw, (void)0);
+
+	const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
+	PTR_FAIL_IF(!const_);
+	set_const(const_, compiler);
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	compiler->mode32 = 0;
+	reg = FAST_IS_REG(dst) ? dst : TMP_REG1;
+
+	if (emit_load_imm64(compiler, reg, init_value))
+		return NULL;
+#else
+	if (emit_mov(compiler, dst, dstw, SLJIT_IMM, init_value))
+		return NULL;
+#endif
+
+	inst = (sljit_u8*)ensure_buf(compiler, 2);
+	PTR_FAIL_IF(!inst);
+
+	*inst++ = 0;
+	*inst++ = 2;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	if (dst & SLJIT_MEM)
+		if (emit_mov(compiler, dst, dstw, TMP_REG1, 0))
+			return NULL;
+#endif
+
+	return const_;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+{
+	struct sljit_put_label *put_label;
+	sljit_u8 *inst;
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	sljit_s32 reg;
+	sljit_uw start_size;
+#endif
+
+	CHECK_ERROR_PTR();
+	CHECK_PTR(check_sljit_emit_put_label(compiler, dst, dstw));
+	ADJUST_LOCAL_OFFSET(dst, dstw);
+
+	CHECK_EXTRA_REGS(dst, dstw, (void)0);
+
+	put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label));
+	PTR_FAIL_IF(!put_label);
+	set_put_label(put_label, compiler, 0);
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	compiler->mode32 = 0;
+	reg = FAST_IS_REG(dst) ? dst : TMP_REG1;
+
+	if (emit_load_imm64(compiler, reg, 0))
+		return NULL;
+#else
+	if (emit_mov(compiler, dst, dstw, SLJIT_IMM, 0))
+		return NULL;
+#endif
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+	if (dst & SLJIT_MEM) {
+		start_size = compiler->size;
+		if (emit_mov(compiler, dst, dstw, TMP_REG1, 0))
+			return NULL;
+		put_label->flags = compiler->size - start_size;
+	}
+#endif
+
+	inst = (sljit_u8*)ensure_buf(compiler, 2);
+	PTR_FAIL_IF(!inst);
+
+	*inst++ = 0;
+	*inst++ = 3;
+
+	return put_label;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
+{
+	SLJIT_UNUSED_ARG(executable_offset);
+
+	SLJIT_UPDATE_WX_FLAGS((void*)addr, (void*)(addr + sizeof(sljit_uw)), 0);
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+	sljit_unaligned_store_sw((void*)addr, new_target - (addr + 4) - (sljit_uw)executable_offset);
+#else
+	sljit_unaligned_store_sw((void*)addr, (sljit_sw) new_target);
+#endif
+	SLJIT_UPDATE_WX_FLAGS((void*)addr, (void*)(addr + sizeof(sljit_uw)), 1);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
+{
+	SLJIT_UNUSED_ARG(executable_offset);
+
+	SLJIT_UPDATE_WX_FLAGS((void*)addr, (void*)(addr + sizeof(sljit_sw)), 0);
+	sljit_unaligned_store_sw((void*)addr, new_constant);
+	SLJIT_UPDATE_WX_FLAGS((void*)addr, (void*)(addr + sizeof(sljit_sw)), 1);
+}
diff --git a/src/c/pcre2/src/sljit/sljitProtExecAllocator.c b/src/c/pcre2/src/sljit/sljitProtExecAllocator.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitProtExecAllocator.c
@@ -0,0 +1,474 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+   This file contains a simple executable memory allocator
+
+   It is assumed, that executable code blocks are usually medium (or sometimes
+   large) memory blocks, and the allocator is not too frequently called (less
+   optimized than other allocators). Thus, using it as a generic allocator is
+   not suggested.
+
+   How does it work:
+     Memory is allocated in continuous memory areas called chunks by alloc_chunk()
+     Chunk format:
+     [ block ][ block ] ... [ block ][ block terminator ]
+
+   All blocks and the block terminator is started with block_header. The block
+   header contains the size of the previous and the next block. These sizes
+   can also contain special values.
+     Block size:
+       0 - The block is a free_block, with a different size member.
+       1 - The block is a block terminator.
+       n - The block is used at the moment, and the value contains its size.
+     Previous block size:
+       0 - This is the first block of the memory chunk.
+       n - The size of the previous block.
+
+   Using these size values we can go forward or backward on the block chain.
+   The unused blocks are stored in a chain list pointed by free_blocks. This
+   list is useful if we need to find a suitable memory area when the allocator
+   is called.
+
+   When a block is freed, the new free block is connected to its adjacent free
+   blocks if possible.
+
+     [ free block ][ used block ][ free block ]
+   and "used block" is freed, the three blocks are connected together:
+     [           one big free block           ]
+*/
+
+/* --------------------------------------------------------------------- */
+/*  System (OS) functions                                                */
+/* --------------------------------------------------------------------- */
+
+/* 64 KByte. */
+#define CHUNK_SIZE	0x10000
+
+struct chunk_header {
+	void *executable;
+};
+
+/*
+   alloc_chunk / free_chunk :
+     * allocate executable system memory chunks
+     * the size is always divisible by CHUNK_SIZE
+   SLJIT_ALLOCATOR_LOCK / SLJIT_ALLOCATOR_UNLOCK :
+     * provided as part of sljitUtils
+     * only the allocator requires this lock, sljit is fully thread safe
+       as it only uses local variables
+*/
+
+#ifndef __NetBSD__
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef O_NOATIME
+#define O_NOATIME 0
+#endif
+
+/* this is a linux extension available since kernel 3.11 */
+#ifndef O_TMPFILE
+#define O_TMPFILE 020200000
+#endif
+
+#ifndef _GNU_SOURCE
+char *secure_getenv(const char *name);
+int mkostemp(char *template, int flags);
+#endif
+
+static SLJIT_INLINE int create_tempfile(void)
+{
+	int fd;
+	char tmp_name[256];
+	size_t tmp_name_len = 0;
+	char *dir;
+	struct stat st;
+#if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED
+	mode_t mode;
+#endif
+
+#ifdef HAVE_MEMFD_CREATE
+	/* this is a GNU extension, make sure to use -D_GNU_SOURCE */
+	fd = memfd_create("sljit", MFD_CLOEXEC);
+	if (fd != -1) {
+		fchmod(fd, 0);
+		return fd;
+	}
+#endif
+
+	dir = secure_getenv("TMPDIR");
+
+	if (dir) {
+		tmp_name_len = strlen(dir);
+		if (tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name)) {
+			if ((stat(dir, &st) == 0) && S_ISDIR(st.st_mode))
+				strcpy(tmp_name, dir);
+		}
+	}
+
+#ifdef P_tmpdir
+	if (!tmp_name_len) {
+		tmp_name_len = strlen(P_tmpdir);
+		if (tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name))
+			strcpy(tmp_name, P_tmpdir);
+	}
+#endif
+	if (!tmp_name_len) {
+		strcpy(tmp_name, "/tmp");
+		tmp_name_len = 4;
+	}
+
+	SLJIT_ASSERT(tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name));
+
+	if (tmp_name[tmp_name_len - 1] == '/')
+		tmp_name[--tmp_name_len] = '\0';
+
+#ifdef __linux__
+	/*
+	 * the previous trimming might had left an empty string if TMPDIR="/"
+	 * so work around the problem below
+	 */
+	fd = open(tmp_name_len ? tmp_name : "/",
+		O_TMPFILE | O_EXCL | O_RDWR | O_NOATIME | O_CLOEXEC, 0);
+	if (fd != -1)
+		return fd;
+#endif
+
+	if (tmp_name_len + 7 >= sizeof(tmp_name))
+		return -1;
+
+	strcpy(tmp_name + tmp_name_len, "/XXXXXX");
+#if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED
+	mode = umask(0777);
+#endif
+	fd = mkostemp(tmp_name, O_CLOEXEC | O_NOATIME);
+#if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED
+	umask(mode);
+#else
+	fchmod(fd, 0);
+#endif
+
+	if (fd == -1)
+		return -1;
+
+	if (unlink(tmp_name)) {
+		close(fd);
+		return -1;
+	}
+
+	return fd;
+}
+
+static SLJIT_INLINE struct chunk_header* alloc_chunk(sljit_uw size)
+{
+	struct chunk_header *retval;
+	int fd;
+
+	fd = create_tempfile();
+	if (fd == -1)
+		return NULL;
+
+	if (ftruncate(fd, size)) {
+		close(fd);
+		return NULL;
+	}
+
+	retval = (struct chunk_header *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+	if (retval == MAP_FAILED) {
+		close(fd);
+		return NULL;
+	}
+
+	retval->executable = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED, fd, 0);
+
+	if (retval->executable == MAP_FAILED) {
+		munmap((void *)retval, size);
+		close(fd);
+		return NULL;
+	}
+
+	close(fd);
+	return retval;
+}
+#else
+/*
+ * MAP_REMAPDUP is a NetBSD extension available sinde 8.0, make sure to
+ * adjust your feature macros (ex: -D_NETBSD_SOURCE) as needed
+ */
+static SLJIT_INLINE struct chunk_header* alloc_chunk(sljit_uw size)
+{
+	struct chunk_header *retval;
+
+	retval = (struct chunk_header *)mmap(NULL, size,
+			PROT_READ | PROT_WRITE | PROT_MPROTECT(PROT_EXEC),
+			MAP_ANON | MAP_SHARED, -1, 0);
+
+	if (retval == MAP_FAILED)
+		return NULL;
+
+	retval->executable = mremap(retval, size, NULL, size, MAP_REMAPDUP);
+	if (retval->executable == MAP_FAILED) {
+		munmap((void *)retval, size);
+		return NULL;
+	}
+
+	if (mprotect(retval->executable, size, PROT_READ | PROT_EXEC) == -1) {
+		munmap(retval->executable, size);
+		munmap((void *)retval, size);
+		return NULL;
+	}
+
+	return retval;
+}
+#endif /* NetBSD */
+
+static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
+{
+	struct chunk_header *header = ((struct chunk_header *)chunk) - 1;
+
+	munmap(header->executable, size);
+	munmap((void *)header, size);
+}
+
+/* --------------------------------------------------------------------- */
+/*  Common functions                                                     */
+/* --------------------------------------------------------------------- */
+
+#define CHUNK_MASK	(~(CHUNK_SIZE - 1))
+
+struct block_header {
+	sljit_uw size;
+	sljit_uw prev_size;
+	sljit_sw executable_offset;
+};
+
+struct free_block {
+	struct block_header header;
+	struct free_block *next;
+	struct free_block *prev;
+	sljit_uw size;
+};
+
+#define AS_BLOCK_HEADER(base, offset) \
+	((struct block_header*)(((sljit_u8*)base) + offset))
+#define AS_FREE_BLOCK(base, offset) \
+	((struct free_block*)(((sljit_u8*)base) + offset))
+#define MEM_START(base)		((void*)((base) + 1))
+#define ALIGN_SIZE(size)	(((size) + sizeof(struct block_header) + 7) & ~7)
+
+static struct free_block* free_blocks;
+static sljit_uw allocated_size;
+static sljit_uw total_size;
+
+static SLJIT_INLINE void sljit_insert_free_block(struct free_block *free_block, sljit_uw size)
+{
+	free_block->header.size = 0;
+	free_block->size = size;
+
+	free_block->next = free_blocks;
+	free_block->prev = NULL;
+	if (free_blocks)
+		free_blocks->prev = free_block;
+	free_blocks = free_block;
+}
+
+static SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block)
+{
+	if (free_block->next)
+		free_block->next->prev = free_block->prev;
+
+	if (free_block->prev)
+		free_block->prev->next = free_block->next;
+	else {
+		SLJIT_ASSERT(free_blocks == free_block);
+		free_blocks = free_block->next;
+	}
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
+{
+	struct chunk_header *chunk_header;
+	struct block_header *header;
+	struct block_header *next_header;
+	struct free_block *free_block;
+	sljit_uw chunk_size;
+	sljit_sw executable_offset;
+
+	SLJIT_ALLOCATOR_LOCK();
+	if (size < (64 - sizeof(struct block_header)))
+		size = (64 - sizeof(struct block_header));
+	size = ALIGN_SIZE(size);
+
+	free_block = free_blocks;
+	while (free_block) {
+		if (free_block->size >= size) {
+			chunk_size = free_block->size;
+			if (chunk_size > size + 64) {
+				/* We just cut a block from the end of the free block. */
+				chunk_size -= size;
+				free_block->size = chunk_size;
+				header = AS_BLOCK_HEADER(free_block, chunk_size);
+				header->prev_size = chunk_size;
+				header->executable_offset = free_block->header.executable_offset;
+				AS_BLOCK_HEADER(header, size)->prev_size = size;
+			}
+			else {
+				sljit_remove_free_block(free_block);
+				header = (struct block_header*)free_block;
+				size = chunk_size;
+			}
+			allocated_size += size;
+			header->size = size;
+			SLJIT_ALLOCATOR_UNLOCK();
+			return MEM_START(header);
+		}
+		free_block = free_block->next;
+	}
+
+	chunk_size = sizeof(struct chunk_header) + sizeof(struct block_header);
+	chunk_size = (chunk_size + size + CHUNK_SIZE - 1) & CHUNK_MASK;
+
+	chunk_header = alloc_chunk(chunk_size);
+	if (!chunk_header) {
+		SLJIT_ALLOCATOR_UNLOCK();
+		return NULL;
+	}
+
+	executable_offset = (sljit_sw)((sljit_u8*)chunk_header->executable - (sljit_u8*)chunk_header);
+
+	chunk_size -= sizeof(struct chunk_header) + sizeof(struct block_header);
+	total_size += chunk_size;
+
+	header = (struct block_header *)(chunk_header + 1);
+
+	header->prev_size = 0;
+	header->executable_offset = executable_offset;
+	if (chunk_size > size + 64) {
+		/* Cut the allocated space into a free and a used block. */
+		allocated_size += size;
+		header->size = size;
+		chunk_size -= size;
+
+		free_block = AS_FREE_BLOCK(header, size);
+		free_block->header.prev_size = size;
+		free_block->header.executable_offset = executable_offset;
+		sljit_insert_free_block(free_block, chunk_size);
+		next_header = AS_BLOCK_HEADER(free_block, chunk_size);
+	}
+	else {
+		/* All space belongs to this allocation. */
+		allocated_size += chunk_size;
+		header->size = chunk_size;
+		next_header = AS_BLOCK_HEADER(header, chunk_size);
+	}
+	next_header->size = 1;
+	next_header->prev_size = chunk_size;
+	next_header->executable_offset = executable_offset;
+	SLJIT_ALLOCATOR_UNLOCK();
+	return MEM_START(header);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
+{
+	struct block_header *header;
+	struct free_block* free_block;
+
+	SLJIT_ALLOCATOR_LOCK();
+	header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header));
+	header = AS_BLOCK_HEADER(header, -header->executable_offset);
+	allocated_size -= header->size;
+
+	/* Connecting free blocks together if possible. */
+
+	/* If header->prev_size == 0, free_block will equal to header.
+	   In this case, free_block->header.size will be > 0. */
+	free_block = AS_FREE_BLOCK(header, -(sljit_sw)header->prev_size);
+	if (SLJIT_UNLIKELY(!free_block->header.size)) {
+		free_block->size += header->size;
+		header = AS_BLOCK_HEADER(free_block, free_block->size);
+		header->prev_size = free_block->size;
+	}
+	else {
+		free_block = (struct free_block*)header;
+		sljit_insert_free_block(free_block, header->size);
+	}
+
+	header = AS_BLOCK_HEADER(free_block, free_block->size);
+	if (SLJIT_UNLIKELY(!header->size)) {
+		free_block->size += ((struct free_block*)header)->size;
+		sljit_remove_free_block((struct free_block*)header);
+		header = AS_BLOCK_HEADER(free_block, free_block->size);
+		header->prev_size = free_block->size;
+	}
+
+	/* The whole chunk is free. */
+	if (SLJIT_UNLIKELY(!free_block->header.prev_size && header->size == 1)) {
+		/* If this block is freed, we still have (allocated_size / 2) free space. */
+		if (total_size - free_block->size > (allocated_size * 3 / 2)) {
+			total_size -= free_block->size;
+			sljit_remove_free_block(free_block);
+			free_chunk(free_block, free_block->size +
+				sizeof(struct chunk_header) +
+				sizeof(struct block_header));
+		}
+	}
+
+	SLJIT_ALLOCATOR_UNLOCK();
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
+{
+	struct free_block* free_block;
+	struct free_block* next_free_block;
+
+	SLJIT_ALLOCATOR_LOCK();
+
+	free_block = free_blocks;
+	while (free_block) {
+		next_free_block = free_block->next;
+		if (!free_block->header.prev_size && 
+				AS_BLOCK_HEADER(free_block, free_block->size)->size == 1) {
+			total_size -= free_block->size;
+			sljit_remove_free_block(free_block);
+			free_chunk(free_block, free_block->size +
+				sizeof(struct chunk_header) +
+				sizeof(struct block_header));
+		}
+		free_block = next_free_block;
+	}
+
+	SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks));
+	SLJIT_ALLOCATOR_UNLOCK();
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr)
+{
+	return ((struct block_header *)(ptr))[-1].executable_offset;
+}
diff --git a/src/c/pcre2/src/sljit/sljitUtils.c b/src/c/pcre2/src/sljit/sljitUtils.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitUtils.c
@@ -0,0 +1,337 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* ------------------------------------------------------------------------ */
+/*  Locks                                                                   */
+/* ------------------------------------------------------------------------ */
+
+/* Executable Allocator */
+
+#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) \
+	&& !(defined SLJIT_WX_EXECUTABLE_ALLOCATOR && SLJIT_WX_EXECUTABLE_ALLOCATOR)
+#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
+#define SLJIT_ALLOCATOR_LOCK()
+#define SLJIT_ALLOCATOR_UNLOCK()
+#elif !(defined _WIN32)
+#include <pthread.h>
+
+static pthread_mutex_t allocator_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#define SLJIT_ALLOCATOR_LOCK() pthread_mutex_lock(&allocator_lock)
+#define SLJIT_ALLOCATOR_UNLOCK() pthread_mutex_unlock(&allocator_lock)
+#else /* windows */
+static HANDLE allocator_lock;
+
+static SLJIT_INLINE void allocator_grab_lock(void)
+{
+	HANDLE lock;
+	if (SLJIT_UNLIKELY(!allocator_lock)) {
+		lock = CreateMutex(NULL, FALSE, NULL);
+		if (InterlockedCompareExchangePointer(&allocator_lock, lock, NULL))
+			CloseHandle(lock);
+	}
+	WaitForSingleObject(allocator_lock, INFINITE);
+}
+
+#define SLJIT_ALLOCATOR_LOCK() allocator_grab_lock()
+#define SLJIT_ALLOCATOR_UNLOCK() ReleaseMutex(allocator_lock)
+#endif /* thread implementation */
+#endif /* SLJIT_EXECUTABLE_ALLOCATOR && !SLJIT_WX_EXECUTABLE_ALLOCATOR */
+
+/* ------------------------------------------------------------------------ */
+/*  Stack                                                                   */
+/* ------------------------------------------------------------------------ */
+
+#if ((defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) \
+	&& !(defined SLJIT_UTIL_SIMPLE_STACK_ALLOCATION && SLJIT_UTIL_SIMPLE_STACK_ALLOCATION)) \
+	|| ((defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) \
+	&& !((defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR) \
+	|| (defined SLJIT_WX_EXECUTABLE_ALLOCATOR && SLJIT_WX_EXECUTABLE_ALLOCATOR)))
+
+#ifndef _WIN32
+/* Provides mmap function. */
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#ifndef MAP_ANON
+#ifdef MAP_ANONYMOUS
+#define MAP_ANON MAP_ANONYMOUS
+#endif /* MAP_ANONYMOUS */
+#endif /* !MAP_ANON */
+
+#ifndef MAP_ANON
+
+#include <fcntl.h>
+
+#ifdef O_CLOEXEC
+#define SLJIT_CLOEXEC	O_CLOEXEC
+#else /* !O_CLOEXEC */
+#define SLJIT_CLOEXEC	0
+#endif /* O_CLOEXEC */
+
+/* Some old systems do not have MAP_ANON. */
+static int dev_zero = -1;
+
+#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
+
+static SLJIT_INLINE int open_dev_zero(void)
+{
+	dev_zero = open("/dev/zero", O_RDWR | SLJIT_CLOEXEC);
+
+	return dev_zero < 0;
+}
+
+#else /* !SLJIT_SINGLE_THREADED */
+
+#include <pthread.h>
+
+static pthread_mutex_t dev_zero_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static SLJIT_INLINE int open_dev_zero(void)
+{
+	pthread_mutex_lock(&dev_zero_mutex);
+	if (SLJIT_UNLIKELY(dev_zero < 0))
+		dev_zero = open("/dev/zero", O_RDWR | SLJIT_CLOEXEC);
+
+	pthread_mutex_unlock(&dev_zero_mutex);
+	return dev_zero < 0;
+}
+
+#endif /* SLJIT_SINGLE_THREADED */
+#undef SLJIT_CLOEXEC
+#endif /* !MAP_ANON */
+#endif /* !_WIN32 */
+#endif /* open_dev_zero */
+
+#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) \
+	|| (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
+
+#ifdef _WIN32
+
+static SLJIT_INLINE sljit_sw get_page_alignment(void) {
+	SYSTEM_INFO si;
+	static sljit_sw sljit_page_align;
+	if (!sljit_page_align) {
+		GetSystemInfo(&si);
+		sljit_page_align = si.dwPageSize - 1;
+	}
+	return sljit_page_align;
+}
+
+#else
+
+#include <unistd.h>
+
+static SLJIT_INLINE sljit_sw get_page_alignment(void) {
+	static sljit_sw sljit_page_align;
+	if (!sljit_page_align) {
+		sljit_page_align = sysconf(_SC_PAGESIZE);
+		/* Should never happen. */
+		if (sljit_page_align < 0)
+			sljit_page_align = 4096;
+		sljit_page_align--;
+	}
+	return sljit_page_align;
+}
+
+#endif /* _WIN32 */
+
+#endif /* get_page_alignment() */
+
+#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK)
+
+#if (defined SLJIT_UTIL_SIMPLE_STACK_ALLOCATION && SLJIT_UTIL_SIMPLE_STACK_ALLOCATION)
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_FUNC sljit_allocate_stack(sljit_uw start_size, sljit_uw max_size, void *allocator_data)
+{
+	struct sljit_stack *stack;
+	void *ptr;
+
+	SLJIT_UNUSED_ARG(allocator_data);
+
+	if (start_size > max_size || start_size < 1)
+		return NULL;
+
+	stack = (struct sljit_stack*)SLJIT_MALLOC(sizeof(struct sljit_stack), allocator_data);
+	if (stack == NULL)
+		return NULL;
+
+	ptr = SLJIT_MALLOC(max_size, allocator_data);
+	if (ptr == NULL) {
+		SLJIT_FREE(stack, allocator_data);
+		return NULL;
+	}
+
+	stack->min_start = (sljit_u8 *)ptr;
+ 	stack->end = stack->min_start + max_size;
+ 	stack->start = stack->end - start_size;
+	stack->top = stack->end;
+	return stack;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void SLJIT_FUNC sljit_free_stack(struct sljit_stack *stack, void *allocator_data)
+{
+	SLJIT_UNUSED_ARG(allocator_data);
+	SLJIT_FREE((void*)stack->min_start, allocator_data);
+	SLJIT_FREE(stack, allocator_data);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_u8 *SLJIT_FUNC sljit_stack_resize(struct sljit_stack *stack, sljit_u8 *new_start)
+{
+	if ((new_start < stack->min_start) || (new_start >= stack->end))
+		return NULL;
+	stack->start = new_start;
+	return new_start;
+}
+
+#else /* !SLJIT_UTIL_SIMPLE_STACK_ALLOCATION */
+
+#ifdef _WIN32
+
+SLJIT_API_FUNC_ATTRIBUTE void SLJIT_FUNC sljit_free_stack(struct sljit_stack *stack, void *allocator_data)
+{
+	SLJIT_UNUSED_ARG(allocator_data);
+	VirtualFree((void*)stack->min_start, 0, MEM_RELEASE);
+	SLJIT_FREE(stack, allocator_data);
+}
+
+#else /* !_WIN32 */
+
+SLJIT_API_FUNC_ATTRIBUTE void SLJIT_FUNC sljit_free_stack(struct sljit_stack *stack, void *allocator_data)
+{
+	SLJIT_UNUSED_ARG(allocator_data);
+	munmap((void*)stack->min_start, stack->end - stack->min_start);
+	SLJIT_FREE(stack, allocator_data);
+}
+
+#endif /* _WIN32 */
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_FUNC sljit_allocate_stack(sljit_uw start_size, sljit_uw max_size, void *allocator_data)
+{
+	struct sljit_stack *stack;
+	void *ptr;
+	sljit_sw page_align;
+
+	SLJIT_UNUSED_ARG(allocator_data);
+
+	if (start_size > max_size || start_size < 1)
+		return NULL;
+
+	stack = (struct sljit_stack*)SLJIT_MALLOC(sizeof(struct sljit_stack), allocator_data);
+	if (stack == NULL)
+		return NULL;
+
+	/* Align max_size. */
+	page_align = get_page_alignment();
+	max_size = (max_size + page_align) & ~page_align;
+
+#ifdef _WIN32
+	ptr = VirtualAlloc(NULL, max_size, MEM_RESERVE, PAGE_READWRITE);
+	if (!ptr) {
+		SLJIT_FREE(stack, allocator_data);
+		return NULL;
+	}
+
+	stack->min_start = (sljit_u8 *)ptr;
+	stack->end = stack->min_start + max_size;
+	stack->start = stack->end;
+
+	if (sljit_stack_resize(stack, stack->end - start_size) == NULL) {
+		sljit_free_stack(stack, allocator_data);
+		return NULL;
+	}
+#else /* !_WIN32 */
+#ifdef MAP_ANON
+	ptr = mmap(NULL, max_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+#else /* !MAP_ANON */
+	if (SLJIT_UNLIKELY((dev_zero < 0) && open_dev_zero())) {
+		SLJIT_FREE(stack, allocator_data);
+		return NULL;
+	}
+	ptr = mmap(NULL, max_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, dev_zero, 0);
+#endif /* MAP_ANON */
+	if (ptr == MAP_FAILED) {
+		SLJIT_FREE(stack, allocator_data);
+		return NULL;
+	}
+	stack->min_start = (sljit_u8 *)ptr;
+	stack->end = stack->min_start + max_size;
+	stack->start = stack->end - start_size;
+#endif /* _WIN32 */
+
+	stack->top = stack->end;
+	return stack;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_u8 *SLJIT_FUNC sljit_stack_resize(struct sljit_stack *stack, sljit_u8 *new_start)
+{
+#if defined _WIN32 || defined(POSIX_MADV_DONTNEED)
+	sljit_uw aligned_old_start;
+	sljit_uw aligned_new_start;
+	sljit_sw page_align;
+#endif
+
+	if ((new_start < stack->min_start) || (new_start >= stack->end))
+		return NULL;
+
+#ifdef _WIN32
+	page_align = get_page_alignment();
+
+	aligned_new_start = (sljit_uw)new_start & ~page_align;
+	aligned_old_start = ((sljit_uw)stack->start) & ~page_align;
+	if (aligned_new_start != aligned_old_start) {
+		if (aligned_new_start < aligned_old_start) {
+			if (!VirtualAlloc((void*)aligned_new_start, aligned_old_start - aligned_new_start, MEM_COMMIT, PAGE_READWRITE))
+				return NULL;
+		}
+		else {
+			if (!VirtualFree((void*)aligned_old_start, aligned_new_start - aligned_old_start, MEM_DECOMMIT))
+				return NULL;
+		}
+	}
+#elif defined(POSIX_MADV_DONTNEED)
+	if (stack->start < new_start) {
+		page_align = get_page_alignment();
+
+		aligned_new_start = (sljit_uw)new_start & ~page_align;
+		aligned_old_start = ((sljit_uw)stack->start) & ~page_align;
+
+		if (aligned_new_start > aligned_old_start) {
+			posix_madvise((void*)aligned_old_start, aligned_new_start - aligned_old_start, POSIX_MADV_DONTNEED);
+#ifdef MADV_FREE
+			madvise((void*)aligned_old_start, aligned_new_start - aligned_old_start, MADV_FREE);
+#endif /* MADV_FREE */
+		}
+	}
+#endif /* _WIN32 */
+
+	stack->start = new_start;
+	return new_start;
+}
+
+#endif /* SLJIT_UTIL_SIMPLE_STACK_ALLOCATION */
+
+#endif /* SLJIT_UTIL_STACK */
diff --git a/src/c/pcre2/src/sljit/sljitWXExecAllocator.c b/src/c/pcre2/src/sljit/sljitWXExecAllocator.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2/src/sljit/sljitWXExecAllocator.c
@@ -0,0 +1,225 @@
+/*
+ *    Stack-less Just-In-Time compiler
+ *
+ *    Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright notice, this list of
+ *      conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *      of conditions and the following disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+   This file contains a simple W^X executable memory allocator for POSIX
+   like systems and Windows
+
+   In *NIX, MAP_ANON is required (that is considered a feature) so make
+   sure to set the right availability macros for your system or the code
+   will fail to build.
+
+   If your system doesn't support mapping of anonymous pages (ex: IRIX) it
+   is also likely that it doesn't need this allocator and should be using
+   the standard one instead.
+
+   It allocates a separate map for each code block and may waste a lot of
+   memory, because whatever was requested, will be rounded up to the page
+   size (minimum 4KB, but could be even bigger).
+
+   It changes the page permissions (RW <-> RX) as needed and therefore, if you
+   will be updating the code after it has been generated, need to make sure to
+   block any concurrent execution, or could result in a SIGBUS, that could
+   even manifest itself at a different address than the one that was being
+   modified.
+
+   Only use if you are unable to use the regular allocator because of security
+   restrictions and adding exceptions to your application or the system are
+   not possible.
+*/
+
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \
+	sljit_update_wx_flags((from), (to), (enable_exec))
+
+#ifndef _WIN32
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#ifdef __NetBSD__
+#if defined(PROT_MPROTECT)
+#define check_se_protected(ptr, size) (0)
+#define SLJIT_PROT_WX PROT_MPROTECT(PROT_EXEC)
+#else /* !PROT_MPROTECT */
+#ifdef _NETBSD_SOURCE
+#include <sys/param.h>
+#else /* !_NETBSD_SOURCE */
+typedef unsigned int	u_int;
+#define devmajor_t sljit_s32
+#endif /* _NETBSD_SOURCE */
+#include <sys/sysctl.h>
+#include <unistd.h>
+
+#define check_se_protected(ptr, size) netbsd_se_protected()
+
+static SLJIT_INLINE int netbsd_se_protected(void)
+{
+	int mib[3];
+	int paxflags;
+	size_t len = sizeof(paxflags);
+
+	mib[0] = CTL_PROC;
+	mib[1] = getpid();
+	mib[2] = PROC_PID_PAXFLAGS;
+
+	if (SLJIT_UNLIKELY(sysctl(mib, 3, &paxflags, &len, NULL, 0) < 0))
+		return -1;
+
+	return (paxflags & CTL_PROC_PAXFLAGS_MPROTECT) ? -1 : 0;
+}
+#endif /* PROT_MPROTECT */
+#else /* POSIX */
+#define check_se_protected(ptr, size) generic_se_protected(ptr, size)
+
+static SLJIT_INLINE int generic_se_protected(void *ptr, sljit_uw size)
+{
+	if (SLJIT_LIKELY(!mprotect(ptr, size, PROT_EXEC)))
+		return mprotect(ptr, size, PROT_READ | PROT_WRITE);
+
+	return -1;
+}
+#endif /* NetBSD */
+
+#if defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED
+#define SLJIT_SE_LOCK()
+#define SLJIT_SE_UNLOCK()
+#else /* !SLJIT_SINGLE_THREADED */
+#include <pthread.h>
+#define SLJIT_SE_LOCK()	pthread_mutex_lock(&se_lock)
+#define SLJIT_SE_UNLOCK()	pthread_mutex_unlock(&se_lock)
+#endif /* SLJIT_SINGLE_THREADED */
+
+#ifndef SLJIT_PROT_WX
+#define SLJIT_PROT_WX 0
+#endif /* !SLJIT_PROT_WX */
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
+{
+#if !(defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
+	static pthread_mutex_t se_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+	static int se_protected = !SLJIT_PROT_WX;
+	sljit_uw* ptr;
+
+	if (SLJIT_UNLIKELY(se_protected < 0))
+		return NULL;
+
+	size += sizeof(sljit_uw);
+	ptr = (sljit_uw*)mmap(NULL, size, PROT_READ | PROT_WRITE | SLJIT_PROT_WX,
+				MAP_PRIVATE | MAP_ANON, -1, 0);
+
+	if (ptr == MAP_FAILED)
+		return NULL;
+
+	if (SLJIT_UNLIKELY(se_protected > 0)) {
+		SLJIT_SE_LOCK();
+		se_protected = check_se_protected(ptr, size);
+		SLJIT_SE_UNLOCK();
+		if (SLJIT_UNLIKELY(se_protected < 0)) {
+			munmap((void *)ptr, size);
+			return NULL;
+		}
+	}
+
+	*ptr++ = size;
+	return ptr;
+}
+
+#undef SLJIT_PROT_WX
+#undef SLJIT_SE_UNLOCK
+#undef SLJIT_SE_LOCK
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
+{
+	sljit_uw *start_ptr = ((sljit_uw*)ptr) - 1;
+	munmap((void*)start_ptr, *start_ptr);
+}
+
+static void sljit_update_wx_flags(void *from, void *to, sljit_s32 enable_exec)
+{
+	sljit_uw page_mask = (sljit_uw)get_page_alignment();
+	sljit_uw start = (sljit_uw)from;
+	sljit_uw end = (sljit_uw)to;
+	int prot = PROT_READ | (enable_exec ? PROT_EXEC : PROT_WRITE);
+
+	SLJIT_ASSERT(start < end);
+
+	start &= ~page_mask;
+	end = (end + page_mask) & ~page_mask;
+
+	mprotect((void*)start, end - start, prot);
+}
+
+#else /* windows */
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
+{
+	sljit_uw *ptr;
+
+	size += sizeof(sljit_uw);
+	ptr = (sljit_uw*)VirtualAlloc(NULL, size,
+				MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+
+	if (!ptr)
+		return NULL;
+
+	*ptr++ = size;
+
+	return ptr;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
+{
+	sljit_uw start = (sljit_uw)ptr - sizeof(sljit_uw);
+#if defined(SLJIT_DEBUG) && SLJIT_DEBUG
+	sljit_uw page_mask = (sljit_uw)get_page_alignment();
+
+	SLJIT_ASSERT(!(start & page_mask));
+#endif
+	VirtualFree((void*)start, 0, MEM_RELEASE);
+}
+
+static void sljit_update_wx_flags(void *from, void *to, sljit_s32 enable_exec)
+{
+	DWORD oldprot;
+	sljit_uw page_mask = (sljit_uw)get_page_alignment();
+	sljit_uw start = (sljit_uw)from;
+	sljit_uw end = (sljit_uw)to;
+	DWORD prot = enable_exec ? PAGE_EXECUTE : PAGE_READWRITE;
+
+	SLJIT_ASSERT(start < end);
+
+	start &= ~page_mask;
+	end = (end + page_mask) & ~page_mask;
+
+	VirtualProtect((void*)start, end - start, prot, &oldprot);
+}
+
+#endif /* !windows */
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
+{
+	/* This allocator does not keep unused memory for future allocations. */
+}
diff --git a/src/c/pcre2_chartables.c b/src/c/pcre2_chartables.c
new file mode 100644
--- /dev/null
+++ b/src/c/pcre2_chartables.c
@@ -0,0 +1,204 @@
+// Copied per the PCRE2 source's NON-AUTOTOOLS-BUILD instructions.
+
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/* This file was automatically written by the pcre2_dftables auxiliary
+program. It contains character tables that are used when no external
+tables are passed to PCRE2 by the application that calls it. The tables
+are used only for characters whose code values are less than 256. */
+
+/* This set of tables was written in the C locale. */
+
+/* The pcre2_ftables program (which is distributed with PCRE2) can be used
+to build alternative versions of this file. This is necessary if you are
+running in an EBCDIC environment, or if you want to default to a different
+encoding, for example ISO-8859-1. When pcre2_dftables is run, it creates
+these tables in the "C" locale by default. This happens automatically if
+PCRE2 is configured with --enable-rebuild-chartables. However, you can run
+pcre2_dftables manually with the -L option to build tables using the LC_ALL
+locale. */
+
+/* The following #include is present because without it gcc 4.x may remove
+the array definition from the final binary if PCRE2 is built into a static
+library and dead code stripping is activated. This leads to link errors.
+Pulling in the header ensures that the array gets flagged as "someone
+outside this compilation unit might reference this" and so it will always
+be supplied to the linker. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+const uint8_t PRIV(default_tables)[] = {
+
+/* This table is a lower casing table. */
+
+    0,  1,  2,  3,  4,  5,  6,  7,
+    8,  9, 10, 11, 12, 13, 14, 15,
+   16, 17, 18, 19, 20, 21, 22, 23,
+   24, 25, 26, 27, 28, 29, 30, 31,
+   32, 33, 34, 35, 36, 37, 38, 39,
+   40, 41, 42, 43, 44, 45, 46, 47,
+   48, 49, 50, 51, 52, 53, 54, 55,
+   56, 57, 58, 59, 60, 61, 62, 63,
+   64, 97, 98, 99,100,101,102,103,
+  104,105,106,107,108,109,110,111,
+  112,113,114,115,116,117,118,119,
+  120,121,122, 91, 92, 93, 94, 95,
+   96, 97, 98, 99,100,101,102,103,
+  104,105,106,107,108,109,110,111,
+  112,113,114,115,116,117,118,119,
+  120,121,122,123,124,125,126,127,
+  128,129,130,131,132,133,134,135,
+  136,137,138,139,140,141,142,143,
+  144,145,146,147,148,149,150,151,
+  152,153,154,155,156,157,158,159,
+  160,161,162,163,164,165,166,167,
+  168,169,170,171,172,173,174,175,
+  176,177,178,179,180,181,182,183,
+  184,185,186,187,188,189,190,191,
+  192,193,194,195,196,197,198,199,
+  200,201,202,203,204,205,206,207,
+  208,209,210,211,212,213,214,215,
+  216,217,218,219,220,221,222,223,
+  224,225,226,227,228,229,230,231,
+  232,233,234,235,236,237,238,239,
+  240,241,242,243,244,245,246,247,
+  248,249,250,251,252,253,254,255,
+
+/* This table is a case flipping table. */
+
+    0,  1,  2,  3,  4,  5,  6,  7,
+    8,  9, 10, 11, 12, 13, 14, 15,
+   16, 17, 18, 19, 20, 21, 22, 23,
+   24, 25, 26, 27, 28, 29, 30, 31,
+   32, 33, 34, 35, 36, 37, 38, 39,
+   40, 41, 42, 43, 44, 45, 46, 47,
+   48, 49, 50, 51, 52, 53, 54, 55,
+   56, 57, 58, 59, 60, 61, 62, 63,
+   64, 97, 98, 99,100,101,102,103,
+  104,105,106,107,108,109,110,111,
+  112,113,114,115,116,117,118,119,
+  120,121,122, 91, 92, 93, 94, 95,
+   96, 65, 66, 67, 68, 69, 70, 71,
+   72, 73, 74, 75, 76, 77, 78, 79,
+   80, 81, 82, 83, 84, 85, 86, 87,
+   88, 89, 90,123,124,125,126,127,
+  128,129,130,131,132,133,134,135,
+  136,137,138,139,140,141,142,143,
+  144,145,146,147,148,149,150,151,
+  152,153,154,155,156,157,158,159,
+  160,161,162,163,164,165,166,167,
+  168,169,170,171,172,173,174,175,
+  176,177,178,179,180,181,182,183,
+  184,185,186,187,188,189,190,191,
+  192,193,194,195,196,197,198,199,
+  200,201,202,203,204,205,206,207,
+  208,209,210,211,212,213,214,215,
+  216,217,218,219,220,221,222,223,
+  224,225,226,227,228,229,230,231,
+  232,233,234,235,236,237,238,239,
+  240,241,242,243,244,245,246,247,
+  248,249,250,251,252,253,254,255,
+
+/* This table contains bit maps for various character classes. Each map is 32
+bytes long and the bits run from the least significant end of each byte. The
+classes that have their own maps are: space, xdigit, digit, upper, lower, word,
+graph, print, punct, and cntrl. Other classes are built from combinations. */
+
+  0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00,  /* space */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,  /* xdigit */
+  0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,  /* digit */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  /* upper */
+  0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  /* lower */
+  0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,  /* word */
+  0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,  /* graph */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,  /* print */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc,  /* punct */
+  0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+  0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,  /* cntrl */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+/* This table identifies various classes of character by individual bits:
+  0x01   white space character
+  0x02   letter
+  0x04   lower case letter
+  0x08   decimal digit
+  0x10   alphanumeric or '_'
+*/
+
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*   0-  7 */
+  0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00, /*   8- 15 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  16- 23 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  24- 31 */
+  0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*    - '  */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  ( - /  */
+  0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, /*  0 - 7  */
+  0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00, /*  8 - ?  */
+  0x00,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /*  @ - G  */
+  0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /*  H - O  */
+  0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /*  P - W  */
+  0x12,0x12,0x12,0x00,0x00,0x00,0x00,0x10, /*  X - _  */
+  0x00,0x16,0x16,0x16,0x16,0x16,0x16,0x16, /*  ` - g  */
+  0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, /*  h - o  */
+  0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16, /*  p - w  */
+  0x16,0x16,0x16,0x00,0x00,0x00,0x00,0x00, /*  x -127 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */
+
+/* End of pcre2_chartables.c */
diff --git a/src/hs/Text/Regex/Pcre2.hs b/src/hs/Text/Regex/Pcre2.hs
new file mode 100644
--- /dev/null
+++ b/src/hs/Text/Regex/Pcre2.hs
@@ -0,0 +1,354 @@
+module Text.Regex.Pcre2 (
+    -- * Matching and substitution
+    {-|
+    /__Introduction__/
+
+    Atop the low-level binding to the C API, we present a high-level interface
+    to add regular expressions to Haskell programs.
+
+    All input and output strings are strict `Text`, which maps directly to how
+    PCRE2 operates on strings of 16-bit-wide code units.
+
+    The C API requires pattern strings to be compiled and the compiled patterns
+    to be executed on subject strings in discrete steps.  We hide this
+    procedure, accepting pattern and subject as arguments in a single function,
+    essentially:
+
+    > pattern -> subject -> result
+
+    The implementation guarantees that,
+    when [partially applied](https://wiki.haskell.org/Partial_application) to
+    pattern but not subject, the resulting function
+    will [close](https://en.wikipedia.org/wiki/Closure_(computer_programming\))
+    on the underlying compiled object and reuse it for every subject it is
+    subsequently applied to.
+
+    Likewise, we do not require the user to know whether a PCRE2 option is to be
+    applied at pattern compile time or match time.  Instead we fold all possible
+    options into a single datatype, `Option`.  Most functions have vanilla and
+    configurable variants; the latter have \"@Opt@\" in the name and accept a
+    value of this type.
+
+    Similar to how @head :: [a] -> a@ sacrifices totality for type simplicity,
+    we represent user errors as imprecise exceptions.  Unlike with @head@, these
+    exceptions are typed (as `SomePcre2Exception`s); moreover, we offer Template
+    Haskell facilities that can intercept some of these errors before the
+    program is run.  (Failure to match is not considered a user error and is
+    represented in the types.)
+
+    [There's more than one way to do it](https://en.wikipedia.org/wiki/There's_more_than_one_way_to_do_it)
+    with this library.  The choices between functions and traversals,
+    poly-kinded `Captures` and plain lists, string literals and
+    quasi-quotations, quasi-quoted expressions and quasi-quoted patterns...these
+    are left to the user.  She will observe that advanced features\' extra
+    safety, power, and convenience entail additional language extensions,
+    cognitive overhead, and (for lenses) library dependencies, so it\'s really a
+    matter of finding the best trade-offs for her case.
+
+    /__Definitions__/
+
+    [Pattern]:  The string defining a regular expression.  Refer to
+    syntax [here](https://pcre.org/current/doc/html/pcre2pattern.html).
+
+    [Subject]:  The string the compiled regular expression is executed on.
+
+    [Regex]:  A function of the form @`Text` -> result@, where the argument is
+    the subject.  It is \"compiled\" via partial application as discussed above.
+    (Lens users:  A regex has the more abstract form
+    @[Traversal\'](https://hackage.haskell.org/package/microlens/docs/Lens-Micro.html#t:Traversal-39-)
+    `Text` result@, but the concept is the same.)
+
+    [Capture (or capture group)]:  Any substrings of the subject matched by the
+    pattern, meaning the whole pattern and any parenthesized groupings.  The
+    PCRE2 docs do not refer to the former as a \"capture\"; however it is
+    accessed the same way in the C API, just with index 0, so we will consider
+    it the 0th capture for consistency.  Parenthesized captures are implicitly
+    numbered from 1.
+
+    [Unset capture]:  A capture considered unset as distinct from empty.  This
+    can arise from matching the pattern @(a)?@ to an empty subject&#x2014;the
+    0th capture will be set as empty, but the 1st will be unset altogether.  We
+    represent both as empty `Text` for simplicity.  See below for discussions
+    about how unset captures may be detected or substituted using this library.
+
+    [Named capture]:  A parenthesized capture can be named like this:
+    @(?\<foo\>...)@.  Whether they have names or not, captures are always
+    numbered as described above.
+
+    /__Performance__/
+
+    Each API function is designed such that, when a regex is obtained, the
+    underlying C data generated from the pattern and any options is reused for
+    that regex\'s lifetime.  Care should be taken that the same regex is not
+    recreated /ex nihilo/ and discarded for each new subject:
+
+    > isEmptyOrHas2Digits :: Text -> Bool
+    > isEmptyOrHas2Digits s = Text.null s || matches "\\d{2}" s -- bad, fully applied
+
+    Instead, store it in a partially applied state:
+
+    > isEmptyOrHas2Digits = (||) <$> Text.null <*> matches "\\d{2}" -- OK but abstruse
+
+    When in doubt, always create regexes as top-level values:
+
+    > has2Digits :: Text -> Bool
+    > has2Digits = matches "\\d{2}"
+    >
+    > isEmptyOrHas2Digits s = Text.null s || has2Digits s -- good
+
+    Note: Template Haskell regexes are immune from this problem and may be
+    freely inlined; see below.
+
+    /__Handling errors__/
+
+    In a few places we use the `Alternative` typeclass to optionally return
+    match results, expressing success via `pure` and failure via `empty`.
+    Typically the user will choose the instance `Maybe`, but other useful ones
+    exist, notably @[STM](https://hackage.haskell.org/package/stm/docs/Control-Monad-STM.html#t:STM)@,
+    that of [optparse-applicative](https://hackage.haskell.org/package/optparse-applicative/docs/Options-Applicative.html#t:Parser),
+    and those of parser combinator libraries such
+    as [megaparsec](https://hackage.haskell.org/package/megaparsec/docs/Text-Megaparsec.html#t:ParsecT).
+
+    By contrast, user errors are thrown purely.  If a user error is to be
+    caught, it must be at the site where the match or substitution results are
+    evaluated&#x2014;in other words, wherever the regex is applied to a subject.
+    Even pattern compile errors are deferred to match sites, due to the way this
+    library employs `System.IO.Unsafe.unsafePerformIO` to implement laziness.
+
+    >>> broken = match "*"
+    >>> broken "foo"
+    *** Exception: pcre2_compile: quantifier does not follow a repeatable item
+                        *
+                        ^
+
+    `Control.Exception.evaluate` comes in handy to force results into the `IO`
+    monad in order to catch errors reliably:
+
+    >>> evaluate (broken "foo") `catch` \(_ :: SomePcre2Exception) -> return Nothing
+    Nothing
+
+    Or simply select `IO` as the `Alternative` instance:
+
+    >>> :t broken
+    broken :: Alternative f => Text -> f Text
+    >>> broken "foo" `catch` \(_ :: SomePcre2Exception) -> return "broken"
+    "broken"
+    -}
+
+    -- ** Basic matching functions
+    match,
+    matchOpt,
+    matches,
+    matchesOpt,
+    captures,
+    capturesOpt,
+    capturesA,
+    capturesOptA,
+
+    -- ** PCRE2-native substitution
+    sub,
+    gsub,
+    subOpt,
+
+    -- ** Lens-powered matching and substitution
+    --
+    -- | To use this portion of the library, there are two prerequisites:
+    --
+    -- 1.  A basic working understanding of optics.  Many tutorials exist
+    -- online, such as
+    -- [this](https://hackage.haskell.org/package/lens-tutorial-1.0.4/docs/Control-Lens-Tutorial.html),
+    -- and videos such as [this](https://www.youtube.com/watch?v=7fbziKgQjnw).
+    --
+    -- 2.  A library providing combinators.  For lens newcomers, it is
+    -- recommended to grab
+    -- [microlens-platform](https://hackage.haskell.org/package/microlens-platform)&#x2014;most
+    -- of the examples in this library work with it,
+    -- @[packed](https://hackage.haskell.org/package/microlens-platform/docs/Lens-Micro-Platform.html#v:packed)@
+    -- and
+    -- @[unpacked](https://hackage.haskell.org/package/microlens-platform/docs/Lens-Micro-Platform.html#v:packed)@
+    -- are included for working with `Text`, and it is upwards-compatible with
+    -- the full [lens](https://hackage.haskell.org/package/lens) library.
+    --
+    -- We expose a set of traversals that focus on matched substrings within a
+    -- subject.  Like the basic functional regexes, they should be \"compiled\"
+    -- and memoized, rather than created inline.
+    --
+    -- > _nee :: Traversal' Text Text
+    -- > _nee = _match "(?i)\\bnee\\b"
+    --
+    -- In addition to getting results, they support substitution through
+    -- setting; more generally, they can accrete effects while performing
+    -- replacements.
+    --
+    -- >>> promptNee = traverseOf (_nee . unpacked) $ \s -> print s >> getLine
+    -- >>> promptNee "We are the knights who say...NEE!"
+    -- "NEE"
+    -- NOO
+    -- "We are the knights who say...NOO!"
+    -- >>>
+    --
+    -- The optic interface signals match failure by not targeting anything.
+    --
+    -- >>> promptNee "Shhhhh"
+    -- "Shhhhh"
+    -- >>>
+    --
+    -- In general these traversals are not law-abiding.
+    _match,
+    _matchOpt,
+    _captures,
+    _capturesOpt,
+
+    -- * Compile-time validation
+    --
+    -- | Despite whatever virtues, the API thus far has some fragility arising
+    -- from various scenarios:
+    --
+    -- * pattern malformation such as mismatched parentheses /(runtime error)/
+    --
+    -- * out-of-bounds indexing of a capture group list /(runtime error)/
+    --
+    -- * out-of-bounds @ix@ing of a @Traversal\'@ target
+    -- /(spurious failure to match)/
+    --
+    -- * case expression containing a Haskell list pattern of the wrong length
+    -- /(spurious failure to match)/
+    --
+    -- * regex created and discarded inline /(suboptimal performance)/
+    --
+    -- * precariously many backslashes in a pattern.  Matching a literal
+    -- backslash requires the sequence @\"\\\\\\\\\"@!
+    --
+    -- Using a combination of language extensions and pattern introspection
+    -- features, we provide a Template Haskell API to mitigate these scenarios.
+    -- To make use of it these must be enabled:
+    --
+    -- +--------------------+---------------------------------------+------------------------------+
+    -- | Extension          | Required for                          | When                         |
+    -- +====================+=======================================+==============================+
+    -- | @DataKinds@        | `GHC.TypeLits.Nat`s (numbers),        | Using `regex`\/`_regex` with |
+    -- |                    | `GHC.TypeLits.Symbol`s (strings), and | a pattern containing         |
+    -- |                    | other type-level data powering        | parenthesized captures       |
+    -- |                    | compile-time capture lookups          |                              |
+    -- +--------------------+---------------------------------------+------------------------------+
+    -- | @QuasiQuotes@      | @[@/f/@|@...@|]@ syntax               | Always                       |
+    -- +--------------------+---------------------------------------+------------------------------+
+    -- | @TemplateHaskell@  | Running PCRE2 at compile time and     | Always                       |
+    -- |                    | generating code                       |                              |
+    -- +--------------------+---------------------------------------+------------------------------+
+    -- | @TypeApplications@ | @\@i@ syntax for supplying type index | Using `capture`\/`_capture`  |
+    -- |                    | arguments to applicable functions     |                              |
+    -- +--------------------+---------------------------------------+------------------------------+
+    -- | @ViewPatterns@     | Running code and binding variables in | Using `regex` as a Haskell   |
+    -- |                    | pattern context proper (pattern       | pattern                      |
+    -- |                    | guards are off-limits for this)       |                              |
+    -- +--------------------+---------------------------------------+------------------------------+
+    --
+    -- The inspiration for this portion of the library is Ruby, which supports
+    -- regular expressions with [superior ergonomics](https://ruby-doc.org/core-2.7.2/Regexp.html#class-Regexp-label-Capturing).
+
+    -- ** Quasi-quoters
+    regex,
+    _regex,
+
+    -- ** Type-indexed capture groups
+    Captures(),
+    capture,
+    _capture,
+
+    -- * Options
+
+    Option(
+        AllowEmptyClass,
+        AltBsux,
+        AltBsuxLegacy,
+        AltCircumflex,
+        AltVerbNames,
+        Anchored,
+        AutoCallout,
+        BadEscapeIsLiteral,
+        Bsr,
+        Caseless,
+        DepthLimit,
+        DollarEndOnly,
+        DotAll,
+        DupNames,
+        EndAnchored,
+        EscapedCrIsLf,
+        Extended,
+        ExtendedMore,
+        FirstLine,
+        HeapLimit,
+        Literal,
+        MatchLimit,
+        MatchLine,
+        MatchUnsetBackRef,
+        MatchWord,
+        MaxPatternLength,
+        Multiline,
+        NeverBackslashC,
+        NeverUcp,
+        Newline,
+        NoAutoCapture,
+        NoAutoPossess,
+        NoDotStarAnchor,
+        NoStartOptimize,
+        NotBol,
+        NotEmpty,
+        NotEmptyAtStart,
+        NotEol,
+        OffsetLimit,
+        ParensLimit,
+        PartialHard,
+        PartialSoft,
+        SubGlobal,
+        SubLiteral,
+        SubReplacementOnly,
+        SubUnknownUnset,
+        SubUnsetEmpty,
+        Ucp,
+        Ungreedy,
+        UnsafeCallout,
+        UnsafeCompileRecGuard,
+        UnsafeSubCallout,
+        Utf),
+
+    Bsr(..),
+    Newline(..),
+
+    -- ** Callout interface
+    -- *** Capture callouts
+    CalloutInfo(..),
+    CalloutIndex(..),
+    CalloutResult(..),
+    -- *** Substitution callouts
+    SubCalloutInfo(..),
+    SubCalloutResult(..),
+
+    -- * User errors
+    SomePcre2Exception(),
+    Pcre2Exception(),
+    Pcre2CompileException(),
+
+    -- * PCRE2 build configuration
+    defaultBsr,
+    compiledWidths,
+    defaultDepthLimit,
+    defaultHeapLimit,
+    supportsJit,
+    jitTarget,
+    linkSize,
+    defaultMatchLimit,
+    defaultNewline,
+    defaultIsNeverBackslashC,
+    defaultParensLimit,
+    defaultTablesLength,
+    unicodeVersion,
+    supportsUnicode,
+    pcreVersion)
+where
+
+import Control.Applicative       (Alternative(..))
+import Data.Text                 (Text)
+import Text.Regex.Pcre2.Internal
+import Text.Regex.Pcre2.TH
diff --git a/src/hs/Text/Regex/Pcre2/Foreign.hs b/src/hs/Text/Regex/Pcre2/Foreign.hs
new file mode 100644
--- /dev/null
+++ b/src/hs/Text/Regex/Pcre2/Foreign.hs
@@ -0,0 +1,639 @@
+{-# LANGUAGE CApiFFI #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+-- | A complete binding to the low-level C API.
+--
+-- Items here are named identically to their C counterparts.  Therefore,
+-- documentation will be sparse;
+-- [the official PCRE2 API docs](https://pcre.org/current/doc/html/pcre2api.html#SEC36)
+-- should suffice.
+module Text.Regex.Pcre2.Foreign where
+
+import Foreign
+import Foreign.C.Types
+import Text.Regex.Pcre2.Foreign.TH (constant, getter)
+
+-- * Types
+
+-- | \"The @UCHAR@ types define unsigned code units of the appropriate widths.
+-- For example, @PCRE2_UCHAR16@ is usually defined as @uint16_t@.\"
+type PCRE2_UCHAR = CUShort
+
+-- | \"The @SPTR@ types are constant pointers to the equivalent @UCHAR@ types,
+-- that is, they are pointers to vectors of unsigned code units.\"
+type PCRE2_SPTR = Ptr PCRE2_UCHAR
+
+-- | \"...string lengths and offsets into strings of code units...are always of
+-- type @PCRE2_SIZE@...currently always defined as @size_t@.\"
+type PCRE2_SIZE = CSize
+
+-- ** Opaque types
+--
+-- $OpaqueTypes
+-- These correspond to structs that are only ever passed by reference.  They
+-- simply exist for type safety and cannot be constructed in Haskell.
+data Pcre2_general_context
+data Pcre2_compile_context
+data Pcre2_match_context
+data Pcre2_callout_block
+data Pcre2_substitute_callout_block
+data Pcre2_code
+data Pcre2_jit_stack
+data Pcre2_match_data
+data Pcre2_callout_enumerate_block
+
+-- * The general context
+
+foreign import capi safe "pcre2.h" pcre2_general_context_create
+    :: FunPtr (PCRE2_SIZE -> Ptr a -> IO (Ptr b)) -- ^ custom malloc
+    -> FunPtr (Ptr b -> Ptr a -> IO ())           -- ^ custom free
+    -> Ptr a
+    -> IO (Ptr Pcre2_general_context)
+
+foreign import capi safe "pcre2.h" pcre2_general_context_copy
+    :: Ptr Pcre2_general_context
+    -> IO (Ptr Pcre2_general_context)
+
+foreign import capi safe "pcre2.h" pcre2_general_context_free
+    :: Ptr Pcre2_general_context
+    -> IO ()
+
+-- * The compile context
+
+foreign import capi safe "pcre2.h" pcre2_compile_context_create
+    :: Ptr Pcre2_general_context
+    -> IO (Ptr Pcre2_compile_context)
+
+foreign import capi safe "pcre2.h" pcre2_compile_context_copy
+    :: Ptr Pcre2_compile_context
+    -> IO (Ptr Pcre2_compile_context)
+
+foreign import capi safe "pcre2.h" pcre2_compile_context_free
+    :: Ptr Pcre2_compile_context
+    -> IO ()
+
+-- ** Compile context setters
+
+-- TODO Maybe this goes next to wherever errors appear in the docs?
+constant "ERROR_BADDATA" ''CInt
+
+foreign import capi unsafe "pcre2.h" pcre2_set_bsr
+    :: Ptr Pcre2_compile_context
+    -> CUInt -- ^ See below for possible values.
+    -> IO CInt
+
+constant "BSR_ANYCRLF" ''CUInt
+constant "BSR_UNICODE" ''CUInt
+
+foreign import capi "pcre2.h" pcre2_set_character_tables
+    :: Ptr Pcre2_compile_context
+    -> Ptr CUChar
+    -> IO CInt
+
+foreign import capi unsafe "pcre2.h" pcre2_set_compile_extra_options
+    :: Ptr Pcre2_compile_context
+    -> CUInt -- ^ See \"Extra compile options\" below for possible bit flags.
+    -> IO CInt
+
+foreign import capi unsafe "pcre2.h" pcre2_set_max_pattern_length
+    :: Ptr Pcre2_compile_context
+    -> PCRE2_SIZE
+    -> IO CInt
+
+foreign import capi unsafe "pcre2.h" pcre2_set_newline
+    :: Ptr Pcre2_compile_context
+    -> CUInt -- ^ See below for possible values.
+    -> IO CInt
+
+constant "NEWLINE_CR" ''CUInt
+constant "NEWLINE_LF" ''CUInt
+constant "NEWLINE_CRLF" ''CUInt
+constant "NEWLINE_ANY" ''CUInt
+constant "NEWLINE_ANYCRLF" ''CUInt
+constant "NEWLINE_NUL" ''CUInt
+
+foreign import capi unsafe "pcre2.h" pcre2_set_parens_nest_limit
+    :: Ptr Pcre2_compile_context
+    -> CUInt
+    -> IO CInt
+
+foreign import capi unsafe "pcre2.h" pcre2_set_compile_recursion_guard
+    :: Ptr Pcre2_compile_context
+    -> FunPtr (CUInt -> Ptr a -> IO CInt)
+    -> Ptr a
+    -> IO CInt
+
+-- * The match context
+
+foreign import capi safe "pcre2.h" pcre2_match_context_create
+    :: Ptr Pcre2_general_context
+    -> IO (Ptr Pcre2_match_context)
+
+foreign import capi safe "pcre2.h" pcre2_match_context_copy
+    :: Ptr Pcre2_match_context
+    -> IO (Ptr Pcre2_match_context)
+
+foreign import capi safe "pcre2.h" pcre2_match_context_free
+    :: Ptr Pcre2_match_context
+    -> IO ()
+
+-- ** Match context setters
+
+foreign import capi unsafe "pcre2.h" pcre2_set_callout
+    :: Ptr Pcre2_match_context
+    -> FunPtr (Ptr Pcre2_callout_block -> Ptr a -> IO CInt)
+    -> Ptr a
+    -> IO CInt
+
+foreign import capi unsafe "pcre2.h" pcre2_set_substitute_callout
+    :: Ptr Pcre2_match_context
+    -> FunPtr (Ptr Pcre2_substitute_callout_block -> Ptr a -> IO CInt)
+    -> Ptr a
+    -> IO CInt
+
+foreign import capi unsafe "pcre2.h" pcre2_set_offset_limit
+    :: Ptr Pcre2_match_context
+    -> PCRE2_SIZE -- ^ Can be unset.  See below.
+    -> IO CInt
+
+constant "UNSET" ''PCRE2_SIZE
+
+foreign import capi unsafe "pcre2.h" pcre2_set_heap_limit
+    :: Ptr Pcre2_match_context
+    -> CUInt
+    -> IO CInt
+
+foreign import capi unsafe "pcre2.h" pcre2_set_match_limit
+    :: Ptr Pcre2_match_context
+    -> CUInt
+    -> IO CInt
+
+foreign import capi unsafe "pcre2.h" pcre2_set_depth_limit
+    :: Ptr Pcre2_match_context
+    -> CUInt
+    -> IO CInt
+
+-- * Checking build-time options
+
+foreign import capi unsafe "pcre2.h" pcre2_config
+    :: CUInt   -- ^ See below for possible values.
+    -> Ptr a   -- ^ See the C API docs for what gets returned here.
+    -> IO CInt
+
+constant "CONFIG_BSR" ''CUInt
+constant "CONFIG_COMPILED_WIDTHS" ''CUInt
+constant "CONFIG_DEPTHLIMIT" ''CUInt
+constant "CONFIG_HEAPLIMIT" ''CUInt
+constant "CONFIG_JIT" ''CUInt
+constant "CONFIG_JITTARGET" ''CUInt
+constant "CONFIG_LINKSIZE" ''CUInt
+constant "CONFIG_MATCHLIMIT" ''CUInt
+constant "CONFIG_NEWLINE" ''CUInt
+constant "CONFIG_NEVER_BACKSLASH_C" ''CUInt
+constant "CONFIG_PARENSLIMIT" ''CUInt
+constant "CONFIG_STACKRECURSE" ''CUInt
+constant "CONFIG_TABLES_LENGTH" ''CUInt
+constant "CONFIG_UNICODE_VERSION" ''CUInt
+constant "CONFIG_UNICODE" ''CUInt
+constant "CONFIG_VERSION" ''CUInt
+
+-- * Compiling a pattern
+
+foreign import capi safe "pcre2.h" pcre2_compile
+    :: PCRE2_SPTR
+    -> PCRE2_SIZE -- ^ Can be zero-terminated.  See below.
+    -> CUInt
+    -- ^ See \"Main compile options\" below for possible bit flags.
+    -> Ptr CInt
+    -> Ptr PCRE2_SIZE
+    -> Ptr Pcre2_compile_context
+    -> IO (Ptr Pcre2_code)
+
+constant "ZERO_TERMINATED" ''PCRE2_SIZE
+
+foreign import capi safe "pcre2.h" pcre2_code_free
+    :: Ptr Pcre2_code
+    -> IO ()
+
+foreign import capi safe "pcre2.h" pcre2_code_copy
+    :: Ptr Pcre2_code
+    -> IO (Ptr Pcre2_code)
+
+foreign import capi "pcre2.h" pcre2_code_copy_with_tables
+    :: Ptr Pcre2_code
+    -> IO (Ptr Pcre2_code)
+
+-- ** Main compile options
+constant "ANCHORED" ''CUInt
+constant "ALLOW_EMPTY_CLASS" ''CUInt
+constant "ALT_BSUX" ''CUInt
+constant "ALT_CIRCUMFLEX" ''CUInt
+constant "ALT_VERBNAMES" ''CUInt
+constant "AUTO_CALLOUT" ''CUInt
+constant "CASELESS" ''CUInt
+constant "DOLLAR_ENDONLY" ''CUInt
+constant "DOTALL" ''CUInt
+constant "DUPNAMES" ''CUInt
+constant "ENDANCHORED" ''CUInt
+constant "EXTENDED" ''CUInt
+constant "EXTENDED_MORE" ''CUInt
+constant "FIRSTLINE" ''CUInt
+constant "LITERAL" ''CUInt
+constant "MATCH_INVALID_UTF" ''CUInt
+constant "MATCH_UNSET_BACKREF" ''CUInt
+constant "MULTILINE" ''CUInt
+constant "NEVER_BACKSLASH_C" ''CUInt
+constant "NEVER_UCP" ''CUInt
+constant "NEVER_UTF" ''CUInt
+constant "NO_AUTO_CAPTURE" ''CUInt
+constant "NO_AUTO_POSSESS" ''CUInt
+constant "NO_DOTSTAR_ANCHOR" ''CUInt
+constant "NO_START_OPTIMIZE" ''CUInt
+constant "NO_UTF_CHECK" ''CUInt
+constant "UCP" ''CUInt
+constant "UNGREEDY" ''CUInt
+constant "USE_OFFSET_LIMIT" ''CUInt
+constant "UTF" ''CUInt
+
+-- ** Extra compile options
+constant "EXTRA_ALLOW_SURROGATE_ESCAPES" ''CUInt
+constant "EXTRA_ALT_BSUX" ''CUInt
+constant "EXTRA_BAD_ESCAPE_IS_LITERAL" ''CUInt
+constant "EXTRA_ESCAPED_CR_IS_LF" ''CUInt
+constant "EXTRA_MATCH_LINE" ''CUInt
+constant "EXTRA_MATCH_WORD" ''CUInt
+
+-- * JIT compilation
+
+foreign import capi safe "pcre2.h" pcre2_jit_compile
+    :: Ptr Pcre2_code
+    -> CUInt -- ^ See below for possible bit flags.
+    -> IO CInt
+
+constant "JIT_COMPLETE" ''CUInt
+constant "JIT_PARTIAL_HARD" ''CUInt
+constant "JIT_PARTIAL_SOFT" ''CUInt
+
+-- | May be returned by 'pcre2_jit_compile'.
+constant "ERROR_JIT_BADOPTION" ''CInt
+
+foreign import capi safe "pcre2.h" pcre2_jit_match
+    :: Ptr Pcre2_code
+    -> PCRE2_SPTR              -- ^ subject
+    -> PCRE2_SIZE              -- ^ length
+    -> PCRE2_SIZE              -- ^ startoffset
+    -> CUInt                   -- ^ options
+    -> Ptr Pcre2_match_data
+    -> Ptr Pcre2_match_context
+    -> IO CInt
+
+foreign import capi safe "pcre2.h" pcre2_jit_free_unused_memory
+    :: Ptr Pcre2_general_context
+    -> IO ()
+
+foreign import capi safe "pcre2.h" pcre2_jit_stack_create
+    :: PCRE2_SIZE
+    -> PCRE2_SIZE
+    -> Ptr Pcre2_general_context
+    -> IO (Ptr Pcre2_jit_stack)
+
+foreign import capi unsafe "pcre2.h" pcre2_jit_stack_assign
+    :: Ptr Pcre2_match_context
+    -> FunPtr (Ptr a -> IO (Ptr Pcre2_jit_stack))
+    -> Ptr a
+    -> IO ()
+
+foreign import capi safe "pcre2.h" pcre2_jit_stack_free
+    :: Ptr Pcre2_jit_stack
+    -> IO ()
+
+-- * Locale support
+
+foreign import capi safe "pcre2.h" pcre2_maketables
+    :: Ptr Pcre2_general_context
+    -> IO (Ptr CUChar)
+
+foreign import capi safe "pcre2.h" pcre2_maketables_free
+    :: Ptr Pcre2_general_context
+    -> Ptr CUChar
+    -> IO ()
+
+-- * Information about a compiled pattern
+
+foreign import capi unsafe "pcre2.h" pcre2_pattern_info
+    :: Ptr Pcre2_code
+    -> CUInt          -- ^ See below for possible values.
+    -> Ptr a
+    -> IO CInt        -- ^ See below for possible error values.
+
+constant "INFO_ALLOPTIONS" ''CUInt
+constant "INFO_ARGOPTIONS" ''CUInt
+constant "INFO_EXTRAOPTIONS" ''CUInt
+constant "INFO_BACKREFMAX" ''CUInt
+constant "INFO_BSR" ''CUInt
+constant "INFO_CAPTURECOUNT" ''CUInt
+constant "INFO_DEPTHLIMIT" ''CUInt
+constant "INFO_FIRSTBITMAP"   ''CUInt
+constant "INFO_FIRSTCODETYPE" ''CUInt
+constant "INFO_FIRSTCODEUNIT" ''CUInt
+constant "INFO_FRAMESIZE" ''CUInt
+constant "INFO_HASBACKSLASHC" ''CUInt
+constant "INFO_HASCRORLF" ''CUInt
+constant "INFO_HEAPLIMIT" ''CUInt
+constant "INFO_JCHANGED" ''CUInt
+constant "INFO_JITSIZE" ''CUInt
+constant "INFO_LASTCODETYPE" ''CUInt
+constant "INFO_LASTCODEUNIT" ''CUInt
+constant "INFO_MATCHEMPTY" ''CUInt
+constant "INFO_MATCHLIMIT" ''CUInt
+constant "INFO_MAXLOOKBEHIND" ''CUInt
+constant "INFO_MINLENGTH" ''CUInt
+constant "INFO_NAMECOUNT" ''CUInt
+constant "INFO_NAMEENTRYSIZE" ''CUInt
+constant "INFO_NAMETABLE" ''CUInt
+constant "INFO_NEWLINE" ''CUInt
+constant "INFO_SIZE" ''CUInt
+
+constant "ERROR_UNSET" ''CInt
+
+-- ** Duplicate capture group names
+foreign import capi unsafe "pcre2.h" pcre2_substring_nametable_scan
+    :: Ptr Pcre2_code
+    -> PCRE2_SPTR     -- ^ name
+    -> Ptr PCRE2_SPTR -- ^ first
+    -> Ptr PCRE2_SPTR -- ^ last
+    -> IO CInt
+
+-- * Callouts
+
+foreign import capi safe "pcre2.h" pcre2_callout_enumerate
+    :: Ptr Pcre2_code
+    -> FunPtr (Ptr Pcre2_callout_enumerate_block -> Ptr a -> IO CInt)
+    -> Ptr a
+    -> IO CInt
+
+-- ** Callout struct getters
+--
+-- $CalloutStructGetters
+-- These functions are not part of the official API; we provide them here.  C
+-- API consumers are supposed to access struct fields directly, but the FFI
+-- cannot yet do that as of GHC 8.8.4.
+
+-- *** @pcre2_callout_block@
+getter "callout_block" "version" ''CUInt
+getter "callout_block" "callout_number" ''CUInt
+getter "callout_block" "capture_top" ''CUInt
+getter "callout_block" "capture_last" ''CUInt
+getter "callout_block" "callout_flags" ''CUInt
+-- ^ See below for possible bit flags.
+constant "CALLOUT_STARTMATCH" ''CUInt
+constant "CALLOUT_BACKTRACK" ''CUInt
+foreign import capi unsafe "getters.h" pcre2_callout_block_offset_vector
+    :: Ptr Pcre2_callout_block
+    -> IO (Ptr PCRE2_SIZE)
+getter "callout_block" "mark" ''PCRE2_SPTR
+getter "callout_block" "subject" ''PCRE2_SPTR
+getter "callout_block" "subject_length" ''PCRE2_SIZE
+getter "callout_block" "start_match" ''PCRE2_SIZE
+getter "callout_block" "current_position" ''PCRE2_SIZE
+getter "callout_block" "pattern_position" ''PCRE2_SIZE
+getter "callout_block" "next_item_length" ''PCRE2_SIZE
+getter "callout_block" "callout_string_offset" ''PCRE2_SIZE
+getter "callout_block" "callout_string_length" ''PCRE2_SIZE
+getter "callout_block" "callout_string" ''PCRE2_SPTR
+
+-- *** @pcre2_callout_enumerate_block@
+getter "callout_enumerate_block" "version" ''CUInt
+getter "callout_enumerate_block" "pattern_position" ''PCRE2_SIZE
+getter "callout_enumerate_block" "next_item_length" ''PCRE2_SIZE
+getter "callout_enumerate_block" "callout_number" ''CUInt
+getter "callout_enumerate_block" "callout_string_offset" ''PCRE2_SIZE
+getter "callout_enumerate_block" "callout_string_length" ''PCRE2_SIZE
+getter "callout_enumerate_block" "callout_string" ''PCRE2_SPTR
+
+-- *** @pcre2_substitute_callout_block@
+getter "substitute_callout_block" "version" ''CUInt
+getter "substitute_callout_block" "subscount" ''CUInt
+getter "substitute_callout_block" "input" ''PCRE2_SPTR
+getter "substitute_callout_block" "output" ''PCRE2_SPTR
+foreign import capi unsafe "getters.h" pcre2_substitute_callout_block_ovector
+    :: Ptr Pcre2_substitute_callout_block
+    -> IO (Ptr PCRE2_SIZE)
+getter "substitute_callout_block" "oveccount" ''CUInt
+foreign import capi unsafe "getters.h"
+    pcre2_substitute_callout_block_output_offsets
+        :: Ptr Pcre2_substitute_callout_block
+        -> IO (Ptr PCRE2_SIZE) -- ^ Array of 2 (@PCRE2_SIZE[2]@)
+
+-- * The match data block
+
+foreign import capi safe "pcre2.h" pcre2_match_data_create
+    :: CUInt                     -- ^ ovecsize
+    -> Ptr Pcre2_general_context
+    -> IO (Ptr Pcre2_match_data)
+
+foreign import capi safe "pcre2.h" pcre2_match_data_create_from_pattern
+    :: Ptr Pcre2_code
+    -> Ptr Pcre2_general_context
+    -> IO (Ptr Pcre2_match_data)
+
+foreign import capi safe "pcre2.h" pcre2_match_data_free
+    :: Ptr Pcre2_match_data
+    -> IO ()
+
+-- * Matching a pattern
+
+foreign import capi safe "pcre2.h" pcre2_match
+    :: Ptr Pcre2_code
+    -> PCRE2_SPTR              -- ^ subject
+    -> PCRE2_SIZE              -- ^ length
+    -> PCRE2_SIZE              -- ^ startoffset
+    -> CUInt                   -- ^ See below for possible bit flags.
+    -> Ptr Pcre2_match_data
+    -> Ptr Pcre2_match_context
+    -> IO CInt
+
+-- ** Match options
+constant "COPY_MATCHED_SUBJECT" ''CUInt
+constant "NOTBOL" ''CUInt
+constant "NOTEOL" ''CUInt
+constant "NOTEMPTY" ''CUInt
+constant "NOTEMPTY_ATSTART" ''CUInt
+constant "NO_JIT" ''CUInt
+constant "PARTIAL_HARD" ''CUInt
+constant "PARTIAL_SOFT" ''CUInt
+
+-- ** Match errors
+constant "ERROR_NOMATCH" ''CInt
+constant "ERROR_PARTIAL" ''CInt
+constant "ERROR_BADMAGIC" ''CInt
+constant "ERROR_BADMODE" ''CInt
+constant "ERROR_BADOFFSET" ''CInt
+constant "ERROR_BADOPTION" ''CInt
+constant "ERROR_BADUTFOFFSET" ''CInt
+constant "ERROR_CALLOUT" ''CInt
+constant "ERROR_DEPTHLIMIT" ''CInt
+constant "ERROR_HEAPLIMIT" ''CInt
+constant "ERROR_INTERNAL" ''CInt
+constant "ERROR_JIT_STACKLIMIT" ''CInt
+constant "ERROR_MATCHLIMIT" ''CInt
+constant "ERROR_NOMEMORY" ''CInt
+constant "ERROR_NULL" ''CInt
+-- *** UTF-16-specific errors
+--
+-- | \"Missing low surrogate at end of string\"
+constant "ERROR_UTF16_ERR1" ''CInt
+-- | \"Invalid low surrogate follows high surrogate\"
+constant "ERROR_UTF16_ERR2" ''CInt
+-- | \"Isolated low surrogate\"
+constant "ERROR_UTF16_ERR3" ''CInt
+
+-- * DFA matching
+
+foreign import capi safe "pcre2.h" pcre2_dfa_match
+    :: Ptr Pcre2_code
+    -> PCRE2_SPTR              -- ^ subject
+    -> PCRE2_SIZE              -- ^ length
+    -> PCRE2_SIZE              -- ^ startoffset
+    -> CUInt                   -- ^ options
+    -> Ptr Pcre2_match_data
+    -> Ptr Pcre2_match_context
+    -> Ptr CInt                -- ^ workspace
+    -> PCRE2_SIZE              -- ^ wscount
+    -> IO CInt
+
+-- ** DFA matching options
+constant "DFA_SHORTEST" ''CUInt
+constant "DFA_RESTART" ''CUInt
+
+-- ** DFA matching errors
+constant "ERROR_DFA_UFUNC" ''CInt
+constant "ERROR_DFA_UITEM" ''CInt
+constant "ERROR_DFA_UCOND" ''CInt
+constant "ERROR_DFA_UINVALID_UTF" ''CInt
+constant "ERROR_DFA_WSSIZE" ''CInt
+constant "ERROR_DFA_RECURSE" ''CInt
+constant "ERROR_DFA_BADRESTART" ''CInt
+
+-- * Returned string and captured substrings
+
+foreign import capi unsafe "pcre2.h" pcre2_get_ovector_count
+    :: Ptr Pcre2_match_data
+    -> IO CUInt
+
+foreign import capi unsafe "pcre2.h" pcre2_get_ovector_pointer
+    :: Ptr Pcre2_match_data
+    -> IO (Ptr PCRE2_SIZE)
+
+foreign import capi unsafe "pcre2.h" pcre2_substring_length_bynumber
+    :: Ptr Pcre2_match_data
+    -> CUInt                -- ^ number
+    -> Ptr PCRE2_SIZE       -- ^ length
+    -> IO CInt
+
+foreign import capi safe "pcre2.h" pcre2_substring_copy_bynumber
+    :: Ptr Pcre2_match_data
+    -> CUInt                -- ^ number
+    -> Ptr PCRE2_UCHAR      -- ^ buffer
+    -> Ptr PCRE2_SIZE       -- ^ bufflen
+    -> IO CInt
+
+foreign import capi safe "pcre2.h" pcre2_substring_get_bynumber
+    :: Ptr Pcre2_match_data
+    -> CUInt                 -- ^ name
+    -> Ptr (Ptr PCRE2_UCHAR) -- ^ bufferptr
+    -> Ptr PCRE2_SIZE        -- ^ bufflen
+    -> IO CInt
+
+foreign import capi unsafe "pcre2.h" pcre2_substring_list_get
+    :: Ptr Pcre2_match_data
+    -> Ptr (Ptr (Ptr PCRE2_UCHAR)) -- ^ listptr
+    -> Ptr (Ptr PCRE2_SIZE)        -- ^ lengthsptr
+    -> IO CInt
+
+foreign import capi safe "pcre2.h" pcre2_substring_list_free
+    :: Ptr PCRE2_SPTR
+    -> IO ()
+
+foreign import capi unsafe "pcre2.h" pcre2_substring_number_from_name
+    :: Ptr Pcre2_code
+    -> PCRE2_SPTR     -- ^ name
+    -> IO CInt
+
+foreign import capi unsafe "pcre2.h" pcre2_substring_length_byname
+    :: Ptr Pcre2_match_data
+    -> PCRE2_SPTR           -- ^ name
+    -> Ptr PCRE2_SIZE       -- ^ length
+    -> IO CInt
+
+foreign import capi safe "pcre2.h" pcre2_substring_copy_byname
+    :: Ptr Pcre2_match_data
+    -> PCRE2_SPTR           -- ^ name
+    -> Ptr PCRE2_UCHAR      -- ^ buffer
+    -> Ptr PCRE2_SIZE       -- ^ bufflen
+    -> IO CInt
+
+foreign import capi safe "pcre2.h" pcre2_substring_get_byname
+    :: Ptr Pcre2_match_data
+    -> PCRE2_SPTR            -- ^ name
+    -> Ptr (Ptr PCRE2_UCHAR) -- ^ bufferptr
+    -> Ptr PCRE2_SIZE        -- ^ bufflen
+    -> IO CInt
+
+-- NOTE Maybe after all other substring functions?
+foreign import capi safe "pcre2.h" pcre2_substring_free
+    :: Ptr PCRE2_UCHAR
+    -> IO ()
+
+constant "ERROR_NOSUBSTRING" ''CInt
+constant "ERROR_NOUNIQUESUBSTRING" ''CInt
+constant "ERROR_UNAVAILABLE" ''CInt
+
+-- * Creating a new string with substitutions
+
+foreign import capi safe "pcre2.h" pcre2_substitute
+    :: Ptr Pcre2_code
+    -> PCRE2_SPTR              -- ^ subject
+    -> PCRE2_SIZE              -- ^ length
+    -> PCRE2_SIZE              -- ^ startoffset
+    -> CUInt                   -- ^ options
+    -> Ptr Pcre2_match_data
+    -> Ptr Pcre2_match_context
+    -> PCRE2_SPTR              -- ^ replacement
+    -> PCRE2_SIZE              -- ^ rlength
+    -> Ptr PCRE2_UCHAR         -- ^ outputbuffer
+    -> Ptr PCRE2_SIZE          -- ^ outlengthptr
+    -> IO CInt
+
+-- ** Substitution options
+constant "SUBSTITUTE_REPLACEMENT_ONLY" ''CUInt
+constant "SUBSTITUTE_GLOBAL" ''CUInt
+constant "SUBSTITUTE_MATCHED" ''CUInt
+constant "SUBSTITUTE_OVERFLOW_LENGTH" ''CUInt
+constant "SUBSTITUTE_LITERAL" ''CUInt
+constant "SUBSTITUTE_UNKNOWN_UNSET" ''CUInt
+constant "SUBSTITUTE_UNSET_EMPTY" ''CUInt
+constant "SUBSTITUTE_EXTENDED" ''CUInt
+
+-- ** Substitution errors
+constant "ERROR_BADREPLACEMENT" ''CInt
+constant "ERROR_BADREPESCAPE" ''CInt
+constant "ERROR_BADSUBSTITUTION" ''CInt
+constant "ERROR_BADSUBSPATTERN" ''CInt
+
+-- * Other information about a match
+
+foreign import capi unsafe "pcre2.h" pcre2_get_mark
+    :: Ptr Pcre2_match_data
+    -> IO PCRE2_SPTR
+
+foreign import capi unsafe "pcre2.h" pcre2_get_startchar
+    :: Ptr Pcre2_match_data
+    -> IO PCRE2_SIZE
+
+-- * Obtaining a textual error message
+foreign import capi safe "pcre2.h" pcre2_get_error_message
+    :: CInt
+    -> Ptr PCRE2_UCHAR
+    -> PCRE2_SIZE
+    -> IO CInt
diff --git a/src/hs/Text/Regex/Pcre2/Foreign/TH.hs b/src/hs/Text/Regex/Pcre2/Foreign/TH.hs
new file mode 100644
--- /dev/null
+++ b/src/hs/Text/Regex/Pcre2/Foreign/TH.hs
@@ -0,0 +1,37 @@
+module Text.Regex.Pcre2.Foreign.TH where
+
+import Language.Haskell.TH
+
+{-
+    For example,
+constant "ERROR_NOMATCH" ''CInt
+    will produce
+foreign import capi unsafe "pcre2.h value PCRE2_ERROR_NOMATCH"
+    pcre2_ERROR_NOMATCH :: CInt
+-}
+constant :: String -> Name -> DecsQ
+constant suffix typeName = return [dec] where
+    dec = ForeignD $ ImportF CApi Unsafe str name ty
+    str = "pcre2.h value PCRE2_" ++ suffix
+    name = mkName $ "pcre2_" ++ suffix
+    ty = ConT typeName
+
+{-
+    For example,
+getter "callout_block" "version" ''CUInt
+    will produce
+foreign import capi unsafe "getters.h" pcre2_callout_block_version
+    :: Ptr Pcre2_callout_block
+    -> IO CUInt
+-}
+getter :: String -> String -> Name -> DecsQ
+getter blockSuffix field typeName = return [dec] where
+    dec = ForeignD $ ImportF CApi Unsafe "getters.h" name ty
+    name = mkName $ "pcre2_" ++ blockSuffix ++ "_" ++ field
+    ty = AppT
+        (AppT ArrowT $ AppT
+            (ConT $ mkName "Ptr")
+            (ConT $ mkName $ "Pcre2_" ++ blockSuffix))
+        (AppT
+            (ConT $ mkName "IO")
+            (ConT typeName))
diff --git a/src/hs/Text/Regex/Pcre2/Internal.hs b/src/hs/Text/Regex/Pcre2/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/hs/Text/Regex/Pcre2/Internal.hs
@@ -0,0 +1,1410 @@
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE UndecidableInstances #-}
+
+module Text.Regex.Pcre2.Internal where
+
+import           Control.Applicative        (Alternative(..))
+import           Control.Exception          hiding (TypeError)
+import           Control.Monad.State.Strict
+import           Data.Either                (partitionEithers)
+import           Data.Function              ((&))
+import           Data.Functor               ((<&>))
+import           Data.Functor.Const         (Const(..))
+import           Data.Functor.Identity      (Identity(..))
+import           Data.IORef
+import           Data.IntMap.Strict         (IntMap)
+import qualified Data.IntMap.Strict         as IM
+import           Data.List                  (foldl', intercalate)
+import           Data.List.NonEmpty         (NonEmpty(..))
+import qualified Data.List.NonEmpty         as NE
+import           Data.Maybe                 (fromJust, fromMaybe)
+import           Data.Monoid                (Alt(..), Any(..), First(..))
+import           Data.Proxy                 (Proxy(..))
+import           Data.Text                  (Text)
+import qualified Data.Text                  as Text
+import qualified Data.Text.Foreign          as Text
+import           Data.Type.Bool             (type (||), If)
+import           Data.Type.Equality         (type (==))
+import           Data.Typeable              (cast)
+import           Foreign
+import           Foreign.C.Types
+import qualified Foreign.Concurrent         as Conc
+import           GHC.TypeLits               hiding (Text)
+import qualified GHC.TypeLits               as TypeLits
+import           System.IO.Unsafe           (unsafePerformIO)
+import           Text.Regex.Pcre2.Foreign
+
+-- * General utilities
+
+-- | There is no @nullForeignPtr@ to pass to `withForeignPtr`, so we have to
+-- fake it with a `Maybe`.
+withForeignOrNullPtr :: Maybe (ForeignPtr a) -> (Ptr a -> IO b) -> IO b
+withForeignOrNullPtr Nothing   = \action -> action nullPtr
+withForeignOrNullPtr (Just fp) = withForeignPtr fp
+
+-- | Helper so we never leak untracked 'Ptr's.
+mkForeignPtr :: (Ptr a -> IO ()) -> IO (Ptr a) -> IO (ForeignPtr a)
+mkForeignPtr finalize create = create >>= Conc.newForeignPtr <*> finalize
+
+-- | Helper so we never leak untracked 'FunPtr's.
+mkFunPtr :: ForeignPtr b -> IO (FunPtr a) -> IO (FunPtr a)
+mkFunPtr anchor create = do
+    fPtr <- create
+    Conc.addForeignPtrFinalizer anchor $ freeHaskellFunPtr fPtr
+    return fPtr
+
+safeLast :: [a] -> Maybe a
+safeLast [] = Nothing
+safeLast xs = Just $ last xs
+
+bitOr :: (Foldable t, Num a, Bits a) => t a -> a
+bitOr = foldl' (.|.) 0
+
+-- | Equivalent to @flip fix@.
+--
+-- Used to express a recursive function of one argument that is called only once
+-- on an initial value:
+--
+-- > let go x = ... in go x0
+--
+-- as:
+--
+-- > fix1 x0 $ \go x -> ...
+fix1 :: a -> ((a -> b) -> a -> b) -> b
+fix1 x f = fix f x
+
+-- | Like `fix1`, but for a function of two arguments.  Currently unused.
+fix2 :: a -> b -> ((a -> b -> c) -> a -> b -> c) -> c
+fix2 x y f = fix f x y
+
+-- | Like `fix1`, but for a function of three arguments.  Currently unused.
+fix3 :: a -> b -> c -> ((a -> b -> c -> d) -> a -> b -> c -> d) -> d
+fix3 x y z f = fix f x y z
+
+-- ** Fast @Text@ slicing
+
+data SliceRange = SliceRange
+    {-# UNPACK #-} !Text.I16
+    {-# UNPACK #-} !Text.I16
+
+-- | Zero-copy slice a 'Text'.  An unset capture is represented by a
+-- `pcre2_UNSET` range and is interpreted in this library as `Text.empty`.
+thinSlice :: Text -> SliceRange -> Text
+thinSlice text (SliceRange off offEnd)
+    | off == fromIntegral pcre2_UNSET = Text.empty
+    | otherwise                       = text
+        & Text.dropWord16 off
+        & Text.takeWord16 (offEnd - off)
+
+-- | Slice a 'Text', copying if it\'s less than half of the original.
+slice :: Text -> SliceRange -> Text
+slice text sliceRange =
+    let substring = thinSlice text sliceRange
+    in if Text.length substring > Text.length text `div` 2
+        then substring
+        else Text.copy substring
+
+-- | Probably unnecessary, but unrestricted 'castPtr' feels dangerous.
+class CastCUs a b | a -> b where
+    castCUs :: Ptr a -> Ptr b
+    castCUs = castPtr
+    {-# INLINE castCUs #-}
+instance CastCUs CUShort Word16
+instance CastCUs Word16 CUShort
+
+-- ** Lens types and utilities
+--
+-- $LensTypesAndUtilities
+-- The combinators\' types are excessively polymorphic\/polykinded\/ugly because
+-- they have no accompanying signatures (not worth the trouble).
+
+type Lens'      s a = forall f. (Functor f)     => (a -> f a) -> s -> f s
+type Traversal' s a = forall f. (Applicative f) => (a -> f a) -> s -> f s
+
+preview l = getFirst . getConst . l (Const . First . Just)
+view l = getConst . l Const
+to k f = Const . getConst . f . k
+has l = getAny . getConst . l (\_ -> Const $ Any True)
+
+-- toAlternativeOf :: (Alternative f) => Getting (Alt f a) s a -> s -> f a
+toAlternativeOf l = getAlt . view (l . to (Alt . pure))
+
+_headNE :: Lens' (NonEmpty a) a
+_headNE f (x :| xs) = f x <&> \x' -> x' :| xs
+
+-- * Assembling inputs into @Matcher@s and @Subber@s
+
+-- | A matching function where all inputs and auxilliary data structures have
+-- been \"compiled\".  It takes a subject and produces a raw result code and
+-- match data, to be passed to further validation and inspection.
+type Matcher = Text -> IO (CInt, MatchData)
+
+-- | A substitution function.  It takes a subject and produces the number of
+-- substitutions performed (0 or 1, or more in the presence of `SubGlobal`)
+-- along with the transformed subject.  Currently the number is unused.
+type Subber = Text -> IO (CInt, Text)
+
+-- ** Options
+
+-- | A `Monoid` representing nearly every facility PCRE2 presents for tweaking
+-- the behavior of regex compilation and execution.
+--
+-- All library functions that take options have the suffix @Opt@ in their names;
+-- for each of them, there\'s also a non-@Opt@ convenience function that simply
+-- has the (unexported) `mempty` option.  For many uses, options won\'t be
+-- needed.
+--
+-- Some options can be enabled by special character sequences in the pattern as
+-- an alternative to specifying them as an `Option`.  See `Caseless` for
+-- example.
+--
+-- Documentation is scant here.  For more complete, accurate information,
+-- including discussions of corner cases arising from specific combinations of
+-- options and pattern items, please see the [C API
+-- documentation](https://pcre.org/current/doc/html/pcre2api.html).
+data Option
+    = NoOptions -- ^ `mempty`
+    | TwoOptions Option Option -- ^ `<>`
+
+    | AllowEmptyClass -- ^ Make @[]@ not match anything, rather than counting
+    -- the @]@ as the first character of the class.
+    | AltBsux -- ^ Like `AltBsuxLegacy`, except with ECMAScript 6 hex literal
+    -- feature for @\\u@.
+    | AltBsuxLegacy -- ^ Behave like ECMAScript 5 for @\\U@, @\\u@, and @\\x@.
+    -- See 'AltBsux'.
+    | AltCircumflex -- ^ Match a @^@ after a newline at the end of the subject.
+    -- Only relevant in multiline mode.
+    | AltVerbNames -- ^ Enable backslash escapes in verb names.  E.g.,
+    -- @(*MARK:L\\(O\\)L)@.
+    | Anchored -- ^ Equivalent to beginning pattern with @^@.
+    | AutoCallout -- ^ Run callout for every pattern item.  Only relevant if a
+    -- callout is set.
+    | BadEscapeIsLiteral -- ^ Do not throw an error for unrecognized or
+    -- malformed escapes.  /\"This is a dangerous option.\"/
+    | Bsr Bsr -- ^ Override what @\\R@ matches (default given by `defaultBsr`).
+    | Caseless -- ^ Case-insensitive match.  Equivalent to @(?i)@.
+    | DepthLimit Word32 -- ^ Override maximum depth of nested backtracking
+    -- (default given by `defaultDepthLimit`).  Equivalent to
+    -- @(*LIMIT_DEPTH=@/number/@)@.
+    | DollarEndOnly -- ^ Don\'t match @$@ with a newline at the end of the
+    -- subject.
+    | DotAll -- ^ A dot also matches a (single-character) newline.  Equivalent
+    -- to @(?s)@.
+    | DupNames -- ^ Allow non-unique capture names.
+    | EndAnchored -- ^ More or less like ending pattern with @$@.
+    | EscapedCrIsLf -- ^ Interpret @\\r@ as @\\n@.
+    | Extended -- ^ In the pattern, ignore whitespace, and enable comments
+    -- starting with @#@.  Equivalent to @(?x)@.
+    | ExtendedMore -- ^ Like `Extended` but also ignore spaces and tabs within
+    -- @[]@.
+    | FirstLine -- ^ The match must begin in the first line of the subject.
+    | HeapLimit Word32 -- ^ Override maximum heap memory (in kibibytes) used to
+    -- hold backtracking information (default given by `defaultHeapLimit`).
+    -- Equivalent to @(*LIMIT_HEAP=@/number/@)@.
+    | Literal -- ^ Treat the pattern as a literal string.
+    | MatchLimit Word32 -- ^ Override maximum value of the main matching loop\'s
+    -- internal counter (default given by `defaultMatchLimit`), as a simple CPU
+    -- throttle.  Equivalent to @(*LIMIT_MATCH=@/number/@)@.
+    | MatchLine -- ^ Only match complete lines.  Equivalent to bracketing the
+    -- pattern with @^(?:@/pattern/@)$@.
+    | MatchUnsetBackRef -- ^ A backreference to an unset capture group matches
+    -- an empty string.
+    | MatchWord -- ^ Only match subjects that have word boundaries at the
+    -- beginning and end.  Equivalent to bracketing the pattern with
+    -- @\\b(?:@/pattern/@)\\b@.
+    | MaxPatternLength Word64 -- ^ Default is `maxBound`.
+    | Multiline -- ^ @^@ and @$@ mean \"beginning\/end of a line\" rather than
+    -- \"beginning\/end of the subject\".  Equivalent to @(?m)@.
+    | NeverBackslashC -- ^ Do not allow the unsafe @\\C@ sequence.
+    | NeverUcp -- ^ Don\'t count Unicode characters in some character classes
+    -- such as @\\d@.  Overrides @(*UCP)@.
+    | Newline Newline -- ^ Override what a newline is (default given by
+    -- `defaultNewline`).  Equivalent to @(*CRLF)@ or similar.
+    | NoAutoCapture -- ^ Disable numbered capturing parentheses.
+    | NoAutoPossess -- ^ Turn off some optimizations, possibly resulting in some
+    -- callouts not being called.
+    | NoDotStarAnchor -- ^ Turn off an optimization involving @.*@, possibly
+    -- resulting in some callouts not being called.
+    | NoStartOptimize -- ^ Turn off some optimizations normally performed at the
+    -- beginning of a pattern.
+    | NotBol -- ^ First character of subject is not the __b__eginning __o__f
+    -- __l__ine.  Only affects @^@.
+    | NotEmpty -- ^ The 0th capture doesn\'t match if it would be empty.
+    | NotEmptyAtStart -- ^ The 0th capture doesn\'t match if it would be empty
+    -- and at the beginning of the subject.
+    | NotEol -- ^ End of subject is not the __e__nd __o__f __l__ine.  Only
+    -- affects @$@.
+    | OffsetLimit Word64 -- ^ Limit how far an unanchored search can advance in
+    -- the subject.
+    | ParensLimit Word32 -- ^ Override max depth of nested parentheses (default
+    -- given by `defaultParensLimit`).
+    | PartialHard -- ^ If the subject ends without finding a complete match,
+    -- stop trying alternatives and signal a partial match immediately.
+    -- Currently we do this by throwing a `Pcre2Exception` but we should do
+    -- better.
+    | PartialSoft -- ^ If the subject ends and all alternatives have been tried,
+    -- but no complete match is found, signal a partial match.  Currently we do
+    -- this by throwing a `Pcre2Exception` but we should do better.
+    | SubGlobal -- ^ /Affects `subOpt`./  Replace all, rather than just the
+    -- first.
+    | SubLiteral -- ^ /Affects `subOpt`./  Treat the replacement as a literal
+    -- string.
+    | SubReplacementOnly -- ^ /Affects `subOpt`./  Return just the rendered
+    -- replacement instead of it within the subject.  With `SubGlobal`, all
+    -- results are concatenated.
+    | SubUnknownUnset -- ^ /Affects `subOpt`./  References in the replacement
+    -- to non-existent captures don\'t error but are treated as unset.
+    | SubUnsetEmpty -- ^ /Affects `subOpt`./  References in the replacement
+    -- to unset captures don\'t error but are treated as empty.
+    | Ucp -- ^ Count Unicode characters in some character classes such as @\\d@.
+    -- Incompatible with `NeverUcp`.
+    | Ungreedy -- ^ Invert the effect of @?@.  Without it, quantifiers are
+    -- non-greedy; with it, they are greedy.  Equivalent to @(?U)@.
+    | UnsafeCallout (CalloutInfo -> IO CalloutResult) -- ^ Run the given callout
+    -- on every capture.  Multiples of this option before the rightmost are
+    -- ignored.
+    --
+    -- /NOTE: The callout is run via `unsafePerformIO` within pure code!/
+    | UnsafeCompileRecGuard (Int -> IO Bool) -- ^ Run the given guard on every
+    -- new descent into a level of parentheses, passing the current depth as
+    -- argument.  Returning @False@ aborts pattern compilation with an
+    -- exception.  Multiples of this option before the rightmost are ignored.
+    --
+    -- /NOTE: Currently (PCRE2 version 10\.35) patterns seem to be parsed in/
+    -- /two passes, both times triggering the recursion guard.  Also, it is/
+    -- /triggered at the beginning of the pattern, passing 0.  None of this is/
+    -- /documented; expect the unexpected in the presence of side effects!/
+    --
+    -- /NOTE: The guard is run via `unsafePerformIO` within pure code!/
+    | UnsafeSubCallout (SubCalloutInfo -> IO SubCalloutResult) -- ^ Run the
+    -- given callout on every substitution.  This is at most once unless
+    -- `SubGlobal` is set.  Multiples of this option before the rightmost are
+    -- ignored.
+    --
+    -- /NOTE: The callout is run via `unsafePerformIO` within pure code!/
+    | Utf -- ^ Treat both the pattern and subject as UTF rather than fixed-width
+    -- 16-bit code units.
+
+instance Semigroup Option where
+    (<>) = TwoOptions
+
+instance Monoid Option where
+    mempty = NoOptions
+
+-- | What @\\R@, __b__ack__s__lash __R__, can mean.
+data Bsr
+    = BsrUnicode -- ^ any Unicode line ending sequence
+    | BsrAnyCrlf -- ^ @\\r@, @\\n@, or @\\r\\n@
+    deriving (Eq, Show)
+
+-- | C to Haskell.
+bsrFromC :: CUInt -> Bsr
+bsrFromC x
+    | x == pcre2_BSR_UNICODE = BsrUnicode
+    | x == pcre2_BSR_ANYCRLF = BsrAnyCrlf
+    | otherwise              = error $ "bsrFromC: bad value " ++ show x
+
+-- | Haskell to C.
+bsrToC :: Bsr -> CUInt
+bsrToC BsrUnicode = pcre2_BSR_UNICODE
+bsrToC BsrAnyCrlf = pcre2_BSR_ANYCRLF
+
+-- | What\'s considered a newline.
+data Newline
+    = NewlineCr      -- ^ @\\r@ only
+    | NewlineLf      -- ^ @\\n@ only
+    | NewlineCrlf    -- ^ @\\r\\n@ only
+    | NewlineAny     -- ^ any Unicode line ending sequence
+    | NewlineAnyCrlf -- ^ any of the above
+    | NewlineNul     -- ^ binary zero
+    deriving (Eq, Show)
+
+-- | C to Haskell.
+newlineFromC :: CUInt -> Newline
+newlineFromC x
+    | x == pcre2_NEWLINE_CR      = NewlineCr
+    | x == pcre2_NEWLINE_LF      = NewlineLf
+    | x == pcre2_NEWLINE_CRLF    = NewlineCrlf
+    | x == pcre2_NEWLINE_ANY     = NewlineAny
+    | x == pcre2_NEWLINE_ANYCRLF = NewlineAnyCrlf
+    | x == pcre2_NEWLINE_NUL     = NewlineNul
+    | otherwise                  = error $ "newlineFromC: bad value " ++ show x
+
+-- | Haskell to C.
+newlineToC :: Newline -> CUInt
+newlineToC NewlineCr      = pcre2_NEWLINE_CR
+newlineToC NewlineLf      = pcre2_NEWLINE_LF
+newlineToC NewlineCrlf    = pcre2_NEWLINE_CRLF
+newlineToC NewlineAny     = pcre2_NEWLINE_ANY
+newlineToC NewlineAnyCrlf = pcre2_NEWLINE_ANYCRLF
+newlineToC NewlineNul     = pcre2_NEWLINE_NUL
+
+-- | Input for user-defined callouts.
+data CalloutInfo
+    = CalloutInfo {
+        -- | The index of which capture we\'re on.  Note that callouts are never
+        -- run for the 0th capture.
+        calloutIndex :: CalloutIndex,
+        -- | The captures that have been set so far.
+        calloutCaptures :: NonEmpty (Maybe Text),
+        -- | The original subject.
+        calloutSubject :: Text,
+        -- | The name of the most recently passed @(*MARK)@, @(*PRUNE)@, or
+        -- @(*THEN)@, if any.
+        calloutMark :: Maybe Text,
+        -- | Is this the first callout after the start of matching?
+        calloutIsFirst :: Bool,
+        -- | Has a backtrack occurred since the previous callout, or the
+        -- beginning of matching if no previous callouts?
+        calloutBacktracked :: Bool}
+    deriving (Show, Eq)
+
+-- | What caused the callout.
+data CalloutIndex
+    = CalloutNumber Int -- ^ Numbered capture.
+    | CalloutName Text -- ^ Named capture.
+    | CalloutAuto Int Int -- ^ The item located at this half-open range of
+    -- offsets within the pattern.  See `AutoCallout`.
+    deriving (Show, Eq)
+
+-- | Callout functions return one of these values, which dictates what happens
+-- next in the match.
+data CalloutResult
+    = CalloutProceed -- ^ Keep going.
+    | CalloutNoMatchHere -- ^ Fail the current capture, but not the whole match.
+    -- For example, backtracking may occur.
+    | CalloutNoMatch -- ^ Fail the whole match.
+    deriving (Show, Eq)
+
+-- | Input for user-defined substitution callouts.
+data SubCalloutInfo
+    = SubCalloutInfo {
+        -- | The 1-based index of which substitution we\'re on.  Only goes past
+        -- 1 during global substitutions.
+        subCalloutSubsCount :: Int,
+        -- | The captures that have been set so far.
+        subCalloutCaptures :: NonEmpty (Maybe Text),
+        -- | The original subject.
+        subCalloutSubject :: Text,
+        -- | The replacement.
+        subCalloutReplacement :: Text}
+    deriving (Show, Eq)
+
+-- | Substitution callout functions return one of these values, which dictates
+-- what happens next in the substitution.
+data SubCalloutResult
+    = SubCalloutAccept -- ^ Succeed, and keep going if in global mode.
+    | SubCalloutSkip -- ^ Do not perform this substitution, but keep going if in
+    -- global mode.
+    | SubCalloutAbort -- ^ Do not perform this or any subsequent substitutions.
+    deriving (Show, Eq)
+
+-- ** Lower-level representation of options and C data
+
+type CompileContext = ForeignPtr Pcre2_compile_context
+type Code           = ForeignPtr Pcre2_code
+type MatchContext   = ForeignPtr Pcre2_match_context
+type MatchData      = ForeignPtr Pcre2_match_data
+
+-- | An `Option` can result in multiple \"plans\".
+applyOption :: Option -> [AppliedOption]
+applyOption = \case
+    NoOptions            -> []
+    TwoOptions opt0 opt1 -> applyOption opt0 ++ applyOption opt1
+
+    -- CompileOption
+    Anchored          -> [CompileOption pcre2_ANCHORED]
+    AllowEmptyClass   -> [CompileOption pcre2_ALLOW_EMPTY_CLASS]
+    AltBsuxLegacy     -> [CompileOption pcre2_ALT_BSUX]
+    AltCircumflex     -> [CompileOption pcre2_ALT_CIRCUMFLEX]
+    AltVerbNames      -> [CompileOption pcre2_ALT_VERBNAMES]
+    AutoCallout       -> [CompileOption pcre2_AUTO_CALLOUT]
+    Caseless          -> [CompileOption pcre2_CASELESS]
+    DollarEndOnly     -> [CompileOption pcre2_DOLLAR_ENDONLY]
+    DotAll            -> [CompileOption pcre2_DOTALL]
+    DupNames          -> [CompileOption pcre2_DUPNAMES]
+    EndAnchored       -> [CompileOption pcre2_ENDANCHORED]
+    Extended          -> [CompileOption pcre2_EXTENDED]
+    ExtendedMore      -> [CompileOption pcre2_EXTENDED_MORE]
+    FirstLine         -> [CompileOption pcre2_FIRSTLINE]
+    Literal           -> [CompileOption pcre2_LITERAL]
+    MatchUnsetBackRef -> [CompileOption pcre2_MATCH_UNSET_BACKREF]
+    Multiline         -> [CompileOption pcre2_MULTILINE]
+    NeverBackslashC   -> [CompileOption pcre2_NEVER_BACKSLASH_C]
+    NeverUcp          -> [CompileOption pcre2_NEVER_UCP]
+    NoAutoCapture     -> [CompileOption pcre2_NO_AUTO_CAPTURE]
+    NoAutoPossess     -> [CompileOption pcre2_NO_AUTO_POSSESS]
+    NoDotStarAnchor   -> [CompileOption pcre2_NO_DOTSTAR_ANCHOR]
+    NoStartOptimize   -> [CompileOption pcre2_NO_START_OPTIMIZE]
+    Ucp               -> [CompileOption pcre2_UCP]
+    Ungreedy          -> [CompileOption pcre2_UNGREEDY]
+    Utf               -> [CompileOption pcre2_UTF]
+
+    -- ExtraCompileOption
+    AltBsux            -> [CompileExtraOption pcre2_EXTRA_ALT_BSUX]
+    BadEscapeIsLiteral -> [CompileExtraOption pcre2_EXTRA_BAD_ESCAPE_IS_LITERAL]
+    EscapedCrIsLf      -> [CompileExtraOption pcre2_EXTRA_ESCAPED_CR_IS_LF]
+    MatchLine          -> [CompileExtraOption pcre2_EXTRA_MATCH_LINE]
+    MatchWord          -> [CompileExtraOption pcre2_EXTRA_MATCH_WORD]
+
+    -- CompileContextOption
+    Bsr bsr -> unary
+        CompileContextOption pcre2_set_bsr (bsrToC bsr)
+    MaxPatternLength len -> unary
+        CompileContextOption pcre2_set_max_pattern_length (fromIntegral len)
+    Newline newline -> unary
+        CompileContextOption pcre2_set_newline (newlineToC newline)
+    ParensLimit limit -> unary
+        CompileContextOption pcre2_set_parens_nest_limit (fromIntegral limit)
+
+    -- CompileRecGuardOption
+    UnsafeCompileRecGuard f -> [CompileRecGuardOption f]
+
+    -- MatchOption
+    NotBol             -> [MatchOption pcre2_NOTBOL]
+    NotEol             -> [MatchOption pcre2_NOTEOL]
+    NotEmpty           -> [MatchOption pcre2_NOTEMPTY]
+    NotEmptyAtStart    -> [MatchOption pcre2_NOTEMPTY_ATSTART]
+    PartialHard        -> [MatchOption pcre2_PARTIAL_HARD]
+    PartialSoft        -> [MatchOption pcre2_PARTIAL_SOFT]
+    SubReplacementOnly -> [MatchOption pcre2_SUBSTITUTE_REPLACEMENT_ONLY]
+    SubGlobal          -> [MatchOption pcre2_SUBSTITUTE_GLOBAL]
+    SubLiteral         -> [MatchOption pcre2_SUBSTITUTE_LITERAL]
+    SubUnknownUnset    -> [MatchOption pcre2_SUBSTITUTE_UNKNOWN_UNSET]
+    SubUnsetEmpty      -> [MatchOption pcre2_SUBSTITUTE_UNSET_EMPTY]
+
+    -- CalloutOption
+    UnsafeCallout f -> [CalloutOption f]
+
+    -- SubCalloutOption
+    UnsafeSubCallout f -> [SubCalloutOption f]
+
+    -- MatchContextOption
+    OffsetLimit limit -> CompileOption pcre2_USE_OFFSET_LIMIT : unary
+        MatchContextOption pcre2_set_offset_limit (fromIntegral limit)
+    HeapLimit limit -> unary
+        MatchContextOption pcre2_set_heap_limit (fromIntegral limit)
+    MatchLimit limit -> unary
+        MatchContextOption pcre2_set_match_limit (fromIntegral limit)
+    DepthLimit limit -> unary
+        MatchContextOption pcre2_set_depth_limit (fromIntegral limit)
+
+    where
+    unary ctor f x = (: []) $ ctor $ \ctx -> withForeignPtr ctx $ \ctxPtr ->
+        f ctxPtr x >>= check (== 0)
+
+-- | Intermediate representation of options expressing what effect they\'ll have
+-- on which stage of regex compilation\/execution.  Also provide fake @Prism'@s.
+data AppliedOption
+    = CompileOption CUInt
+    | CompileExtraOption CUInt
+    | CompileContextOption (CompileContext -> IO ())
+    | CompileRecGuardOption (Int -> IO Bool)
+    | MatchOption CUInt
+    | CalloutOption (CalloutInfo -> IO CalloutResult)
+    | SubCalloutOption (SubCalloutInfo -> IO SubCalloutResult)
+    | MatchContextOption (MatchContext -> IO ())
+
+_CompileOption f =
+    \case CompileOption x -> CompileOption <$> f x; o -> pure o
+_CompileExtraOption f =
+    \case CompileExtraOption x -> CompileExtraOption <$> f x; o -> pure o
+_CompileContextOption f =
+    \case CompileContextOption x -> CompileContextOption <$> f x; o -> pure o
+_CompileRecGuardOption f =
+    \case CompileRecGuardOption x -> CompileRecGuardOption <$> f x; o -> pure o
+_MatchOption f =
+    \case MatchOption x -> MatchOption <$> f x; o -> pure o
+_CalloutOption f =
+    \case CalloutOption x -> CalloutOption <$> f x; o -> pure o
+_SubCalloutOption f =
+    \case SubCalloutOption x -> SubCalloutOption <$> f x; o -> pure o
+_MatchContextOption f =
+    \case MatchContextOption x -> MatchContextOption <$> f x; o -> pure o
+
+-- ** Extracting options at the right times
+--
+-- $ExtractingOptionsAtTheRightTimes
+-- We interleave the extraction of options with the manipulation of foreign data
+-- en route to the target `Matcher` or `Subber`.
+
+-- | A `Monad` modeling both option extraction and foreign effects.
+type ExtractOpts = StateT [AppliedOption] IO
+
+-- | Use a fake @Prism'@ to extract a category of options.
+extractOptsOf :: Traversal' AppliedOption a -> ExtractOpts [a]
+extractOptsOf traversal = state $ partitionEithers . map discrim where
+    discrim opt = maybe (Right opt) Left $ preview traversal opt
+
+-- | Prepare to compile a `Code`.
+extractCompileEnv :: ExtractOpts CompileEnv
+extractCompileEnv = do
+    ctxUpds <- extractOptsOf _CompileContextOption
+    xtraOpts <- bitOr <$> extractOptsOf _CompileExtraOption
+    recGuard <- safeLast <$> extractOptsOf _CompileRecGuardOption
+
+    compileEnvCtx <- sequence $ do
+        guard $ not $ null ctxUpds && xtraOpts == 0 && null recGuard
+        Just $ liftIO $ do
+            ctx <- mkForeignPtr pcre2_compile_context_free $
+                pcre2_compile_context_create nullPtr
+
+            forM_ ctxUpds $ \update -> update ctx
+            when (xtraOpts /= 0) $ withForeignPtr ctx $ \ctxPtr ->
+                pcre2_set_compile_extra_options ctxPtr xtraOpts >>= check (== 0)
+
+            return ctx
+
+    compileEnvERef <- sequence $ do
+        ctx <- compileEnvCtx
+        f <- recGuard
+        Just $ liftIO $ do
+            eRef <- newIORef Nothing
+            fPtr <- mkFunPtr ctx $ mkRecursionGuard $ \depth _ -> do
+                resultOrE <- try $ do
+                    f <- evaluate f
+                    result <- f $ fromIntegral depth
+                    evaluate result
+                case resultOrE of
+                    Right success -> return $ if success then 0 else 1
+                    Left e        -> writeIORef eRef (Just e) >> return 1
+
+            withForeignPtr ctx $ \ctxPtr -> do
+                result <- pcre2_set_compile_recursion_guard ctxPtr fPtr nullPtr
+                check (== 0) result
+
+            return eRef
+
+    return $ CompileEnv {..}
+
+-- | Inputs to `Code` compilation besides the pattern.
+data CompileEnv = CompileEnv {
+    compileEnvCtx :: Maybe CompileContext,
+    -- | A register for catching exceptions thrown in recursion guards, if
+    -- needed.
+    compileEnvERef :: Maybe (IORef (Maybe SomeException))}
+
+-- | Compile a `Code`.
+extractCode :: Text -> CompileEnv -> ExtractOpts Code
+extractCode patt (CompileEnv {..}) = do
+    opts <- bitOr <$> extractOptsOf _CompileOption
+
+    liftIO $ mkForeignPtr pcre2_code_free $
+        Text.useAsPtr patt $ \pattPtr pattCUs ->
+        alloca $ \errorCodePtr ->
+        alloca $ \errorOffPtr ->
+        withForeignOrNullPtr compileEnvCtx $ \ctxPtr -> do
+            codePtr <- pcre2_compile
+                (castCUs pattPtr)
+                (fromIntegral pattCUs)
+                opts
+                errorCodePtr
+                errorOffPtr
+                ctxPtr
+            when (codePtr == nullPtr) $ do
+                -- Re-throw exception (if any) from recursion guard (if any)
+                forM_ compileEnvERef $ readIORef >=> mapM_ throwIO
+                -- Otherwise throw PCRE2 error
+                errorCode <- peek errorCodePtr
+                offCUs <- peek errorOffPtr
+                throwIO $ Pcre2CompileException errorCode patt offCUs
+
+            return codePtr
+
+-- | `Code` and auxiliary compiled data used in preparation for a match or
+-- substitution.  This remains constant for the lifetime of a `Matcher` or
+-- `Subber`.
+data MatchEnv = MatchEnv {
+    matchEnvCode       :: Code,
+    matchEnvOpts       :: CUInt,
+    matchEnvCtx        :: Maybe MatchContext,
+    matchEnvCallout    :: Maybe (CalloutInfo -> IO CalloutResult),
+    matchEnvSubCallout :: Maybe (SubCalloutInfo -> IO SubCalloutResult)}
+
+-- | Prepare a matching function.
+extractMatchEnv :: Code -> ExtractOpts MatchEnv
+extractMatchEnv matchEnvCode = do
+    matchEnvOpts <- bitOr <$> extractOptsOf _MatchOption
+
+    matchEnvCtx <- extractOptsOf _MatchContextOption >>= \case
+        []      -> return Nothing
+        ctxUpds -> liftIO $ Just <$> do
+            ctx <- mkForeignPtr pcre2_match_context_free $
+                pcre2_match_context_create nullPtr
+
+            forM_ ctxUpds $ \update -> update ctx
+
+            return ctx
+
+    matchEnvCallout <- safeLast <$> extractOptsOf _CalloutOption
+    matchEnvSubCallout <- safeLast <$> extractOptsOf _SubCalloutOption
+
+    return $ MatchEnv {..}
+
+-- | Helper for @assemble*@ functions.  Basically, extract all options and help
+-- produce a function that takes a `Text` subject and does something.
+assembleSubjFun
+    :: (MatchEnv -> Text -> IO a)
+    -> Option
+    -> Text
+    -> IO (Text -> IO a)
+assembleSubjFun mkSubjFun option patt =
+    runStateT extractAll (applyOption option) <&> \case
+        (subjFun, []) -> subjFun
+        _             -> error "BUG! Options not fully extracted"
+
+    where
+    extractAll = do
+        compileEnv <- extractCompileEnv
+        code <- extractCode patt compileEnv
+        matchEnv <- extractMatchEnv code
+
+        return $ mkSubjFun matchEnv
+
+-- | Produce a `Matcher`.
+assembleMatcher
+    :: Option
+    -> Text       -- ^ pattern
+    -> IO Matcher
+assembleMatcher = assembleSubjFun $ \matchEnv@(MatchEnv {..}) ->
+    let matchTempEnvWithSubj = mkMatchTempEnv matchEnv
+    in \subject -> withForeignPtr matchEnvCode $ \codePtr -> do
+        matchData <- mkForeignPtr pcre2_match_data_free $
+            pcre2_match_data_create_from_pattern codePtr nullPtr
+
+        MatchTempEnv {..} <- matchTempEnvWithSubj subject
+        result <-
+            Text.useAsPtr subject $ \subjPtr subjCUs ->
+            withForeignOrNullPtr matchTempEnvCtx $ \ctxPtr ->
+            withForeignPtr matchData $ \matchDataPtr -> pcre2_match
+                codePtr
+                (castCUs subjPtr)
+                (fromIntegral subjCUs)
+                0
+                matchEnvOpts
+                matchDataPtr
+                ctxPtr
+        maybeRethrow matchTempEnvRef
+
+        return (result, matchData)
+
+-- | A `Subber` works by first writing results to a reasonably-sized buffer.  If
+-- we run out of room, PCRE2 allows us to simulate the rest of the substitution
+-- without writing anything, in order to calculate how big the buffer actually
+-- has to be.  In this event, we rerun the substitution with a new,
+-- exactly-sized buffer.
+--
+-- One potential issue arising from two attempts is running effectful callouts
+-- twice.  We mitigate this by skipping callouts the second time:
+--
+-- * all capture callouts, since they had run during the simulation, and
+--
+-- * those substitution callouts that had run the first time.
+--
+-- Therefore, the first time, log the substitution callout indexes that had run
+-- along with their results, and replay the log the second time, returning those
+-- same results without re-incurring effects.
+assembleSubber
+    :: Text      -- ^ replacement
+    -> Option
+    -> Text      -- ^ pattern
+    -> IO Subber
+assembleSubber replacement =
+    assembleSubjFun $ \firstMatchEnv@(MatchEnv {..}) ->
+    -- Subber
+    \subject ->
+    withForeignPtr matchEnvCode $ \codePtr ->
+    Text.useAsPtr subject $ \subjPtr subjCUs ->
+    Text.useAsPtr replacement $ \replPtr replCUs ->
+    alloca $ \outLenPtr -> do
+        let checkAndGetOutput :: CInt -> PCRE2_SPTR -> IO (CInt, Text)
+            checkAndGetOutput 0      _         = return (0, subject)
+            checkAndGetOutput result outBufPtr = do
+                check (> 0) result
+                outLen <- peek outLenPtr
+                out <- Text.fromPtr (castCUs outBufPtr) (fromIntegral outLen)
+                return (result, out)
+
+            run :: CUInt -> Ptr Pcre2_match_context -> PCRE2_SPTR -> IO CInt
+            run curOpts ctxPtr outBufPtr = pcre2_substitute
+                codePtr
+                (castCUs subjPtr)
+                (fromIntegral subjCUs)
+                0
+                (matchEnvOpts .|. curOpts)
+                nullPtr
+                ctxPtr
+                (castCUs replPtr)
+                (fromIntegral replCUs)
+                outBufPtr
+                outLenPtr
+
+            -- Guess the size of the output to be <= 2x that of the subject.
+            initOutLen = Text.length subject * 2
+
+        poke outLenPtr $ fromIntegral initOutLen
+        MatchTempEnv {..} <- mkMatchTempEnv firstMatchEnv subject
+        firstAttempt <- withForeignOrNullPtr matchTempEnvCtx $ \ctxPtr ->
+            allocaArray initOutLen $ \outBufPtr -> do
+                result <- run pcre2_SUBSTITUTE_OVERFLOW_LENGTH ctxPtr outBufPtr
+                maybeRethrow matchTempEnvRef
+                if result == pcre2_ERROR_NOMEMORY
+                    then Left <$> case matchTempEnvRef of
+                        Nothing  -> return IM.empty
+                        Just ref -> calloutStateSubsLog <$> readIORef ref
+                    else Right <$> checkAndGetOutput result outBufPtr
+
+        case firstAttempt of
+            Right resultAndOutput -> return resultAndOutput
+            Left subsLog          -> do
+                -- The output was bigger than we guessed.  Try again.
+                computedOutLen <- fromIntegral <$> peek outLenPtr
+                let finalMatchEnv = firstMatchEnv {
+                        -- Do not run capture callouts again.
+                        matchEnvCallout = Nothing,
+                        -- Do not run any substitution callouts run previously.
+                        matchEnvSubCallout = fastFwd <$> matchEnvSubCallout}
+                    fastFwd f = \info ->
+                        case subsLog IM.!? subCalloutSubsCount info of
+                            Just result -> return result
+                            Nothing     -> f info
+                MatchTempEnv {..} <- mkMatchTempEnv finalMatchEnv subject
+                withForeignOrNullPtr matchTempEnvCtx $ \ctxPtr ->
+                    allocaArray computedOutLen $ \outBufPtr -> do
+                        result <- run 0 ctxPtr outBufPtr
+                        maybeRethrow matchTempEnvRef
+                        checkAndGetOutput result outBufPtr
+
+-- | Generate per-call data for @pcre2_match()@ etc., to accommodate callouts.
+--
+-- We need to save and inspect state that occurs in potentially concurrent
+-- matches.  This means a new state ref for each match, which means a new
+-- `FunPtr` to close on it, which means a new match context to set it to.
+mkMatchTempEnv
+    :: MatchEnv
+    -> Text -- ^ Callout info requires access to the original subject.
+    -> IO MatchTempEnv
+mkMatchTempEnv (MatchEnv {..})
+    | null matchEnvCallout && null matchEnvSubCallout = \_ -> return noCallouts
+    | otherwise                                       = \subject -> do
+        calloutStateRef <- newIORef $ CalloutState {
+            calloutStateException = Nothing,
+            calloutStateSubsLog   = IM.empty}
+        ctx <- mkForeignPtr pcre2_match_context_free ctxPtrForCallouts
+
+        -- Install C function pointers in the @pcre2_match_context@.  When
+        -- dereferenced and called, they will force the user-supplied Haskell
+        -- callout functions and their results, catching any exceptions and
+        -- saving them.
+
+        -- Install callout, if any
+        forM_ matchEnvCallout $ \f -> do
+            fPtr <- mkFunPtr ctx $ mkCallout $ \blockPtr _ -> do
+                info <- getCalloutInfo subject blockPtr
+                resultOrE <- try $ do
+                    f <- evaluate f
+                    result <- f info
+                    evaluate result
+                case resultOrE of
+                    Right result -> return $ case result of
+                        CalloutProceed     -> 0
+                        CalloutNoMatchHere -> 1
+                        CalloutNoMatch     -> pcre2_ERROR_NOMATCH
+                    Left e -> do
+                        modifyIORef' calloutStateRef $ \cst -> cst {
+                            calloutStateException = Just e}
+                        return pcre2_ERROR_CALLOUT
+            withForeignPtr ctx $ \ctxPtr ->
+                pcre2_set_callout ctxPtr fPtr nullPtr >>= check (== 0)
+
+        -- Install substitution callout, if any
+        forM_ matchEnvSubCallout $ \f -> do
+            fPtr <- mkFunPtr ctx $ mkCallout $ \blockPtr _ -> do
+                info <- getSubCalloutInfo subject blockPtr
+                resultOrE <- try $ do
+                    f <- evaluate f
+                    result <- f info
+                    evaluate result
+                case resultOrE of
+                    Right result -> do
+                        modifyIORef' calloutStateRef $ \cst -> cst {
+                            calloutStateSubsLog = IM.insert
+                                (subCalloutSubsCount info)
+                                result
+                                (calloutStateSubsLog cst)}
+                        return $ case result of
+                            SubCalloutAccept ->  0
+                            SubCalloutSkip   ->  1
+                            SubCalloutAbort  -> -1
+                    Left e -> do
+                        modifyIORef' calloutStateRef $ \cst -> cst {
+                            calloutStateException = Just e}
+                        return (-1)
+            withForeignPtr ctx $ \ctxPtr -> do
+                result <- pcre2_set_substitute_callout ctxPtr fPtr nullPtr
+                check (== 0) result
+
+        return $ MatchTempEnv {
+            matchTempEnvCtx = Just ctx,
+            matchTempEnvRef = Just calloutStateRef}
+
+    where
+    noCallouts = MatchTempEnv {
+        matchTempEnvCtx = matchEnvCtx,
+        matchTempEnvRef = Nothing}
+    ctxPtrForCallouts = case matchEnvCtx of
+        -- No pre-existing match context, so create one afresh.
+        Nothing -> pcre2_match_context_create nullPtr
+        -- Pre-existing match context, so copy it.
+        Just ctx -> withForeignPtr ctx pcre2_match_context_copy
+
+-- | Per-call data for @pcre2_match()@ etc.
+data MatchTempEnv = MatchTempEnv {
+    matchTempEnvCtx :: Maybe MatchContext,
+    matchTempEnvRef :: Maybe (IORef CalloutState)}
+
+-- | Data computed during callouts that will be stashed in an IORef and
+-- inspected after @pcre2_match()@ or similar completes.
+data CalloutState = CalloutState {
+    calloutStateException :: Maybe SomeException,
+    calloutStateSubsLog   :: IntMap SubCalloutResult}
+
+-- | FFI wrapper.
+foreign import ccall "wrapper" mkRecursionGuard
+    :: (CUInt -> Ptr a -> IO CInt)
+    -> IO (FunPtr (CUInt -> Ptr a -> IO CInt))
+
+-- | FFI wrapper.
+foreign import ccall "wrapper" mkCallout
+    :: (Ptr block -> Ptr a -> IO CInt)
+    -> IO (FunPtr (Ptr block -> Ptr a -> IO CInt))
+
+-- | Within a callout, marshal the original subject and @pcre2_callout_block@
+-- data to Haskell and present to the user function.  Ensure no pointers are
+-- leaked!
+getCalloutInfo :: Text -> Ptr Pcre2_callout_block -> IO CalloutInfo
+getCalloutInfo subject blockPtr = do
+    calloutIndex <- do
+        str <- pcre2_callout_block_callout_string blockPtr
+        if str == nullPtr
+            then pcre2_callout_block_callout_number blockPtr >>= \case
+                -- Auto callout
+                255 -> liftM2 CalloutAuto pattPos itemLen where
+                    pattPos = intVia pcre2_callout_block_pattern_position
+                    itemLen = intVia pcre2_callout_block_next_item_length
+                    intVia getter = fromIntegral <$> getter blockPtr
+                -- Numerical callout
+                number -> return $ CalloutNumber $ fromIntegral number
+            else do
+                -- String callout
+                len <- pcre2_callout_block_callout_string_length blockPtr
+                CalloutName <$> Text.fromPtr (castCUs str) (fromIntegral len)
+
+    let calloutSubject = subject
+
+    calloutCaptures <- do
+        ovecPtr <- pcre2_callout_block_offset_vector blockPtr
+        top <- pcre2_callout_block_capture_top blockPtr
+        forM (0 :| [1 .. fromIntegral top - 1]) $ \n -> do
+            start <- peekElemOff ovecPtr $ n * 2
+            if start == pcre2_UNSET
+                then return Nothing
+                else Just <$> do
+                    end <- peekElemOff ovecPtr $ n * 2 + 1
+                    return $ slice calloutSubject $ SliceRange
+                        (fromIntegral start)
+                        (fromIntegral end)
+
+    calloutMark <- do
+        ptr <- pcre2_callout_block_mark blockPtr
+        if ptr == nullPtr
+            then return Nothing
+            else Just <$> do
+                -- TODO Replace this with a more obviously best way to slurp a
+                -- zero-terminated region of memory into a `Text`, given
+                -- whatever the pcre2callout spec means by "zero-terminated".
+                len <- fix1 0 $ \go off -> peekElemOff ptr off >>= \case
+                    0 -> return off
+                    _ -> go $ off + 1
+                Text.fromPtr (castCUs ptr) (fromIntegral len)
+
+    flags <- pcre2_callout_block_callout_flags blockPtr
+    let calloutIsFirst = flags .&. pcre2_CALLOUT_STARTMATCH /= 0
+        calloutBacktracked = flags .&. pcre2_CALLOUT_BACKTRACK /= 0
+
+    return $ CalloutInfo {..}
+
+-- | Within a substitution callout, marshal the original subject and
+-- @pcre2_substitute_callout_block@ data to Haskell and present to the user
+-- function.  Ensure no pointers are leaked!
+getSubCalloutInfo
+    :: Text -> Ptr Pcre2_substitute_callout_block -> IO SubCalloutInfo
+getSubCalloutInfo subCalloutSubject blockPtr = do
+    subCalloutSubsCount <-
+        fromIntegral <$> pcre2_substitute_callout_block_subscount blockPtr
+
+    subCalloutCaptures <- do
+        ovecPtr <- pcre2_substitute_callout_block_ovector blockPtr
+        ovecCount <- pcre2_substitute_callout_block_oveccount blockPtr
+        forM (0 :| [1 .. fromIntegral ovecCount - 1]) $ \n -> do
+            start <- peekElemOff ovecPtr $ n * 2
+            if start == pcre2_UNSET
+                then return Nothing
+                else Just <$> do
+                    end <- peekElemOff ovecPtr $ n * 2 + 1
+                    return $ slice subCalloutSubject $ SliceRange
+                        (fromIntegral start)
+                        (fromIntegral end)
+
+    subCalloutReplacement <- do
+        outPtr <- pcre2_substitute_callout_block_output blockPtr
+        offsetsPtr <- pcre2_substitute_callout_block_output_offsets blockPtr
+        [start, end] <- forM [0, 1] $ peekElemOff offsetsPtr
+        Text.fromPtr
+            (castCUs $ advancePtr outPtr $ fromIntegral start)
+            (fromIntegral $ end - start)
+
+    return $ SubCalloutInfo {..}
+
+-- | If there was a callout and it threw an exception, rethrow it.
+maybeRethrow :: Maybe (IORef CalloutState) -> IO ()
+maybeRethrow = mapM_ $ readIORef >=> mapM_ throwIO . calloutStateException
+
+-- * Packaging @Matcher@s and @Subber@s as public API functions
+
+-- | The most general form of a matching function, which can also be used as a
+-- @Setter'@ to perform substitutions at the Haskell level.
+--
+-- When any capture is forced, all captures are forced in order to GC C data
+-- more promptly.  When we need /some/ captures but not /all/ captures, we can
+-- pass in a whitelist of the numbers of captures we want, thereby avoiding
+-- unnecessary allocations.
+--
+-- Internal only!  Users should not (have to) know about `Matcher`.
+_capturesInternal :: Matcher -> [Int] -> Traversal' Text (NonEmpty Text)
+_capturesInternal matcher whitelist f subject
+    | result == pcre2_ERROR_NOMATCH = pure subject
+    | result <= 0                   = throw $ Pcre2Exception result
+    | otherwise                     = f cs <&> \cs' ->
+        -- Swag foldl-as-foldr to create only as many segments as we need to
+        -- stitch back together and no more.
+        let triples = ovecEntries `NE.zip` cs `NE.zip` cs'
+        in Text.concat $ foldr mkSegments termSegments triples 0
+
+    where
+
+    (result, matchData) = unsafePerformIO $ matcher subject
+    cs = unsafePerformIO $ forM ovecEntries $ evaluate . slice subject
+    ovecEntries = unsafePerformIO $ getOvecEntriesAt whitelist matchData
+
+    mkSegments ((SliceRange off offEnd, c), c') r prevOffEnd
+        | off == fromIntegral pcre2_UNSET || c == c' =
+            -- This substring is unset or unchanged.  Keep going without making
+            -- cuts.
+            r prevOffEnd
+        | otherwise =
+            -- Emit the subject up until here, and the new substring, and keep
+            -- going, remembering where we are now.
+            thinSlice subject (SliceRange prevOffEnd off) : c' : r offEnd
+    termSegments off =
+        let offEnd = fromIntegral $ Text.length subject
+        -- If the terminal segment is empty, omit it altogether.  That way,
+        -- `Text.concat` can just return the subject without copying anything in
+        -- cases where no substring is changed.
+        in [thinSlice subject (SliceRange off offEnd) | off /= offEnd]
+
+-- | Strictly read specifically indexed captures' offsets from match results.
+-- Truncate indexes when they go out of bounds, to support infinite lists.
+getOvecEntriesAt :: [Int] -> MatchData -> IO (NonEmpty SliceRange)
+getOvecEntriesAt ns matchData = withForeignPtr matchData $ \matchDataPtr -> do
+    count <- fromIntegral <$> pcre2_get_ovector_count matchDataPtr
+
+    case NE.nonEmpty $ takeWhile (< count) ns of
+        Nothing -> error "BUG! Tried to get empty list of captures"
+        Just ns -> do
+            ovecPtr <- pcre2_get_ovector_pointer matchDataPtr
+
+            let peekOvec :: Int -> IO Text.I16
+                peekOvec = fmap fromIntegral . peekElemOff ovecPtr
+
+            forM ns $ \n -> liftM2 SliceRange
+                (peekOvec $ n * 2)
+                (peekOvec $ n * 2 + 1)
+
+-- | Helper to create non-Template Haskell API functions.  They all take options
+-- and a pattern, and then do something via a 'Matcher'.
+withMatcher :: (Matcher -> a) -> Option -> Text -> a
+withMatcher f option patt = f $ unsafePerformIO $ assembleMatcher option patt
+
+-- | Match a pattern to a subject and return a list of captures, or @[]@ if no
+-- match.
+captures :: Text -> Text -> [Text]
+captures = capturesOpt mempty
+
+-- | @capturesOpt mempty = captures@
+capturesOpt :: Option -> Text -> Text -> [Text]
+capturesOpt option patt = view $ _capturesOpt option patt . to NE.toList
+
+-- | Match a pattern to a subject and return a non-empty list of captures in an
+-- `Alternative`, or `empty` if no match.  The non-empty list constructor `:|`
+-- serves as a cue to differentiate the 0th capture from the others:
+--
+-- > let parseDate = capturesA "(\\d{4})-(\\d{2})-(\\d{2})"
+-- > in case parseDate "submitted 2020-10-20" of
+-- >     Just (date :| [y, m, d]) -> ...
+-- >     Nothing                  -> putStrLn "didn't match"
+capturesA :: (Alternative f) => Text -> Text -> f (NonEmpty Text)
+capturesA = capturesOptA mempty
+
+-- | @capturesOptA mempty = capturesA@
+capturesOptA :: (Alternative f) => Option -> Text -> Text -> f (NonEmpty Text)
+capturesOptA option patt = toAlternativeOf $ _capturesOpt option patt
+
+-- | Does the pattern match the subject?
+matches :: Text -> Text -> Bool
+matches = matchesOpt mempty
+
+-- | @matchesOpt mempty = matches@
+matchesOpt :: Option -> Text -> Text -> Bool
+matchesOpt = withMatcher $ \matcher -> has $ _capturesInternal matcher []
+
+-- | Match a pattern to a subject and return the portion that matched in an
+-- @Alternative@, or `empty` if no match.
+match :: (Alternative f) => Text -> Text -> f Text
+match = matchOpt mempty
+
+-- | @matchOpt mempty = match@
+matchOpt :: (Alternative f) => Option -> Text -> Text -> f Text
+matchOpt option patt = toAlternativeOf $ _matchOpt option patt
+
+-- | Perform at most one substitution.  See
+-- [the docs](https://pcre.org/current/doc/html/pcre2api.html#SEC36) for the
+-- special syntax of /replacement/.
+--
+-- >>> sub "(\\w+) calling the (\\w+)" "$2 calling the $1" "the pot calling the kettle black"
+-- "the kettle calling the pot black"
+sub
+    :: Text -- ^ pattern
+    -> Text -- ^ replacement
+    -> Text -- ^ subject
+    -> Text -- ^ result
+sub = subOpt mempty
+
+-- | Perform substitutions globally.
+--
+-- >>> gsub "a" "o" "apples and bananas"
+-- "opples ond bononos"
+gsub :: Text -> Text -> Text -> Text
+gsub = subOpt SubGlobal
+
+-- | @
+-- subOpt mempty = sub
+-- subOpt SubGlobal = gsub
+-- @
+subOpt :: Option -> Text -> Text -> Text -> Text
+subOpt option patt replacement = snd . unsafePerformIO . subber where
+    subber = unsafePerformIO $ assembleSubber replacement option patt
+
+-- | Given a pattern, produce an affine traversal (0 or 1 targets) that focuses
+-- from a subject to a potential non-empty list of captures.
+--
+-- Substitution works in the following way:  If a capture is set such that the
+-- new `Text` is not equal to the old one, a substitution occurs, otherwise it
+-- doesn\'t.  This matters in cases where a capture encloses another
+-- capture&#x2014;notably, /all/ parenthesized captures are enclosed by the 0th.
+--
+-- >>> threeAndMiddle = _captures ". (.) ."
+-- >>> "A A A" & threeAndMiddle .~ "A A A" :| ["B"]
+-- "A B A"
+-- >>> "A A A" & threeAndMiddle .~ "A B A" :| ["A"]
+-- "A B A"
+--
+-- Changing multiple overlapping captures won\'t do what you want and is
+-- unsupported.
+--
+-- Changing an unset capture is unsupported because the PCRE2 match API does not
+-- give location info about it.  Currently we ignore all such attempts.  (Native
+-- substitution functions like `sub` do not have this limitation.  See also
+-- `SubUnknownUnset` and `SubUnsetEmpty`.)
+--
+-- If the list becomes longer for some reason, the extra elements are ignored.
+-- If it\'s shortened, the absent elements are considered to be unchanged.
+--
+-- It's recommended that the list be modified capture-wise,
+-- using [@ix@](https://hackage.haskell.org/package/microlens/docs/Lens-Micro.html#v:ix).
+--
+-- > let madlibs = _captures "(\\w+) my (\\w+)"
+-- >
+-- > print $ "Well bust my buttons!" &~ do
+-- >     zoom madlibs $ do
+-- >         ix 1 . _head .= 'd'
+-- >         ix 2 %= Text.reverse
+-- >     _last .= '?'
+-- >
+-- > -- "Well dust my snottub?"
+_captures :: Text -> Traversal' Text (NonEmpty Text)
+_captures = _capturesOpt mempty
+
+-- | @_capturesOpt mempty = _captures@
+_capturesOpt :: Option -> Text -> Traversal' Text (NonEmpty Text)
+_capturesOpt = withMatcher $ \matcher -> _capturesInternal matcher [0 ..]
+
+-- | Given a pattern, produce an affine traversal (0 or 1 targets) that focuses
+-- from a subject to the portion of it that matches.
+--
+-- Equivalent to @\\patt -> `_captures` patt . ix 0@, but more efficient.
+_match :: Text -> Traversal' Text Text
+_match = _matchOpt mempty
+
+-- | @_matchOpt mempty = _match@
+_matchOpt :: Option -> Text -> Traversal' Text Text
+_matchOpt = withMatcher $ \matcher -> _capturesInternal matcher [0] . _headNE
+
+-- * Support for Template Haskell compile-time regex analysis
+
+-- | From options and pattern, determine parenthesized patterns\' names in
+-- order.
+predictCaptureNames :: Option -> Text -> IO [Maybe Text]
+predictCaptureNames option patt = do
+    code <- evalStateT
+        (extractCompileEnv >>= extractCode patt)
+        (applyOption option)
+
+    withForeignPtr code getCaptureNames
+
+-- | NOTE: The 0th capture is always named @Nothing@.
+getCaptureNames :: Ptr Pcre2_code -> IO [Maybe Text]
+getCaptureNames codePtr = do
+    nameCount <- getCodeInfo @CUInt codePtr pcre2_INFO_NAMECOUNT
+    nameEntrySize <- getCodeInfo @CUInt codePtr pcre2_INFO_NAMEENTRYSIZE
+    nameTable <- getCodeInfo @PCRE2_SPTR codePtr pcre2_INFO_NAMETABLE
+
+    -- Can't do [0 .. nameCount - 1] because it underflows when nameCount == 0
+    let indexes = takeWhile (< nameCount) [0 ..]
+    names <- fmap IM.fromList $ forM indexes $ \i -> do
+        let entryPtr = nameTable `advancePtr` fromIntegral (i * nameEntrySize)
+            groupNamePtr = entryPtr `advancePtr` 1
+        groupNumber <- peek entryPtr
+        groupNameLen <- lengthArray0 0 groupNamePtr
+        groupName <- Text.fromPtr
+            (castCUs groupNamePtr)
+            (fromIntegral groupNameLen)
+        return (fromIntegral groupNumber, groupName)
+
+    hiCaptNum <- getCodeInfo @CUInt codePtr pcre2_INFO_CAPTURECOUNT
+
+    return $ map (names IM.!?) [0 .. fromIntegral hiCaptNum]
+
+-- | Low-level access to compiled pattern info, per the docs.
+getCodeInfo :: (Storable a) => Ptr Pcre2_code -> CUInt -> IO a
+getCodeInfo codePtr what = alloca $ \wherePtr -> do
+    pcre2_pattern_info codePtr what wherePtr >>= check (== 0)
+    peek wherePtr
+
+-- | A wrapper around a list of captures that carries additional type-level
+-- information about the number and names of those captures.
+--
+-- This type is only intended to be created by
+-- `Text.Regex.Pcre2.regex`\/`Text.Regex.Pcre2._regex` and consumed by
+-- `Text.Regex.Pcre2.capture`\/`Text.Regex.Pcre2._capture`, relying on type
+-- inference.  Specifying the @info@ explicitly in a type signature is not
+-- supported&#x2014;the definition of `CapturesInfo` is not part of the public
+-- API and may change without warning.
+--
+-- After obtaining `Captures` it\'s recommended to immediately consume them and
+-- transform them into application-level data, to avoid leaking the types to top
+-- level and having to write signatures.  In times of need, \"@Captures _@\" may
+-- be written with the help of @{-\# LANGUAGE PartialTypeSignatures \#-}@.
+newtype Captures (info :: CapturesInfo) = Captures (NonEmpty Text)
+
+-- | The kind of `Captures`\'s @info@.
+type CapturesInfo = (Nat, [(Symbol, Nat)])
+
+-- | Look up the number of a capture at compile time, either by number or by
+-- name.  Throw a helpful 'TypeError' if the index doesn\'t exist.
+type family CaptNum (i :: k) (info :: CapturesInfo) :: Nat where
+    CaptNum (num :: Nat) '(hi, _) =
+        If (CmpNat num 0 == 'LT || CmpNat num hi == 'GT)
+            -- then
+            (TypeError (TypeLits.Text "No capture numbered " :<>: ShowType num))
+            -- else
+            num
+
+    CaptNum (name :: Symbol) '(_, '(name, num) ': _) = num
+    CaptNum (name :: Symbol) '(hi, _ ': kvs) = 1 + CaptNum name '(hi, kvs)
+    CaptNum (name :: Symbol) _ = TypeError
+        (TypeLits.Text "No capture named " :<>: ShowType name)
+
+    CaptNum _ _ = TypeError
+        (TypeLits.Text "Capture index must be a number (Nat) or name (Symbol)")
+
+-- | Safely lookup a capture in a `Captures` result obtained from a Template
+-- Haskell-generated matching function.
+--
+-- The ugly type signature may be interpreted like this:  /Given some capture/
+-- /group index @i@ and some @info@ about a regex, ensure that index exists and/
+-- /is resolved to the number @num@ at compile time.  Then, at runtime, get a/
+-- /capture group from a list of captures./
+--
+-- In practice the variable @i@ is specified by type application and the other
+-- variables are inferred.
+--
+-- > capture @3
+-- > capture @"bar"
+--
+-- Specifying a nonexistant number or name will result in a type error.
+capture :: forall i info num. (CaptNum i info ~ num, KnownNat num) =>
+    Captures info -> Text
+capture = view $ _capture @i
+
+-- | Like `capture` but focus from a `Captures` to a capture.
+_capture :: forall i info num. (CaptNum i info ~ num, KnownNat num) =>
+    Lens' (Captures info) Text
+_capture f (Captures cs) =
+    let (ls, c : rs) = NE.splitAt (fromInteger $ natVal @num Proxy) cs
+    in f c <&> \c' -> Captures $ NE.fromList $ ls ++ c' : rs
+
+-- * Exceptions
+
+-- | The root of the PCRE2 exception hierarchy.
+data SomePcre2Exception = forall e. (Exception e) => SomePcre2Exception e
+instance Show SomePcre2Exception where
+    show (SomePcre2Exception e) = show e
+instance Exception SomePcre2Exception
+
+-- | Vanilla PCRE2 exceptions with messages generated by the underlying C
+-- library.
+newtype Pcre2Exception = Pcre2Exception CInt
+instance Show Pcre2Exception where
+    show (Pcre2Exception x) = "pcre2: " ++ Text.unpack (getErrorMessage x)
+instance Exception Pcre2Exception where
+    toException = toException . SomePcre2Exception
+    fromException = fromException >=> \(SomePcre2Exception e) -> cast e
+
+-- | PCRE2 compile exceptions.  Along with a message stating the cause, we show
+-- the pattern with a cursor pointing at where the error is (if not after the
+-- last character).
+data Pcre2CompileException = Pcre2CompileException !CInt !Text !PCRE2_SIZE
+instance Show Pcre2CompileException where
+    show (Pcre2CompileException x patt offset) = intercalate "\n" $ [
+        "pcre2_compile: " ++ Text.unpack (getErrorMessage x),
+        replicate tab ' ' ++ Text.unpack patt] ++
+        [replicate (tab + offset') ' ' ++ "^" | offset' < Text.length patt]
+        where
+        tab = 20
+        offset' = fromIntegral offset
+instance Exception Pcre2CompileException where
+    toException = toException . SomePcre2Exception
+    fromException = fromException >=> \(SomePcre2Exception e) -> cast e
+
+-- | Built-in message corresponding to the integer error code.
+getErrorMessage :: CInt -> Text
+getErrorMessage errorCode = unsafePerformIO $ do
+    let bufCUs = 120
+    allocaBytes (bufCUs * 2) $ \bufPtr -> do
+        cus <- pcre2_get_error_message errorCode bufPtr (fromIntegral bufCUs)
+        Text.fromPtr (castCUs bufPtr) (fromIntegral cus)
+
+-- | Most PCRE2 C functions return an @int@ indicating a possible error.  Test
+-- it against a predicate, and throw an exception upon failure.
+check :: (CInt -> Bool) -> CInt -> IO ()
+check p x = unless (p x) $ throwIO $ Pcre2Exception x
+
+-- * PCRE2 compile-time config
+
+-- | Helper for getting PCRE2 compile-time config integers.
+getConfigNumeric :: CUInt -> CUInt
+getConfigNumeric what = unsafePerformIO $ alloca $ \ptr -> do
+    pcre2_config what ptr
+    peek ptr
+
+-- | Helper for getting PCRE2 compile-time config strings.
+getConfigString :: CUInt -> Maybe Text
+getConfigString what = unsafePerformIO $ do
+    len <- pcre2_config what nullPtr
+    if len == pcre2_ERROR_BADOPTION
+        then return Nothing
+        -- FIXME Do we really need "+ 1" here?
+        else allocaBytes (fromIntegral (len + 1) * 2) $ \ptr -> do
+            pcre2_config what ptr
+            Just <$> Text.fromPtr ptr (fromIntegral len - 1)
+
+-- | See `Bsr`.
+defaultBsr :: Bsr
+defaultBsr = bsrFromC $ getConfigNumeric pcre2_CONFIG_BSR
+
+-- | Which code widths PCRE2 is compiled to operate on.  Can be any combination
+-- of 8, 16, and 32.  Should be @[16]@ but provided here for completeness.
+compiledWidths :: [Int]
+compiledWidths =
+    let bitmap = getConfigNumeric pcre2_CONFIG_COMPILED_WIDTHS
+    in [w | (b, w) <- [(1, 8), (2, 16), (4, 32)], b .&. bitmap /= 0]
+
+-- | See `DepthLimit`.
+defaultDepthLimit :: Int
+defaultDepthLimit = fromIntegral $ getConfigNumeric pcre2_CONFIG_DEPTHLIMIT
+
+-- | See `HeapLimit`.
+defaultHeapLimit :: Int
+defaultHeapLimit = fromIntegral $ getConfigNumeric pcre2_CONFIG_HEAPLIMIT
+
+-- | Was PCRE2 built with JIT support?
+supportsJit :: Bool
+supportsJit = getConfigNumeric pcre2_CONFIG_JIT == 1
+
+-- | A nice description of the CPU architecture JIT support is compiled for, if
+-- any.
+jitTarget :: Maybe Text
+jitTarget = getConfigString pcre2_CONFIG_JITTARGET
+
+-- | Number of bytes used for internal linkage in compiled regexes.
+linkSize :: Int
+linkSize = fromIntegral $ getConfigNumeric pcre2_CONFIG_LINKSIZE
+
+-- | See `MatchLimit`.
+defaultMatchLimit :: Int
+defaultMatchLimit = fromIntegral $ getConfigNumeric pcre2_CONFIG_MATCHLIMIT
+
+-- | See `Newline`.
+defaultNewline :: Newline
+defaultNewline = newlineFromC $ getConfigNumeric pcre2_CONFIG_NEWLINE
+
+-- | See `NeverBackslashC`.
+defaultIsNeverBackslashC :: Bool
+defaultIsNeverBackslashC = getConfigNumeric pcre2_CONFIG_NEVER_BACKSLASH_C == 1
+
+-- | See `ParensLimit`.
+defaultParensLimit :: Int
+defaultParensLimit = fromIntegral $ getConfigNumeric pcre2_CONFIG_PARENSLIMIT
+
+-- | Size in bytes of PCRE2\'s built-in character processing tables.
+defaultTablesLength :: Int
+defaultTablesLength = fromIntegral $ getConfigNumeric pcre2_CONFIG_TABLES_LENGTH
+
+-- | Unicode version string such as @8.0.0@, if Unicode is supported at all.
+unicodeVersion :: Maybe Text
+unicodeVersion = case getConfigString pcre2_CONFIG_UNICODE_VERSION of
+    Just v | Text.unpack v == "Unicode not supported" -> Nothing
+    maybeV                                            -> maybeV
+
+-- | Was PCRE2 built with Unicode support?
+supportsUnicode :: Bool
+supportsUnicode = getConfigNumeric pcre2_CONFIG_UNICODE == 1
+
+-- | Version of the built-in C library.  The versioning scheme is that PCRE
+-- legacy is 8.x and PCRE2 is 10.x, so this should be @10.@/something/.
+pcreVersion :: Text
+pcreVersion = case getConfigString pcre2_CONFIG_VERSION of
+    Just v  -> v
+    Nothing -> error "pcreVersion: unable to get string"
diff --git a/src/hs/Text/Regex/Pcre2/TH.hs b/src/hs/Text/Regex/Pcre2/TH.hs
new file mode 100644
--- /dev/null
+++ b/src/hs/Text/Regex/Pcre2/TH.hs
@@ -0,0 +1,165 @@
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+module Text.Regex.Pcre2.TH where
+
+import           Control.Applicative        (Alternative(..))
+import           Data.IORef
+import           Data.Functor               ((<&>))
+import           Data.List.NonEmpty         (NonEmpty)
+import qualified Data.List.NonEmpty         as NE
+import           Data.Map.Lazy              (Map)
+import qualified Data.Map.Lazy              as Map
+import           Data.Text                  (Text)
+import qualified Data.Text                  as Text
+import           Language.Haskell.TH
+import           Language.Haskell.TH.Quote
+import           Language.Haskell.TH.Syntax
+import           System.IO.Unsafe           (unsafePerformIO)
+import           Text.Regex.Pcre2.Internal
+
+globalMatcherCache :: IORef (Map Text Matcher)
+globalMatcherCache = unsafePerformIO $ newIORef Map.empty
+
+memoMatcher :: Text -> Matcher
+memoMatcher patt = unsafePerformIO $ do
+    cache <- readIORef globalMatcherCache
+    case Map.lookup patt cache of
+        Just matcher -> return matcher
+        Nothing      -> do
+            let matcher = unsafePerformIO $ assembleMatcher mempty patt
+            atomicModifyIORef' globalMatcherCache $ \cache ->
+                (Map.insert patt matcher cache, ())
+            return matcher
+
+matcherQ :: String -> ExpQ
+matcherQ s = [e| memoMatcher $ Text.pack $(stringE s) |]
+
+predictCaptureNamesQ :: String -> Q [Maybe Text]
+predictCaptureNamesQ = runIO . predictCaptureNames mempty . Text.pack
+
+toKVs :: [Maybe Text] -> [(Int, Text)]
+toKVs names = [(number, name) | (number, Just name) <- zip [0 ..] names]
+
+capturesInfoQ :: String -> Q (Maybe Type)
+capturesInfoQ s = predictCaptureNamesQ s >>= \case
+    -- No named captures, so need for Captures, so no info.
+    [Nothing] -> return Nothing
+
+    -- Named captures.  Present
+    --     [Nothing, Just "foo", Just "bar", Nothing]
+    -- as
+    --     '(3, '[ '("foo", 1), '("bar", 2)]).
+    captureNames -> Just <$> promotedTupleT 2 `appT` hi `appT` kvs where
+        -- 3
+        hi = litT $ numTyLit $ fromIntegral $ length captureNames - 1
+        -- '[ '("foo", 1), '("bar", 2)]
+        kvs = foldr f promotedNilT $ toKVs captureNames where
+            -- '("foo", 1) ': ...
+            f (number, name) = appT $ appT promotedConsT $       -- ':
+                promotedTupleT 2                                 -- '(,)
+                    `appT` litT (strTyLit $ Text.unpack name)    -- "foo"
+                    `appT` litT (numTyLit $ fromIntegral number) -- 1
+
+-- | /__As an expression__/
+--
+-- > regex :: (Alternative f) => String -> Text -> f (Captures info)
+--
+-- in the presence of parenthesized captures, or
+--
+-- > regex :: (Alternative f) => String -> Text -> f Text
+--
+-- if there are none.  In other words, if there is more than the 0th capture,
+-- this behaves like `capturesA` (except returning an opaque `Captures` instead
+-- of a list), otherwise it behaves like `match`.
+--
+-- To retrieve an individual capture from a `Captures`, use `capture`.
+--
+-- > case [regex|(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})|] "submitted 2020-10-20" of
+-- >     Just cs ->
+-- >         let date = capture @0 cs
+-- >             year = read @Int $ Text.unpack $ capture @"y" cs
+-- >             ...
+--
+-- > forM_ ([regex|^\s+$|] line :: Maybe Text) $ \spaces ->
+-- >     error $ "line has spaces only: " ++ show spaces
+--
+-- /__As a pattern__/
+--
+-- This matches when the regex matches, whereupon any named captures are bound
+-- to variables of the same names.
+--
+-- > case "submitted 2020-10-20" of
+-- >     [regex|(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})|] ->
+-- >         let year = read @Int $ Text.unpack y
+-- >             ...
+--
+-- Note that it is not possible to access the 0th capture this way.  As a
+-- workaround, explicitly capture the whole pattern and name it.
+--
+-- If there are no named captures, this simply acts as a guard.
+regex :: QuasiQuoter
+regex = QuasiQuoter {
+    quoteExp = \s -> capturesInfoQ s >>= \case
+        Nothing -> [e|
+            let _cs = _capturesInternal $(matcherQ s) [0]
+            in toAlternativeOf $ _cs . _headNE |]
+        Just info -> [e|
+            let wrap cs = Captures cs :: Captures $(return info)
+                _cs = _capturesInternal $(matcherQ s) [0 ..]
+            in toAlternativeOf $ _cs . to wrap |],
+
+    quotePat = \s -> do
+        captureNames <- predictCaptureNamesQ s
+
+        case toKVs captureNames of
+            -- No named captures.  Test whether the string matches without
+            -- creating any new Text values.
+            [] -> viewP
+                [e| has $ _capturesInternal $(matcherQ s) [] |]
+                [p| True |]
+
+            -- One or more named captures.  Attempt to bind only those to local
+            -- variables of the same names.
+            numberedNames -> viewP e p where
+                (nums, names) = unzip numberedNames
+                e = [e|
+                    let _cs = _capturesInternal $(matcherQ s) $(liftData nums)
+                    in view $ _cs . to NE.toList |]
+                p = listP $ map (varP . mkName . Text.unpack) names,
+
+    quoteType = const $ fail "regex: cannot produce a type",
+
+    quoteDec = const $ fail "regex: cannot produce declarations"}
+
+-- | A lens variant of `regex`.  Can only be used as an expression.
+--
+-- > _regex :: String -> Traversal' Text (Captures info)
+-- > _regex :: String -> Traversal' Text Text
+--
+-- > import Control.Lens
+-- > import Data.Text.Lens
+-- >
+-- > embeddedNumber :: Traversal' String Int
+-- > embeddedNumber = packed . [_regex|\d+|] . unpacked . _Show
+-- >
+-- > main :: IO ()
+-- > main = putStrLn $ "There are 14 competing standards" & embeddedNumber %~ (+ 1)
+-- >
+-- > -- There are 15 competing standards
+--
+_regex :: QuasiQuoter
+_regex = QuasiQuoter {
+    quoteExp = \s -> capturesInfoQ s >>= \case
+        Nothing   -> [e| _capturesInternal $(matcherQ s) [0] . _headNE |]
+        Just info -> [e|
+            let wrapped :: Lens' (NonEmpty Text) (Captures $(return info))
+                wrapped f cs = f (Captures cs) <&> \(Captures cs') -> cs'
+            in _capturesInternal $(matcherQ s) [0 ..] . wrapped |],
+
+    quotePat = const $ fail "_regex: cannot produce a pattern",
+
+    quoteType = const $ fail "_regex: cannot produce a type",
+
+    quoteDec = const $ fail "_regex: cannot produce declarations"}
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,220 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE ViewPatterns #-}
+
+module Main where
+
+import           Control.Applicative    (Alternative)
+import           Control.Exception      (catch, evaluate, handle)
+import           Control.Monad.RWS.Lazy (ask, evalRWS, forM_, tell, void)
+import           Data.IORef
+import           Data.List.NonEmpty     (NonEmpty(..))
+import           Data.Text              (Text)
+import qualified Data.Text              as Text
+import           Lens.Micro.Platform
+import           Test.Hspec
+import           Text.Regex.Pcre2
+
+main :: IO ()
+main = hspec $ do
+    let submitted = "submitted 2020-10-20"
+
+    describe "partial application" $ do
+        it "only causes one compilation" $ do
+            onlyCausesOneCompilation $ \option ->
+                matchesOpt option "foo"
+
+        it "only causes one compilation (point-free expression)" $ do
+            onlyCausesOneCompilation $ \option ->
+                (||) <$> Text.null <*> matchesOpt option "foo"
+
+    describe "basic matching" $ do
+        -- verifies that NotEmpty makes a difference, see below
+        it "matches an empty pattern to an empty subject" $ do
+            match "" "" `shouldBe` Just ""
+
+        it "works using matches" $ do
+            matches "(?i)foo" "FOO" `shouldBe` True
+
+        it "works using capturesA" $ do
+            case capturesA "(\\d{4})-(\\d{2})-(\\d{2})" submitted of
+                Just ne -> ne `shouldBe` "2020-10-20" :| ["2020", "10", "20"]
+                Nothing -> expectationFailure "didn't match"
+
+    describe "lens-powered matching" $ do
+        let _nee :: Traversal' Text Text
+            _nee = _match "(?i)\\bnee\\b"
+            promptNee = traverseOf (_nee . unpacked) $ \s -> tell [s] >> ask
+
+        it "can accrete effects while performing replacements" $ do
+            let result = evalRWS
+                    (promptNee "We are the knights who say...NEE!")
+                    "NOO"
+                    undefined
+            result `shouldBe` ("We are the knights who say...NOO!", ["NEE"])
+
+        it "signals match failure by not targeting anything" $ do
+            let result = evalRWS
+                    (promptNee "Shhhhh")
+                    undefined
+                    undefined
+            result `shouldBe` ("Shhhhh", [])
+
+        it "does not substitute when setting equal Text" $ do
+            let threeAndMiddle = _captures ". (.) ."
+            ("A A A" & threeAndMiddle .~ "A A A" :| ["B"]) `shouldBe` "A B A"
+            ("A A A" & threeAndMiddle .~ "A B A" :| ["A"]) `shouldBe` "A B A"
+
+    describe "option handling" $ do
+        it "includes compile options" $ do
+            matchOpt Ungreedy "a+" "aaa" `shouldBe` Just "a"
+
+        it "includes extra compile options" $ do
+            matchOpt BadEscapeIsLiteral "\\j" "\\j" `shouldBe` Just "j"
+
+        it "includes compile context options" $ do
+            let otherBsr
+                    | defaultBsr == BsrUnicode = BsrAnyCrlf
+                    | otherwise                = BsrUnicode
+                lineSep = "\x2028"
+            matches "\\R" lineSep
+                `shouldNotBe` matchesOpt (Bsr otherBsr) "\\R" lineSep
+
+        -- We already know it includes compile recursion guards
+
+        it "includes match options" $ do
+            matchOpt NotEmpty "" "" `shouldBe` Nothing
+
+        it "includes callouts" $ do
+            calloutRanRef <- newIORef 0
+            let callout = UnsafeCallout $ \_ -> do
+                    modifyIORef calloutRanRef (+ 1)
+                    return CalloutProceed
+            matchOpt callout "(?C'foo')a(?C42)a" "aa" `shouldBe` Just "aa"
+            readIORef calloutRanRef `shouldReturn` 2
+
+        it "includes substitution callouts" $ do
+            subCalloutRanRef <- newIORef 0
+            let subCallout = UnsafeSubCallout $ \_ -> do
+                    modifyIORef subCalloutRanRef (+ 1)
+                    return SubCalloutAccept
+            subOpt (subCallout <> SubGlobal) "a" "b" "aa" `shouldBe` "bb"
+            readIORef subCalloutRanRef `shouldReturn` 2
+
+        it "includes match context options" $ do
+            matchOpt (OffsetLimit 10) "b" "aaaaaaaaaaab" `shouldBe` Nothing
+
+    describe "user errors" $ do
+        it "are thrown at match time" $ do
+            (broken @Maybe "foo" `seq` return ())
+                `shouldThrow` anyPcre2Exception
+
+        it "are catchable using Control.Exception.evaluate" $ do
+            let example = evaluate (broken "foo") `catch`
+                    \(_ :: SomePcre2Exception) -> return Nothing
+            example `shouldReturn` Nothing
+
+        it "are catchable using instance Alternative IO" $ do
+            let example = broken "foo" `catch`
+                    \(_ :: SomePcre2Exception) -> return "broken"
+            example `shouldReturn` "broken"
+
+    describe "native substitution" $ do
+        it "works using sub" $ do
+            let result = sub
+                    "(\\w+) calling the (\\w+)"
+                    "$2 calling the $1"
+                    "the pot calling the kettle black"
+            result `shouldBe` "the kettle calling the pot black"
+
+        it "works using gsub" $ do
+            gsub "a" "o" "apples and bananas" `shouldBe` "opples ond bononos"
+
+    describe "regex :: QuasiQuoter" $ do
+        context "as an expression" $ do
+            it "works with parenthesized captures" $ do
+                case [regex|(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})|] submitted of
+                    Nothing -> expectationFailure "regex didn't match"
+                    Just cs -> do
+                        let date = capture @0 cs
+                            year = read @Int $ Text.unpack $ capture @"y" cs
+                        (date, year) `shouldBe` ("2020-10-20", 2020)
+
+            it "works without parenthesized captures" $ do
+                let example = forM_ @Maybe ([regex|^\s+$|] "  ") $ \spaces ->
+                        error $ "line has spaces only: " ++ show spaces
+                example `shouldThrow` anyErrorCall
+
+        context "as a pattern" $ do
+            it "works with named captures" $ do
+                case submitted of
+                    [regex|(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})|] -> do
+                        let year = read @Int $ Text.unpack y
+                        year `shouldBe` 2020
+                    _ -> expectationFailure "regex didn't match"
+
+            it "works without named captures" $ do
+                case "abc" of
+                    [regex|a(b)c|] -> return ()
+                    _              -> expectationFailure "regex didn't match"
+
+    describe "_regex" $ do
+        it "works with parenthesized captures" $ do
+            -- Adapt the _captures example for use here
+            let result = "Well bust my buttons!" &~ do
+                    zoom [_regex|(\w+) my (\w+)|] $ do
+                        _capture @1 . _head .= 'd'
+                        _capture @2 %= Text.reverse
+                    _last .= '?'
+            result `shouldBe` "Well dust my snottub?"
+
+        it "works without parenthesized captures" $ do
+            let embeddedNumber :: Traversal' String Int
+                embeddedNumber = packed . [_regex|\d+|] . unpacked . _Show
+                result = "There are 14 competing standards"
+                    & embeddedNumber %~ (+ 1)
+            result `shouldBe` "There are 15 competing standards"
+
+    describe "an unset capture" $ do
+        it "is treated as empty" $ do
+            captures "(a)?" "" `shouldBe` ["", ""]
+
+        it "is unchanged via Traversal'" $ do
+            ("" & [_regex|(a)?|] . _capture @1 .~ "foo") `shouldBe` ""
+
+        it "permits other captures to be changed via Traversal'" $ do
+            ("" & [_regex|(a)?|] . _capture @0 .~ "foo") `shouldBe` "foo"
+
+onlyCausesOneCompilation :: (Option -> Text -> a) -> Expectation
+onlyCausesOneCompilation regexWithOpt = do
+    counter <- newIORef (0 :: Int)
+    let option = UnsafeCompileRecGuard $ \_ -> do
+            modifyIORef counter (+ 1)
+            return True
+        run = void . evaluate . regexWithOpt option
+        getCount = readIORef counter
+
+    run "foo"
+    countAfterOnce <- getCount
+    countAfterOnce `shouldSatisfy` (> 0) -- probably 2!
+
+    run "bar"
+    run "baz"
+    countAfterTwiceMore <- getCount
+    countAfterTwiceMore `shouldBe` countAfterOnce
+
+anyPcre2Exception :: Selector SomePcre2Exception
+anyPcre2Exception _ = True
+
+broken :: (Alternative f) => Text -> f Text
+broken = match "*"
+
+-- microlens doesn't have this yet as of 12/5/2020
+_Show :: (Read a, Show a) => Traversal' String a
+_Show f s = case reads s of
+    [(x, "")] -> show <$> f x
+    _         -> pure s
